diff --git a/Cargo.lock b/Cargo.lock index 7fa6f3e0f7..78ef44ca57 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -294,7 +294,7 @@ checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" name = "component" version = "0.0.0" dependencies = [ - "wasmprinter 0.212.0", + "wasmprinter 0.213.0", "wat", "wit-bindgen-rt", ] @@ -942,9 +942,9 @@ checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "logos" @@ -1302,6 +1302,9 @@ name = "semver" version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +dependencies = [ + "serde", +] [[package]] name = "serde" @@ -1564,7 +1567,7 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-compose" -version = "0.212.0" +version = "0.213.0" dependencies = [ "anyhow", "glob", @@ -1578,9 +1581,9 @@ dependencies = [ "serde_derive", "serde_yaml", "smallvec", - "wasm-encoder 0.212.0", - "wasmparser 0.212.0", - "wasmprinter 0.212.0", + "wasm-encoder 0.213.0", + "wasmparser 0.213.0", + "wasmprinter 0.213.0", "wat", "wit-component", ] @@ -1596,17 +1599,17 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.212.0" +version = "0.213.0" dependencies = [ "anyhow", "leb128", "tempfile", - "wasmparser 0.212.0", + "wasmparser 0.213.0", ] [[package]] name = "wasm-metadata" -version = "0.212.0" +version = "0.213.0" dependencies = [ "anyhow", "clap", @@ -1615,14 +1618,14 @@ dependencies = [ "serde_derive", "serde_json", "spdx", - "wasm-encoder 0.212.0", - "wasmparser 0.212.0", + "wasm-encoder 0.213.0", + "wasmparser 0.213.0", "wat", ] [[package]] name = "wasm-mutate" -version = "0.212.0" +version = "0.213.0" dependencies = [ "anyhow", "clap", @@ -1631,9 +1634,9 @@ dependencies = [ "log", "rand", "thiserror", - "wasm-encoder 0.212.0", - "wasmparser 0.212.0", - "wasmprinter 0.212.0", + "wasm-encoder 0.213.0", + "wasmparser 0.213.0", + "wasmprinter 0.213.0", "wat", ] @@ -1650,14 +1653,14 @@ dependencies = [ "num_cpus", "rand", "wasm-mutate", - "wasmparser 0.212.0", - "wasmprinter 0.212.0", + "wasmparser 0.213.0", + "wasmprinter 0.213.0", "wasmtime", ] [[package]] name = "wasm-shrink" -version = "0.212.0" +version = "0.213.0" dependencies = [ "anyhow", "blake3", @@ -1666,14 +1669,14 @@ dependencies = [ "log", "rand", "wasm-mutate", - "wasmparser 0.212.0", - "wasmprinter 0.212.0", + "wasmparser 0.213.0", + "wasmprinter 0.213.0", "wat", ] [[package]] name = "wasm-smith" -version = "0.212.0" +version = "0.213.0" dependencies = [ "anyhow", "arbitrary", @@ -1686,19 +1689,20 @@ dependencies = [ "rand", "serde", "serde_derive", - "wasm-encoder 0.212.0", - "wasmparser 0.212.0", - "wasmprinter 0.212.0", + "wasm-encoder 0.213.0", + "wasmparser 0.213.0", + "wasmprinter 0.213.0", "wat", ] [[package]] name = "wasm-tools" -version = "1.212.0" +version = "1.213.0" dependencies = [ "addr2line", "anyhow", "arbitrary", + "bitflags", "clap", "clap_complete", "cpp_demangle", @@ -1718,18 +1722,18 @@ dependencies = [ "tempfile", "termcolor", "wasm-compose", - "wasm-encoder 0.212.0", + "wasm-encoder 0.213.0", "wasm-metadata", "wasm-mutate", "wasm-shrink", "wasm-smith", - "wasmparser 0.212.0", - "wasmprinter 0.212.0", + "wasmparser 0.213.0", + "wasmprinter 0.213.0", "wast", "wat", "wit-component", "wit-encoder", - "wit-parser 0.212.0", + "wit-parser 0.213.0", "wit-smith", ] @@ -1741,8 +1745,8 @@ dependencies = [ "wasm-mutate", "wasm-shrink", "wasm-smith", - "wasmparser 0.212.0", - "wasmprinter 0.212.0", + "wasmparser 0.213.0", + "wasmprinter 0.213.0", "wast", "wat", ] @@ -1757,28 +1761,28 @@ dependencies = [ "libfuzzer-sys", "log", "tempfile", - "wasm-encoder 0.212.0", + "wasm-encoder 0.213.0", "wasm-mutate", "wasm-smith", - "wasmparser 0.212.0", - "wasmprinter 0.212.0", + "wasmparser 0.213.0", + "wasmprinter 0.213.0", "wasmtime", "wast", "wat", "wit-component", - "wit-parser 0.212.0", + "wit-parser 0.213.0", "wit-smith", ] [[package]] name = "wasm-wave" -version = "0.212.0" +version = "0.213.0" dependencies = [ "anyhow", "indexmap 2.2.6", "logos", "thiserror", - "wit-parser 0.212.0", + "wit-parser 0.213.0", ] [[package]] @@ -1797,7 +1801,7 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.212.0" +version = "0.213.0" dependencies = [ "ahash", "anyhow", @@ -1811,7 +1815,7 @@ dependencies = [ "rayon", "semver", "serde", - "wasm-encoder 0.212.0", + "wasm-encoder 0.213.0", "wast", "wat", ] @@ -1828,14 +1832,14 @@ dependencies = [ [[package]] name = "wasmprinter" -version = "0.212.0" +version = "0.213.0" dependencies = [ "anyhow", "diff", "rayon", "tempfile", "termcolor", - "wasmparser 0.212.0", + "wasmparser 0.213.0", "wast", "wat", ] @@ -2034,7 +2038,7 @@ dependencies = [ [[package]] name = "wast" -version = "212.0.0" +version = "213.0.0" dependencies = [ "anyhow", "bumpalo", @@ -2044,14 +2048,14 @@ dependencies = [ "memchr", "rand", "unicode-width", - "wasm-encoder 0.212.0", - "wasmparser 0.212.0", + "wasm-encoder 0.213.0", + "wasmparser 0.213.0", "wat", ] [[package]] name = "wat" -version = "1.212.0" +version = "1.213.0" dependencies = [ "wast", ] @@ -2188,7 +2192,7 @@ dependencies = [ [[package]] name = "wit-component" -version = "0.212.0" +version = "0.213.0" dependencies = [ "anyhow", "bitflags", @@ -2201,23 +2205,24 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "wasm-encoder 0.212.0", + "wasm-encoder 0.213.0", "wasm-metadata", - "wasmparser 0.212.0", - "wasmprinter 0.212.0", + "wasmparser 0.213.0", + "wasmprinter 0.213.0", "wasmtime", "wast", "wat", - "wit-parser 0.212.0", + "wit-parser 0.213.0", ] [[package]] name = "wit-encoder" -version = "0.212.0" +version = "0.213.0" dependencies = [ "indoc", "pretty_assertions", "semver", + "serde", ] [[package]] @@ -2240,7 +2245,7 @@ dependencies = [ [[package]] name = "wit-parser" -version = "0.212.0" +version = "0.213.0" dependencies = [ "anyhow", "env_logger", @@ -2254,9 +2259,9 @@ dependencies = [ "serde_derive", "serde_json", "unicode-xid", - "wasmparser 0.212.0", + "wasmparser 0.213.0", "wat", - "wit-parser 0.212.0", + "wit-parser 0.213.0", ] [[package]] @@ -2267,13 +2272,13 @@ dependencies = [ "env_logger", "libfuzzer-sys", "log", - "wasmprinter 0.212.0", - "wit-parser 0.212.0", + "wasmprinter 0.213.0", + "wit-parser 0.213.0", ] [[package]] name = "wit-smith" -version = "0.212.0" +version = "0.213.0" dependencies = [ "arbitrary", "clap", @@ -2281,7 +2286,7 @@ dependencies = [ "log", "semver", "wit-component", - "wit-parser 0.212.0", + "wit-parser 0.213.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index b9ba2fe4c3..5a84f9266c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasm-tools" -version = "1.212.0" +version = "1.213.0" authors = ["The Wasmtime Project Developers"] edition.workspace = true description = "CLI tools for interoperating with WebAssembly files" @@ -52,7 +52,7 @@ all = "allow" [workspace.package] edition = '2021' -version = "0.212.0" +version = "0.213.0" # Current policy for wasm-tools is the same as Wasmtime which is that this # number can be no larger than the current stable release of Rust minus 2. rust-version = "1.76.0" @@ -87,20 +87,20 @@ termcolor = "1.2.0" indoc = "2.0.5" gimli = "0.30.0" -wasm-compose = { version = "0.212.0", path = "crates/wasm-compose" } -wasm-encoder = { version = "0.212.0", path = "crates/wasm-encoder" } -wasm-metadata = { version = "0.212.0", path = "crates/wasm-metadata" } -wasm-mutate = { version = "0.212.0", path = "crates/wasm-mutate" } -wasm-shrink = { version = "0.212.0", path = "crates/wasm-shrink" } -wasm-smith = { version = "0.212.0", path = "crates/wasm-smith" } -wasmparser = { version = "0.212.0", path = "crates/wasmparser", default-features = false, features = ['std'] } -wasmprinter = { version = "0.212.0", path = "crates/wasmprinter" } -wast = { version = "212.0.0", path = "crates/wast" } -wat = { version = "1.212.0", path = "crates/wat" } -wit-component = { version = "0.212.0", path = "crates/wit-component" } -wit-encoder = { version = "0.212.0", path = "crates/wit-encoder" } -wit-parser = { version = "0.212.0", path = "crates/wit-parser" } -wit-smith = { version = "0.212.0", path = "crates/wit-smith" } +wasm-compose = { version = "0.213.0", path = "crates/wasm-compose" } +wasm-encoder = { version = "0.213.0", path = "crates/wasm-encoder" } +wasm-metadata = { version = "0.213.0", path = "crates/wasm-metadata" } +wasm-mutate = { version = "0.213.0", path = "crates/wasm-mutate" } +wasm-shrink = { version = "0.213.0", path = "crates/wasm-shrink" } +wasm-smith = { version = "0.213.0", path = "crates/wasm-smith" } +wasmparser = { version = "0.213.0", path = "crates/wasmparser", default-features = false, features = ['std'] } +wasmprinter = { version = "0.213.0", path = "crates/wasmprinter" } +wast = { version = "213.0.0", path = "crates/wast" } +wat = { version = "1.213.0", path = "crates/wat" } +wit-component = { version = "0.213.0", path = "crates/wit-component" } +wit-encoder = { version = "0.213.0", path = "crates/wit-encoder" } +wit-parser = { version = "0.213.0", path = "crates/wit-parser" } +wit-smith = { version = "0.213.0", path = "crates/wit-smith" } [dependencies] anyhow = { workspace = true } @@ -115,6 +115,7 @@ termcolor = { workspace = true } # Dependencies of `validate` wasmparser = { workspace = true, optional = true, features = ['validate'] } rayon = { workspace = true, optional = true } +bitflags = { workspace = true, optional = true } # Dependencies of `print` wasmprinter = { workspace = true } @@ -201,7 +202,7 @@ default = [ ] # Each subcommand is gated behind a feature and lists the dependencies it needs -validate = ['dep:wasmparser', 'rayon', 'dep:addr2line', 'dep:gimli'] +validate = ['dep:wasmparser', 'rayon', 'dep:addr2line', 'dep:gimli', 'dep:bitflags'] print = [] parse = [] smith = ['wasm-smith', 'arbitrary', 'dep:serde', 'dep:serde_derive', 'dep:serde_json'] diff --git a/crates/wasm-encoder/src/core/code.rs b/crates/wasm-encoder/src/core/code.rs index 12a4eae25a..8bfb8fdcf6 100644 --- a/crates/wasm-encoder/src/core/code.rs +++ b/crates/wasm-encoder/src/core/code.rs @@ -1087,6 +1087,122 @@ pub enum Instruction<'a> { ordering: Ordering, global_index: u32, }, + TableAtomicGet { + ordering: Ordering, + table_index: u32, + }, + TableAtomicSet { + ordering: Ordering, + table_index: u32, + }, + TableAtomicRmwXchg { + ordering: Ordering, + table_index: u32, + }, + TableAtomicRmwCmpxchg { + ordering: Ordering, + table_index: u32, + }, + StructAtomicGet { + ordering: Ordering, + struct_type_index: u32, + field_index: u32, + }, + StructAtomicGetS { + ordering: Ordering, + struct_type_index: u32, + field_index: u32, + }, + StructAtomicGetU { + ordering: Ordering, + struct_type_index: u32, + field_index: u32, + }, + StructAtomicSet { + ordering: Ordering, + struct_type_index: u32, + field_index: u32, + }, + StructAtomicRmwAdd { + ordering: Ordering, + struct_type_index: u32, + field_index: u32, + }, + StructAtomicRmwSub { + ordering: Ordering, + struct_type_index: u32, + field_index: u32, + }, + StructAtomicRmwAnd { + ordering: Ordering, + struct_type_index: u32, + field_index: u32, + }, + StructAtomicRmwOr { + ordering: Ordering, + struct_type_index: u32, + field_index: u32, + }, + StructAtomicRmwXor { + ordering: Ordering, + struct_type_index: u32, + field_index: u32, + }, + StructAtomicRmwXchg { + ordering: Ordering, + struct_type_index: u32, + field_index: u32, + }, + StructAtomicRmwCmpxchg { + ordering: Ordering, + struct_type_index: u32, + field_index: u32, + }, + ArrayAtomicGet { + ordering: Ordering, + array_type_index: u32, + }, + ArrayAtomicGetS { + ordering: Ordering, + array_type_index: u32, + }, + ArrayAtomicGetU { + ordering: Ordering, + array_type_index: u32, + }, + ArrayAtomicSet { + ordering: Ordering, + array_type_index: u32, + }, + ArrayAtomicRmwAdd { + ordering: Ordering, + array_type_index: u32, + }, + ArrayAtomicRmwSub { + ordering: Ordering, + array_type_index: u32, + }, + ArrayAtomicRmwAnd { + ordering: Ordering, + array_type_index: u32, + }, + ArrayAtomicRmwOr { + ordering: Ordering, + array_type_index: u32, + }, + ArrayAtomicRmwXor { + ordering: Ordering, + array_type_index: u32, + }, + ArrayAtomicRmwXchg { + ordering: Ordering, + array_type_index: u32, + }, + ArrayAtomicRmwCmpxchg { + ordering: Ordering, + array_type_index: u32, + }, + RefI31Shared, } impl Encode for Instruction<'_> { @@ -3319,6 +3435,266 @@ impl Encode for Instruction<'_> { ordering.encode(sink); global_index.encode(sink); } + Instruction::TableAtomicGet { + ordering, + table_index, + } => { + sink.push(0xFE); + sink.push(0x58); + ordering.encode(sink); + table_index.encode(sink); + } + Instruction::TableAtomicSet { + ordering, + table_index, + } => { + sink.push(0xFE); + sink.push(0x59); + ordering.encode(sink); + table_index.encode(sink); + } + Instruction::TableAtomicRmwXchg { + ordering, + table_index, + } => { + sink.push(0xFE); + sink.push(0x5A); + ordering.encode(sink); + table_index.encode(sink); + } + Instruction::TableAtomicRmwCmpxchg { + ordering, + table_index, + } => { + sink.push(0xFE); + sink.push(0x5B); + ordering.encode(sink); + table_index.encode(sink); + } + Instruction::StructAtomicGet { + ordering, + struct_type_index, + field_index, + } => { + sink.push(0xFE); + sink.push(0x5C); + ordering.encode(sink); + struct_type_index.encode(sink); + field_index.encode(sink); + } + Instruction::StructAtomicGetS { + ordering, + struct_type_index, + field_index, + } => { + sink.push(0xFE); + sink.push(0x5D); + ordering.encode(sink); + struct_type_index.encode(sink); + field_index.encode(sink); + } + Instruction::StructAtomicGetU { + ordering, + struct_type_index, + field_index, + } => { + sink.push(0xFE); + sink.push(0x5E); + ordering.encode(sink); + struct_type_index.encode(sink); + field_index.encode(sink); + } + Instruction::StructAtomicSet { + ordering, + struct_type_index, + field_index, + } => { + sink.push(0xFE); + sink.push(0x5F); + ordering.encode(sink); + struct_type_index.encode(sink); + field_index.encode(sink); + } + Instruction::StructAtomicRmwAdd { + ordering, + struct_type_index, + field_index, + } => { + sink.push(0xFE); + sink.push(0x60); + ordering.encode(sink); + struct_type_index.encode(sink); + field_index.encode(sink); + } + Instruction::StructAtomicRmwSub { + ordering, + struct_type_index, + field_index, + } => { + sink.push(0xFE); + sink.push(0x61); + ordering.encode(sink); + struct_type_index.encode(sink); + field_index.encode(sink); + } + Instruction::StructAtomicRmwAnd { + ordering, + struct_type_index, + field_index, + } => { + sink.push(0xFE); + sink.push(0x62); + ordering.encode(sink); + struct_type_index.encode(sink); + field_index.encode(sink); + } + Instruction::StructAtomicRmwOr { + ordering, + struct_type_index, + field_index, + } => { + sink.push(0xFE); + sink.push(0x63); + ordering.encode(sink); + struct_type_index.encode(sink); + field_index.encode(sink); + } + Instruction::StructAtomicRmwXor { + ordering, + struct_type_index, + field_index, + } => { + sink.push(0xFE); + sink.push(0x64); + ordering.encode(sink); + struct_type_index.encode(sink); + field_index.encode(sink); + } + Instruction::StructAtomicRmwXchg { + ordering, + struct_type_index, + field_index, + } => { + sink.push(0xFE); + sink.push(0x65); + ordering.encode(sink); + struct_type_index.encode(sink); + field_index.encode(sink); + } + Instruction::StructAtomicRmwCmpxchg { + ordering, + struct_type_index, + field_index, + } => { + sink.push(0xFE); + sink.push(0x66); + ordering.encode(sink); + struct_type_index.encode(sink); + field_index.encode(sink); + } + Instruction::ArrayAtomicGet { + ordering, + array_type_index, + } => { + sink.push(0xFE); + sink.push(0x67); + ordering.encode(sink); + array_type_index.encode(sink); + } + Instruction::ArrayAtomicGetS { + ordering, + array_type_index, + } => { + sink.push(0xFE); + sink.push(0x68); + ordering.encode(sink); + array_type_index.encode(sink); + } + Instruction::ArrayAtomicGetU { + ordering, + array_type_index, + } => { + sink.push(0xFE); + sink.push(0x69); + ordering.encode(sink); + array_type_index.encode(sink); + } + Instruction::ArrayAtomicSet { + ordering, + array_type_index, + } => { + sink.push(0xFE); + sink.push(0x6A); + ordering.encode(sink); + array_type_index.encode(sink); + } + Instruction::ArrayAtomicRmwAdd { + ordering, + array_type_index, + } => { + sink.push(0xFE); + sink.push(0x6B); + ordering.encode(sink); + array_type_index.encode(sink); + } + Instruction::ArrayAtomicRmwSub { + ordering, + array_type_index, + } => { + sink.push(0xFE); + sink.push(0x6C); + ordering.encode(sink); + array_type_index.encode(sink); + } + Instruction::ArrayAtomicRmwAnd { + ordering, + array_type_index, + } => { + sink.push(0xFE); + sink.push(0x6D); + ordering.encode(sink); + array_type_index.encode(sink); + } + Instruction::ArrayAtomicRmwOr { + ordering, + array_type_index, + } => { + sink.push(0xFE); + sink.push(0x6E); + ordering.encode(sink); + array_type_index.encode(sink); + } + Instruction::ArrayAtomicRmwXor { + ordering, + array_type_index, + } => { + sink.push(0xFE); + sink.push(0x6F); + ordering.encode(sink); + array_type_index.encode(sink); + } + Instruction::ArrayAtomicRmwXchg { + ordering, + array_type_index, + } => { + sink.push(0xFE); + sink.push(0x70); + ordering.encode(sink); + array_type_index.encode(sink); + } + Instruction::ArrayAtomicRmwCmpxchg { + ordering, + array_type_index, + } => { + sink.push(0xFE); + sink.push(0x71); + ordering.encode(sink); + array_type_index.encode(sink); + } + Instruction::RefI31Shared => { + sink.push(0xFE); + sink.push(0x1F); + } } } } diff --git a/crates/wasm-encoder/src/core/elements.rs b/crates/wasm-encoder/src/core/elements.rs index 28a1031ed8..6ed6e03e3b 100644 --- a/crates/wasm-encoder/src/core/elements.rs +++ b/crates/wasm-encoder/src/core/elements.rs @@ -18,6 +18,7 @@ use crate::{encode_section, ConstExpr, Encode, RefType, Section, SectionId}; /// minimum: 128, /// maximum: None, /// table64: false, +/// shared: false, /// }); /// /// let mut elements = ElementSection::new(); diff --git a/crates/wasm-encoder/src/core/tables.rs b/crates/wasm-encoder/src/core/tables.rs index 6b35915b0d..3bb2d58e3a 100644 --- a/crates/wasm-encoder/src/core/tables.rs +++ b/crates/wasm-encoder/src/core/tables.rs @@ -15,6 +15,7 @@ use crate::{encode_section, ConstExpr, Encode, RefType, Section, SectionId, ValT /// minimum: 128, /// maximum: None, /// table64: false, +/// shared: false, /// }); /// /// let mut module = Module::new(); @@ -87,6 +88,10 @@ pub struct TableType { pub minimum: u64, /// Maximum size, in elements, of this table pub maximum: Option, + /// Whether this table is shared or not. + /// + /// This is included the shared-everything-threads proposal. + pub shared: bool, } impl TableType { @@ -106,6 +111,9 @@ impl Encode for TableType { if self.maximum.is_some() { flags |= 0b001; } + if self.shared { + flags |= 0b010; + } if self.table64 { flags |= 0b100; } diff --git a/crates/wasm-encoder/src/reencode.rs b/crates/wasm-encoder/src/reencode.rs index 5c6a67116f..6c60ba550f 100644 --- a/crates/wasm-encoder/src/reencode.rs +++ b/crates/wasm-encoder/src/reencode.rs @@ -41,6 +41,10 @@ pub trait Reencode { utils::type_index(self, ty) } + fn component_type_index(&mut self, ty: u32) -> u32 { + utils::component_type_index(self, ty) + } + fn abstract_heap_type( &mut self, value: wasmparser::AbstractHeapType, @@ -69,6 +73,45 @@ pub trait Reencode { utils::component_primitive_val_type(self, ty) } + fn component_export_kind( + &mut self, + ty: wasmparser::ComponentExternalKind, + ) -> crate::component::ComponentExportKind { + utils::component_export_kind(self, ty) + } + + fn component_outer_alias_kind( + &mut self, + kind: wasmparser::ComponentOuterAliasKind, + ) -> crate::component::ComponentOuterAliasKind { + utils::component_outer_alias_kind(self, kind) + } + + fn component_val_type( + &mut self, + ty: wasmparser::ComponentValType, + ) -> crate::component::ComponentValType { + utils::component_val_type(self, ty) + } + + fn type_bounds(&mut self, ty: wasmparser::TypeBounds) -> crate::component::TypeBounds { + utils::type_bounds(self, ty) + } + + fn canonical_option( + &mut self, + ty: wasmparser::CanonicalOption, + ) -> crate::component::CanonicalOption { + utils::canonical_option(self, ty) + } + + fn component_type_ref( + &mut self, + ty: wasmparser::ComponentTypeRef, + ) -> crate::component::ComponentTypeRef { + utils::component_type_ref(self, ty) + } + fn const_expr( &mut self, const_expr: wasmparser::ConstExpr, @@ -806,6 +849,116 @@ pub mod utils { } } + pub fn component_export_kind( + _reencoder: &mut T, + ty: wasmparser::ComponentExternalKind, + ) -> crate::component::ComponentExportKind { + match ty { + wasmparser::ComponentExternalKind::Module => crate::ComponentExportKind::Module, + wasmparser::ComponentExternalKind::Func => crate::ComponentExportKind::Func, + wasmparser::ComponentExternalKind::Value => crate::ComponentExportKind::Value, + wasmparser::ComponentExternalKind::Type => crate::ComponentExportKind::Type, + wasmparser::ComponentExternalKind::Instance => crate::ComponentExportKind::Instance, + wasmparser::ComponentExternalKind::Component => crate::ComponentExportKind::Component, + } + } + + pub fn component_outer_alias_kind( + _reencoder: &mut T, + ty: wasmparser::ComponentOuterAliasKind, + ) -> crate::component::ComponentOuterAliasKind { + match ty { + wasmparser::ComponentOuterAliasKind::CoreModule => { + crate::component::ComponentOuterAliasKind::CoreModule + } + wasmparser::ComponentOuterAliasKind::CoreType => { + crate::component::ComponentOuterAliasKind::CoreType + } + wasmparser::ComponentOuterAliasKind::Type => { + crate::component::ComponentOuterAliasKind::Type + } + wasmparser::ComponentOuterAliasKind::Component => { + crate::ComponentOuterAliasKind::Component + } + } + } + + pub fn component_val_type( + reencoder: &mut T, + ty: wasmparser::ComponentValType, + ) -> crate::component::ComponentValType { + match ty { + wasmparser::ComponentValType::Type(u) => { + crate::component::ComponentValType::Type(reencoder.component_type_index(u)) + } + wasmparser::ComponentValType::Primitive(pty) => { + crate::component::ComponentValType::Primitive( + crate::component::PrimitiveValType::from(pty), + ) + } + } + } + + pub fn type_bounds( + reencoder: &mut T, + ty: wasmparser::TypeBounds, + ) -> crate::component::TypeBounds { + match ty { + wasmparser::TypeBounds::Eq(u) => { + crate::component::TypeBounds::Eq(reencoder.component_type_index(u)) + } + wasmparser::TypeBounds::SubResource => crate::component::TypeBounds::SubResource, + } + } + + pub fn component_type_ref( + reencoder: &mut T, + ty: wasmparser::ComponentTypeRef, + ) -> crate::component::ComponentTypeRef { + match ty { + wasmparser::ComponentTypeRef::Module(u) => { + crate::component::ComponentTypeRef::Module(reencoder.component_type_index(u)) + } + wasmparser::ComponentTypeRef::Func(u) => { + crate::component::ComponentTypeRef::Func(reencoder.component_type_index(u)) + } + wasmparser::ComponentTypeRef::Value(valty) => { + crate::component::ComponentTypeRef::Value(reencoder.component_val_type(valty)) + } + wasmparser::ComponentTypeRef::Type(bounds) => { + crate::component::ComponentTypeRef::Type(reencoder.type_bounds(bounds)) + } + wasmparser::ComponentTypeRef::Instance(u) => { + crate::component::ComponentTypeRef::Instance(reencoder.component_type_index(u)) + } + wasmparser::ComponentTypeRef::Component(u) => { + crate::component::ComponentTypeRef::Component(reencoder.component_type_index(u)) + } + } + } + + pub fn canonical_option( + reencoder: &mut T, + ty: wasmparser::CanonicalOption, + ) -> crate::component::CanonicalOption { + match ty { + wasmparser::CanonicalOption::UTF8 => crate::component::CanonicalOption::UTF8, + wasmparser::CanonicalOption::UTF16 => crate::component::CanonicalOption::UTF16, + wasmparser::CanonicalOption::CompactUTF16 => { + crate::component::CanonicalOption::CompactUTF16 + } + wasmparser::CanonicalOption::Memory(u) => { + crate::component::CanonicalOption::Memory(reencoder.memory_index(u)) + } + wasmparser::CanonicalOption::Realloc(u) => { + crate::component::CanonicalOption::Realloc(reencoder.function_index(u)) + } + wasmparser::CanonicalOption::PostReturn(u) => { + crate::component::CanonicalOption::PostReturn(reencoder.function_index(u)) + } + } + } + pub fn memory_index(_reencoder: &mut T, memory: u32) -> u32 { memory } @@ -916,6 +1069,10 @@ pub mod utils { ty } + pub fn component_type_index(_reencoder: &mut T, ty: u32) -> u32 { + ty + } + pub fn tag_type( reencoder: &mut T, tag_ty: wasmparser::TagType, @@ -1154,6 +1311,7 @@ pub mod utils { minimum: table_ty.initial, maximum: table_ty.maximum, table64: table_ty.table64, + shared: table_ty.shared, }) } @@ -1619,6 +1777,42 @@ pub mod utils { } } +impl From for crate::ComponentValType { + fn from(ty: wasmparser::ComponentValType) -> Self { + RoundtripReencoder.component_val_type(ty) + } +} + +impl From for crate::TypeBounds { + fn from(ty: wasmparser::TypeBounds) -> Self { + RoundtripReencoder.type_bounds(ty) + } +} + +impl From for crate::CanonicalOption { + fn from(opt: wasmparser::CanonicalOption) -> Self { + RoundtripReencoder.canonical_option(opt) + } +} + +impl From for crate::ComponentExportKind { + fn from(kind: wasmparser::ComponentExternalKind) -> Self { + RoundtripReencoder.component_export_kind(kind) + } +} + +impl From for crate::ComponentOuterAliasKind { + fn from(kind: wasmparser::ComponentOuterAliasKind) -> Self { + RoundtripReencoder.component_outer_alias_kind(kind) + } +} + +impl From for crate::ComponentTypeRef { + fn from(ty: wasmparser::ComponentTypeRef) -> Self { + RoundtripReencoder.component_type_ref(ty) + } +} + impl From for crate::PrimitiveValType { fn from(ty: wasmparser::PrimitiveValType) -> Self { RoundtripReencoder.component_primitive_val_type(ty) diff --git a/crates/wasm-mutate/src/mutators/translate.rs b/crates/wasm-mutate/src/mutators/translate.rs index 706e7629ad..d1ac04c532 100644 --- a/crates/wasm-mutate/src/mutators/translate.rs +++ b/crates/wasm-mutate/src/mutators/translate.rs @@ -156,6 +156,7 @@ pub fn table_type( minimum: ty.initial, maximum: ty.maximum, table64: ty.table64, + shared: ty.shared, }) } diff --git a/crates/wasm-smith/src/core.rs b/crates/wasm-smith/src/core.rs index 43acc72b11..2f8b552982 100644 --- a/crates/wasm-smith/src/core.rs +++ b/crates/wasm-smith/src/core.rs @@ -2542,6 +2542,7 @@ pub(crate) fn arbitrary_table_type( minimum, maximum, table64, + shared: false, // TODO: handle shared }) } diff --git a/crates/wasmparser/src/binary_reader.rs b/crates/wasmparser/src/binary_reader.rs index 4df0029072..3fa9a772c8 100644 --- a/crates/wasmparser/src/binary_reader.rs +++ b/crates/wasmparser/src/binary_reader.rs @@ -688,8 +688,18 @@ impl<'a> BinaryReader<'a> { Ok(Ieee64(value)) } + /// (internal) Reads a fixed-size WebAssembly string from the module. + fn internal_read_string(&mut self, len: usize) -> Result<&'a str> { + let bytes = self.read_bytes(len)?; + str::from_utf8(bytes).map_err(|_| { + BinaryReaderError::new("malformed UTF-8 encoding", self.original_position() - 1) + }) + } + /// Reads a WebAssembly string from the module. + /// /// # Errors + /// /// If `BinaryReader` has less than up to four bytes remaining, the string's /// length exceeds the remaining bytes, the string's length exceeds /// `limits::MAX_WASM_STRING_SIZE`, or the string contains invalid utf-8. @@ -701,10 +711,17 @@ impl<'a> BinaryReader<'a> { self.original_position() - 1, )); } - let bytes = self.read_bytes(len)?; - str::from_utf8(bytes).map_err(|_| { - BinaryReaderError::new("malformed UTF-8 encoding", self.original_position() - 1) - }) + return self.internal_read_string(len); + } + + /// Reads a unlimited WebAssembly string from the module. + /// + /// Note that this is similar to [`BinaryReader::read_string`] except that + /// it will not limit the size of the returned string by + /// `limits::MAX_WASM_STRING_SIZE`. + pub fn read_unlimited_string(&mut self) -> Result<&'a str> { + let len = self.read_var_u32()? as usize; + return self.internal_read_string(len); } #[cold] @@ -1710,6 +1727,85 @@ impl<'a> BinaryReader<'a> { 0x57 => { visitor.visit_global_atomic_rmw_cmpxchg(self.read_ordering()?, self.read_var_u32()?) } + 0x58 => visitor.visit_table_atomic_get(self.read_ordering()?, self.read_var_u32()?), + 0x59 => visitor.visit_table_atomic_set(self.read_ordering()?, self.read_var_u32()?), + 0x5a => { + visitor.visit_table_atomic_rmw_xchg(self.read_ordering()?, self.read_var_u32()?) + } + 0x5b => { + visitor.visit_table_atomic_rmw_cmpxchg(self.read_ordering()?, self.read_var_u32()?) + } + 0x5c => visitor.visit_struct_atomic_get( + self.read_ordering()?, + self.read_var_u32()?, + self.read_var_u32()?, + ), + 0x5d => visitor.visit_struct_atomic_get_s( + self.read_ordering()?, + self.read_var_u32()?, + self.read_var_u32()?, + ), + 0x5e => visitor.visit_struct_atomic_get_u( + self.read_ordering()?, + self.read_var_u32()?, + self.read_var_u32()?, + ), + 0x5f => visitor.visit_struct_atomic_set( + self.read_ordering()?, + self.read_var_u32()?, + self.read_var_u32()?, + ), + 0x60 => visitor.visit_struct_atomic_rmw_add( + self.read_ordering()?, + self.read_var_u32()?, + self.read_var_u32()?, + ), + 0x61 => visitor.visit_struct_atomic_rmw_sub( + self.read_ordering()?, + self.read_var_u32()?, + self.read_var_u32()?, + ), + 0x62 => visitor.visit_struct_atomic_rmw_and( + self.read_ordering()?, + self.read_var_u32()?, + self.read_var_u32()?, + ), + 0x63 => visitor.visit_struct_atomic_rmw_or( + self.read_ordering()?, + self.read_var_u32()?, + self.read_var_u32()?, + ), + 0x64 => visitor.visit_struct_atomic_rmw_xor( + self.read_ordering()?, + self.read_var_u32()?, + self.read_var_u32()?, + ), + 0x65 => visitor.visit_struct_atomic_rmw_xchg( + self.read_ordering()?, + self.read_var_u32()?, + self.read_var_u32()?, + ), + 0x66 => visitor.visit_struct_atomic_rmw_cmpxchg( + self.read_ordering()?, + self.read_var_u32()?, + self.read_var_u32()?, + ), + 0x67 => visitor.visit_array_atomic_get(self.read_ordering()?, self.read_var_u32()?), + 0x68 => visitor.visit_array_atomic_get_s(self.read_ordering()?, self.read_var_u32()?), + 0x69 => visitor.visit_array_atomic_get_u(self.read_ordering()?, self.read_var_u32()?), + 0x6a => visitor.visit_array_atomic_set(self.read_ordering()?, self.read_var_u32()?), + 0x6b => visitor.visit_array_atomic_rmw_add(self.read_ordering()?, self.read_var_u32()?), + 0x6c => visitor.visit_array_atomic_rmw_sub(self.read_ordering()?, self.read_var_u32()?), + 0x6d => visitor.visit_array_atomic_rmw_and(self.read_ordering()?, self.read_var_u32()?), + 0x6e => visitor.visit_array_atomic_rmw_or(self.read_ordering()?, self.read_var_u32()?), + 0x6f => visitor.visit_array_atomic_rmw_xor(self.read_ordering()?, self.read_var_u32()?), + 0x70 => { + visitor.visit_array_atomic_rmw_xchg(self.read_ordering()?, self.read_var_u32()?) + } + 0x71 => { + visitor.visit_array_atomic_rmw_cmpxchg(self.read_ordering()?, self.read_var_u32()?) + } + 0x72 => visitor.visit_ref_i31_shared(), _ => bail!(pos, "unknown 0xfe subopcode: 0x{code:x}"), }) diff --git a/crates/wasmparser/src/features.rs b/crates/wasmparser/src/features.rs index 6478cf9c91..be5e14641b 100644 --- a/crates/wasmparser/src/features.rs +++ b/crates/wasmparser/src/features.rs @@ -148,6 +148,13 @@ define_wasm_features! { pub component_model_nested_names: COMPONENT_MODEL_NESTED_NAMES(1 << 22) = false; /// Support for more than 32 flags per-type in the component model. pub component_model_more_flags: COMPONENT_MODEL_MORE_FLAGS(1 << 23) = false; + /// The WebAssembly legacy exception handling proposal (phase 1) + /// + /// # Note + /// + /// Support this feature as long as all leading browsers also support it + /// https://github.com/WebAssembly/exception-handling/blob/main/proposals/exception-handling/legacy/Exceptions.md + pub legacy_exceptions: LEGACY_EXCEPTIONS(1 << 24) = false; } } diff --git a/crates/wasmparser/src/lib.rs b/crates/wasmparser/src/lib.rs index 06b1a9add5..0b1c02db94 100644 --- a/crates/wasmparser/src/lib.rs +++ b/crates/wasmparser/src/lib.rs @@ -158,11 +158,11 @@ macro_rules! for_each_operator { @exceptions Throw { tag_index: u32 } => visit_throw @exceptions ThrowRef => visit_throw_ref // Deprecated old instructions from the exceptions proposal - @exceptions Try { blockty: $crate::BlockType } => visit_try - @exceptions Catch { tag_index: u32 } => visit_catch - @exceptions Rethrow { relative_depth: u32 } => visit_rethrow - @exceptions Delegate { relative_depth: u32 } => visit_delegate - @exceptions CatchAll => visit_catch_all + @legacy_exceptions Try { blockty: $crate::BlockType } => visit_try + @legacy_exceptions Catch { tag_index: u32 } => visit_catch + @legacy_exceptions Rethrow { relative_depth: u32 } => visit_rethrow + @legacy_exceptions Delegate { relative_depth: u32 } => visit_delegate + @legacy_exceptions CatchAll => visit_catch_all @mvp End => visit_end @mvp Br { relative_depth: u32 } => visit_br @mvp BrIf { relative_depth: u32 } => visit_br_if @@ -505,6 +505,33 @@ macro_rules! for_each_operator { @shared_everything_threads GlobalAtomicRmwXor { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_xor @shared_everything_threads GlobalAtomicRmwXchg { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_xchg @shared_everything_threads GlobalAtomicRmwCmpxchg { ordering: $crate::Ordering, global_index: u32 } => visit_global_atomic_rmw_cmpxchg + @shared_everything_threads TableAtomicGet { ordering: $crate::Ordering, table_index: u32 } => visit_table_atomic_get + @shared_everything_threads TableAtomicSet { ordering: $crate::Ordering, table_index: u32 } => visit_table_atomic_set + @shared_everything_threads TableAtomicRmwXchg { ordering: $crate::Ordering, table_index: u32 } => visit_table_atomic_rmw_xchg + @shared_everything_threads TableAtomicRmwCmpxchg { ordering: $crate::Ordering, table_index: u32 } => visit_table_atomic_rmw_cmpxchg + @shared_everything_threads StructAtomicGet { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_get + @shared_everything_threads StructAtomicGetS { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_get_s + @shared_everything_threads StructAtomicGetU { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_get_u + @shared_everything_threads StructAtomicSet { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_set + @shared_everything_threads StructAtomicRmwAdd { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_rmw_add + @shared_everything_threads StructAtomicRmwSub { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_rmw_sub + @shared_everything_threads StructAtomicRmwAnd { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_rmw_and + @shared_everything_threads StructAtomicRmwOr { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_rmw_or + @shared_everything_threads StructAtomicRmwXor { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_rmw_xor + @shared_everything_threads StructAtomicRmwXchg { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_rmw_xchg + @shared_everything_threads StructAtomicRmwCmpxchg { ordering: $crate::Ordering, struct_type_index: u32, field_index: u32 } => visit_struct_atomic_rmw_cmpxchg + @shared_everything_threads ArrayAtomicGet { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_get + @shared_everything_threads ArrayAtomicGetS { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_get_s + @shared_everything_threads ArrayAtomicGetU { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_get_u + @shared_everything_threads ArrayAtomicSet { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_set + @shared_everything_threads ArrayAtomicRmwAdd { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_rmw_add + @shared_everything_threads ArrayAtomicRmwSub { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_rmw_sub + @shared_everything_threads ArrayAtomicRmwAnd { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_rmw_and + @shared_everything_threads ArrayAtomicRmwOr { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_rmw_or + @shared_everything_threads ArrayAtomicRmwXor { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_rmw_xor + @shared_everything_threads ArrayAtomicRmwXchg { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_rmw_xchg + @shared_everything_threads ArrayAtomicRmwCmpxchg { ordering: $crate::Ordering, array_type_index: u32 } => visit_array_atomic_rmw_cmpxchg + @shared_everything_threads RefI31Shared => visit_ref_i31_shared // 0xFD operators // 128-bit SIMD diff --git a/crates/wasmparser/src/readers/core/names.rs b/crates/wasmparser/src/readers/core/names.rs index 986e89506c..d53211ad8a 100644 --- a/crates/wasmparser/src/readers/core/names.rs +++ b/crates/wasmparser/src/readers/core/names.rs @@ -33,7 +33,10 @@ pub struct Naming<'a> { impl<'a> FromReader<'a> for Naming<'a> { fn from_reader(reader: &mut BinaryReader<'a>) -> Result { let index = reader.read_var_u32()?; - let name = reader.read_string()?; + // This seems to match what browsers do where they don't limit the + // length of names in the `name` section while they do limit the names + // in the import and export section for example. + let name = reader.read_unlimited_string()?; Ok(Naming { index, name }) } } diff --git a/crates/wasmparser/src/readers/core/operators.rs b/crates/wasmparser/src/readers/core/operators.rs index fe77547662..9fa2731abe 100644 --- a/crates/wasmparser/src/readers/core/operators.rs +++ b/crates/wasmparser/src/readers/core/operators.rs @@ -88,6 +88,14 @@ impl Ieee32 { } } +impl From for Ieee32 { + fn from(value: f32) -> Self { + Ieee32 { + 0: u32::from_le_bytes(value.to_le_bytes()), + } + } +} + impl From for f32 { fn from(bits: Ieee32) -> f32 { f32::from_bits(bits.bits()) @@ -108,6 +116,14 @@ impl Ieee64 { } } +impl From for Ieee64 { + fn from(value: f64) -> Self { + Ieee64 { + 0: u64::from_le_bytes(value.to_le_bytes()), + } + } +} + impl From for f64 { fn from(bits: Ieee64) -> f64 { f64::from_bits(bits.bits()) diff --git a/crates/wasmparser/src/readers/core/tables.rs b/crates/wasmparser/src/readers/core/tables.rs index 6c144a578f..7df2a76707 100644 --- a/crates/wasmparser/src/readers/core/tables.rs +++ b/crates/wasmparser/src/readers/core/tables.rs @@ -68,10 +68,11 @@ impl<'a> FromReader<'a> for TableType { let element_type = reader.read()?; let pos = reader.original_position(); let flags = reader.read_u8()?; - if (flags & !0b101) != 0 { + if (flags & !0b111) != 0 { bail!(pos, "invalid table resizable limits flags"); } let has_max = (flags & 0b001) != 0; + let shared = (flags & 0b010) != 0; let table64 = (flags & 0b100) != 0; Ok(TableType { element_type, @@ -88,6 +89,7 @@ impl<'a> FromReader<'a> for TableType { } else { Some(reader.read_var_u32()?.into()) }, + shared, }) } } diff --git a/crates/wasmparser/src/readers/core/types.rs b/crates/wasmparser/src/readers/core/types.rs index f85ca09319..7acc612847 100644 --- a/crates/wasmparser/src/readers/core/types.rs +++ b/crates/wasmparser/src/readers/core/types.rs @@ -1700,6 +1700,10 @@ pub struct TableType { /// For 32-bit tables (when `table64` is `false`) this is guaranteed to /// be at most `u32::MAX` for valid types. pub maximum: Option, + /// Whether this table is shared or not. + /// + /// This is included the shared-everything-threads proposal. + pub shared: bool, } impl TableType { diff --git a/crates/wasmparser/src/validator.rs b/crates/wasmparser/src/validator.rs index 4396cb51f4..de9e1e42cc 100644 --- a/crates/wasmparser/src/validator.rs +++ b/crates/wasmparser/src/validator.rs @@ -1537,6 +1537,7 @@ mod tests { maximum: None, element_type: RefType::FUNCREF, table64: false, + shared: false, } ); diff --git a/crates/wasmparser/src/validator/core.rs b/crates/wasmparser/src/validator/core.rs index 4c78eaf4a9..003dbe5916 100644 --- a/crates/wasmparser/src/validator/core.rs +++ b/crates/wasmparser/src/validator/core.rs @@ -146,7 +146,7 @@ impl ModuleState { offset: usize, ) -> Result<()> { self.module - .check_table_type(&mut table.ty, features, offset)?; + .check_table_type(&mut table.ty, features, types, offset)?; match &table.init { TableInit::RefNull => { @@ -870,7 +870,7 @@ impl Module { EntityType::Func(self.types[*type_index as usize]) } TypeRef::Table(t) => { - self.check_table_type(t, features, offset)?; + self.check_table_type(t, features, types, offset)?; EntityType::Table(*t) } TypeRef::Memory(t) => { @@ -892,10 +892,11 @@ impl Module { &self, ty: &mut TableType, features: &WasmFeatures, + types: &TypeList, offset: usize, ) -> Result<()> { - // the `funcref` value type is allowed all the way back to the MVP, so - // don't check it here + // The `funcref` value type is allowed all the way back to the MVP, so + // don't check it here. if ty.element_type != RefType::FUNCREF { self.check_ref_type(&mut ty.element_type, features, offset)? } @@ -914,6 +915,23 @@ impl Module { offset, )); } + + if ty.shared { + if !features.shared_everything_threads() { + return Err(BinaryReaderError::new( + "shared tables require the shared-everything-threads proposal", + offset, + )); + } + + if !types.reftype_is_shared(ty.element_type) { + return Err(BinaryReaderError::new( + "shared tables must have a shared element type", + offset, + )); + } + } + Ok(()) } diff --git a/crates/wasmparser/src/validator/operators.rs b/crates/wasmparser/src/validator/operators.rs index e0f2c7aeef..65c44b9216 100644 --- a/crates/wasmparser/src/validator/operators.rs +++ b/crates/wasmparser/src/validator/operators.rs @@ -28,7 +28,7 @@ use crate::{ Result, StorageType, StructType, SubType, TableType, TryTable, UnpackedIndex, ValType, VisitOperator, WasmFeatures, WasmModuleResources, V128, }; -use crate::{prelude::*, CompositeInnerType}; +use crate::{prelude::*, CompositeInnerType, Ordering}; use core::ops::{Deref, DerefMut}; pub(crate) struct OperatorValidator { @@ -121,6 +121,24 @@ pub enum FrameKind { /// /// This belongs to the Wasm exception handling proposal. TryTable, + /// A Wasm legacy `try` control block. + /// + /// # Note + /// + /// See: `WasmFeatures::legacy_exceptions` Note in `crates/wasmparser/src/features.rs` + LegacyTry, + /// A Wasm legacy `catch` control block. + /// + /// # Note + /// + /// See: `WasmFeatures::legacy_exceptions` Note in `crates/wasmparser/src/features.rs` + LegacyCatch, + /// A Wasm legacy `catch_all` control block. + /// + /// # Note + /// + /// See: `WasmFeatures::legacy_exceptions` Note in `crates/wasmparser/src/features.rs` + LegacyCatchAll, } struct OperatorValidatorTemp<'validator, 'resources, T> { @@ -740,17 +758,6 @@ where Ok(index_ty) } - /// Validates that the `table` is valid and returns the type it points to. - fn check_table_index(&self, table: u32) -> Result { - match self.resources.table_at(table) { - Some(ty) => Ok(ty), - None => bail!( - self.offset, - "unknown table {table}: table index out of bounds" - ), - } - } - fn check_floats_enabled(&self) -> Result<()> { if !self.features.floats() { bail!(self.offset, "floating-point instruction disallowed"); @@ -874,7 +881,7 @@ where type_index: u32, table_index: u32, ) -> Result<&'resources FuncType> { - let tab = self.check_table_index(table_index)?; + let tab = self.table_type_at(table_index)?; if !self .resources .is_subtype(ValType::Ref(tab.element_type), ValType::FUNCREF) @@ -1155,6 +1162,52 @@ where Ok(ty) } + /// Common helper for checking the types of structs accessed with atomic RMW + /// instructions, which only allow `i32` and `i64` types. + fn check_struct_atomic_rmw( + &mut self, + op: &'static str, + struct_type_index: u32, + field_index: u32, + ) -> Result<()> { + let ty = self + .struct_field_at(struct_type_index, field_index)? + .element_type; + let field_ty = match ty { + StorageType::Val(ValType::I32) => ValType::I32, + StorageType::Val(ValType::I64) => ValType::I64, + _ => bail!( + self.offset, + "invalid type: `struct.atomic.rmw.{}` only allows `i32` and `i64`", + op + ), + }; + self.pop_operand(Some(field_ty))?; + self.pop_concrete_ref(true, struct_type_index)?; + self.push_operand(field_ty)?; + Ok(()) + } + + /// Common helper for checking the types of arrays accessed with atomic RMW + /// instructions, which only allow `i32` and `i64`. + fn check_array_atomic_rmw(&mut self, op: &'static str, type_index: u32) -> Result<()> { + let ty = self.array_type_at(type_index)?.0.element_type; + let elem_ty = match ty { + StorageType::Val(ValType::I32) => ValType::I32, + StorageType::Val(ValType::I64) => ValType::I64, + _ => bail!( + self.offset, + "invalid type: `array.atomic.rmw.{}` only allows `i32` and `i64`", + op + ), + }; + self.pop_operand(Some(elem_ty))?; + self.pop_operand(Some(ValType::I32))?; + self.pop_concrete_ref(true, type_index)?; + self.push_operand(elem_ty)?; + Ok(()) + } + fn element_type_at(&self, elem_index: u32) -> Result { match self.resources.element_type_at(elem_index) { Some(ty) => Ok(ty), @@ -1235,6 +1288,17 @@ where } } + /// Validates that the `table` is valid and returns the type it points to. + fn table_type_at(&self, table: u32) -> Result { + match self.resources.table_at(table) { + Some(ty) => Ok(ty), + None => bail!( + self.offset, + "unknown table {table}: table index out of bounds" + ), + } + } + fn params(&self, ty: BlockType) -> Result + 'resources> { Ok(match ty { BlockType::Empty | BlockType::Type(_) => Either::B(None.into_iter()), @@ -1322,6 +1386,7 @@ macro_rules! validate_proposal { (desc function_references) => ("function references"); (desc memory_control) => ("memory control"); (desc gc) => ("gc"); + (desc legacy_exceptions) => ("legacy exceptions"); } impl<'a, T> VisitOperator<'a> for WasmProposalValidator<'_, '_, T> @@ -1486,21 +1551,6 @@ where self.unreachable()?; Ok(()) } - fn visit_try(&mut self, _: BlockType) -> Self::Output { - bail!(self.offset, "unimplemented validation of deprecated opcode") - } - fn visit_catch(&mut self, _: u32) -> Self::Output { - bail!(self.offset, "unimplemented validation of deprecated opcode") - } - fn visit_rethrow(&mut self, _: u32) -> Self::Output { - bail!(self.offset, "unimplemented validation of deprecated opcode") - } - fn visit_delegate(&mut self, _: u32) -> Self::Output { - bail!(self.offset, "unimplemented validation of deprecated opcode") - } - fn visit_catch_all(&mut self) -> Self::Output { - bail!(self.offset, "unimplemented validation of deprecated opcode") - } fn visit_end(&mut self) -> Self::Output { let mut frame = self.pop_ctrl()?; @@ -1687,11 +1737,7 @@ where self.push_operand(ty)?; Ok(()) } - fn visit_global_atomic_get( - &mut self, - _ordering: crate::Ordering, - global_index: u32, - ) -> Self::Output { + fn visit_global_atomic_get(&mut self, _ordering: Ordering, global_index: u32) -> Self::Output { self.visit_global_get(global_index)?; // No validation of `ordering` is needed because `global.atomic.get` can // be used on both shared and unshared globals. But we do need to limit @@ -1714,11 +1760,7 @@ where self.pop_operand(Some(ty.content_type))?; Ok(()) } - fn visit_global_atomic_set( - &mut self, - _ordering: crate::Ordering, - global_index: u32, - ) -> Self::Output { + fn visit_global_atomic_set(&mut self, _ordering: Ordering, global_index: u32) -> Self::Output { self.visit_global_set(global_index)?; // No validation of `ordering` is needed because `global.atomic.get` can // be used on both shared and unshared globals. @@ -3612,7 +3654,7 @@ where Ok(()) } fn visit_table_init(&mut self, segment: u32, table: u32) -> Self::Output { - let table = self.check_table_index(table)?; + let table = self.table_type_at(table)?; let segment_ty = self.element_type_at(segment)?; if !self .resources @@ -3636,8 +3678,8 @@ where Ok(()) } fn visit_table_copy(&mut self, dst_table: u32, src_table: u32) -> Self::Output { - let src = self.check_table_index(src_table)?; - let dst = self.check_table_index(dst_table)?; + let src = self.table_type_at(src_table)?; + let dst = self.table_type_at(dst_table)?; if !self.resources.is_subtype( ValType::Ref(src.element_type), ValType::Ref(dst.element_type), @@ -3659,21 +3701,51 @@ where Ok(()) } fn visit_table_get(&mut self, table: u32) -> Self::Output { - let table = self.check_table_index(table)?; + let table = self.table_type_at(table)?; debug_assert_type_indices_are_ids(table.element_type.into()); self.pop_operand(Some(table.index_type()))?; self.push_operand(table.element_type)?; Ok(()) } + fn visit_table_atomic_get(&mut self, _ordering: Ordering, table: u32) -> Self::Output { + self.visit_table_get(table)?; + // No validation of `ordering` is needed because `table.atomic.get` can + // be used on both shared and unshared tables. But we do need to limit + // which types can be used with this instruction. + let ty = self.table_type_at(table)?.element_type; + let supertype = RefType::ANYREF.shared().unwrap(); + if !self.resources.is_subtype(ty.into(), supertype.into()) { + bail!( + self.offset, + "invalid type: `table.atomic.get` only allows subtypes of `anyref`" + ); + } + Ok(()) + } fn visit_table_set(&mut self, table: u32) -> Self::Output { - let table = self.check_table_index(table)?; + let table = self.table_type_at(table)?; debug_assert_type_indices_are_ids(table.element_type.into()); self.pop_operand(Some(table.element_type.into()))?; self.pop_operand(Some(table.index_type()))?; Ok(()) } + fn visit_table_atomic_set(&mut self, _ordering: Ordering, table: u32) -> Self::Output { + self.visit_table_set(table)?; + // No validation of `ordering` is needed because `table.atomic.set` can + // be used on both shared and unshared tables. But we do need to limit + // which types can be used with this instruction. + let ty = self.table_type_at(table)?.element_type; + let supertype = RefType::ANYREF.shared().unwrap(); + if !self.resources.is_subtype(ty.into(), supertype.into()) { + bail!( + self.offset, + "invalid type: `table.atomic.set` only allows subtypes of `anyref`" + ); + } + Ok(()) + } fn visit_table_grow(&mut self, table: u32) -> Self::Output { - let table = self.check_table_index(table)?; + let table = self.table_type_at(table)?; debug_assert_type_indices_are_ids(table.element_type.into()); self.pop_operand(Some(table.index_type()))?; self.pop_operand(Some(table.element_type.into()))?; @@ -3681,18 +3753,51 @@ where Ok(()) } fn visit_table_size(&mut self, table: u32) -> Self::Output { - let table = self.check_table_index(table)?; + let table = self.table_type_at(table)?; self.push_operand(table.index_type())?; Ok(()) } fn visit_table_fill(&mut self, table: u32) -> Self::Output { - let table = self.check_table_index(table)?; + let table = self.table_type_at(table)?; debug_assert_type_indices_are_ids(table.element_type.into()); self.pop_operand(Some(table.index_type()))?; self.pop_operand(Some(table.element_type.into()))?; self.pop_operand(Some(table.index_type()))?; Ok(()) } + fn visit_table_atomic_rmw_xchg(&mut self, _ordering: Ordering, table: u32) -> Self::Output { + let table = self.table_type_at(table)?; + let elem_ty = table.element_type.into(); + debug_assert_type_indices_are_ids(elem_ty); + let supertype = RefType::ANYREF.shared().unwrap(); + if !self.resources.is_subtype(elem_ty, supertype.into()) { + bail!( + self.offset, + "invalid type: `table.atomic.rmw.xchg` only allows subtypes of `anyref`" + ); + } + self.pop_operand(Some(elem_ty))?; + self.pop_operand(Some(table.index_type()))?; + self.push_operand(elem_ty)?; + Ok(()) + } + fn visit_table_atomic_rmw_cmpxchg(&mut self, _ordering: Ordering, table: u32) -> Self::Output { + let table = self.table_type_at(table)?; + let elem_ty = table.element_type.into(); + debug_assert_type_indices_are_ids(elem_ty); + let supertype = RefType::EQREF.shared().unwrap(); + if !self.resources.is_subtype(elem_ty, supertype.into()) { + bail!( + self.offset, + "invalid type: `table.atomic.rmw.cmpxchg` only allows subtypes of `eqref`" + ); + } + self.pop_operand(Some(elem_ty))?; + self.pop_operand(Some(elem_ty))?; + self.pop_operand(Some(table.index_type()))?; + self.push_operand(elem_ty)?; + Ok(()) + } fn visit_struct_new(&mut self, struct_type_index: u32) -> Self::Output { let struct_ty = self.struct_type_at(struct_type_index)?; for ty in struct_ty.fields.iter().rev() { @@ -3726,6 +3831,32 @@ where self.pop_concrete_ref(true, struct_type_index)?; self.push_operand(field_ty.element_type.unpack()) } + fn visit_struct_atomic_get( + &mut self, + _ordering: Ordering, + struct_type_index: u32, + field_index: u32, + ) -> Self::Output { + self.visit_struct_get(struct_type_index, field_index)?; + // The `atomic` version has some additional type restrictions. + let ty = self + .struct_field_at(struct_type_index, field_index)? + .element_type; + let is_valid_type = match ty { + StorageType::Val(ValType::I32) | StorageType::Val(ValType::I64) => true, + StorageType::Val(v) => self + .resources + .is_subtype(v, RefType::ANYREF.shared().unwrap().into()), + _ => false, + }; + if !is_valid_type { + bail!( + self.offset, + "invalid type: `struct.atomic.get` only allows `i32`, `i64` and subtypes of `anyref`" + ); + } + Ok(()) + } fn visit_struct_get_s(&mut self, struct_type_index: u32, field_index: u32) -> Self::Output { let field_ty = self.struct_field_at(struct_type_index, field_index)?; if !field_ty.element_type.is_packed() { @@ -3737,6 +3868,21 @@ where self.pop_concrete_ref(true, struct_type_index)?; self.push_operand(field_ty.element_type.unpack()) } + fn visit_struct_atomic_get_s( + &mut self, + _ordering: Ordering, + struct_type_index: u32, + field_index: u32, + ) -> Self::Output { + self.visit_struct_get_s(struct_type_index, field_index)?; + // This instruction has the same type restrictions as the non-`atomic` version. + debug_assert!(matches!( + self.struct_field_at(struct_type_index, field_index)? + .element_type, + StorageType::I8 | StorageType::I16 + )); + Ok(()) + } fn visit_struct_get_u(&mut self, struct_type_index: u32, field_index: u32) -> Self::Output { let field_ty = self.struct_field_at(struct_type_index, field_index)?; if !field_ty.element_type.is_packed() { @@ -3748,6 +3894,21 @@ where self.pop_concrete_ref(true, struct_type_index)?; self.push_operand(field_ty.element_type.unpack()) } + fn visit_struct_atomic_get_u( + &mut self, + _ordering: Ordering, + struct_type_index: u32, + field_index: u32, + ) -> Self::Output { + self.visit_struct_get_s(struct_type_index, field_index)?; + // This instruction has the same type restrictions as the non-`atomic` version. + debug_assert!(matches!( + self.struct_field_at(struct_type_index, field_index)? + .element_type, + StorageType::I8 | StorageType::I16 + )); + Ok(()) + } fn visit_struct_set(&mut self, struct_type_index: u32, field_index: u32) -> Self::Output { let field_ty = self.struct_field_at(struct_type_index, field_index)?; if !field_ty.mutable { @@ -3757,6 +3918,129 @@ where self.pop_concrete_ref(true, struct_type_index)?; Ok(()) } + fn visit_struct_atomic_set( + &mut self, + _ordering: Ordering, + struct_type_index: u32, + field_index: u32, + ) -> Self::Output { + self.visit_struct_set(struct_type_index, field_index)?; + // The `atomic` version has some additional type restrictions. + let ty = self + .struct_field_at(struct_type_index, field_index)? + .element_type; + let is_valid_type = match ty { + StorageType::I8 | StorageType::I16 => true, + StorageType::Val(ValType::I32) | StorageType::Val(ValType::I64) => true, + StorageType::Val(v) => self + .resources + .is_subtype(v, RefType::ANYREF.shared().unwrap().into()), + }; + if !is_valid_type { + bail!( + self.offset, + "invalid type: `struct.atomic.set` only allows `i8`, `i16`, `i32`, `i64` and subtypes of `anyref`" + ); + } + Ok(()) + } + fn visit_struct_atomic_rmw_add( + &mut self, + _ordering: Ordering, + struct_type_index: u32, + field_index: u32, + ) -> Self::Output { + self.check_struct_atomic_rmw("add", struct_type_index, field_index) + } + fn visit_struct_atomic_rmw_sub( + &mut self, + _ordering: Ordering, + struct_type_index: u32, + field_index: u32, + ) -> Self::Output { + self.check_struct_atomic_rmw("sub", struct_type_index, field_index) + } + fn visit_struct_atomic_rmw_and( + &mut self, + _ordering: Ordering, + struct_type_index: u32, + field_index: u32, + ) -> Self::Output { + self.check_struct_atomic_rmw("and", struct_type_index, field_index) + } + fn visit_struct_atomic_rmw_or( + &mut self, + _ordering: Ordering, + struct_type_index: u32, + field_index: u32, + ) -> Self::Output { + self.check_struct_atomic_rmw("or", struct_type_index, field_index) + } + fn visit_struct_atomic_rmw_xor( + &mut self, + _ordering: Ordering, + struct_type_index: u32, + field_index: u32, + ) -> Self::Output { + self.check_struct_atomic_rmw("xor", struct_type_index, field_index) + } + fn visit_struct_atomic_rmw_xchg( + &mut self, + _ordering: Ordering, + struct_type_index: u32, + field_index: u32, + ) -> Self::Output { + let field_ty = self + .struct_field_at(struct_type_index, field_index)? + .element_type; + let is_valid_type = match field_ty { + StorageType::Val(ValType::I32) | StorageType::Val(ValType::I64) => true, + StorageType::Val(v) => self + .resources + .is_subtype(v, RefType::ANYREF.shared().unwrap().into()), + _ => false, + }; + if !is_valid_type { + bail!( + self.offset, + "invalid type: `struct.atomic.rmw.xchg` only allows `i32`, `i64` and subtypes of `anyref`" + ); + } + let field_ty = field_ty.unpack(); + self.pop_operand(Some(field_ty))?; + self.pop_concrete_ref(true, struct_type_index)?; + self.push_operand(field_ty)?; + Ok(()) + } + fn visit_struct_atomic_rmw_cmpxchg( + &mut self, + _ordering: Ordering, + struct_type_index: u32, + field_index: u32, + ) -> Self::Output { + let field_ty = self + .struct_field_at(struct_type_index, field_index)? + .element_type; + let is_valid_type = match field_ty { + StorageType::Val(ValType::I32) | StorageType::Val(ValType::I64) => true, + StorageType::Val(v) => self + .resources + .is_subtype(v, RefType::EQREF.shared().unwrap().into()), + _ => false, + }; + if !is_valid_type { + bail!( + self.offset, + "invalid type: `struct.atomic.rmw.cmpxchg` only allows `i32`, `i64` and subtypes of `eqref`" + ); + } + let field_ty = field_ty.unpack(); + self.pop_operand(Some(field_ty))?; + self.pop_operand(Some(field_ty))?; + self.pop_concrete_ref(true, struct_type_index)?; + self.push_operand(field_ty)?; + Ok(()) + } fn visit_array_new(&mut self, type_index: u32) -> Self::Output { let array_ty = self.array_type_at(type_index)?; self.pop_operand(Some(ValType::I32))?; @@ -3839,6 +4123,25 @@ where self.pop_concrete_ref(true, type_index)?; self.push_operand(elem_ty.unpack()) } + fn visit_array_atomic_get(&mut self, _ordering: Ordering, type_index: u32) -> Self::Output { + self.visit_array_get(type_index)?; + // The `atomic` version has some additional type restrictions. + let elem_ty = self.array_type_at(type_index)?.0.element_type; + let is_valid_type = match elem_ty { + StorageType::Val(ValType::I32) | StorageType::Val(ValType::I64) => true, + StorageType::Val(v) => self + .resources + .is_subtype(v, RefType::ANYREF.shared().unwrap().into()), + _ => false, + }; + if !is_valid_type { + bail!( + self.offset, + "invalid type: `array.atomic.get` only allows `i32`, `i64` and subtypes of `anyref`" + ); + } + Ok(()) + } fn visit_array_get_s(&mut self, type_index: u32) -> Self::Output { let array_ty = self.array_type_at(type_index)?; let elem_ty = array_ty.0.element_type; @@ -3852,6 +4155,15 @@ where self.pop_concrete_ref(true, type_index)?; self.push_operand(elem_ty.unpack()) } + fn visit_array_atomic_get_s(&mut self, _ordering: Ordering, type_index: u32) -> Self::Output { + self.visit_array_get_s(type_index)?; + // This instruction has the same type restrictions as the non-`atomic` version. + debug_assert!(matches!( + self.array_type_at(type_index)?.0.element_type, + StorageType::I8 | StorageType::I16 + )); + Ok(()) + } fn visit_array_get_u(&mut self, type_index: u32) -> Self::Output { let array_ty = self.array_type_at(type_index)?; let elem_ty = array_ty.0.element_type; @@ -3865,6 +4177,15 @@ where self.pop_concrete_ref(true, type_index)?; self.push_operand(elem_ty.unpack()) } + fn visit_array_atomic_get_u(&mut self, _ordering: Ordering, type_index: u32) -> Self::Output { + self.visit_array_get_u(type_index)?; + // This instruction has the same type restrictions as the non-`atomic` version. + debug_assert!(matches!( + self.array_type_at(type_index)?.0.element_type, + StorageType::I8 | StorageType::I16 + )); + Ok(()) + } fn visit_array_set(&mut self, type_index: u32) -> Self::Output { let array_ty = self.array_type_at(type_index)?; if !array_ty.0.mutable { @@ -3875,6 +4196,25 @@ where self.pop_concrete_ref(true, type_index)?; Ok(()) } + fn visit_array_atomic_set(&mut self, _ordering: Ordering, type_index: u32) -> Self::Output { + self.visit_array_set(type_index)?; + // The `atomic` version has some additional type restrictions. + let elem_ty = self.array_type_at(type_index)?.0.element_type; + let is_valid_type = match elem_ty { + StorageType::I8 | StorageType::I16 => true, + StorageType::Val(ValType::I32) | StorageType::Val(ValType::I64) => true, + StorageType::Val(v) => self + .resources + .is_subtype(v, RefType::ANYREF.shared().unwrap().into()), + }; + if !is_valid_type { + bail!( + self.offset, + "invalid type: `array.atomic.set` only allows `i8`, `i16`, `i32`, `i64` and subtypes of `anyref`" + ); + } + Ok(()) + } fn visit_array_len(&mut self) -> Self::Output { self.pop_operand(Some(RefType::ARRAY.nullable().into()))?; self.push_operand(ValType::I32) @@ -3989,6 +4329,74 @@ where self.pop_concrete_ref(true, type_index)?; Ok(()) } + fn visit_array_atomic_rmw_add(&mut self, _ordering: Ordering, type_index: u32) -> Self::Output { + self.check_array_atomic_rmw("add", type_index) + } + fn visit_array_atomic_rmw_sub(&mut self, _ordering: Ordering, type_index: u32) -> Self::Output { + self.check_array_atomic_rmw("sub", type_index) + } + fn visit_array_atomic_rmw_and(&mut self, _ordering: Ordering, type_index: u32) -> Self::Output { + self.check_array_atomic_rmw("and", type_index) + } + fn visit_array_atomic_rmw_or(&mut self, _ordering: Ordering, type_index: u32) -> Self::Output { + self.check_array_atomic_rmw("or", type_index) + } + fn visit_array_atomic_rmw_xor(&mut self, _ordering: Ordering, type_index: u32) -> Self::Output { + self.check_array_atomic_rmw("xor", type_index) + } + fn visit_array_atomic_rmw_xchg( + &mut self, + _ordering: Ordering, + type_index: u32, + ) -> Self::Output { + let elem_ty = self.array_type_at(type_index)?.0.element_type; + let is_valid_type = match elem_ty { + StorageType::Val(ValType::I32) | StorageType::Val(ValType::I64) => true, + StorageType::Val(v) => self + .resources + .is_subtype(v, RefType::ANYREF.shared().unwrap().into()), + _ => false, + }; + if !is_valid_type { + bail!( + self.offset, + "invalid type: `array.atomic.rmw.xchg` only allows `i32`, `i64` and subtypes of `anyref`" + ); + } + let elem_ty = elem_ty.unpack(); + self.pop_operand(Some(elem_ty))?; + self.pop_operand(Some(ValType::I32))?; + self.pop_concrete_ref(true, type_index)?; + self.push_operand(elem_ty)?; + Ok(()) + } + fn visit_array_atomic_rmw_cmpxchg( + &mut self, + _ordering: Ordering, + type_index: u32, + ) -> Self::Output { + let elem_ty = self.array_type_at(type_index)?.0.element_type; + let is_valid_type = match elem_ty { + StorageType::Val(ValType::I32) | StorageType::Val(ValType::I64) => true, + StorageType::Val(v) => self + .resources + .is_subtype(v, RefType::EQREF.shared().unwrap().into()), + _ => false, + }; + if !is_valid_type { + bail!( + self.offset, + "invalid type: `array.atomic.rmw.cmpxchg` only allows `i32`, `i64` and subtypes of `eqref`" + ); + } + let elem_ty = elem_ty.unpack(); + self.pop_operand(Some(elem_ty))?; + self.pop_operand(Some(elem_ty))?; + self.pop_operand(Some(ValType::I32))?; + self.pop_concrete_ref(true, type_index)?; + self.push_operand(elem_ty)?; + Ok(()) + } fn visit_any_convert_extern(&mut self) -> Self::Output { let extern_ref = self.pop_operand(Some(RefType::EXTERNREF.into()))?; let is_nullable = extern_ref @@ -4060,7 +4468,7 @@ where ), None => bail!( self.offset, - "type mismtach: br_on_cast to label with empty types, must have a reference type" + "type mismatch: br_on_cast to label with empty types, must have a reference type" ), }; @@ -4116,6 +4524,10 @@ where self.pop_operand(Some(ValType::I32))?; self.push_operand(ValType::Ref(RefType::I31)) } + fn visit_ref_i31_shared(&mut self) -> Self::Output { + self.pop_operand(Some(ValType::I32))?; + self.push_operand(ValType::Ref(RefType::I31)) // TODO: handle shared--is this correct? + } fn visit_i31_get_s(&mut self) -> Self::Output { self.pop_operand(Some(ValType::Ref(RefType::I31REF)))?; self.push_operand(ValType::I32) @@ -4124,6 +4536,80 @@ where self.pop_operand(Some(ValType::Ref(RefType::I31REF)))?; self.push_operand(ValType::I32) } + fn visit_try(&mut self, mut ty: BlockType) -> Self::Output { + self.check_block_type(&mut ty)?; + for ty in self.params(ty)?.rev() { + self.pop_operand(Some(ty))?; + } + self.push_ctrl(FrameKind::LegacyTry, ty)?; + Ok(()) + } + fn visit_catch(&mut self, index: u32) -> Self::Output { + let frame = self.pop_ctrl()?; + if frame.kind != FrameKind::LegacyTry && frame.kind != FrameKind::LegacyCatch { + bail!(self.offset, "catch found outside of an `try` block"); + } + // Start a new frame and push `exnref` value. + let height = self.operands.len(); + let init_height = self.inits.len(); + self.control.push(Frame { + kind: FrameKind::LegacyCatch, + block_type: frame.block_type, + height, + unreachable: false, + init_height, + }); + // Push exception argument types. + let ty = self.tag_at(index)?; + for ty in ty.params() { + self.push_operand(*ty)?; + } + Ok(()) + } + fn visit_rethrow(&mut self, relative_depth: u32) -> Self::Output { + // This is not a jump, but we need to check that the `rethrow` + // targets an actual `catch` to get the exception. + let (_, kind) = self.jump(relative_depth)?; + if kind != FrameKind::LegacyCatch && kind != FrameKind::LegacyCatchAll { + bail!( + self.offset, + "invalid rethrow label: target was not a `catch` block" + ); + } + self.unreachable()?; + Ok(()) + } + fn visit_delegate(&mut self, relative_depth: u32) -> Self::Output { + let frame = self.pop_ctrl()?; + if frame.kind != FrameKind::LegacyTry { + bail!(self.offset, "delegate found outside of an `try` block"); + } + // This operation is not a jump, but we need to check the + // depth for validity + let _ = self.jump(relative_depth)?; + for ty in self.results(frame.block_type)? { + self.push_operand(ty)?; + } + Ok(()) + } + fn visit_catch_all(&mut self) -> Self::Output { + let frame = self.pop_ctrl()?; + if frame.kind == FrameKind::LegacyCatchAll { + bail!(self.offset, "only one catch_all allowed per `try` block"); + } else if frame.kind != FrameKind::LegacyTry && frame.kind != FrameKind::LegacyCatch { + bail!(self.offset, "catch_all found outside of a `try` block"); + } + let height = self.operands.len(); + let init_height = self.inits.len(); + self.control.push(Frame { + kind: FrameKind::LegacyCatchAll, + block_type: frame.block_type, + height, + unreachable: false, + init_height, + }); + Ok(()) + } } #[derive(Clone, Debug)] diff --git a/crates/wasmparser/src/validator/types.rs b/crates/wasmparser/src/validator/types.rs index 578ba8b236..d713fbeee7 100644 --- a/crates/wasmparser/src/validator/types.rs +++ b/crates/wasmparser/src/validator/types.rs @@ -2834,19 +2834,23 @@ impl TypeList { } /// Is `ty` shared? - /// - /// This is complicated by reference types, since they may have concrete - /// heap types whose shared-ness must be checked by looking at the type they - /// point to. pub fn valtype_is_shared(&self, ty: ValType) -> bool { match ty { ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => true, - ValType::Ref(rt) => match rt.heap_type() { - HeapType::Abstract { shared, .. } => shared, - HeapType::Concrete(index) => { - self[index.as_core_type_id().unwrap()].composite_type.shared - } - }, + ValType::Ref(rt) => self.reftype_is_shared(rt), + } + } + + /// Is the reference type `ty` shared? + /// + /// This is complicated by concrete heap types whose shared-ness must be + /// checked by looking at the type they point to. + pub fn reftype_is_shared(&self, ty: RefType) -> bool { + match ty.heap_type() { + HeapType::Abstract { shared, .. } => shared, + HeapType::Concrete(index) => { + self[index.as_core_type_id().unwrap()].composite_type.shared + } } } diff --git a/crates/wasmprinter/src/lib.rs b/crates/wasmprinter/src/lib.rs index 6c6d2943e9..f8e09f623a 100644 --- a/crates/wasmprinter/src/lib.rs +++ b/crates/wasmprinter/src/lib.rs @@ -1130,6 +1130,9 @@ impl Printer<'_, '_> { self.print_name(&state.core.table_names, state.core.tables)?; self.result.write_str(" ")?; } + if ty.shared { + self.print_type_keyword("shared ")?; + } if ty.table64 { self.print_type_keyword("i64 ")?; } diff --git a/crates/wasmprinter/src/operator.rs b/crates/wasmprinter/src/operator.rs index fa7e2ca456..558bdc863f 100644 --- a/crates/wasmprinter/src/operator.rs +++ b/crates/wasmprinter/src/operator.rs @@ -595,6 +595,78 @@ macro_rules! define_visit { $self.push_str(" ")?; $self.printer.print_field_idx($self.state, $ty, $field)?; ); + (payload $self:ident StructAtomicGet $order:ident $ty:ident $field:ident) => ( + $self.ordering($order)?; + $self.struct_type_index($ty)?; + $self.push_str(" ")?; + $self.printer.print_field_idx($self.state, $ty, $field)?; + ); + (payload $self:ident StructAtomicGetS $order:ident $ty:ident $field:ident) => ( + $self.ordering($order)?; + $self.struct_type_index($ty)?; + $self.push_str(" ")?; + $self.printer.print_field_idx($self.state, $ty, $field)?; + ); + (payload $self:ident StructAtomicGetU $order:ident $ty:ident $field:ident) => ( + $self.ordering($order)?; + $self.struct_type_index($ty)?; + $self.push_str(" ")?; + $self.printer.print_field_idx($self.state, $ty, $field)?; + ); + (payload $self:ident StructAtomicSet $order:ident $ty:ident $field:ident) => ( + $self.ordering($order)?; + $self.struct_type_index($ty)?; + $self.push_str(" ")?; + $self.printer.print_field_idx($self.state, $ty, $field)?; + ); + (payload $self:ident StructAtomicSet $order:ident $ty:ident $field:ident) => ( + $self.ordering($order)?; + $self.struct_type_index($ty)?; + $self.push_str(" ")?; + $self.printer.print_field_idx($self.state, $ty, $field)?; + ); + (payload $self:ident StructAtomicRmwAdd $order:ident $ty:ident $field:ident) => ( + $self.ordering($order)?; + $self.struct_type_index($ty)?; + $self.push_str(" ")?; + $self.printer.print_field_idx($self.state, $ty, $field)?; + ); + (payload $self:ident StructAtomicRmwSub $order:ident $ty:ident $field:ident) => ( + $self.ordering($order)?; + $self.struct_type_index($ty)?; + $self.push_str(" ")?; + $self.printer.print_field_idx($self.state, $ty, $field)?; + ); + (payload $self:ident StructAtomicRmwAnd $order:ident $ty:ident $field:ident) => ( + $self.ordering($order)?; + $self.struct_type_index($ty)?; + $self.push_str(" ")?; + $self.printer.print_field_idx($self.state, $ty, $field)?; + ); + (payload $self:ident StructAtomicRmwOr $order:ident $ty:ident $field:ident) => ( + $self.ordering($order)?; + $self.struct_type_index($ty)?; + $self.push_str(" ")?; + $self.printer.print_field_idx($self.state, $ty, $field)?; + ); + (payload $self:ident StructAtomicRmwXor $order:ident $ty:ident $field:ident) => ( + $self.ordering($order)?; + $self.struct_type_index($ty)?; + $self.push_str(" ")?; + $self.printer.print_field_idx($self.state, $ty, $field)?; + ); + (payload $self:ident StructAtomicRmwXchg $order:ident $ty:ident $field:ident) => ( + $self.ordering($order)?; + $self.struct_type_index($ty)?; + $self.push_str(" ")?; + $self.printer.print_field_idx($self.state, $ty, $field)?; + ); + (payload $self:ident StructAtomicRmwCmpxchg $order:ident $ty:ident $field:ident) => ( + $self.ordering($order)?; + $self.struct_type_index($ty)?; + $self.push_str(" ")?; + $self.printer.print_field_idx($self.state, $ty, $field)?; + ); (payload $self:ident $op:ident $($arg:ident)*) => ( $($self.$arg($arg)?;)* ); @@ -1180,6 +1252,33 @@ macro_rules! define_visit { (name GlobalAtomicRmwXor) => ("global.atomic.rmw.xor"); (name GlobalAtomicRmwXchg) => ("global.atomic.rmw.xchg"); (name GlobalAtomicRmwCmpxchg) => ("global.atomic.rmw.cmpxchg"); + (name TableAtomicGet) => ("table.atomic.get"); + (name TableAtomicSet) => ("table.atomic.set"); + (name TableAtomicRmwXchg) => ("table.atomic.rmw.xchg"); + (name TableAtomicRmwCmpxchg) => ("table.atomic.rmw.cmpxchg"); + (name StructAtomicGet) => ("struct.atomic.get"); + (name StructAtomicGetS) => ("struct.atomic.get_s"); + (name StructAtomicGetU) => ("struct.atomic.get_u"); + (name StructAtomicSet) => ("struct.atomic.set"); + (name StructAtomicRmwAdd) => ("struct.atomic.rmw.add"); + (name StructAtomicRmwSub) => ("struct.atomic.rmw.sub"); + (name StructAtomicRmwAnd) => ("struct.atomic.rmw.and"); + (name StructAtomicRmwOr) => ("struct.atomic.rmw.or"); + (name StructAtomicRmwXor) => ("struct.atomic.rmw.xor"); + (name StructAtomicRmwXchg) => ("struct.atomic.rmw.xchg"); + (name StructAtomicRmwCmpxchg) => ("struct.atomic.rmw.cmpxchg"); + (name ArrayAtomicGet) => ("array.atomic.get"); + (name ArrayAtomicGetS) => ("array.atomic.get_s"); + (name ArrayAtomicGetU) => ("array.atomic.get_u"); + (name ArrayAtomicSet) => ("array.atomic.set"); + (name ArrayAtomicRmwAdd) => ("array.atomic.rmw.add"); + (name ArrayAtomicRmwSub) => ("array.atomic.rmw.sub"); + (name ArrayAtomicRmwAnd) => ("array.atomic.rmw.and"); + (name ArrayAtomicRmwOr) => ("array.atomic.rmw.or"); + (name ArrayAtomicRmwXor) => ("array.atomic.rmw.xor"); + (name ArrayAtomicRmwXchg) => ("array.atomic.rmw.xchg"); + (name ArrayAtomicRmwCmpxchg) => ("array.atomic.rmw.cmpxchg"); + (name RefI31Shared) => ("ref.i31_shared") } impl<'a> VisitOperator<'a> for PrintOperator<'_, '_, '_, '_> { diff --git a/crates/wast/Cargo.toml b/crates/wast/Cargo.toml index ce098c47be..728c109b0d 100644 --- a/crates/wast/Cargo.toml +++ b/crates/wast/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wast" -version = "212.0.0" +version = "213.0.0" authors = ["Alex Crichton "] edition.workspace = true license = "Apache-2.0 WITH LLVM-exception" diff --git a/crates/wast/src/component/binary.rs b/crates/wast/src/component/binary.rs index c57d633345..19806666e1 100644 --- a/crates/wast/src/component/binary.rs +++ b/crates/wast/src/component/binary.rs @@ -648,6 +648,7 @@ impl From> for wasm_encoder::TableType { minimum: ty.limits.min, maximum: ty.limits.max, table64: ty.limits.is64, + shared: ty.shared, } } } diff --git a/crates/wast/src/core/binary.rs b/crates/wast/src/core/binary.rs index 7beaa82e01..5007c4255d 100644 --- a/crates/wast/src/core/binary.rs +++ b/crates/wast/src/core/binary.rs @@ -560,6 +560,9 @@ impl<'a> Encode for TableType<'a> { if self.limits.max.is_some() { flags |= 1 << 0; } + if self.shared { + flags |= 1 << 1; + } if self.limits.is64 { flags |= 1 << 2; } @@ -925,10 +928,13 @@ impl Encode for Ordering { } } -impl Encode for OrderedAccess<'_> { +impl Encode for Ordered +where + T: Encode, +{ fn encode(&self, buf: &mut Vec) { self.ordering.encode(buf); - self.index.encode(buf); + self.inner.encode(buf); } } diff --git a/crates/wast/src/core/expr.rs b/crates/wast/src/core/expr.rs index 9104a8ea7f..c45203106b 100644 --- a/crates/wast/src/core/expr.rs +++ b/crates/wast/src/core/expr.rs @@ -859,15 +859,42 @@ instructions! { I64AtomicRmw32CmpxchgU(MemArg<4>) : [0xfe, 0x4e] : "i64.atomic.rmw32.cmpxchg_u", // proposal: shared-everything-threads - GlobalAtomicGet(OrderedAccess<'a>) : [0xfe, 0x4f] : "global.atomic.get", - GlobalAtomicSet(OrderedAccess<'a>) : [0xfe, 0x50] : "global.atomic.set", - GlobalAtomicRmwAdd(OrderedAccess<'a>) : [0xfe, 0x51] : "global.atomic.rmw.add", - GlobalAtomicRmwSub(OrderedAccess<'a>) : [0xfe, 0x52] : "global.atomic.rmw.sub", - GlobalAtomicRmwAnd(OrderedAccess<'a>) : [0xfe, 0x53] : "global.atomic.rmw.and", - GlobalAtomicRmwOr(OrderedAccess<'a>) : [0xfe, 0x54] : "global.atomic.rmw.or", - GlobalAtomicRmwXor(OrderedAccess<'a>) : [0xfe, 0x55] : "global.atomic.rmw.xor", - GlobalAtomicRmwXchg(OrderedAccess<'a>) : [0xfe, 0x56] : "global.atomic.rmw.xchg", - GlobalAtomicRmwCmpxchg(OrderedAccess<'a>) : [0xfe, 0x57] : "global.atomic.rmw.cmpxchg", + GlobalAtomicGet(Ordered>) : [0xfe, 0x4f] : "global.atomic.get", + GlobalAtomicSet(Ordered>) : [0xfe, 0x50] : "global.atomic.set", + GlobalAtomicRmwAdd(Ordered>) : [0xfe, 0x51] : "global.atomic.rmw.add", + GlobalAtomicRmwSub(Ordered>) : [0xfe, 0x52] : "global.atomic.rmw.sub", + GlobalAtomicRmwAnd(Ordered>) : [0xfe, 0x53] : "global.atomic.rmw.and", + GlobalAtomicRmwOr(Ordered>) : [0xfe, 0x54] : "global.atomic.rmw.or", + GlobalAtomicRmwXor(Ordered>) : [0xfe, 0x55] : "global.atomic.rmw.xor", + GlobalAtomicRmwXchg(Ordered>) : [0xfe, 0x56] : "global.atomic.rmw.xchg", + GlobalAtomicRmwCmpxchg(Ordered>) : [0xfe, 0x57] : "global.atomic.rmw.cmpxchg", + TableAtomicGet(Ordered>) : [0xfe, 0x58] : "table.atomic.get", + TableAtomicSet(Ordered>) : [0xfe, 0x59] : "table.atomic.set", + TableAtomicRmwXchg(Ordered>) : [0xfe, 0x5A] : "table.atomic.rmw.xchg", + TableAtomicRmwCmpxchg(Ordered>) : [0xFE, 0x5B] : "table.atomic.rmw.cmpxchg", + StructAtomicGet(Ordered>) : [0xFE, 0x5C] : "struct.atomic.get", + StructAtomicGetS(Ordered>) : [0xFE, 0x5D] : "struct.atomic.get_s", + StructAtomicGetU(Ordered>) : [0xFE, 0x5E] : "struct.atomic.get_u", + StructAtomicSet(Ordered>) : [0xFE, 0x5F] : "struct.atomic.set", + StructAtomicRmwAdd(Ordered>) : [0xFE, 0x60] : "struct.atomic.rmw.add", + StructAtomicRmwSub(Ordered>) : [0xFE, 0x61] : "struct.atomic.rmw.sub", + StructAtomicRmwAnd(Ordered>) : [0xFE, 0x62] : "struct.atomic.rmw.and", + StructAtomicRmwOr(Ordered>) : [0xFE, 0x63] : "struct.atomic.rmw.or", + StructAtomicRmwXor(Ordered>) : [0xFE, 0x64] : "struct.atomic.rmw.xor", + StructAtomicRmwXchg(Ordered>) : [0xFE, 0x65] : "struct.atomic.rmw.xchg", + StructAtomicRmwCmpxchg(Ordered>) : [0xFE, 0x66] : "struct.atomic.rmw.cmpxchg", + ArrayAtomicGet(Ordered>) : [0xFE, 0x67] : "array.atomic.get", + ArrayAtomicGetS(Ordered>) : [0xFE, 0x68] : "array.atomic.get_s", + ArrayAtomicGetU(Ordered>) : [0xFE, 0x69] : "array.atomic.get_u", + ArrayAtomicSet(Ordered>) : [0xFE, 0x6A] : "array.atomic.set", + ArrayAtomicRmwAdd(Ordered>) : [0xFE, 0x6B] : "array.atomic.rmw.add", + ArrayAtomicRmwSub(Ordered>) : [0xFE, 0x6C] : "array.atomic.rmw.sub", + ArrayAtomicRmwAnd(Ordered>) : [0xFE, 0x6D] : "array.atomic.rmw.and", + ArrayAtomicRmwOr(Ordered>) : [0xFE, 0x6E] : "array.atomic.rmw.or", + ArrayAtomicRmwXor(Ordered>) : [0xFE, 0x6F] : "array.atomic.rmw.xor", + ArrayAtomicRmwXchg(Ordered>) : [0xFE, 0x70] : "array.atomic.rmw.xchg", + ArrayAtomicRmwCmpxchg(Ordered>) : [0xFE, 0x71] : "array.atomic.rmw.cmpxchg", + RefI31Shared : [0xFE, 0x72] : "ref.i31_shared", // proposal: simd // @@ -1531,6 +1558,8 @@ pub struct TableArg<'a> { pub dst: Index<'a>, } +// `TableArg` could be an unwrapped as an `Index` if not for this custom parse +// behavior: if we cannot parse a table index, we default to table `0`. impl<'a> Parse<'a> for TableArg<'a> { fn parse(parser: Parser<'a>) -> Result { let dst = if let Some(dst) = parser.parse()? { @@ -1831,20 +1860,27 @@ impl<'a> Parse<'a> for Ordering { } } -/// Extra data associated with the `global.atomic.*` instructions. +/// Add a memory [`Ordering`] to the argument `T` of some instruction. +/// +/// This is helpful for many kinds of `*.atomic.*` instructions introduced by +/// the shared-everything-threads proposal. Many of these instructions "build +/// on" existing instructions by simply adding a memory order to them. #[derive(Clone, Debug)] -pub struct OrderedAccess<'a> { +pub struct Ordered { /// The memory ordering for this atomic instruction. pub ordering: Ordering, - /// The index of the global to access. - pub index: Index<'a>, + /// The original argument type. + pub inner: T, } -impl<'a> Parse<'a> for OrderedAccess<'a> { +impl<'a, T> Parse<'a> for Ordered +where + T: Parse<'a>, +{ fn parse(parser: Parser<'a>) -> Result { let ordering = parser.parse()?; - let index = parser.parse()?; - Ok(OrderedAccess { ordering, index }) + let inner = parser.parse()?; + Ok(Ordered { ordering, inner }) } } diff --git a/crates/wast/src/core/resolve/deinline_import_export.rs b/crates/wast/src/core/resolve/deinline_import_export.rs index 8dbb5f6a17..06cb870b39 100644 --- a/crates/wast/src/core/resolve/deinline_import_export.rs +++ b/crates/wast/src/core/resolve/deinline_import_export.rs @@ -103,11 +103,13 @@ pub fn run(fields: &mut Vec) { }, }); } - // If data is defined inline insert an explicit `data` module - // field here instead, switching this to a `Normal` memory. + // If data is defined inline insert an explicit `data` + // module field here instead, switching this to a `Normal` + // memory. TableKind::Inline { payload, elem, + shared, is64, } => { let is64 = *is64; @@ -123,6 +125,7 @@ pub fn run(fields: &mut Vec) { is64, }, elem: *elem, + shared: *shared, }, init_expr: None, }; diff --git a/crates/wast/src/core/resolve/names.rs b/crates/wast/src/core/resolve/names.rs index d2b7eb1db4..c0c5e5b586 100644 --- a/crates/wast/src/core/resolve/names.rs +++ b/crates/wast/src/core/resolve/names.rs @@ -453,6 +453,13 @@ impl<'a, 'b> ExprResolver<'a, 'b> { self.resolver.resolve(&mut i.dst, Ns::Table)?; } + TableAtomicGet(i) + | TableAtomicSet(i) + | TableAtomicRmwXchg(i) + | TableAtomicRmwCmpxchg(i) => { + self.resolver.resolve(&mut i.inner.dst, Ns::Table)?; + } + GlobalSet(i) | GlobalGet(i) => { self.resolver.resolve(i, Ns::Global)?; } @@ -466,7 +473,7 @@ impl<'a, 'b> ExprResolver<'a, 'b> { | GlobalAtomicRmwXor(i) | GlobalAtomicRmwXchg(i) | GlobalAtomicRmwCmpxchg(i) => { - self.resolver.resolve(&mut i.index, Ns::Global)?; + self.resolver.resolve(&mut i.inner, Ns::Global)?; } LocalSet(i) | LocalGet(i) | LocalTee(i) => { @@ -614,14 +621,21 @@ impl<'a, 'b> ExprResolver<'a, 'b> { } StructSet(s) | StructGet(s) | StructGetS(s) | StructGetU(s) => { - let type_index = self.resolver.resolve(&mut s.r#struct, Ns::Type)?; - if let Index::Id(field_id) = s.field { - self.resolver - .fields - .get(&type_index) - .ok_or(Error::new(field_id.span(), format!("accessing a named field `{}` in a struct without named fields, type index {}", field_id.name(), type_index)))? - .resolve(&mut s.field, "field")?; - } + self.resolve_field(s)?; + } + + StructAtomicGet(s) + | StructAtomicGetS(s) + | StructAtomicGetU(s) + | StructAtomicSet(s) + | StructAtomicRmwAdd(s) + | StructAtomicRmwSub(s) + | StructAtomicRmwAnd(s) + | StructAtomicRmwOr(s) + | StructAtomicRmwXor(s) + | StructAtomicRmwXchg(s) + | StructAtomicRmwCmpxchg(s) => { + self.resolve_field(&mut s.inner)?; } ArrayNewFixed(a) => { @@ -651,6 +665,20 @@ impl<'a, 'b> ExprResolver<'a, 'b> { self.resolver.elems.resolve(&mut a.segment, "elem")?; } + ArrayAtomicGet(i) + | ArrayAtomicGetS(i) + | ArrayAtomicGetU(i) + | ArrayAtomicSet(i) + | ArrayAtomicRmwAdd(i) + | ArrayAtomicRmwSub(i) + | ArrayAtomicRmwAnd(i) + | ArrayAtomicRmwOr(i) + | ArrayAtomicRmwXor(i) + | ArrayAtomicRmwXchg(i) + | ArrayAtomicRmwCmpxchg(i) => { + self.resolver.resolve(&mut i.inner, Ns::Type)?; + } + RefNull(ty) => self.resolver.resolve_heaptype(ty)?, _ => {} @@ -678,6 +706,18 @@ impl<'a, 'b> ExprResolver<'a, 'b> { None => Err(resolve_error(id, "label")), } } + + fn resolve_field(&self, s: &mut StructAccess<'a>) -> Result<(), Error> { + let type_index = self.resolver.resolve(&mut s.r#struct, Ns::Type)?; + if let Index::Id(field_id) = s.field { + self.resolver + .fields + .get(&type_index) + .ok_or(Error::new(field_id.span(), format!("accessing a named field `{}` in a struct without named fields, type index {}", field_id.name(), type_index)))? + .resolve(&mut s.field, "field")?; + } + Ok(()) + } } enum TypeInfo<'a> { diff --git a/crates/wast/src/core/table.rs b/crates/wast/src/core/table.rs index 3d48903394..80875df650 100644 --- a/crates/wast/src/core/table.rs +++ b/crates/wast/src/core/table.rs @@ -29,7 +29,7 @@ pub enum TableKind<'a> { ty: TableType<'a>, }, - /// A typical memory definition which simply says the limits of the table + /// A typical memory definition which simply says the limits of the table. Normal { /// Table type. ty: TableType<'a>, @@ -37,12 +37,14 @@ pub enum TableKind<'a> { init_expr: Option>, }, - /// The elem segments of this table, starting from 0, explicitly listed + /// The elem segments of this table, starting from 0, explicitly listed. Inline { /// The element type of this table. elem: RefType<'a>, - /// Whether or not this will be creating a 64-bit table + /// Whether or not this will be creating a 64-bit table. is64: bool, + /// Whether this table is shared or not. + shared: bool, /// The element table entries to have, and the length of this list is /// the limits of the table as well. payload: ElemPayload<'a>, @@ -58,13 +60,19 @@ impl<'a> Parse<'a> for Table<'a> { // Afterwards figure out which style this is, either: // - // * `elemtype (elem ...)` - // * `(import "a" "b") limits` - // * `limits` + // * inline: `elemtype (elem ...)` + // * normal: `tabletype` + // * import: `(import "a" "b") tabletype` + // + // Where `tabletype := shared? index_type limits reftype` let mut l = parser.lookahead1(); + let is_shared = l.peek::()?; let has_index_type = l.peek::()? | l.peek::()?; - let kind = if l.peek::()? || (has_index_type && parser.peek2::()?) { + let kind = if l.peek::()? + || ((is_shared || has_index_type) && parser.peek2::()?) + { + let shared = parser.parse::>()?.is_some(); let is64 = if parser.parse::>()?.is_some() { false } else { @@ -82,9 +90,10 @@ impl<'a> Parse<'a> for Table<'a> { TableKind::Inline { elem, is64, + shared, payload, } - } else if has_index_type || l.peek::()? { + } else if is_shared || has_index_type || l.peek::()? { TableKind::Normal { ty: parser.parse()?, init_expr: if !parser.is_empty() { diff --git a/crates/wast/src/core/types.rs b/crates/wast/src/core/types.rs index 48f128c0f2..a20d65e42c 100644 --- a/crates/wast/src/core/types.rs +++ b/crates/wast/src/core/types.rs @@ -587,18 +587,21 @@ impl<'a> Parse<'a> for Limits { } } -/// Configuration for a table of a wasm mdoule +/// Configuration for a table of a wasm module. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub struct TableType<'a> { /// Limits on the element sizes of this table pub limits: Limits, /// The type of element stored in this table pub elem: RefType<'a>, + /// Whether or not this is a shared table. + pub shared: bool, } impl<'a> Parse<'a> for TableType<'a> { fn parse(parser: Parser<'a>) -> Result { Ok(TableType { + shared: parser.parse::>()?.is_some(), limits: parser.parse()?, elem: parser.parse()?, }) diff --git a/crates/wat/Cargo.toml b/crates/wat/Cargo.toml index 489b4c6071..15f82f362e 100644 --- a/crates/wat/Cargo.toml +++ b/crates/wat/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wat" -version = "1.212.0" +version = "1.213.0" authors = ["Alex Crichton "] edition.workspace = true license = "Apache-2.0 WITH LLVM-exception" diff --git a/crates/wit-component/src/encoding.rs b/crates/wit-component/src/encoding.rs index f045cb8366..35599208ad 100644 --- a/crates/wit-component/src/encoding.rs +++ b/crates/wit-component/src/encoding.rs @@ -1269,6 +1269,7 @@ impl<'a> EncodingState<'a> { minimum: signatures.len() as u64, maximum: Some(signatures.len() as u64), table64: false, + shared: false, }; tables.table(table_type); diff --git a/crates/wit-component/src/linking.rs b/crates/wit-component/src/linking.rs index a9d3ca95b8..0ba89cbe0b 100644 --- a/crates/wit-component/src/linking.rs +++ b/crates/wit-component/src/linking.rs @@ -468,6 +468,7 @@ fn make_env_module<'a>( minimum: table_offset.into(), maximum: None, table64: false, + shared: false, }); exports.export("__indirect_function_table", ExportKind::Table, 0); module.section(&tables); @@ -560,6 +561,7 @@ fn make_init_module( minimum: 0, maximum: None, table64: false, + shared: false, }, ); diff --git a/crates/wit-component/src/printing.rs b/crates/wit-component/src/printing.rs index daad8ef67e..5c2ce5813f 100644 --- a/crates/wit-component/src/printing.rs +++ b/crates/wit-component/src/printing.rs @@ -51,8 +51,13 @@ impl WitPrinter { } /// Print a set of one or more WIT packages into a string. - pub fn print(&mut self, resolve: &Resolve, pkg_ids: &[PackageId]) -> Result { - let has_multiple_packages = pkg_ids.len() > 1; + pub fn print( + &mut self, + resolve: &Resolve, + pkg_ids: &[PackageId], + force_print_package_in_curlies: bool, + ) -> Result { + let print_package_in_curlies = force_print_package_in_curlies || pkg_ids.len() > 1; for (i, pkg_id) in pkg_ids.into_iter().enumerate() { if i > 0 { self.output.push_str("\n\n"); @@ -68,7 +73,7 @@ impl WitPrinter { self.output.push_str(&format!("@{version}")); } - if has_multiple_packages { + if print_package_in_curlies { self.output.push_str(" {\n"); } else { self.print_semicolon(); @@ -95,8 +100,8 @@ impl WitPrinter { writeln!(&mut self.output, "}}")?; } - if has_multiple_packages { - self.output.push_str("}"); + if print_package_in_curlies { + self.output.push_str("}\n"); } } diff --git a/crates/wit-component/tests/components.rs b/crates/wit-component/tests/components.rs index de2ff79c67..9d00e2f764 100644 --- a/crates/wit-component/tests/components.rs +++ b/crates/wit-component/tests/components.rs @@ -171,7 +171,7 @@ fn run_test(path: &Path) -> Result<()> { } }; let wit = WitPrinter::default() - .print(&resolve, &[pkg]) + .print(&resolve, &[pkg], false) .context("failed to print WIT")?; assert_output(&wit, &component_wit_path)?; diff --git a/crates/wit-component/tests/interfaces.rs b/crates/wit-component/tests/interfaces.rs index df857ebb96..26a2192dde 100644 --- a/crates/wit-component/tests/interfaces.rs +++ b/crates/wit-component/tests/interfaces.rs @@ -89,7 +89,7 @@ fn run_test(path: &Path, is_dir: bool) -> Result<()> { } fn assert_print(resolve: &Resolve, pkg_ids: &[PackageId], path: &Path, is_dir: bool) -> Result<()> { - let output = WitPrinter::default().print(resolve, &pkg_ids)?; + let output = WitPrinter::default().print(resolve, &pkg_ids, false)?; for pkg_id in pkg_ids { let pkg = &resolve.packages[*pkg_id]; let expected = if is_dir { diff --git a/crates/wit-component/tests/interfaces/multiple-packages.wit.print b/crates/wit-component/tests/interfaces/multiple-packages.wit.print index 50aa8e9356..f992861f81 100644 --- a/crates/wit-component/tests/interfaces/multiple-packages.wit.print +++ b/crates/wit-component/tests/interfaces/multiple-packages.wit.print @@ -9,6 +9,7 @@ package another:thing { } + package third:pkg { @since(version = 1.2.3) interface things { @@ -20,9 +21,10 @@ package third:pkg { } + package foo:bar { world this-world { import another:thing/something; import third:pkg/things; } -} \ No newline at end of file +} diff --git a/crates/wit-component/tests/merge.rs b/crates/wit-component/tests/merge.rs index f9a70859bb..3dd25da957 100644 --- a/crates/wit-component/tests/merge.rs +++ b/crates/wit-component/tests/merge.rs @@ -46,7 +46,7 @@ fn merging() -> Result<()> { .join("merge") .join(&pkg.name.name) .with_extension("wit"); - let output = WitPrinter::default().print(&into, &[id])?; + let output = WitPrinter::default().print(&into, &[id], false)?; assert_output(&expected, &output)?; } } diff --git a/crates/wit-encoder/Cargo.toml b/crates/wit-encoder/Cargo.toml index 00f80ba338..cc72b4c766 100644 --- a/crates/wit-encoder/Cargo.toml +++ b/crates/wit-encoder/Cargo.toml @@ -10,9 +10,24 @@ version.workspace = true [lints] workspace = true +[features] +default = ["serde"] + +# Enables JSON serialization/deserialization of the wit-encoder structures. + +# *Note*: The JSON that this generates is different from the JSON generated from wit-parser. +# If you're looking to create WIT from JSON, then this is the crate and feature for you. But if +# you're parsing WIT and reading the output through JSON, then wit-parser is probably the better +# option. + +# *Note*: The exact structure of the JSON is likely not going to be very stable over time, +# so slight tweaks and variants should be expected as this crate evolves. +serde = ["dep:serde", "semver/serde"] + [dependencies] semver = { workspace = true } pretty_assertions = { workspace = true } +serde = { workspace = true, optional = true, features = ["derive"] } [dev-dependencies] indoc = { workspace = true } diff --git a/crates/wit-encoder/src/docs.rs b/crates/wit-encoder/src/docs.rs index 137fd744e7..86fe20592c 100644 --- a/crates/wit-encoder/src/docs.rs +++ b/crates/wit-encoder/src/docs.rs @@ -4,6 +4,8 @@ use crate::{Render, RenderOpts}; /// Documentation #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub struct Docs { contents: String, } diff --git a/crates/wit-encoder/src/enum_.rs b/crates/wit-encoder/src/enum_.rs index b84f372550..73f17eb3ab 100644 --- a/crates/wit-encoder/src/enum_.rs +++ b/crates/wit-encoder/src/enum_.rs @@ -2,6 +2,8 @@ use crate::{Docs, Ident}; /// A variant without a payload #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub struct Enum { pub(crate) cases: Vec, } @@ -36,6 +38,8 @@ impl Enum { } #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub struct EnumCase { pub(crate) name: Ident, pub(crate) docs: Option, diff --git a/crates/wit-encoder/src/flags.rs b/crates/wit-encoder/src/flags.rs index 81e2fd0f4a..69735cbb3b 100644 --- a/crates/wit-encoder/src/flags.rs +++ b/crates/wit-encoder/src/flags.rs @@ -1,6 +1,8 @@ use crate::{ident::Ident, Docs}; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub struct Flags { pub(crate) flags: Vec, } @@ -22,6 +24,8 @@ impl Flags { } #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub struct Flag { pub(crate) name: Ident, pub(crate) docs: Option, diff --git a/crates/wit-encoder/src/function.rs b/crates/wit-encoder/src/function.rs index 6c86aa26ab..d00a87523e 100644 --- a/crates/wit-encoder/src/function.rs +++ b/crates/wit-encoder/src/function.rs @@ -3,6 +3,8 @@ use std::fmt::{self, Display}; use crate::{ident::Ident, Docs, Type}; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub struct Params { items: Vec<(Ident, Type)>, } @@ -61,6 +63,8 @@ impl Params { } #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub enum Results { Named(Params), Anon(Type), @@ -141,6 +145,8 @@ impl Results { } #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub struct StandaloneFunc { pub(crate) name: Ident, pub(crate) params: Params, diff --git a/crates/wit-encoder/src/ident.rs b/crates/wit-encoder/src/ident.rs index 4b7116f5ef..d0a2962743 100644 --- a/crates/wit-encoder/src/ident.rs +++ b/crates/wit-encoder/src/ident.rs @@ -1,16 +1,13 @@ use std::{borrow::Cow, fmt}; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub struct Ident(Cow<'static, str>); impl Ident { pub fn new(s: impl Into>) -> Self { - let s: Cow<'static, str> = s.into(); - if is_keyword(&s) { - Self(Cow::Owned(format!("%{}", s))) - } else { - Self(s) - } + Self(s.into()) } } @@ -25,6 +22,9 @@ where impl fmt::Display for Ident { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if is_keyword(&self.0) { + write!(f, "%")?; + } self.0.fmt(f) } } @@ -37,8 +37,8 @@ impl AsRef for Ident { fn is_keyword(name: &str) -> bool { match name { - "u8" | "u16" | "u32" | "u64" | "s8" | "s16" | "s32" | "s64" | "float32" | "float64" - | "char" | "bool" | "string" | "tuple" | "list" | "option" | "result" | "use" | "type" + "u8" | "u16" | "u32" | "u64" | "s8" | "s16" | "s32" | "s64" | "f32" | "f64" | "char" + | "bool" | "string" | "tuple" | "list" | "option" | "result" | "use" | "type" | "resource" | "func" | "record" | "enum" | "flags" | "variant" | "static" | "interface" | "world" | "import" | "export" | "package" | "own" | "borrow" => true, _ => false, diff --git a/crates/wit-encoder/src/include.rs b/crates/wit-encoder/src/include.rs index 9f276381a0..f9a5cd930c 100644 --- a/crates/wit-encoder/src/include.rs +++ b/crates/wit-encoder/src/include.rs @@ -4,6 +4,8 @@ use crate::{Ident, Render}; /// Enable the union of a world with another world #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub struct Include { use_path: Ident, include_names_list: Vec<(String, String)>, diff --git a/crates/wit-encoder/src/interface.rs b/crates/wit-encoder/src/interface.rs index 5641426c62..a4b876110b 100644 --- a/crates/wit-encoder/src/interface.rs +++ b/crates/wit-encoder/src/interface.rs @@ -1,8 +1,10 @@ use std::fmt; -use crate::{Docs, Ident, Render, RenderOpts, StandaloneFunc, TypeDef}; +use crate::{Docs, Ident, Render, RenderOpts, StandaloneFunc, TypeDef, Use}; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub struct Interface { /// Name of this interface. pub(crate) name: Ident, @@ -34,6 +36,11 @@ impl Interface { self.items.push(InterfaceItem::Function(function)); } + /// Add a `Use` to the interface + pub fn use_(&mut self, use_: Use) { + self.items.push(InterfaceItem::Use(use_)); + } + pub fn items(&self) -> &[InterfaceItem] { &self.items } @@ -49,8 +56,11 @@ impl Interface { } #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub enum InterfaceItem { TypeDef(TypeDef), + Use(Use), Function(StandaloneFunc), } @@ -73,6 +83,9 @@ impl Render for InterfaceItems { } write!(f, ";\n")?; } + InterfaceItem::Use(use_) => { + use_.render(f, opts)?; + } } } Ok(()) diff --git a/crates/wit-encoder/src/lib.rs b/crates/wit-encoder/src/lib.rs index c4e8eb4fc2..902ffc007a 100644 --- a/crates/wit-encoder/src/lib.rs +++ b/crates/wit-encoder/src/lib.rs @@ -17,6 +17,7 @@ mod resource; mod result; mod tuple; mod ty; +mod use_; mod variant; mod world; @@ -34,5 +35,6 @@ pub use resource::*; pub use result::*; pub use tuple::*; pub use ty::*; +pub use use_::*; pub use variant::*; pub use world::*; diff --git a/crates/wit-encoder/src/package.rs b/crates/wit-encoder/src/package.rs index 0289e052d9..74fa962367 100644 --- a/crates/wit-encoder/src/package.rs +++ b/crates/wit-encoder/src/package.rs @@ -10,6 +10,8 @@ use crate::{ident::Ident, Interface, Render, RenderOpts, World}; /// have a unique identifier that affects generated components and uniquely /// identifiers this particular package. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub struct Package { /// A unique name corresponding to this package. name: PackageName, @@ -81,6 +83,8 @@ impl fmt::Display for Package { } #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub enum PackageItem { Interface(Interface), World(World), @@ -92,6 +96,8 @@ pub enum PackageItem { /// This is directly encoded as an "ID" in the binary component representation /// with an interfaced tacked on as well. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub struct PackageName { /// A namespace such as `wasi` in `wasi:foo/bar` namespace: String, diff --git a/crates/wit-encoder/src/record.rs b/crates/wit-encoder/src/record.rs index 9f91a8cd19..35c7f677c7 100644 --- a/crates/wit-encoder/src/record.rs +++ b/crates/wit-encoder/src/record.rs @@ -1,6 +1,8 @@ use crate::{ident::Ident, Docs, Type}; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub struct Record { pub(crate) fields: Vec, } @@ -22,6 +24,8 @@ impl Record { } #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub struct Field { pub(crate) name: Ident, pub(crate) ty: Type, diff --git a/crates/wit-encoder/src/render.rs b/crates/wit-encoder/src/render.rs index 62cda3c8cc..60a710f93c 100644 --- a/crates/wit-encoder/src/render.rs +++ b/crates/wit-encoder/src/render.rs @@ -1,6 +1,8 @@ use std::fmt; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub struct RenderOpts { /// width of each indent pub indent_width: usize, diff --git a/crates/wit-encoder/src/resource.rs b/crates/wit-encoder/src/resource.rs index 644cca97e6..85d51714c5 100644 --- a/crates/wit-encoder/src/resource.rs +++ b/crates/wit-encoder/src/resource.rs @@ -1,6 +1,8 @@ use crate::{ident::Ident, Docs, Params, Results}; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub struct Resource { pub(crate) funcs: Vec, } @@ -24,6 +26,8 @@ impl Resource { } #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub struct ResourceFunc { pub(crate) kind: ResourceFuncKind, pub(crate) params: Params, @@ -31,6 +35,8 @@ pub struct ResourceFunc { } #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub enum ResourceFuncKind { Method(Ident, Results), Static(Ident, Results), diff --git a/crates/wit-encoder/src/result.rs b/crates/wit-encoder/src/result.rs index de4dc9cbfa..ee8ff11909 100644 --- a/crates/wit-encoder/src/result.rs +++ b/crates/wit-encoder/src/result.rs @@ -3,6 +3,8 @@ use std::fmt::Display; use crate::Type; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub struct Result_ { ok: Option, err: Option, diff --git a/crates/wit-encoder/src/tuple.rs b/crates/wit-encoder/src/tuple.rs index 0bc97bacf5..ee3c9a4ce8 100644 --- a/crates/wit-encoder/src/tuple.rs +++ b/crates/wit-encoder/src/tuple.rs @@ -3,6 +3,8 @@ use std::fmt::Display; use crate::Type; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub struct Tuple { pub(crate) types: Vec, } diff --git a/crates/wit-encoder/src/ty.rs b/crates/wit-encoder/src/ty.rs index 3e45f6d6ea..95b7268250 100644 --- a/crates/wit-encoder/src/ty.rs +++ b/crates/wit-encoder/src/ty.rs @@ -6,6 +6,8 @@ use crate::{ }; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub enum Type { Bool, U8, @@ -111,6 +113,8 @@ impl Display for Type { } #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub struct VariantCase { name: Ident, ty: Option, @@ -176,6 +180,8 @@ where } #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub struct TypeDef { name: Ident, kind: TypeDefKind, @@ -273,6 +279,8 @@ impl TypeDef { } #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub enum TypeDefKind { Record(Record), Resource(Resource), diff --git a/crates/wit-encoder/src/use_.rs b/crates/wit-encoder/src/use_.rs new file mode 100644 index 0000000000..bb549adba6 --- /dev/null +++ b/crates/wit-encoder/src/use_.rs @@ -0,0 +1,46 @@ +use std::fmt; + +use crate::{Ident, Render}; + +/// Enable the union of a world with another world +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] +pub struct Use { + target: Ident, + use_names_list: Vec<(String, Option)>, +} + +impl Use { + pub fn new(use_target: impl Into) -> Self { + Self { + target: use_target.into(), + use_names_list: vec![], + } + } + + pub fn item(&mut self, id: &str, alias: Option<&str>) { + self.use_names_list + .push((id.to_string(), alias.map(|s| s.to_string()))); + } +} + +impl Render for Use { + fn render(&self, f: &mut fmt::Formatter<'_>, opts: &crate::RenderOpts) -> fmt::Result { + let len = self.use_names_list.len(); + + write!(f, "{}use {}.{{ ", opts.spaces(), self.target)?; + for (i, (id, alias)) in self.use_names_list.iter().enumerate() { + if let Some(alias) = alias { + write!(f, "{id} as {alias}")?; + } else { + write!(f, "{id}")?; + } + if i < len - 1 { + write!(f, ", ")?; + } + } + write!(f, " }};\n")?; + Ok(()) + } +} diff --git a/crates/wit-encoder/src/variant.rs b/crates/wit-encoder/src/variant.rs index 2322f9da31..43bdf676c0 100644 --- a/crates/wit-encoder/src/variant.rs +++ b/crates/wit-encoder/src/variant.rs @@ -1,6 +1,8 @@ use crate::VariantCase; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub struct Variant { pub(crate) cases: Vec, } diff --git a/crates/wit-encoder/src/world.rs b/crates/wit-encoder/src/world.rs index 7203524bb1..d380f62be0 100644 --- a/crates/wit-encoder/src/world.rs +++ b/crates/wit-encoder/src/world.rs @@ -1,8 +1,10 @@ use std::fmt; -use crate::{ident::Ident, Docs, Include, Interface, Render, RenderOpts, StandaloneFunc}; +use crate::{ident::Ident, Docs, Include, Interface, Render, RenderOpts, StandaloneFunc, Use}; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub struct World { /// The WIT identifier name of this world. name: Ident, @@ -55,6 +57,9 @@ impl World { pub fn include(&mut self, include: Include) { self.item(WorldItem::Include(include)); } + pub fn use_(&mut self, use_: Use) { + self.item(WorldItem::Use(use_)); + } /// Set the documentation pub fn docs(&mut self, docs: Option>) { @@ -143,6 +148,7 @@ impl Render for World { render_function(f, opts, function)?; } WorldItem::Include(include) => include.render(f, opts)?, + WorldItem::Use(use_) => use_.render(f, opts)?, } } let opts = &opts.outdent(); @@ -152,6 +158,8 @@ impl Render for World { } #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub enum WorldItem { /// An imported inline interface InlineInterfaceImport(Interface), @@ -173,6 +181,9 @@ pub enum WorldItem { /// Include type Include(Include), + + /// Use + Use(Use), } impl WorldItem { @@ -200,6 +211,8 @@ impl WorldItem { } #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))] pub struct WorldNamedInterface { /// Name of this interface. pub(crate) name: Ident, diff --git a/crates/wit-encoder/tests/type_defs.rs b/crates/wit-encoder/tests/type_defs.rs index fb2d211a1c..2f96a9a640 100644 --- a/crates/wit-encoder/tests/type_defs.rs +++ b/crates/wit-encoder/tests/type_defs.rs @@ -103,6 +103,7 @@ const PACKAGE: &str = indoc::indoc! {" type t46 = t44; type foo = bar; type bar = u32; + type %f64 = f64; resource t50 { } resource t51 { @@ -211,6 +212,8 @@ fn types() { interface.type_def(TypeDef::type_("foo", Type::named("bar"))); interface.type_def(TypeDef::type_("bar", Type::U32)); + interface.type_def(TypeDef::type_("f64", Type::F64)); + interface.type_def(TypeDef::resource("t50", Vec::::new())); interface.type_def(TypeDef::resource( "t51", diff --git a/crates/wit-encoder/tests/use.rs b/crates/wit-encoder/tests/use.rs new file mode 100644 index 0000000000..c3d891c6fc --- /dev/null +++ b/crates/wit-encoder/tests/use.rs @@ -0,0 +1,45 @@ +use pretty_assertions::assert_eq; +use wit_encoder::{Interface, Package, PackageName, ResourceFunc, TypeDef, Use, World}; + +const PACKAGE: &str = indoc::indoc! {" + package foo:foo; + + interface foo { + resource bar { + } + } + + interface bar { + use foo.{ bar as foobar }; + resource baz { + } + } + + world baz { + use bar.{ baz }; + } +"}; + +#[test] +fn concrete_types() { + let mut package = Package::new(PackageName::new("foo", "foo", None)); + + let mut interface = Interface::new("foo"); + interface.type_def(TypeDef::resource("bar", Vec::::new())); + package.interface(interface); + + let mut interface = Interface::new("bar"); + let mut use_ = Use::new("foo"); + use_.item("bar", Some("foobar")); + interface.use_(use_); + interface.type_def(TypeDef::resource("baz", Vec::::new())); + package.interface(interface); + + let mut world = World::new("baz"); + let mut use_ = Use::new("bar"); + use_.item("baz", None); + world.use_(use_); + package.world(world); + + assert_eq!(package.to_string(), PACKAGE); +} diff --git a/crates/wit-parser/src/metadata.rs b/crates/wit-parser/src/metadata.rs index a9a6967d88..78554a3ad0 100644 --- a/crates/wit-parser/src/metadata.rs +++ b/crates/wit-parser/src/metadata.rs @@ -530,7 +530,7 @@ impl InterfaceMetadata { fn extract(resolve: &Resolve, id: InterfaceId) -> Self { let interface = &resolve.interfaces[id]; - let funcs: IndexMap = interface + let funcs = interface .functions .iter() .map(|(name, func)| (name.to_string(), FunctionMetadata::extract(func))) diff --git a/fuzz/src/roundtrip_wit.rs b/fuzz/src/roundtrip_wit.rs index dfc162c18f..3c0090e35b 100644 --- a/fuzz/src/roundtrip_wit.rs +++ b/fuzz/src/roundtrip_wit.rs @@ -86,7 +86,7 @@ fn roundtrip_through_printing(file: &str, resolve: &Resolve, wasm: &[u8]) { for (id, pkg) in resolve.packages.iter() { let mut map = SourceMap::new(); let pkg_name = &pkg.name; - let doc = WitPrinter::default().print(resolve, &[id]).unwrap(); + let doc = WitPrinter::default().print(resolve, &[id], false).unwrap(); write_file(&format!("{file}-{pkg_name}.wit"), &doc); map.push(format!("{pkg_name}.wit").as_ref(), doc); let unresolved = map.parse().unwrap(); diff --git a/src/addr2line.rs b/src/addr2line.rs index f81986ee66..1be023c57a 100644 --- a/src/addr2line.rs +++ b/src/addr2line.rs @@ -107,7 +107,7 @@ impl<'a> Addr2lineModules<'a> { Some(start) => addr .checked_sub(start) .context("address is before the beginning of the text section")?, - None => bail!("no code section found in module"), + None => return Ok(None), } }; diff --git a/src/bin/wasm-tools/component.rs b/src/bin/wasm-tools/component.rs index 9f5b1c18eb..598c4df897 100644 --- a/src/bin/wasm-tools/component.rs +++ b/src/bin/wasm-tools/component.rs @@ -523,9 +523,7 @@ impl WitOpts { // This interprets all of the output options and performs such a task. if self.json { self.emit_json(&decoded)?; - return Ok(()); - } - if self.wasm || self.wat { + } else if self.wasm || self.wat { self.emit_wasm(&decoded)?; } else { self.emit_wit(&decoded)?; @@ -615,7 +613,6 @@ impl WitOpts { assert!(!self.wasm && !self.wat); let resolve = decoded.resolve(); - let main = decoded.packages(); let mut printer = WitPrinter::default(); printer.emit_docs(!self.no_docs); @@ -638,28 +635,38 @@ impl WitOpts { *cnt += 1; } + let main = decoded.packages(); for (id, pkg) in resolve.packages.iter() { - let output = printer.print(resolve, &[id])?; - let out_dir = if main.contains(&id) { + let is_main = main.contains(&id); + let output = printer.print(resolve, &[id], is_main)?; + let out_dir = if is_main { dir.clone() } else { - let dir = dir.join("deps"); - let packages_with_same_name = &names[&pkg.name.name]; - if packages_with_same_name.len() == 1 { - dir.join(&pkg.name.name) + dir.join("deps") + }; + let packages_with_same_name = &names[&pkg.name.name]; + let packages_with_same_namespace = packages_with_same_name[&pkg.name.namespace]; + let stem = if packages_with_same_name.len() == 1 { + if packages_with_same_namespace == 1 { + pkg.name.name.clone() + } else { + pkg.name + .version + .as_ref() + .map(|ver| format!("{}@{}", pkg.name.name, ver)) + .unwrap_or_else(|| pkg.name.name.clone()) + } + } else { + if packages_with_same_namespace == 1 { + format!("{}:{}", pkg.name.namespace, pkg.name.name) } else { - let packages_with_same_namespace = - packages_with_same_name[&pkg.name.namespace]; - if packages_with_same_namespace == 1 { - dir.join(format!("{}:{}", pkg.name.namespace, pkg.name.name)) - } else { - dir.join(pkg.name.to_string()) - } + pkg.name.to_string() } }; std::fs::create_dir_all(&out_dir) .with_context(|| format!("failed to create directory: {out_dir:?}"))?; - let path = out_dir.join("main.wit"); + let filename = format!("{stem}.wit"); + let path = out_dir.join(&filename); std::fs::write(&path, &output) .with_context(|| format!("failed to write file: {path:?}"))?; println!("Writing: {}", path.display()); @@ -669,8 +676,7 @@ impl WitOpts { self.output.output( &self.general, Output::Wit { - resolve: &resolve, - ids: &main, + wit: &decoded, printer, }, )?; diff --git a/src/bin/wasm-tools/validate.rs b/src/bin/wasm-tools/validate.rs index c0268ccb0d..b94596b51d 100644 --- a/src/bin/wasm-tools/validate.rs +++ b/src/bin/wasm-tools/validate.rs @@ -1,5 +1,6 @@ use addr2line::LookupResult; use anyhow::{anyhow, Context, Result}; +use bitflags::Flags; use rayon::prelude::*; use std::fmt::Write; use std::mem; @@ -171,37 +172,9 @@ impl Opts { fn parse_features(arg: &str) -> Result { let mut ret = WasmFeatures::default(); - const FEATURES: &[(&str, WasmFeatures)] = &[ - ("reference-types", WasmFeatures::REFERENCE_TYPES), - ("function-references", WasmFeatures::FUNCTION_REFERENCES), - ("simd", WasmFeatures::SIMD), - ("threads", WasmFeatures::THREADS), - ( - "shared-everything-threads", - WasmFeatures::SHARED_EVERYTHING_THREADS, - ), - ("bulk-memory", WasmFeatures::BULK_MEMORY), - ("multi-value", WasmFeatures::MULTI_VALUE), - ("tail-call", WasmFeatures::TAIL_CALL), - ("component-model", WasmFeatures::COMPONENT_MODEL), - ( - "component-model-values", - WasmFeatures::COMPONENT_MODEL_VALUES, - ), - ("multi-memory", WasmFeatures::MULTI_MEMORY), - ("exception-handling", WasmFeatures::EXCEPTIONS), - ("memory64", WasmFeatures::MEMORY64), - ("extended-const", WasmFeatures::EXTENDED_CONST), - ("floats", WasmFeatures::FLOATS), - ( - "saturating-float-to-int", - WasmFeatures::SATURATING_FLOAT_TO_INT, - ), - ("sign-extension", WasmFeatures::SIGN_EXTENSION), - ("mutable-global", WasmFeatures::MUTABLE_GLOBAL), - ("relaxed-simd", WasmFeatures::RELAXED_SIMD), - ("gc", WasmFeatures::GC), - ]; + fn flag_name(flag: &bitflags::Flag) -> String { + flag.name().to_lowercase().replace('_', "-") + } for part in arg.split(',').map(|s| s.trim()).filter(|s| !s.is_empty()) { let (enable, part) = if let Some(part) = part.strip_prefix("-") { @@ -211,28 +184,27 @@ fn parse_features(arg: &str) -> Result { }; match part { "all" => { - for (name, feature) in FEATURES { - // don't count this under "all" for now. - if *name == "deterministic" { - continue; - } - ret.set(*feature, enable); + for flag in WasmFeatures::FLAGS.iter() { + ret.set(*flag.value(), enable); } } name => { - let (_, feature) = FEATURES.iter().find(|(n, _)| *n == name).ok_or_else(|| { - anyhow!( - "unknown feature `{}`\nValid features: {}", - name, - FEATURES - .iter() - .map(|(name, _)| *name) - .collect::>() - .join(", "), - ) - })?; - ret.set(*feature, enable); + let flag = WasmFeatures::FLAGS + .iter() + .find(|f| flag_name(f) == name) + .ok_or_else(|| { + anyhow!( + "unknown feature `{}`\nValid features: {}", + name, + WasmFeatures::FLAGS + .iter() + .map(flag_name) + .collect::>() + .join(", "), + ) + })?; + ret.set(*flag.value(), enable); } } } diff --git a/src/lib.rs b/src/lib.rs index b9536eff81..70210b8356 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -143,8 +143,7 @@ pub struct OutputArg { pub enum Output<'a> { #[cfg(feature = "component")] Wit { - resolve: &'a wit_parser::Resolve, - ids: &'a [wit_parser::PackageId], + wit: &'a wit_component::DecodedWasm, printer: wit_component::WitPrinter, }, Wasm(&'a [u8]), @@ -233,12 +232,14 @@ impl OutputArg { } Output::Json(s) => self.output_str(s), #[cfg(feature = "component")] - Output::Wit { - resolve, - ids, - mut printer, - } => { - let output = printer.print(resolve, ids)?; + Output::Wit { wit, mut printer } => { + let resolve = wit.resolve(); + let ids = resolve + .packages + .iter() + .map(|(id, _)| id) + .collect::>(); + let output = printer.print(resolve, &ids, false)?; self.output_str(&output) } } diff --git a/tests/cli.rs b/tests/cli.rs index 3c8d2cfd23..2e9d16645a 100644 --- a/tests/cli.rs +++ b/tests/cli.rs @@ -32,6 +32,7 @@ use std::env; use std::io::Write; use std::path::{Path, PathBuf}; use std::process::{Command, Output, Stdio}; +use tempfile::TempDir; fn main() { let mut tests = Vec::new(); @@ -76,6 +77,7 @@ fn run_test(test: &Path, bless: bool) -> Result<()> { let mut cmd = wasm_tools_exe(); let mut stdin = None; + let tempdir = TempDir::new()?; for arg in line.split_whitespace() { if arg == "|" { let output = execute(&mut cmd, stdin.as_deref(), false)?; @@ -83,6 +85,8 @@ fn run_test(test: &Path, bless: bool) -> Result<()> { cmd = wasm_tools_exe(); } else if arg == "%" { cmd.arg(test); + } else if arg == "%tmpdir" { + cmd.arg(tempdir.path()); } else { cmd.arg(arg); } @@ -94,12 +98,14 @@ fn run_test(test: &Path, bless: bool) -> Result<()> { bless, &output.stdout, &test.with_extension(&format!("{extension}.stdout")), + &tempdir, ) .context("failed to check stdout expectation (auto-update with BLESS=1)")?; assert_output( bless, &output.stderr, &test.with_extension(&format!("{extension}.stderr")), + &tempdir, ) .context("failed to check stderr expectation (auto-update with BLESS=1)")?; Ok(()) @@ -145,7 +151,14 @@ fn execute(cmd: &mut Command, stdin: Option<&[u8]>, should_fail: bool) -> Result Ok(output) } -fn assert_output(bless: bool, output: &[u8], path: &Path) -> Result<()> { +fn assert_output(bless: bool, output: &[u8], path: &Path, tempdir: &TempDir) -> Result<()> { + let tempdir = tempdir.path().to_str().unwrap(); + // sanitize the output to be consistent across platforms and handle per-test + // differences such as `%tmpdir`. + let output = String::from_utf8_lossy(output) + .replace(tempdir, "%tmpdir") + .replace("\\", "/"); + if bless { if output.is_empty() { drop(std::fs::remove_file(path)); @@ -162,7 +175,6 @@ fn assert_output(bless: bool, output: &[u8], path: &Path) -> Result<()> { Ok(()) } } else { - let output = std::str::from_utf8(output)?; let contents = std::fs::read_to_string(path) .with_context(|| format!("failed to read {path:?}"))? .replace("\r\n", "\n"); diff --git a/tests/cli/dump-llvm-object.wat.stdout b/tests/cli/dump-llvm-object.wat.stdout index a421d7231f..fb518e2210 100644 --- a/tests/cli/dump-llvm-object.wat.stdout +++ b/tests/cli/dump-llvm-object.wat.stdout @@ -47,7 +47,7 @@ | 39 65 32 32 | 65 30 65 45 | 00 02 - 0x98 | 03 65 6e 76 | import [table 0] Import { module: "env", name: "__indirect_function_table", ty: Table(TableType { element_type: funcref, table64: false, initial: 4, maximum: None }) } + 0x98 | 03 65 6e 76 | import [table 0] Import { module: "env", name: "__indirect_function_table", ty: Table(TableType { element_type: funcref, table64: false, initial: 4, maximum: None, shared: false }) } | 19 5f 5f 69 | 6e 64 69 72 | 65 63 74 5f diff --git a/tests/cli/dump/alias2.wat.stdout b/tests/cli/dump/alias2.wat.stdout index 2710d46edf..c88baadeed 100644 --- a/tests/cli/dump/alias2.wat.stdout +++ b/tests/cli/dump/alias2.wat.stdout @@ -133,7 +133,7 @@ 0x161 | 00 | [func 0] type 0 0x162 | 04 04 | table section 0x164 | 01 | 1 count - 0x165 | 70 00 01 | [table 0] Table { ty: TableType { element_type: funcref, table64: false, initial: 1, maximum: None }, init: RefNull } + 0x165 | 70 00 01 | [table 0] Table { ty: TableType { element_type: funcref, table64: false, initial: 1, maximum: None, shared: false }, init: RefNull } 0x168 | 05 03 | memory section 0x16a | 01 | 1 count 0x16b | 00 01 | [memory 0] MemoryType { memory64: false, shared: false, initial: 1, maximum: None, page_size_log2: None } @@ -173,7 +173,7 @@ | 00 01 0x1b6 | 00 01 33 03 | import [global 0] Import { module: "", name: "3", ty: Global(GlobalType { content_type: I32, mutable: false, shared: false }) } | 7f 00 - 0x1bc | 00 01 34 01 | import [table 0] Import { module: "", name: "4", ty: Table(TableType { element_type: funcref, table64: false, initial: 1, maximum: None }) } + 0x1bc | 00 01 34 01 | import [table 0] Import { module: "", name: "4", ty: Table(TableType { element_type: funcref, table64: false, initial: 1, maximum: None, shared: false }) } | 70 00 01 0x1c3 | 00 0a | custom section 0x1c5 | 04 6e 61 6d | name: "name" diff --git a/tests/cli/dump/module-types.wat.stdout b/tests/cli/dump/module-types.wat.stdout index ddde806ebd..1e36b9d1b7 100644 --- a/tests/cli/dump/module-types.wat.stdout +++ b/tests/cli/dump/module-types.wat.stdout @@ -2,7 +2,7 @@ | 0d 00 01 00 0x8 | 03 23 | core type section 0xa | 01 | 1 count - 0xb | 50 05 01 60 | [core type 0] Module([Type(SubType { is_final: true, supertype_idx: None, composite_type: CompositeType { inner: Func(FuncType { params: [], results: [] }), shared: false } }), Import(Import { module: "", name: "f", ty: Func(0) }), Import(Import { module: "", name: "g", ty: Global(GlobalType { content_type: I32, mutable: false, shared: false }) }), Import(Import { module: "", name: "t", ty: Table(TableType { element_type: funcref, table64: false, initial: 1, maximum: None }) }), Import(Import { module: "", name: "m", ty: Memory(MemoryType { memory64: false, shared: false, initial: 1, maximum: None, page_size_log2: None }) })]) + 0xb | 50 05 01 60 | [core type 0] Module([Type(SubType { is_final: true, supertype_idx: None, composite_type: CompositeType { inner: Func(FuncType { params: [], results: [] }), shared: false } }), Import(Import { module: "", name: "f", ty: Func(0) }), Import(Import { module: "", name: "g", ty: Global(GlobalType { content_type: I32, mutable: false, shared: false }) }), Import(Import { module: "", name: "t", ty: Table(TableType { element_type: funcref, table64: false, initial: 1, maximum: None, shared: false }) }), Import(Import { module: "", name: "m", ty: Memory(MemoryType { memory64: false, shared: false, initial: 1, maximum: None, page_size_log2: None }) })]) | 00 00 00 00 | 01 66 00 00 | 00 00 01 67 diff --git a/tests/cli/dump/simple.wat.stdout b/tests/cli/dump/simple.wat.stdout index 59e8902f66..b01a25e80b 100644 --- a/tests/cli/dump/simple.wat.stdout +++ b/tests/cli/dump/simple.wat.stdout @@ -17,7 +17,7 @@ 0x20 | 01 | [func 3] type 1 0x21 | 04 04 | table section 0x23 | 01 | 1 count - 0x24 | 70 00 01 | [table 0] Table { ty: TableType { element_type: funcref, table64: false, initial: 1, maximum: None }, init: RefNull } + 0x24 | 70 00 01 | [table 0] Table { ty: TableType { element_type: funcref, table64: false, initial: 1, maximum: None, shared: false }, init: RefNull } 0x27 | 05 03 | memory section 0x29 | 01 | 1 count 0x2a | 00 01 | [memory 0] MemoryType { memory64: false, shared: false, initial: 1, maximum: None, page_size_log2: None } diff --git a/tests/cli/print-core-wasm-wit-multiple-packages.wit.stdout b/tests/cli/print-core-wasm-wit-multiple-packages.wit.stdout index 75feb032d8..57c65fce90 100644 --- a/tests/cli/print-core-wasm-wit-multiple-packages.wit.stdout +++ b/tests/cli/print-core-wasm-wit-multiple-packages.wit.stdout @@ -1,5 +1,16 @@ -package root:root; +package root:root { + world root { + import bar:bar/my-interface; + } +} + + +package bar:bar { + interface my-interface { + foo: func(); + } -world root { - import bar:bar/my-interface; + world my-world { + import my-interface; + } } diff --git a/tests/cli/print-core-wasm-wit.wit.stdout b/tests/cli/print-core-wasm-wit.wit.stdout index e560f82ea0..c1eb1f6319 100644 --- a/tests/cli/print-core-wasm-wit.wit.stdout +++ b/tests/cli/print-core-wasm-wit.wit.stdout @@ -1,5 +1,16 @@ -package root:root; +package root:root { + world root { + import foo:foo/my-interface; + } +} + + +package foo:foo { + interface my-interface { + foo: func(); + } -world root { - import foo:foo/my-interface; + world my-world { + import my-interface; + } } diff --git a/tests/cli/validate-features.wat b/tests/cli/validate-features.wat new file mode 100644 index 0000000000..3aad684f90 --- /dev/null +++ b/tests/cli/validate-features.wat @@ -0,0 +1,5 @@ +;; FAIL: validate --features=-all % + +(module + (import "x" "y" (global v128)) +) diff --git a/tests/cli/validate-features.wat.stderr b/tests/cli/validate-features.wat.stderr new file mode 100644 index 0000000000..45ead379a2 --- /dev/null +++ b/tests/cli/validate-features.wat.stderr @@ -0,0 +1 @@ +error: SIMD support is not enabled (at offset 0xb) diff --git a/tests/cli/validate-features2.wat b/tests/cli/validate-features2.wat new file mode 100644 index 0000000000..4bf1c1352e --- /dev/null +++ b/tests/cli/validate-features2.wat @@ -0,0 +1,6 @@ +;; RUN: validate --features=-all,simd % + +(module + (import "x" "y" (global v128)) +) + diff --git a/tests/cli/validate-unknown-features.wat b/tests/cli/validate-unknown-features.wat new file mode 100644 index 0000000000..daebd5c64b --- /dev/null +++ b/tests/cli/validate-unknown-features.wat @@ -0,0 +1,4 @@ +;; FAIL: validate --features=unknown % + +(module) + diff --git a/tests/cli/validate-unknown-features.wat.stderr b/tests/cli/validate-unknown-features.wat.stderr new file mode 100644 index 0000000000..3a72311f23 --- /dev/null +++ b/tests/cli/validate-unknown-features.wat.stderr @@ -0,0 +1,4 @@ +error: invalid value 'unknown' for '--features ': unknown feature `unknown` +Valid features: mutable-global, saturating-float-to-int, sign-extension, reference-types, multi-value, bulk-memory, simd, relaxed-simd, threads, shared-everything-threads, tail-call, floats, multi-memory, exceptions, memory64, extended-const, component-model, function-references, memory-control, gc, custom-page-sizes, component-model-values, component-model-nested-names, component-model-more-flags, legacy-exceptions + +For more information, try '--help'. diff --git a/tests/cli/wit-directory-output-in-deps-folder-with-multiple-version.wit b/tests/cli/wit-directory-output-in-deps-folder-with-multiple-version.wit new file mode 100644 index 0000000000..980d99db88 --- /dev/null +++ b/tests/cli/wit-directory-output-in-deps-folder-with-multiple-version.wit @@ -0,0 +1,16 @@ +// RUN: component wit % --out-dir %tmpdir | component wit %tmpdir + +package a:b@0.2.0 { + interface foo {} +} + +package a:b { + interface foo {} +} + +package a:c { + world a { + import a:b/foo@0.2.0; + import a:b/foo; + } +} \ No newline at end of file diff --git a/tests/cli/wit-directory-output-in-deps-folder-with-multiple-version.wit.stdout b/tests/cli/wit-directory-output-in-deps-folder-with-multiple-version.wit.stdout new file mode 100644 index 0000000000..f306ee9c73 --- /dev/null +++ b/tests/cli/wit-directory-output-in-deps-folder-with-multiple-version.wit.stdout @@ -0,0 +1,20 @@ +package a:b { + interface foo { + } + +} + + +package a:b@0.2.0 { + interface foo { + } + +} + + +package a:c { + world a { + import a:b/foo@0.2.0; + import a:b/foo; + } +} diff --git a/tests/cli/wit-directory-output-in-deps-folder.wit b/tests/cli/wit-directory-output-in-deps-folder.wit new file mode 100644 index 0000000000..58ff346e05 --- /dev/null +++ b/tests/cli/wit-directory-output-in-deps-folder.wit @@ -0,0 +1,14 @@ +// RUN: component embed --dummy % --world a:b/c | component wit --out-dir %tmpdir + +package a:b { + interface foo {} + + world c { + import foo; + import a:c/foo; + } +} + +package a:c { + interface foo {} +} diff --git a/tests/cli/wit-directory-output-in-deps-folder.wit.stdout b/tests/cli/wit-directory-output-in-deps-folder.wit.stdout new file mode 100644 index 0000000000..8c2fc622ef --- /dev/null +++ b/tests/cli/wit-directory-output-in-deps-folder.wit.stdout @@ -0,0 +1,3 @@ +Writing: %tmpdir/root.wit +Writing: %tmpdir/deps/b.wit +Writing: %tmpdir/deps/c.wit diff --git a/tests/cli/wit-directory-output-valid.wit b/tests/cli/wit-directory-output-valid.wit new file mode 100644 index 0000000000..01e60dca1b --- /dev/null +++ b/tests/cli/wit-directory-output-valid.wit @@ -0,0 +1,14 @@ +// RUN: component wit % --out-dir %tmpdir | component wit %tmpdir + +package a:b { + interface foo {} + + world c { + import foo; + import a:c/foo; + } +} + +package a:c { + interface foo {} +} diff --git a/tests/cli/wit-directory-output-valid.wit.stdout b/tests/cli/wit-directory-output-valid.wit.stdout new file mode 100644 index 0000000000..33576bc7a2 --- /dev/null +++ b/tests/cli/wit-directory-output-valid.wit.stdout @@ -0,0 +1,16 @@ +package a:c { + interface foo { + } + +} + + +package a:b { + interface foo { + } + + world c { + import foo; + import a:c/foo; + } +} diff --git a/tests/cli/wit-directory-output.wit b/tests/cli/wit-directory-output.wit new file mode 100644 index 0000000000..88d6f83d7d --- /dev/null +++ b/tests/cli/wit-directory-output.wit @@ -0,0 +1,14 @@ +// RUN: component wit % --out-dir %tmpdir + +package a:b { + interface foo {} + + world c { + import foo; + import a:c/foo; + } +} + +package a:c { + interface foo {} +} diff --git a/tests/cli/wit-directory-output.wit.stdout b/tests/cli/wit-directory-output.wit.stdout new file mode 100644 index 0000000000..9524cea580 --- /dev/null +++ b/tests/cli/wit-directory-output.wit.stdout @@ -0,0 +1,2 @@ +Writing: %tmpdir/c.wit +Writing: %tmpdir/b.wit diff --git a/tests/local/legacy-exceptions/legacy-exceptions.wat b/tests/local/legacy-exceptions/legacy-exceptions.wat new file mode 100644 index 0000000000..f923a69ae1 --- /dev/null +++ b/tests/local/legacy-exceptions/legacy-exceptions.wat @@ -0,0 +1,17 @@ +;; --enable-legacy-exceptions +(module + (type (;0;) (func)) + (func (;0;) (type 0) + try ;; label = @1 + try ;; label = @2 + try ;; label = @3 + throw 0 + catch_all + rethrow 0 (;@3;) + end + delegate 0 (;@2;) + catch 0 + end + ) + (tag (;0;) (type 0)) +) diff --git a/tests/local/legacy-exceptions/rethrow.wast b/tests/local/legacy-exceptions/rethrow.wast new file mode 100644 index 0000000000..5a7b320c5d --- /dev/null +++ b/tests/local/legacy-exceptions/rethrow.wast @@ -0,0 +1,124 @@ +;; Test rethrow instruction. + +(module + (tag $e0) + (tag $e1) + + (func (export "catch-rethrow-0") + try + throw $e0 + catch $e0 + rethrow 0 + end + ) + + (func (export "catch-rethrow-1") (param i32) (result i32) + try (result i32) + throw $e0 + catch $e0 + local.get 0 + i32.eqz + if + rethrow 1 + end + i32.const 23 + end + ) + + (func (export "catchall-rethrow-0") + try + throw $e0 + catch_all + rethrow 0 + end + ) + + (func (export "catchall-rethrow-1") (param i32) (result i32) + try (result i32) + throw $e0 + catch_all + local.get 0 + i32.eqz + if + rethrow 1 + end + i32.const 23 + end + ) + + (func (export "rethrow-nested") (param i32) (result i32) + try (result i32) + throw $e1 + catch $e1 + try (result i32) + throw $e0 + catch $e0 + local.get 0 + i32.const 0 + i32.eq + if + rethrow 1 + end + local.get 0 + i32.const 1 + i32.eq + if + rethrow 2 + end + i32.const 23 + end + end + ) + + (func (export "rethrow-recatch") (param i32) (result i32) + try (result i32) + throw $e0 + catch $e0 + try (result i32) + local.get 0 + i32.eqz + if + rethrow 2 + end + i32.const 42 + catch $e0 + i32.const 23 + end + end + ) + + (func (export "rethrow-stack-polymorphism") + try + throw $e0 + catch $e0 + i32.const 1 + rethrow 0 + end + ) +) + +(assert_exception (invoke "catch-rethrow-0")) + +(assert_exception (invoke "catch-rethrow-1" (i32.const 0))) +(assert_return (invoke "catch-rethrow-1" (i32.const 1)) (i32.const 23)) + +(assert_exception (invoke "catchall-rethrow-0")) + +(assert_exception (invoke "catchall-rethrow-1" (i32.const 0))) +(assert_return (invoke "catchall-rethrow-1" (i32.const 1)) (i32.const 23)) +(assert_exception (invoke "rethrow-nested" (i32.const 0))) +(assert_exception (invoke "rethrow-nested" (i32.const 1))) +(assert_return (invoke "rethrow-nested" (i32.const 2)) (i32.const 23)) + +(assert_return (invoke "rethrow-recatch" (i32.const 0)) (i32.const 23)) +(assert_return (invoke "rethrow-recatch" (i32.const 1)) (i32.const 42)) + +(assert_exception (invoke "rethrow-stack-polymorphism")) + +(assert_invalid (module (func (rethrow 0))) "invalid rethrow label") +(assert_invalid (module (func (block (rethrow 0)))) "invalid rethrow label") +(assert_invalid (module (func + try + rethrow 0 + delegate 0)) + "invalid rethrow label") diff --git a/tests/local/legacy-exceptions/throw.wast b/tests/local/legacy-exceptions/throw.wast new file mode 100644 index 0000000000..2ab9f2f330 --- /dev/null +++ b/tests/local/legacy-exceptions/throw.wast @@ -0,0 +1,56 @@ +;; Test throw instruction. + +(module + (tag $e0) + (tag $e-i32 (param i32)) + (tag $e-f32 (param f32)) + (tag $e-i64 (param i64)) + (tag $e-f64 (param f64)) + (tag $e-i32-i32 (param i32 i32)) + + (func $throw-if (export "throw-if") (param i32) (result i32) + (local.get 0) + (i32.const 0) (if (i32.ne) (then (throw $e0))) + (i32.const 0) + ) + + (func (export "throw-param-f32") (param f32) (local.get 0) (throw $e-f32)) + + (func (export "throw-param-i64") (param i64) (local.get 0) (throw $e-i64)) + + (func (export "throw-param-f64") (param f64) (local.get 0) (throw $e-f64)) + + (func $throw-1-2 (i32.const 1) (i32.const 2) (throw $e-i32-i32)) + (func (export "test-throw-1-2") + try + call $throw-1-2 + catch $e-i32-i32 + i32.const 2 + i32.ne + if + unreachable + end + i32.const 1 + i32.ne + if + unreachable + end + end + ) +) + +(assert_return (invoke "throw-if" (i32.const 0)) (i32.const 0)) +(assert_exception (invoke "throw-if" (i32.const 10))) +(assert_exception (invoke "throw-if" (i32.const -1))) + +(assert_exception (invoke "throw-param-f32" (f32.const 5.0))) +(assert_exception (invoke "throw-param-i64" (i64.const 5))) +(assert_exception (invoke "throw-param-f64" (f64.const 5.0))) + +(assert_return (invoke "test-throw-1-2")) + +(assert_invalid (module (func (throw 0))) "unknown tag 0") +(assert_invalid (module (tag (param i32)) (func (throw 0))) + "type mismatch: instruction requires [i32] but stack has []") +(assert_invalid (module (tag (param i32)) (func (i64.const 5) (throw 0))) + "type mismatch: instruction requires [i32] but stack has [i64]") diff --git a/tests/local/legacy-exceptions/try_catch.wast b/tests/local/legacy-exceptions/try_catch.wast new file mode 100644 index 0000000000..8819e82487 --- /dev/null +++ b/tests/local/legacy-exceptions/try_catch.wast @@ -0,0 +1,309 @@ +;; Test try-catch blocks. + +(module + (tag $e0 (export "e0")) + (func (export "throw") (throw $e0)) +) + +(register "test") + +(module + (tag $imported-e0 (import "test" "e0")) + (func $imported-throw (import "test" "throw")) + (tag $e0) + (tag $e1) + (tag $e2) + (tag $e-i32 (param i32)) + (tag $e-f32 (param f32)) + (tag $e-i64 (param i64)) + (tag $e-f64 (param f64)) + + (func $throw-if (param i32) (result i32) + (local.get 0) + (i32.const 0) (if (i32.ne) (then (throw $e0))) + (i32.const 0) + ) + + (func (export "empty-catch") + try + catch $e0 + end + ) + + (func (export "simple-throw-catch") (param i32) (result i32) + try (result i32) + local.get 0 + i32.eqz + if + throw 1 + end + i32.const 42 + catch 1 + i32.const 23 + end + ) + + (func (export "unreachable-not-caught") try unreachable catch_all end) + + (func $div (param i32 i32) (result i32) + (local.get 0) (local.get 1) (i32.div_u) + ) + (func (export "trap-in-callee") (param i32 i32) (result i32) + try (result i32) + local.get 0 + local.get 1 + call 5 + catch_all + i32.const 11 + end + ) + + (func (export "catch-complex-1") (param i32) (result i32) + try (result i32) + try (result i32) + local.get 0 + i32.eqz + if + throw 1 + else + local.get 0 + i32.const 1 + i32.eq + if + throw 2 + else + throw 3 + end + end + i32.const 2 + catch 1 + i32.const 3 + end + catch 2 + i32.const 4 + end + ) + + (func (export "catch-complex-2") (param i32) (result i32) + try (result i32) + local.get 0 + i32.eqz + if + throw 1 + else + local.get 0 + i32.const 1 + i32.eq + if + throw 2 + else + throw 3 + end + end + i32.const 2 + catch 1 + i32.const 3 + catch 2 + i32.const 4 + end + ) + + (func (export "throw-catch-param-i32") (param i32) (result i32) + try (result i32) + local.get 0 + throw 4 + i32.const 2 + catch 4 + return + end + ) + + (func (export "throw-catch-param-f32") (param f32) (result f32) + try (result f32) + local.get 0 + throw 5 + f32.const 0 + catch 5 + return + end + ) + + (func (export "throw-catch-param-i64") (param i64) (result i64) + try (result i64) + local.get 0 + throw 6 + i64.const 2 + catch 6 + return + end + ) + + (func (export "throw-catch-param-f64") (param f64) (result f64) + try (result f64) + local.get 0 + throw 7 + f64.const 0 + catch 7 + return + end + ) + + (func $throw-param-i32 (param i32) (local.get 0) (throw $e-i32)) + (func (export "catch-param-i32") (param i32) (result i32) + try (result i32) + i32.const 0 + local.get 0 + call 13 + catch 4 + end + ) + + (func (export "catch-imported") (result i32) + try (result i32) + i32.const 1 + call 0 + catch 0 + i32.const 2 + end + ) + + (func (export "catchless-try") (param i32) (result i32) + try (result i32) + try (result i32) + local.get 0 + call 1 + end + catch 1 + i32.const 1 + end + ) + + (func $throw-void (throw $e0)) + (func (export "return-call-in-try-catch") + try + return_call 17 + catch 1 + end + ) + + (table funcref (elem $throw-void)) + (func (export "return-call-indirect-in-try-catch") + try + i32.const 0 + return_call_indirect (type 0) + catch 1 + end + ) + + (func (export "break-try-catch") + try + br 0 + catch 1 + end + ) + + (func (export "break-try-catch_all") + try + br 0 + catch_all + end + ) +) + +(assert_return (invoke "empty-catch")) + +(assert_return (invoke "simple-throw-catch" (i32.const 0)) (i32.const 23)) +(assert_return (invoke "simple-throw-catch" (i32.const 1)) (i32.const 42)) + +(assert_trap (invoke "unreachable-not-caught") "unreachable") + +(assert_return (invoke "trap-in-callee" (i32.const 7) (i32.const 2)) (i32.const 3)) +(assert_trap (invoke "trap-in-callee" (i32.const 1) (i32.const 0)) "integer divide by zero") + +(assert_return (invoke "catch-complex-1" (i32.const 0)) (i32.const 3)) +(assert_return (invoke "catch-complex-1" (i32.const 1)) (i32.const 4)) +(assert_exception (invoke "catch-complex-1" (i32.const 2))) + +(assert_return (invoke "catch-complex-2" (i32.const 0)) (i32.const 3)) +(assert_return (invoke "catch-complex-2" (i32.const 1)) (i32.const 4)) +(assert_exception (invoke "catch-complex-2" (i32.const 2))) + +(assert_return (invoke "throw-catch-param-i32" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "throw-catch-param-i32" (i32.const 1)) (i32.const 1)) +(assert_return (invoke "throw-catch-param-i32" (i32.const 10)) (i32.const 10)) + +(assert_return (invoke "throw-catch-param-f32" (f32.const 5.0)) (f32.const 5.0)) +(assert_return (invoke "throw-catch-param-f32" (f32.const 10.5)) (f32.const 10.5)) + +(assert_return (invoke "throw-catch-param-i64" (i64.const 5)) (i64.const 5)) +(assert_return (invoke "throw-catch-param-i64" (i64.const 0)) (i64.const 0)) +(assert_return (invoke "throw-catch-param-i64" (i64.const -1)) (i64.const -1)) + +(assert_return (invoke "throw-catch-param-f64" (f64.const 5.0)) (f64.const 5.0)) +(assert_return (invoke "throw-catch-param-f64" (f64.const 10.5)) (f64.const 10.5)) + +(assert_return (invoke "catch-param-i32" (i32.const 5)) (i32.const 5)) + +(assert_return (invoke "catch-imported") (i32.const 2)) + +(assert_return (invoke "catchless-try" (i32.const 0)) (i32.const 0)) +(assert_return (invoke "catchless-try" (i32.const 1)) (i32.const 1)) + +(assert_exception (invoke "return-call-in-try-catch")) +(assert_exception (invoke "return-call-indirect-in-try-catch")) + +(assert_return (invoke "break-try-catch")) +(assert_return (invoke "break-try-catch_all")) + +(module + (func $imported-throw (import "test" "throw")) + (tag $e0) + + (func (export "imported-mismatch") (result i32) + try (result i32) ;; label = @1 + try (result i32) ;; label = @2 + i32.const 1 + call 0 + catch 0 + i32.const 2 + end + catch_all + i32.const 3 + end + ) +) + +(assert_return (invoke "imported-mismatch") (i32.const 3)) + +;; Ignore per https://github.com/bytecodealliance/wasm-tools/issues/1671 +;; +;; (assert_malformed +;; (module quote "(module (func (catch_all)))") +;; "unexpected token" +;; ) + +;; (assert_malformed +;; (module quote "(module (tag $e) (func (catch $e)))") +;; "unexpected token" +;; ) + +;; (assert_malformed +;; (module quote +;; "(module (func try catch_all catch_all end))" +;; ) +;; "unexpected token" +;; ) + +(assert_invalid (module (func (result i32) try (result i32) end)) + "type mismatch: instruction requires [i32] but stack has []") +(assert_invalid (module (func (result i32) try (result i32) i64.const 42 end)) + "type mismatch: instruction requires [i32] but stack has [i64]") +(assert_invalid (module (tag) (func try catch 0 i32.const 42 end)) + "type mismatch: block requires [] but stack has [i32]") +(assert_invalid (module + (tag (param i64)) + (func (result i32) + try (result i32) i32.const 42 catch 0 end)) + "type mismatch: instruction requires [i32] but stack has [i64]") +(assert_invalid (module (func try catch_all i32.const 32 end)) + "type mismatch: block requires [] but stack has [i32]") diff --git a/tests/local/legacy-exceptions/try_delegate.wast b/tests/local/legacy-exceptions/try_delegate.wast new file mode 100644 index 0000000000..8f115268d9 --- /dev/null +++ b/tests/local/legacy-exceptions/try_delegate.wast @@ -0,0 +1,275 @@ +;; Test try-delegate blocks. + +(module + (tag $e0) + (tag $e1) + + (func (export "delegate-no-throw") (result i32) + try (result i32) ;; label = @1 + try (result i32) ;; label = @2 + i32.const 1 + delegate 0 + catch 0 + i32.const 2 + end + ) + + (func $throw-if (param i32) + (local.get 0) + (if (then (throw $e0)) (else)) + ) + + (func (export "delegate-throw") (param i32) (result i32) + try (result i32) ;; label = @1 + try (result i32) ;; label = @2 + local.get 0 + call 1 + i32.const 1 + delegate 0 + catch 0 + i32.const 2 + end + ) + + (func (export "delegate-skip") (result i32) + try (result i32) ;; label = @1 + try (result i32) ;; label = @2 + try (result i32) ;; label = @3 + throw 0 + i32.const 1 + delegate 1 + catch 0 + i32.const 2 + end + catch 0 + i32.const 3 + end + ) + + (func (export "delegate-to-block") (result i32) + try (result i32) ;; label = @1 + block ;; label = @2 + try ;; label = @3 + throw 0 + delegate 0 + end + i32.const 0 + catch_all + i32.const 1 + end + ) + + (func (export "delegate-to-catch") (result i32) + try (result i32) ;; label = @1 + try ;; label = @2 + throw 0 + catch 0 + try ;; label = @3 + rethrow 1 (;@2;) + delegate 0 + end + i32.const 0 + catch_all + i32.const 1 + end + ) + + (func (export "delegate-to-caller-trivial") + try ;; label = @1 + throw 0 + delegate 0) + + (func (export "delegate-to-caller-skipping") + try ;; label = @1 + try ;; label = @2 + throw 0 + delegate 1 + catch_all + end + ) + + (func $select-tag (param i32) + block ;; label = @1 + block ;; label = @2 + block ;; label = @3 + local.get 0 + br_table 0 (;@3;) 1 (;@2;) 2 (;@1;) + end + return + end + throw 0 + end + throw 1 + ) + + (func (export "delegate-merge") (param i32 i32) (result i32) + try (result i32) ;; label = @1 + local.get 0 + call 8 + try (result i32) ;; label = @2 + local.get 1 + call 8 + i32.const 1 + delegate 0 + catch 0 + i32.const 2 + end + ) + + (func (export "delegate-throw-no-catch") (result i32) + try (result i32) ;; label = @1 + try (result i32) ;; label = @2 + throw 0 + i32.const 1 + delegate 0 + catch 1 + i32.const 2 + end + ) + + (func (export "delegate-correct-targets") (result i32) + try (result i32) ;; label = @1 + try ;; label = @2 + try ;; label = @3 + try ;; label = @4 + try ;; label = @5 + try ;; label = @6 + throw 0 + delegate 1 + catch_all + unreachable + end + delegate 1 + catch_all + unreachable + end + catch_all + try ;; label = @3 + throw 0 + delegate 0 + end + unreachable + catch_all + i32.const 1 + end) + + (func $throw-void (throw $e0)) + (func (export "return-call-in-try-delegate") + try ;; label = @1 + try ;; label = @2 + return_call 12 + delegate 0 + catch 0 + end + ) + + (table funcref (elem $throw-void)) + (func (export "return-call-indirect-in-try-delegate") + try ;; label = @1 + try ;; label = @2 + i32.const 0 + return_call_indirect (type 0) + delegate 0 + catch 0 + end + ) + + (func (export "break-try-delegate") + try ;; label = @1 + br 0 (;@1;) + delegate 0) + + (func (export "break-and-call-throw") (result i32) + try (result i32) ;; label = @1 + try (result i32) ;; label = @2 + block ;; label = @3 + try ;; label = @4 + br 1 (;@3;) + delegate 2 + end + call 12 + i32.const 0 + catch 0 + i32.const 1 + end + catch 0 + i32.const 2 + end + ) + + (func (export "break-and-throw") (result i32) + try (result i32) ;; label = @1 + try (result i32) ;; label = @2 + block ;; label = @3 + try ;; label = @4 + br 1 (;@3;) + delegate 2 + end + throw 0 + i32.const 0 + catch 0 + i32.const 1 + end + catch 0 + i32.const 2 + end + ) +) + +(assert_return (invoke "delegate-no-throw") (i32.const 1)) + +(assert_return (invoke "delegate-throw" (i32.const 0)) (i32.const 1)) +(assert_return (invoke "delegate-throw" (i32.const 1)) (i32.const 2)) + +(assert_exception (invoke "delegate-throw-no-catch")) + +(assert_return (invoke "delegate-merge" (i32.const 1) (i32.const 0)) (i32.const 2)) +(assert_exception (invoke "delegate-merge" (i32.const 2) (i32.const 0))) +(assert_return (invoke "delegate-merge" (i32.const 0) (i32.const 1)) (i32.const 2)) +(assert_exception (invoke "delegate-merge" (i32.const 0) (i32.const 2))) +(assert_return (invoke "delegate-merge" (i32.const 0) (i32.const 0)) (i32.const 1)) + +(assert_return (invoke "delegate-skip") (i32.const 3)) + +(assert_return (invoke "delegate-to-block") (i32.const 1)) +(assert_return (invoke "delegate-to-catch") (i32.const 1)) + +(assert_exception (invoke "delegate-to-caller-trivial")) +(assert_exception (invoke "delegate-to-caller-skipping")) + +(assert_return (invoke "delegate-correct-targets") (i32.const 1)) + +(assert_exception (invoke "return-call-in-try-delegate")) +(assert_exception (invoke "return-call-indirect-in-try-delegate")) + +(assert_return (invoke "break-try-delegate")) + +(assert_return (invoke "break-and-call-throw") (i32.const 1)) +(assert_return (invoke "break-and-throw") (i32.const 1)) + +;; Ignore per https://github.com/bytecodealliance/wasm-tools/issues/1671 +;; +;; (assert_malformed +;; (module quote "(module (func (delegate 0)))") +;; "unexpected token" +;; ) + +;; (assert_malformed +;; (module quote "(module (tag $e) (func try catch $e delegate 0))") +;; "unexpected token" +;; ) + +;; (assert_malformed +;; (module quote "(module (func try catch_all delegate 0))") +;; "unexpected token" +;; ) + +;; (assert_malformed +;; (module quote "(module (func try delegate delegate 0))") +;; "unexpected token" +;; ) + +(assert_invalid + (module (func try delegate 1)) + "unknown label" +) diff --git a/tests/local/missing-features/tables.wast b/tests/local/missing-features/tables.wast new file mode 100644 index 0000000000..49e4b6f655 --- /dev/null +++ b/tests/local/missing-features/tables.wast @@ -0,0 +1,5 @@ +(assert_invalid + (module + (table shared 1 funcref) + ) + "shared tables require the shared-everything-threads proposal") diff --git a/tests/local/shared-everything-threads/array.wast b/tests/local/shared-everything-threads/array.wast index e3fb3adbad..064fcecf80 100644 --- a/tests/local/shared-everything-threads/array.wast +++ b/tests/local/shared-everything-threads/array.wast @@ -1,4 +1,4 @@ -;; Shared array declaration syntax +;; Shared array declaration syntax. (module (type (shared (array i8))) (type (sub final (shared (array i8)))) @@ -11,7 +11,7 @@ (global (ref 2) (array.new_default 0 (i32.const 1))) ) -;; Shared arrays are distinct from non-shared arrays +;; Shared arrays are distinct from non-shared arrays. (assert_invalid (module (type (shared (array i8))) @@ -32,7 +32,7 @@ "type mismatch" ) -;; Shared arrays may not be subtypes of non-shared arrays +;; Shared arrays may not be subtypes of non-shared arrays. (assert_invalid (module (type (sub (array i8))) @@ -41,7 +41,7 @@ "sub type must match super type" ) -;; Non-shared arrays may not be subtypes of shared arrays +;; Non-shared arrays may not be subtypes of shared arrays. (assert_invalid (module (type (sub (shared (array i8)))) @@ -50,7 +50,7 @@ "sub type must match super type" ) -;; Shared arrays may not contain non-shared references +;; Shared arrays may not contain non-shared references. (assert_invalid (module (type (shared (array anyref))) @@ -58,12 +58,12 @@ "must contain shared type" ) -;; But they may contain shared references +;; But they may contain shared references. (module (type (shared (array (ref null (shared any))))) ) -;; Non-shared arrays may contain shared references +;; Non-shared arrays may contain shared references. (module (type (array (ref null (shared any)))) ) @@ -113,3 +113,641 @@ (func (param (ref null $i8)) (array.init_data $i8 0 (local.get 0) (i32.const 0) (i32.const 0) (i32.const 0))) ) + +;; Check `array.atomic.rmw.*` instructions. +(module (; get, i32, seq_cst ;) + (type $a (shared (array (mut i32)))) + (func (export "array-atomic-get-i32-seq_cst") (param $x (ref null $a)) (param $y i32) (result i32) + local.get $x + local.get $y + array.atomic.get seq_cst $a) +) + +(module (; get, i64, seq_cst ;) + (type $a (shared (array (mut i64)))) + (func (export "array-atomic-get-i64-seq_cst") (param $x (ref null $a)) (param $y i32) (result i64) + local.get $x + local.get $y + array.atomic.get seq_cst $a) +) + +(module (; get, anyref, seq_cst ;) + (type $a (shared (array (mut (ref null (shared any)))))) + (func (export "array-atomic-get-anyref-seq_cst") (param $x (ref null $a)) (param $y i32) (result (ref null (shared any))) + local.get $x + local.get $y + array.atomic.get seq_cst $a) +) + +(module (; get, i32, acq_rel ;) + (type $a (shared (array (mut i32)))) + (func (export "array-atomic-get-i32-acq_rel") (param $x (ref null $a)) (param $y i32) (result i32) + local.get $x + local.get $y + array.atomic.get acq_rel $a) +) + +(module (; get, i64, acq_rel ;) + (type $a (shared (array (mut i64)))) + (func (export "array-atomic-get-i64-acq_rel") (param $x (ref null $a)) (param $y i32) (result i64) + local.get $x + local.get $y + array.atomic.get acq_rel $a) +) + +(module (; get, anyref, acq_rel ;) + (type $a (shared (array (mut (ref null (shared any)))))) + (func (export "array-atomic-get-anyref-acq_rel") (param $x (ref null $a)) (param $y i32) (result (ref null (shared any))) + local.get $x + local.get $y + array.atomic.get acq_rel $a) +) + +(module (; get_s, i8, seq_cst ;) + (type $a (shared (array (mut i8)))) + (func (export "array-atomic-get_s-i8-seq_cst") (param $x (ref null $a)) (param $y i32) (result i32) + local.get $x + local.get $y + array.atomic.get_s seq_cst $a) +) + +(module (; get_s, i16, seq_cst ;) + (type $a (shared (array (mut i16)))) + (func (export "array-atomic-get_s-i16-seq_cst") (param $x (ref null $a)) (param $y i32) (result i32) + local.get $x + local.get $y + array.atomic.get_s seq_cst $a) +) + +(module (; get_s, i8, acq_rel ;) + (type $a (shared (array (mut i8)))) + (func (export "array-atomic-get_s-i8-acq_rel") (param $x (ref null $a)) (param $y i32) (result i32) + local.get $x + local.get $y + array.atomic.get_s acq_rel $a) +) + +(module (; get_s, i16, acq_rel ;) + (type $a (shared (array (mut i16)))) + (func (export "array-atomic-get_s-i16-acq_rel") (param $x (ref null $a)) (param $y i32) (result i32) + local.get $x + local.get $y + array.atomic.get_s acq_rel $a) +) + +(module (; get_u, i8, seq_cst ;) + (type $a (shared (array (mut i8)))) + (func (export "array-atomic-get_u-i8-seq_cst") (param $x (ref null $a)) (param $y i32) (result i32) + local.get $x + local.get $y + array.atomic.get_u seq_cst $a) +) + +(module (; get_u, i16, seq_cst ;) + (type $a (shared (array (mut i16)))) + (func (export "array-atomic-get_u-i16-seq_cst") (param $x (ref null $a)) (param $y i32) (result i32) + local.get $x + local.get $y + array.atomic.get_u seq_cst $a) +) + +(module (; get_u, i8, acq_rel ;) + (type $a (shared (array (mut i8)))) + (func (export "array-atomic-get_u-i8-acq_rel") (param $x (ref null $a)) (param $y i32) (result i32) + local.get $x + local.get $y + array.atomic.get_u acq_rel $a) +) + +(module (; get_u, i16, acq_rel ;) + (type $a (shared (array (mut i16)))) + (func (export "array-atomic-get_u-i16-acq_rel") (param $x (ref null $a)) (param $y i32) (result i32) + local.get $x + local.get $y + array.atomic.get_u acq_rel $a) +) + +(module (; set, i8, seq_cst ;) + (type $a (shared (array (mut i8)))) + (func (export "array-atomic-set-i8-seq_cst") (param $x (ref null $a)) (param $y i32) (param $z i32) + local.get $x + local.get $y + local.get $z + array.atomic.set seq_cst $a) +) + +(module (; set, i16, seq_cst ;) + (type $a (shared (array (mut i16)))) + (func (export "array-atomic-set-i16-seq_cst") (param $x (ref null $a)) (param $y i32) (param $z i32) + local.get $x + local.get $y + local.get $z + array.atomic.set seq_cst $a) +) + +(module (; set, i32, seq_cst ;) + (type $a (shared (array (mut i32)))) + (func (export "array-atomic-set-i32-seq_cst") (param $x (ref null $a)) (param $y i32) (param $z i32) + local.get $x + local.get $y + local.get $z + array.atomic.set seq_cst $a) +) + +(module (; set, i64, seq_cst ;) + (type $a (shared (array (mut i64)))) + (func (export "array-atomic-set-i64-seq_cst") (param $x (ref null $a)) (param $y i32) (param $z i64) + local.get $x + local.get $y + local.get $z + array.atomic.set seq_cst $a) +) + +(module (; set, anyref, seq_cst ;) + (type $a (shared (array (mut (ref null (shared any)))))) + (func (export "array-atomic-set-anyref-seq_cst") (param $x (ref null $a)) (param $y i32) (param $z (ref null (shared any))) + local.get $x + local.get $y + local.get $z + array.atomic.set seq_cst $a) +) + +(module (; set, i8, acq_rel ;) + (type $a (shared (array (mut i8)))) + (func (export "array-atomic-set-i8-acq_rel") (param $x (ref null $a)) (param $y i32) (param $z i32) + local.get $x + local.get $y + local.get $z + array.atomic.set acq_rel $a) +) + +(module (; set, i16, acq_rel ;) + (type $a (shared (array (mut i16)))) + (func (export "array-atomic-set-i16-acq_rel") (param $x (ref null $a)) (param $y i32) (param $z i32) + local.get $x + local.get $y + local.get $z + array.atomic.set acq_rel $a) +) + +(module (; set, i32, acq_rel ;) + (type $a (shared (array (mut i32)))) + (func (export "array-atomic-set-i32-acq_rel") (param $x (ref null $a)) (param $y i32) (param $z i32) + local.get $x + local.get $y + local.get $z + array.atomic.set acq_rel $a) +) + +(module (; set, i64, acq_rel ;) + (type $a (shared (array (mut i64)))) + (func (export "array-atomic-set-i64-acq_rel") (param $x (ref null $a)) (param $y i32) (param $z i64) + local.get $x + local.get $y + local.get $z + array.atomic.set acq_rel $a) +) + +(module (; set, anyref, acq_rel ;) + (type $a (shared (array (mut (ref null (shared any)))))) + (func (export "array-atomic-set-anyref-acq_rel") (param $x (ref null $a)) (param $y i32) (param $z (ref null (shared any))) + local.get $x + local.get $y + local.get $z + array.atomic.set acq_rel $a) +) + +(module (; rmw.add, i32, seq_cst ;) + (type $a (shared (array (mut i32)))) + (func (export "array-atomic-rmw.add-i32-seq_cst") (param $x (ref null $a)) (param $y i32) (param $z i32) (result i32) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.add seq_cst $a) +) + +(module (; rmw.add, i64, seq_cst ;) + (type $a (shared (array (mut i64)))) + (func (export "array-atomic-rmw.add-i64-seq_cst") (param $x (ref null $a)) (param $y i32) (param $z i64) (result i64) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.add seq_cst $a) +) + +(module (; rmw.add, i32, acq_rel ;) + (type $a (shared (array (mut i32)))) + (func (export "array-atomic-rmw.add-i32-acq_rel") (param $x (ref null $a)) (param $y i32) (param $z i32) (result i32) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.add acq_rel $a) +) + +(module (; rmw.add, i64, acq_rel ;) + (type $a (shared (array (mut i64)))) + (func (export "array-atomic-rmw.add-i64-acq_rel") (param $x (ref null $a)) (param $y i32) (param $z i64) (result i64) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.add acq_rel $a) +) + +(module (; rmw.sub, i32, seq_cst ;) + (type $a (shared (array (mut i32)))) + (func (export "array-atomic-rmw.sub-i32-seq_cst") (param $x (ref null $a)) (param $y i32) (param $z i32) (result i32) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.sub seq_cst $a) +) + +(module (; rmw.sub, i64, seq_cst ;) + (type $a (shared (array (mut i64)))) + (func (export "array-atomic-rmw.sub-i64-seq_cst") (param $x (ref null $a)) (param $y i32) (param $z i64) (result i64) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.sub seq_cst $a) +) + +(module (; rmw.sub, i32, acq_rel ;) + (type $a (shared (array (mut i32)))) + (func (export "array-atomic-rmw.sub-i32-acq_rel") (param $x (ref null $a)) (param $y i32) (param $z i32) (result i32) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.sub acq_rel $a) +) + +(module (; rmw.sub, i64, acq_rel ;) + (type $a (shared (array (mut i64)))) + (func (export "array-atomic-rmw.sub-i64-acq_rel") (param $x (ref null $a)) (param $y i32) (param $z i64) (result i64) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.sub acq_rel $a) +) + +(module (; rmw.and, i32, seq_cst ;) + (type $a (shared (array (mut i32)))) + (func (export "array-atomic-rmw.and-i32-seq_cst") (param $x (ref null $a)) (param $y i32) (param $z i32) (result i32) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.and seq_cst $a) +) + +(module (; rmw.and, i64, seq_cst ;) + (type $a (shared (array (mut i64)))) + (func (export "array-atomic-rmw.and-i64-seq_cst") (param $x (ref null $a)) (param $y i32) (param $z i64) (result i64) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.and seq_cst $a) +) + +(module (; rmw.and, i32, acq_rel ;) + (type $a (shared (array (mut i32)))) + (func (export "array-atomic-rmw.and-i32-acq_rel") (param $x (ref null $a)) (param $y i32) (param $z i32) (result i32) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.and acq_rel $a) +) + +(module (; rmw.and, i64, acq_rel ;) + (type $a (shared (array (mut i64)))) + (func (export "array-atomic-rmw.and-i64-acq_rel") (param $x (ref null $a)) (param $y i32) (param $z i64) (result i64) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.and acq_rel $a) +) + +(module (; rmw.or, i32, seq_cst ;) + (type $a (shared (array (mut i32)))) + (func (export "array-atomic-rmw.or-i32-seq_cst") (param $x (ref null $a)) (param $y i32) (param $z i32) (result i32) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.or seq_cst $a) +) + +(module (; rmw.or, i64, seq_cst ;) + (type $a (shared (array (mut i64)))) + (func (export "array-atomic-rmw.or-i64-seq_cst") (param $x (ref null $a)) (param $y i32) (param $z i64) (result i64) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.or seq_cst $a) +) + +(module (; rmw.or, i32, acq_rel ;) + (type $a (shared (array (mut i32)))) + (func (export "array-atomic-rmw.or-i32-acq_rel") (param $x (ref null $a)) (param $y i32) (param $z i32) (result i32) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.or acq_rel $a) +) + +(module (; rmw.or, i64, acq_rel ;) + (type $a (shared (array (mut i64)))) + (func (export "array-atomic-rmw.or-i64-acq_rel") (param $x (ref null $a)) (param $y i32) (param $z i64) (result i64) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.or acq_rel $a) +) + +(module (; rmw.xor, i32, seq_cst ;) + (type $a (shared (array (mut i32)))) + (func (export "array-atomic-rmw.xor-i32-seq_cst") (param $x (ref null $a)) (param $y i32) (param $z i32) (result i32) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.xor seq_cst $a) +) + +(module (; rmw.xor, i64, seq_cst ;) + (type $a (shared (array (mut i64)))) + (func (export "array-atomic-rmw.xor-i64-seq_cst") (param $x (ref null $a)) (param $y i32) (param $z i64) (result i64) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.xor seq_cst $a) +) + +(module (; rmw.xor, i32, acq_rel ;) + (type $a (shared (array (mut i32)))) + (func (export "array-atomic-rmw.xor-i32-acq_rel") (param $x (ref null $a)) (param $y i32) (param $z i32) (result i32) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.xor acq_rel $a) +) + +(module (; rmw.xor, i64, acq_rel ;) + (type $a (shared (array (mut i64)))) + (func (export "array-atomic-rmw.xor-i64-acq_rel") (param $x (ref null $a)) (param $y i32) (param $z i64) (result i64) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.xor acq_rel $a) +) + +(module (; rmw.xchg, i32, seq_cst ;) + (type $a (shared (array (mut i32)))) + (func (export "array-atomic-rmw.xchg-i32-seq_cst") (param $x (ref null $a)) (param $y i32) (param $z i32) (result i32) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.xchg seq_cst $a) +) + +(module (; rmw.xchg, i64, seq_cst ;) + (type $a (shared (array (mut i64)))) + (func (export "array-atomic-rmw.xchg-i64-seq_cst") (param $x (ref null $a)) (param $y i32) (param $z i64) (result i64) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.xchg seq_cst $a) +) + +(module (; rmw.xchg, anyref, seq_cst ;) + (type $a (shared (array (mut (ref null (shared any)))))) + (func (export "array-atomic-rmw.xchg-anyref-seq_cst") (param $x (ref null $a)) (param $y i32) (param $z (ref null (shared any))) (result (ref null (shared any))) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.xchg seq_cst $a) +) + +(module (; rmw.xchg, i32, acq_rel ;) + (type $a (shared (array (mut i32)))) + (func (export "array-atomic-rmw.xchg-i32-acq_rel") (param $x (ref null $a)) (param $y i32) (param $z i32) (result i32) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.xchg acq_rel $a) +) + +(module (; rmw.xchg, i64, acq_rel ;) + (type $a (shared (array (mut i64)))) + (func (export "array-atomic-rmw.xchg-i64-acq_rel") (param $x (ref null $a)) (param $y i32) (param $z i64) (result i64) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.xchg acq_rel $a) +) + +(module (; rmw.xchg, anyref, acq_rel ;) + (type $a (shared (array (mut (ref null (shared any)))))) + (func (export "array-atomic-rmw.xchg-anyref-acq_rel") (param $x (ref null $a)) (param $y i32) (param $z (ref null (shared any))) (result (ref null (shared any))) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.xchg acq_rel $a) +) + +(module (; rmw.cmpxchg, i32, seq_cst ;) + (type $a (shared (array (mut i32)))) + (func (export "array-atomic-rmw.cmpxchg-i32-seq_cst") (param $x (ref null $a)) (param $y i32) (param $z i32) (param $A i32) (result i32) + local.get $x + local.get $y + local.get $z + local.get $A + array.atomic.rmw.cmpxchg seq_cst $a) +) + +(module (; rmw.cmpxchg, i64, seq_cst ;) + (type $a (shared (array (mut i64)))) + (func (export "array-atomic-rmw.cmpxchg-i64-seq_cst") (param $x (ref null $a)) (param $y i32) (param $z i64) (param $A i64) (result i64) + local.get $x + local.get $y + local.get $z + local.get $A + array.atomic.rmw.cmpxchg seq_cst $a) +) + +(module (; rmw.cmpxchg, eqref, seq_cst ;) + (type $a (shared (array (mut (ref null (shared eq)))))) + (func (export "array-atomic-rmw.cmpxchg-eqref-seq_cst") (param $x (ref null $a)) (param $y i32) (param $z (ref null (shared eq))) (param $A (ref null (shared eq))) (result (ref null (shared eq))) + local.get $x + local.get $y + local.get $z + local.get $A + array.atomic.rmw.cmpxchg seq_cst $a) +) + +(module (; rmw.cmpxchg, i32, acq_rel ;) + (type $a (shared (array (mut i32)))) + (func (export "array-atomic-rmw.cmpxchg-i32-acq_rel") (param $x (ref null $a)) (param $y i32) (param $z i32) (param $A i32) (result i32) + local.get $x + local.get $y + local.get $z + local.get $A + array.atomic.rmw.cmpxchg acq_rel $a) +) + +(module (; rmw.cmpxchg, i64, acq_rel ;) + (type $a (shared (array (mut i64)))) + (func (export "array-atomic-rmw.cmpxchg-i64-acq_rel") (param $x (ref null $a)) (param $y i32) (param $z i64) (param $A i64) (result i64) + local.get $x + local.get $y + local.get $z + local.get $A + array.atomic.rmw.cmpxchg acq_rel $a) +) + +(module (; rmw.cmpxchg, eqref, acq_rel ;) + (type $a (shared (array (mut (ref null (shared eq)))))) + (func (export "array-atomic-rmw.cmpxchg-eqref-acq_rel") (param $x (ref null $a)) (param $y i32) (param $z (ref null (shared eq))) (param $A (ref null (shared eq))) (result (ref null (shared eq))) + local.get $x + local.get $y + local.get $z + local.get $A + array.atomic.rmw.cmpxchg acq_rel $a) +) + +(assert_invalid (; get, i8 ;) + (module + (type $a (shared (array (mut i8)))) + (func (param $x (ref null $a)) (param $y i32) (result i32) + local.get $x + local.get $y + array.atomic.get seq_cst $a) + ) + "packed storage type" +) +(assert_invalid (; get_s, i32 ;) + (module + (type $a (shared (array (mut i32)))) + (func (param $x (ref null $a)) (param $y i32) (result i32) + local.get $x + local.get $y + array.atomic.get_s seq_cst $a) + ) + "non-packed storage type" +) +(assert_invalid (; get_s, anyref ;) + (module + (type $a (shared (array (mut (ref null (shared any)))))) + (func (param $x (ref null $a)) (param $y i32) (result (ref null (shared any))) + local.get $x + local.get $y + array.atomic.get_s seq_cst $a) + ) + "non-packed storage type" +) +(assert_invalid (; get_u, i32 ;) + (module + (type $a (shared (array (mut i32)))) + (func (param $x (ref null $a)) (param $y i32) (result i32) + local.get $x + local.get $y + array.atomic.get_u seq_cst $a) + ) + "non-packed storage type" +) +(assert_invalid (; get_u, anyref ;) + (module + (type $a (shared (array (mut (ref null (shared any)))))) + (func (param $x (ref null $a)) (param $y i32) (result (ref null (shared any))) + local.get $x + local.get $y + array.atomic.get_u seq_cst $a) + ) + "non-packed storage type" +) +(assert_invalid (; rmw.add, anyref ;) + (module + (type $a (shared (array (mut (ref null (shared any)))))) + (func (param $x (ref null $a)) (param $y i32) (param $z (ref null (shared any))) (result (ref null (shared any))) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.add seq_cst $a) + ) + "invalid type" +) +(assert_invalid (; rmw.sub, anyref ;) + (module + (type $a (shared (array (mut (ref null (shared any)))))) + (func (param $x (ref null $a)) (param $y i32) (param $z (ref null (shared any))) (result (ref null (shared any))) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.sub seq_cst $a) + ) + "invalid type" +) +(assert_invalid (; rmw.and, anyref ;) + (module + (type $a (shared (array (mut (ref null (shared any)))))) + (func (param $x (ref null $a)) (param $y i32) (param $z (ref null (shared any))) (result (ref null (shared any))) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.and seq_cst $a) + ) + "invalid type" +) +(assert_invalid (; rmw.or, anyref ;) + (module + (type $a (shared (array (mut (ref null (shared any)))))) + (func (param $x (ref null $a)) (param $y i32) (param $z (ref null (shared any))) (result (ref null (shared any))) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.or seq_cst $a) + ) + "invalid type" +) +(assert_invalid (; rmw.xor, anyref ;) + (module + (type $a (shared (array (mut (ref null (shared any)))))) + (func (param $x (ref null $a)) (param $y i32) (param $z (ref null (shared any))) (result (ref null (shared any))) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.xor seq_cst $a) + ) + "invalid type" +) +(assert_invalid (; rmw.xchg, i8 ;) + (module + (type $a (shared (array (mut i8)))) + (func (param $x (ref null $a)) (param $y i32) (param $z i32) (result i32) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.xchg seq_cst $a) + ) + "invalid type" +) +(assert_invalid (; rmw.cmpxchg, i8 ;) + (module + (type $a (shared (array (mut i8)))) + (func (param $x (ref null $a)) (param $y i32) (param $z i32) (param $A i32) (result i32) + local.get $x + local.get $y + local.get $z + local.get $A + array.atomic.rmw.cmpxchg seq_cst $a) + ) + "invalid type" +) +(assert_invalid (; rmw.cmpxchg, anyref ;) + (module + (type $a (shared (array (mut (ref null (shared any)))))) + (func (param $x (ref null $a)) (param $y i32) (param $z (ref null (shared any))) (param $A (ref null (shared any))) (result (ref null (shared any))) + local.get $x + local.get $y + local.get $z + local.get $A + array.atomic.rmw.cmpxchg seq_cst $a) + ) + "invalid type" +) diff --git a/tests/local/shared-everything-threads/global.wast b/tests/local/shared-everything-threads/global.wast index 9d47be9ff0..1066fcf406 100644 --- a/tests/local/shared-everything-threads/global.wast +++ b/tests/local/shared-everything-threads/global.wast @@ -1,4 +1,4 @@ -;; Check shared attribute. +;; Check the `shared` attribute on globals. (module ;; Imported. diff --git a/tests/local/shared-everything-threads/struct.wast b/tests/local/shared-everything-threads/struct.wast index 91b1cec268..cd6664631a 100644 --- a/tests/local/shared-everything-threads/struct.wast +++ b/tests/local/shared-everything-threads/struct.wast @@ -1,4 +1,4 @@ -;; Shared struct declaration syntax +;; Shared struct declaration syntax. (module (type (shared (struct))) (type (sub final (shared (struct)))) @@ -11,7 +11,7 @@ (global (ref 2) (struct.new 0)) ) -;; Shared structs are distinct from non-shared structs +;; Shared structs are distinct from non-shared structs. (assert_invalid (module (type (shared (struct))) @@ -32,7 +32,7 @@ "type mismatch" ) -;; Shared structs may not be subtypes of non-shared structs +;; Shared structs may not be subtypes of non-shared structs. (assert_invalid (module (type (sub (struct))) @@ -41,7 +41,7 @@ "must match super type" ) -;; Non-shared structs may not be subtypes of shared structs +;; Non-shared structs may not be subtypes of shared structs. (assert_invalid (module (type (sub (shared (struct)))) @@ -50,7 +50,7 @@ "must match super type" ) -;; Shared structs may not contain non-shared references +;; Shared structs may not contain non-shared references. (assert_invalid (module (type (shared (struct (field anyref)))) @@ -58,12 +58,12 @@ "must contain shared type" ) -;; But they may contain shared references +;; But they may contain shared references. (module (type (shared (struct (field (ref null (shared any)))))) ) -;; Non-shared structs may contain shared references +;; Non-shared structs may contain shared references. (module (type (struct (field (ref null (shared any))))) ) @@ -90,3 +90,358 @@ (func (param (ref null $i8)) (struct.set $i8 0 (local.get 0) (i32.const 0))) ) + +;; Check struct.atomic.rmw.* instructions +(module + (type $s (shared (struct + (field $i8 (mut i8)) + (field $i16 (mut i16)) + (field $i32 (mut i32)) + (field $i64 (mut i64)) + (field $anyref (mut (ref null (shared any)))) + (field $eqref (mut (ref null (shared eq))))))) + (func (export "struct-atomic-get-i32-seq_cst") (param $x (ref null $s)) (result i32) + local.get $x + struct.atomic.get seq_cst $s $i32) + (func (export "struct-atomic-get-i64-seq_cst") (param $x (ref null $s)) (result i64) + local.get $x + struct.atomic.get seq_cst $s $i64) + (func (export "struct-atomic-get-anyref-seq_cst") (param $x (ref null $s)) (result (ref null (shared any))) + local.get $x + struct.atomic.get seq_cst $s $anyref) + (func (export "struct-atomic-get-i32-acq_rel") (param $x (ref null $s)) (result i32) + local.get $x + struct.atomic.get acq_rel $s $i32) + (func (export "struct-atomic-get-i64-acq_rel") (param $x (ref null $s)) (result i64) + local.get $x + struct.atomic.get acq_rel $s $i64) + (func (export "struct-atomic-get-anyref-acq_rel") (param $x (ref null $s)) (result (ref null (shared any))) + local.get $x + struct.atomic.get acq_rel $s $anyref) + (func (export "struct-atomic-get_s-i8-seq_cst") (param $x (ref null $s)) (result i32) + local.get $x + struct.atomic.get_s seq_cst $s $i8) + (func (export "struct-atomic-get_s-i16-seq_cst") (param $x (ref null $s)) (result i32) + local.get $x + struct.atomic.get_s seq_cst $s $i16) + (func (export "struct-atomic-get_s-i8-acq_rel") (param $x (ref null $s)) (result i32) + local.get $x + struct.atomic.get_s acq_rel $s $i8) + (func (export "struct-atomic-get_s-i16-acq_rel") (param $x (ref null $s)) (result i32) + local.get $x + struct.atomic.get_s acq_rel $s $i16) + (func (export "struct-atomic-get_u-i8-seq_cst") (param $x (ref null $s)) (result i32) + local.get $x + struct.atomic.get_u seq_cst $s $i8) + (func (export "struct-atomic-get_u-i16-seq_cst") (param $x (ref null $s)) (result i32) + local.get $x + struct.atomic.get_u seq_cst $s $i16) + (func (export "struct-atomic-get_u-i8-acq_rel") (param $x (ref null $s)) (result i32) + local.get $x + struct.atomic.get_u acq_rel $s $i8) + (func (export "struct-atomic-get_u-i16-acq_rel") (param $x (ref null $s)) (result i32) + local.get $x + struct.atomic.get_u acq_rel $s $i16) + (func (export "struct-atomic-set-i8-seq_cst") (param $x (ref null $s)) (param $y i32) + local.get $x + local.get $y + struct.atomic.set seq_cst $s $i8) + (func (export "struct-atomic-set-i16-seq_cst") (param $x (ref null $s)) (param $y i32) + local.get $x + local.get $y + struct.atomic.set seq_cst $s $i16) + (func (export "struct-atomic-set-i32-seq_cst") (param $x (ref null $s)) (param $y i32) + local.get $x + local.get $y + struct.atomic.set seq_cst $s $i32) + (func (export "struct-atomic-set-i64-seq_cst") (param $x (ref null $s)) (param $y i64) + local.get $x + local.get $y + struct.atomic.set seq_cst $s $i64) + (func (export "struct-atomic-set-anyref-seq_cst") (param $x (ref null $s)) (param $y (ref null (shared any))) + local.get $x + local.get $y + struct.atomic.set seq_cst $s $anyref) + (func (export "struct-atomic-set-i8-acq_rel") (param $x (ref null $s)) (param $y i32) + local.get $x + local.get $y + struct.atomic.set acq_rel $s $i8) + (func (export "struct-atomic-set-i16-acq_rel") (param $x (ref null $s)) (param $y i32) + local.get $x + local.get $y + struct.atomic.set acq_rel $s $i16) + (func (export "struct-atomic-set-i32-acq_rel") (param $x (ref null $s)) (param $y i32) + local.get $x + local.get $y + struct.atomic.set acq_rel $s $i32) + (func (export "struct-atomic-set-i64-acq_rel") (param $x (ref null $s)) (param $y i64) + local.get $x + local.get $y + struct.atomic.set acq_rel $s $i64) + (func (export "struct-atomic-set-anyref-acq_rel") (param $x (ref null $s)) (param $y (ref null (shared any))) + local.get $x + local.get $y + struct.atomic.set acq_rel $s $anyref) + (func (export "struct-atomic-rmw.add-i32-seq_cst") (param $x (ref null $s)) (param $y i32) (result i32) + local.get $x + local.get $y + struct.atomic.rmw.add seq_cst $s $i32) + (func (export "struct-atomic-rmw.add-i64-seq_cst") (param $x (ref null $s)) (param $y i64) (result i64) + local.get $x + local.get $y + struct.atomic.rmw.add seq_cst $s $i64) + (func (export "struct-atomic-rmw.add-i32-acq_rel") (param $x (ref null $s)) (param $y i32) (result i32) + local.get $x + local.get $y + struct.atomic.rmw.add acq_rel $s $i32) + (func (export "struct-atomic-rmw.add-i64-acq_rel") (param $x (ref null $s)) (param $y i64) (result i64) + local.get $x + local.get $y + struct.atomic.rmw.add acq_rel $s $i64) + (func (export "struct-atomic-rmw.sub-i32-seq_cst") (param $x (ref null $s)) (param $y i32) (result i32) + local.get $x + local.get $y + struct.atomic.rmw.sub seq_cst $s $i32) + (func (export "struct-atomic-rmw.sub-i64-seq_cst") (param $x (ref null $s)) (param $y i64) (result i64) + local.get $x + local.get $y + struct.atomic.rmw.sub seq_cst $s $i64) + (func (export "struct-atomic-rmw.sub-i32-acq_rel") (param $x (ref null $s)) (param $y i32) (result i32) + local.get $x + local.get $y + struct.atomic.rmw.sub acq_rel $s $i32) + (func (export "struct-atomic-rmw.sub-i64-acq_rel") (param $x (ref null $s)) (param $y i64) (result i64) + local.get $x + local.get $y + struct.atomic.rmw.sub acq_rel $s $i64) + (func (export "struct-atomic-rmw.and-i32-seq_cst") (param $x (ref null $s)) (param $y i32) (result i32) + local.get $x + local.get $y + struct.atomic.rmw.and seq_cst $s $i32) + (func (export "struct-atomic-rmw.and-i64-seq_cst") (param $x (ref null $s)) (param $y i64) (result i64) + local.get $x + local.get $y + struct.atomic.rmw.and seq_cst $s $i64) + (func (export "struct-atomic-rmw.and-i32-acq_rel") (param $x (ref null $s)) (param $y i32) (result i32) + local.get $x + local.get $y + struct.atomic.rmw.and acq_rel $s $i32) + (func (export "struct-atomic-rmw.and-i64-acq_rel") (param $x (ref null $s)) (param $y i64) (result i64) + local.get $x + local.get $y + struct.atomic.rmw.and acq_rel $s $i64) + (func (export "struct-atomic-rmw.or-i32-seq_cst") (param $x (ref null $s)) (param $y i32) (result i32) + local.get $x + local.get $y + struct.atomic.rmw.or seq_cst $s $i32) + (func (export "struct-atomic-rmw.or-i64-seq_cst") (param $x (ref null $s)) (param $y i64) (result i64) + local.get $x + local.get $y + struct.atomic.rmw.or seq_cst $s $i64) + (func (export "struct-atomic-rmw.or-i32-acq_rel") (param $x (ref null $s)) (param $y i32) (result i32) + local.get $x + local.get $y + struct.atomic.rmw.or acq_rel $s $i32) + (func (export "struct-atomic-rmw.or-i64-acq_rel") (param $x (ref null $s)) (param $y i64) (result i64) + local.get $x + local.get $y + struct.atomic.rmw.or acq_rel $s $i64) + (func (export "struct-atomic-rmw.xor-i32-seq_cst") (param $x (ref null $s)) (param $y i32) (result i32) + local.get $x + local.get $y + struct.atomic.rmw.xor seq_cst $s $i32) + (func (export "struct-atomic-rmw.xor-i64-seq_cst") (param $x (ref null $s)) (param $y i64) (result i64) + local.get $x + local.get $y + struct.atomic.rmw.xor seq_cst $s $i64) + (func (export "struct-atomic-rmw.xor-i32-acq_rel") (param $x (ref null $s)) (param $y i32) (result i32) + local.get $x + local.get $y + struct.atomic.rmw.xor acq_rel $s $i32) + (func (export "struct-atomic-rmw.xor-i64-acq_rel") (param $x (ref null $s)) (param $y i64) (result i64) + local.get $x + local.get $y + struct.atomic.rmw.xor acq_rel $s $i64) + (func (export "struct-atomic-rmw.xchg-i32-seq_cst") (param $x (ref null $s)) (param $y i32) (result i32) + local.get $x + local.get $y + struct.atomic.rmw.xchg seq_cst $s $i32) + (func (export "struct-atomic-rmw.xchg-i64-seq_cst") (param $x (ref null $s)) (param $y i64) (result i64) + local.get $x + local.get $y + struct.atomic.rmw.xchg seq_cst $s $i64) + (func (export "struct-atomic-rmw.xchg-anyref-seq_cst") (param $x (ref null $s)) (param $y (ref null (shared any))) (result (ref null (shared any))) + local.get $x + local.get $y + struct.atomic.rmw.xchg seq_cst $s $anyref) + (func (export "struct-atomic-rmw.xchg-i32-acq_rel") (param $x (ref null $s)) (param $y i32) (result i32) + local.get $x + local.get $y + struct.atomic.rmw.xchg acq_rel $s $i32) + (func (export "struct-atomic-rmw.xchg-i64-acq_rel") (param $x (ref null $s)) (param $y i64) (result i64) + local.get $x + local.get $y + struct.atomic.rmw.xchg acq_rel $s $i64) + (func (export "struct-atomic-rmw.xchg-anyref-acq_rel") (param $x (ref null $s)) (param $y (ref null (shared any))) (result (ref null (shared any))) + local.get $x + local.get $y + struct.atomic.rmw.xchg acq_rel $s $anyref) + (func (export "struct-atomic-rmw.cmpxchg-i32-seq_cst") (param $x (ref null $s)) (param $y i32) (param $z i32) (result i32) + local.get $x + local.get $y + local.get $z + struct.atomic.rmw.cmpxchg seq_cst $s $i32) + (func (export "struct-atomic-rmw.cmpxchg-i64-seq_cst") (param $x (ref null $s)) (param $y i64) (param $z i64) (result i64) + local.get $x + local.get $y + local.get $z + struct.atomic.rmw.cmpxchg seq_cst $s $i64) + (func (export "struct-atomic-rmw.cmpxchg-eqref-seq_cst") (param $x (ref null $s)) (param $y (ref null (shared eq))) (param $z (ref null (shared eq))) (result (ref null (shared eq))) + local.get $x + local.get $y + local.get $z + struct.atomic.rmw.cmpxchg seq_cst $s $eqref) + (func (export "struct-atomic-rmw.cmpxchg-i32-acq_rel") (param $x (ref null $s)) (param $y i32) (param $z i32) (result i32) + local.get $x + local.get $y + local.get $z + struct.atomic.rmw.cmpxchg acq_rel $s $i32) + (func (export "struct-atomic-rmw.cmpxchg-i64-acq_rel") (param $x (ref null $s)) (param $y i64) (param $z i64) (result i64) + local.get $x + local.get $y + local.get $z + struct.atomic.rmw.cmpxchg acq_rel $s $i64) + (func (export "struct-atomic-rmw.cmpxchg-eqref-acq_rel") (param $x (ref null $s)) (param $y (ref null (shared eq))) (param $z (ref null (shared eq))) (result (ref null (shared eq))) + local.get $x + local.get $y + local.get $z + struct.atomic.rmw.cmpxchg acq_rel $s $eqref) +) + +(assert_invalid (; get, i8 ;) + (module + (type $s (shared (struct (field $i8 (mut i8))))) + (func (param $x (ref null $s)) (result i32) + local.get $x + struct.atomic.get seq_cst $s $i8) + ) + "non-packed storage type" +) +(assert_invalid (; get_s, i32 ;) + (module + (type $s (shared (struct (field $i32 (mut i32))))) + (func (param $x (ref null $s)) (result i32) + local.get $x + struct.atomic.get_s seq_cst $s $i32) + ) + "non-packed storage types" +) +(assert_invalid (; get_s, anyref ;) + (module + (type $s (shared (struct (field $anyref (mut (ref null (shared any))))))) + (func (param $x (ref null $s)) (result (ref null (shared any))) + local.get $x + struct.atomic.get_s seq_cst $s $anyref) + ) + "non-packed storage types" +) +(assert_invalid (; get_u, i32 ;) + (module + (type $s (shared (struct (field $i32 (mut i32))))) + (func (param $x (ref null $s)) (result i32) + local.get $x + struct.atomic.get_u seq_cst $s $i32) + ) + "non-packed storage types" +) +(assert_invalid (; get_u, anyref ;) + (module + (type $s (shared (struct (field $anyref (mut (ref null (shared any))))))) + (func (param $x (ref null $s)) (result (ref null (shared any))) + local.get $x + struct.atomic.get_u seq_cst $s $anyref) + ) + "non-packed storage types" +) +(assert_invalid (; rmw.add, anyref ;) + (module + (type $s (shared (struct (field $anyref (mut (ref null (shared any))))))) + (func (param $x (ref null $s)) (param $y (ref null (shared any))) (result (ref null (shared any))) + local.get $x + local.get $y + struct.atomic.rmw.add seq_cst $s $anyref) + ) + "invalid type" +) +(assert_invalid (; rmw.sub, anyref ;) + (module + (type $s (shared (struct (field $anyref (mut (ref null (shared any))))))) + (func (param $x (ref null $s)) (param $y (ref null (shared any))) (result (ref null (shared any))) + local.get $x + local.get $y + struct.atomic.rmw.sub seq_cst $s $anyref) + ) + "invalid type" +) +(assert_invalid (; rmw.and, anyref ;) + (module + (type $s (shared (struct (field $anyref (mut (ref null (shared any))))))) + (func (param $x (ref null $s)) (param $y (ref null (shared any))) (result (ref null (shared any))) + local.get $x + local.get $y + struct.atomic.rmw.and seq_cst $s $anyref) + ) + "invalid type" +) +(assert_invalid (; rmw.or, anyref ;) + (module + (type $s (shared (struct (field $anyref (mut (ref null (shared any))))))) + (func (param $x (ref null $s)) (param $y (ref null (shared any))) (result (ref null (shared any))) + local.get $x + local.get $y + struct.atomic.rmw.or seq_cst $s $anyref) + ) + "invalid type" +) +(assert_invalid (; rmw.xor, anyref ;) + (module + (type $s (shared (struct (field $anyref (mut (ref null (shared any))))))) + (func (param $x (ref null $s)) (param $y (ref null (shared any))) (result (ref null (shared any))) + local.get $x + local.get $y + struct.atomic.rmw.xor seq_cst $s $anyref) + ) + "invalid type" +) +(assert_invalid (; rmw.xchg, i8 ;) + (module + (type $s (shared (struct (field $i8 (mut i8))))) + (func (param $x (ref null $s)) (param $y i32) (result i32) + local.get $x + local.get $y + struct.atomic.rmw.xchg seq_cst $s $i8) + ) + "invalid type" +) +(assert_invalid (; rmw.cmpxchg, i8 ;) + (module + (type $s (shared (struct (field $i8 (mut i8))))) + (func (param $x (ref null $s)) (param $y i32) (param $z i32) (result i32) + local.get $x + local.get $y + local.get $z + struct.atomic.rmw.cmpxchg seq_cst $s $i8) + ) + "invalid type" +) +(assert_invalid (; rmw.cmpxchg, anyref ;) + (module + (type $s (shared (struct (field $anyref (mut (ref null (shared any))))))) + (func (param $x (ref null $s)) (param $y (ref null (shared any))) (param $z (ref null (shared any))) (result (ref null (shared any))) + local.get $x + local.get $y + local.get $z + struct.atomic.rmw.cmpxchg seq_cst $s $anyref) + ) + "invalid type" +) diff --git a/tests/local/shared-everything-threads/table.wast b/tests/local/shared-everything-threads/table.wast new file mode 100644 index 0000000000..b733ec4c2b --- /dev/null +++ b/tests/local/shared-everything-threads/table.wast @@ -0,0 +1,174 @@ +;; Check the `shared` attribute on tables. + +(module + ;; Imported. + (table (import "spectest" "table_ref") shared 1 (ref null (shared func))) + (table (import "spectest" "table_ref_with_max") shared 1 1 (ref null (shared func))) + + ;; Normal. + (table shared 1 (ref null (shared func))) + (table shared 1 1 (ref null (shared func))) + + ;; Inlined. + (table shared (ref null (shared func)) (elem (ref.null (shared func)))) +) + +;; Note that shared elements can live within an unshared table. +(module + (table (import "spectest" "table_ref") 1 (ref null (shared func))) +) + +(assert_malformed + (module quote "(table 1 shared funcref)") + "unexpected token") + +(assert_malformed + (module quote "(table 1 funcref shared)") + "unexpected token") + +;; The proposal creates too much ambiguity to allow this syntax: the parser +;; would need to lookahead multiple tokens. +(assert_malformed + (module quote "(table shared i64 (ref null (shared func)) (elem (ref.null (shared func))))") + "unexpected token") + +(assert_invalid + (module (table (import "spectest" "table_ref") shared 0 funcref)) + "shared tables must have a shared element type") + +(assert_invalid + (module + (type $t (func)) + (table shared 0 (ref $t))) + "shared tables must have a shared element type") + +;; Check `table.atomic.*` instructions. +(module (;eq;) + (table $a (import "spectest" "table_eq") shared 1 (ref null (shared eq))) + (table $b shared 1 (ref null (shared eq))) + (func (export "table-atomic-get-eq-seq_cst-$a") (param $x i32) (result (ref null (shared eq))) + local.get $x + table.atomic.get seq_cst $a) + (func (export "table-atomic-get-eq-seq_cst-$b") (param $x i32) (result (ref null (shared eq))) + local.get $x + table.atomic.get seq_cst $b) + (func (export "table-atomic-get-eq-acq_rel-$a") (param $x i32) (result (ref null (shared eq))) + local.get $x + table.atomic.get acq_rel $a) + (func (export "table-atomic-get-eq-acq_rel-$b") (param $x i32) (result (ref null (shared eq))) + local.get $x + table.atomic.get acq_rel $b) + (func (export "table-atomic-set-eq-seq_cst-$a") (param $x i32) (param $y (ref null (shared eq))) + local.get $x + local.get $y + table.atomic.set seq_cst $a) + (func (export "table-atomic-set-eq-seq_cst-$b") (param $x i32) (param $y (ref null (shared eq))) + local.get $x + local.get $y + table.atomic.set seq_cst $b) + (func (export "table-atomic-set-eq-acq_rel-$a") (param $x i32) (param $y (ref null (shared eq))) + local.get $x + local.get $y + table.atomic.set acq_rel $a) + (func (export "table-atomic-set-eq-acq_rel-$b") (param $x i32) (param $y (ref null (shared eq))) + local.get $x + local.get $y + table.atomic.set acq_rel $b) + (func (export "table-atomic-rmw.xchg-eq-seq_cst-$a") (param $x i32) (param $y (ref null (shared eq))) (result (ref null (shared eq))) + local.get $x + local.get $y + table.atomic.rmw.xchg seq_cst $a) + (func (export "table-atomic-rmw.xchg-eq-seq_cst-$b") (param $x i32) (param $y (ref null (shared eq))) (result (ref null (shared eq))) + local.get $x + local.get $y + table.atomic.rmw.xchg seq_cst $b) + (func (export "table-atomic-rmw.xchg-eq-acq_rel-$a") (param $x i32) (param $y (ref null (shared eq))) (result (ref null (shared eq))) + local.get $x + local.get $y + table.atomic.rmw.xchg acq_rel $a) + (func (export "table-atomic-rmw.xchg-eq-acq_rel-$b") (param $x i32) (param $y (ref null (shared eq))) (result (ref null (shared eq))) + local.get $x + local.get $y + table.atomic.rmw.xchg acq_rel $b) + (func (export "table-atomic-rmw.cmpxchg-eq-seq_cst-$a") (param $x i32) (param $y (ref null (shared eq))) (param $z (ref null (shared eq))) (result (ref null (shared eq))) + local.get $x + local.get $y + local.get $z + table.atomic.rmw.cmpxchg seq_cst $a) + (func (export "table-atomic-rmw.cmpxchg-eq-seq_cst-$b") (param $x i32) (param $y (ref null (shared eq))) (param $z (ref null (shared eq))) (result (ref null (shared eq))) + local.get $x + local.get $y + local.get $z + table.atomic.rmw.cmpxchg seq_cst $b) + (func (export "table-atomic-rmw.cmpxchg-eq-acq_rel-$a") (param $x i32) (param $y (ref null (shared eq))) (param $z (ref null (shared eq))) (result (ref null (shared eq))) + local.get $x + local.get $y + local.get $z + table.atomic.rmw.cmpxchg acq_rel $a) + (func (export "table-atomic-rmw.cmpxchg-eq-acq_rel-$b") (param $x i32) (param $y (ref null (shared eq))) (param $z (ref null (shared eq))) (result (ref null (shared eq))) + local.get $x + local.get $y + local.get $z + table.atomic.rmw.cmpxchg acq_rel $b) +) + +(module (;any;) + (table $a (import "spectest" "table_any") shared 1 (ref null (shared any))) + (table $b shared 1 (ref null (shared any))) + (func (export "table-atomic-get-any-seq_cst-$a") (param $x i32) (result (ref null (shared any))) + local.get $x + table.atomic.get seq_cst $a) + (func (export "table-atomic-get-any-seq_cst-$b") (param $x i32) (result (ref null (shared any))) + local.get $x + table.atomic.get seq_cst $b) + (func (export "table-atomic-get-any-acq_rel-$a") (param $x i32) (result (ref null (shared any))) + local.get $x + table.atomic.get acq_rel $a) + (func (export "table-atomic-get-any-acq_rel-$b") (param $x i32) (result (ref null (shared any))) + local.get $x + table.atomic.get acq_rel $b) + (func (export "table-atomic-set-any-seq_cst-$a") (param $x i32) (param $y (ref null (shared any))) + local.get $x + local.get $y + table.atomic.set seq_cst $a) + (func (export "table-atomic-set-any-seq_cst-$b") (param $x i32) (param $y (ref null (shared any))) + local.get $x + local.get $y + table.atomic.set seq_cst $b) + (func (export "table-atomic-set-any-acq_rel-$a") (param $x i32) (param $y (ref null (shared any))) + local.get $x + local.get $y + table.atomic.set acq_rel $a) + (func (export "table-atomic-set-any-acq_rel-$b") (param $x i32) (param $y (ref null (shared any))) + local.get $x + local.get $y + table.atomic.set acq_rel $b) + (func (export "table-atomic-rmw.xchg-any-seq_cst-$a") (param $x i32) (param $y (ref null (shared any))) (result (ref null (shared any))) + local.get $x + local.get $y + table.atomic.rmw.xchg seq_cst $a) + (func (export "table-atomic-rmw.xchg-any-seq_cst-$b") (param $x i32) (param $y (ref null (shared any))) (result (ref null (shared any))) + local.get $x + local.get $y + table.atomic.rmw.xchg seq_cst $b) + (func (export "table-atomic-rmw.xchg-any-acq_rel-$a") (param $x i32) (param $y (ref null (shared any))) (result (ref null (shared any))) + local.get $x + local.get $y + table.atomic.rmw.xchg acq_rel $a) + (func (export "table-atomic-rmw.xchg-any-acq_rel-$b") (param $x i32) (param $y (ref null (shared any))) (result (ref null (shared any))) + local.get $x + local.get $y + table.atomic.rmw.xchg acq_rel $b) + ;; table.atomic.rmw.cmpxchg only works with subtypes of eqref. +) + +;; Check that cmpxchg only works with eqref subtypes. +(assert_invalid + (module + (table $a shared 0 (ref null (shared any))) + (func (param $x i32) (param $y (ref null (shared any))) (param $z (ref null (shared any))) (result (ref null (shared any))) + local.get $x + local.get $y + local.get $z + table.atomic.rmw.cmpxchg seq_cst $a)) + "invalid type") diff --git a/tests/roundtrip.rs b/tests/roundtrip.rs index 66fdc1e49b..b788a81f3f 100644 --- a/tests/roundtrip.rs +++ b/tests/roundtrip.rs @@ -579,7 +579,8 @@ impl TestState { & !WasmFeatures::SHARED_EVERYTHING_THREADS & !WasmFeatures::COMPONENT_MODEL & !WasmFeatures::COMPONENT_MODEL_NESTED_NAMES - & !WasmFeatures::COMPONENT_MODEL_MORE_FLAGS; + & !WasmFeatures::COMPONENT_MODEL_MORE_FLAGS + & !WasmFeatures::LEGACY_EXCEPTIONS; for part in test.iter().filter_map(|t| t.to_str()) { match part { "testsuite" => { @@ -604,6 +605,7 @@ impl TestState { } "simd" => features.insert(WasmFeatures::SIMD), "exception-handling" => features.insert(WasmFeatures::EXCEPTIONS), + "legacy-exceptions" => features.insert(WasmFeatures::LEGACY_EXCEPTIONS), "tail-call" => features.insert(WasmFeatures::TAIL_CALL), "memory64" => features.insert(WasmFeatures::MEMORY64), "component-model" => features.insert(WasmFeatures::COMPONENT_MODEL), @@ -655,11 +657,13 @@ fn error_matches(error: &str, message: &str) -> bool { || message == "alignment must be a power of two" || message == "i32 constant out of range" || message == "constant expression required" + || message == "legacy exceptions support is not enabled" { return error.contains("expected ") || error.contains("constant out of range") || error.contains("extra tokens remaining") - || error.contains("unimplemented validation of deprecated opcode"); + || error.contains("unimplemented validation of deprecated opcode") + || error.contains("legacy exceptions support is not enabled"); } if message == "illegal character" { @@ -717,6 +721,7 @@ fn error_matches(error: &str, message: &str) -> bool { // wasmparser implements more features than the default spec // interpreter, so these error looks different. return error.contains("threads must be enabled for shared memories") + || error.contains("shared tables require the shared-everything-threads proposal") || error.contains("invalid table resizable limits flags") // honestly this feels like the spec interpreter is just weird || error.contains("unexpected end-of-file") diff --git a/tests/snapshots/local/legacy-exceptions/legacy-exceptions.wat.print b/tests/snapshots/local/legacy-exceptions/legacy-exceptions.wat.print new file mode 100644 index 0000000000..8ae9aa1a02 --- /dev/null +++ b/tests/snapshots/local/legacy-exceptions/legacy-exceptions.wat.print @@ -0,0 +1,16 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + try ;; label = @1 + try ;; label = @2 + try ;; label = @3 + throw 0 + catch_all + rethrow 0 (;@3;) + end + delegate 0 (;@1;) + catch 0 + end + ) + (tag (;0;) (type 0)) +) diff --git a/tests/snapshots/local/legacy-exceptions/rethrow.wast.json b/tests/snapshots/local/legacy-exceptions/rethrow.wast.json new file mode 100644 index 0000000000..40a67982c1 --- /dev/null +++ b/tests/snapshots/local/legacy-exceptions/rethrow.wast.json @@ -0,0 +1,214 @@ +{ + "source_filename": "tests/local/legacy-exceptions/rethrow.wast", + "commands": [ + { + "type": "module", + "line": 3, + "filename": "rethrow.0.wasm" + }, + { + "type": "assert_exception", + "line": 100, + "action": { + "type": "invoke", + "field": "catch-rethrow-0", + "args": [] + } + }, + { + "type": "assert_exception", + "line": 102, + "action": { + "type": "invoke", + "field": "catch-rethrow-1", + "args": [ + { + "type": "i32", + "value": "0" + } + ] + } + }, + { + "type": "assert_return", + "line": 103, + "action": { + "type": "invoke", + "field": "catch-rethrow-1", + "args": [ + { + "type": "i32", + "value": "1" + } + ] + }, + "expected": [ + { + "type": "i32", + "value": "23" + } + ] + }, + { + "type": "assert_exception", + "line": 105, + "action": { + "type": "invoke", + "field": "catchall-rethrow-0", + "args": [] + } + }, + { + "type": "assert_exception", + "line": 107, + "action": { + "type": "invoke", + "field": "catchall-rethrow-1", + "args": [ + { + "type": "i32", + "value": "0" + } + ] + } + }, + { + "type": "assert_return", + "line": 108, + "action": { + "type": "invoke", + "field": "catchall-rethrow-1", + "args": [ + { + "type": "i32", + "value": "1" + } + ] + }, + "expected": [ + { + "type": "i32", + "value": "23" + } + ] + }, + { + "type": "assert_exception", + "line": 109, + "action": { + "type": "invoke", + "field": "rethrow-nested", + "args": [ + { + "type": "i32", + "value": "0" + } + ] + } + }, + { + "type": "assert_exception", + "line": 110, + "action": { + "type": "invoke", + "field": "rethrow-nested", + "args": [ + { + "type": "i32", + "value": "1" + } + ] + } + }, + { + "type": "assert_return", + "line": 111, + "action": { + "type": "invoke", + "field": "rethrow-nested", + "args": [ + { + "type": "i32", + "value": "2" + } + ] + }, + "expected": [ + { + "type": "i32", + "value": "23" + } + ] + }, + { + "type": "assert_return", + "line": 113, + "action": { + "type": "invoke", + "field": "rethrow-recatch", + "args": [ + { + "type": "i32", + "value": "0" + } + ] + }, + "expected": [ + { + "type": "i32", + "value": "23" + } + ] + }, + { + "type": "assert_return", + "line": 114, + "action": { + "type": "invoke", + "field": "rethrow-recatch", + "args": [ + { + "type": "i32", + "value": "1" + } + ] + }, + "expected": [ + { + "type": "i32", + "value": "42" + } + ] + }, + { + "type": "assert_exception", + "line": 116, + "action": { + "type": "invoke", + "field": "rethrow-stack-polymorphism", + "args": [] + } + }, + { + "type": "assert_invalid", + "line": 118, + "filename": "rethrow.1.wasm", + "text": "invalid rethrow label", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 119, + "filename": "rethrow.2.wasm", + "text": "invalid rethrow label", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 120, + "filename": "rethrow.3.wasm", + "text": "invalid rethrow label", + "module_type": "binary" + } + ] +} \ No newline at end of file diff --git a/tests/snapshots/local/legacy-exceptions/rethrow.wast/0.print b/tests/snapshots/local/legacy-exceptions/rethrow.wast/0.print new file mode 100644 index 0000000000..998341854e --- /dev/null +++ b/tests/snapshots/local/legacy-exceptions/rethrow.wast/0.print @@ -0,0 +1,98 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (param i32) (result i32))) + (func (;0;) (type 0) + try ;; label = @1 + throw $e0 + catch $e0 + rethrow 0 (;@1;) + end + ) + (func (;1;) (type 1) (param i32) (result i32) + try (result i32) ;; label = @1 + throw $e0 + catch $e0 + local.get 0 + i32.eqz + if ;; label = @2 + rethrow 1 (;@1;) + end + i32.const 23 + end + ) + (func (;2;) (type 0) + try ;; label = @1 + throw $e0 + catch_all + rethrow 0 (;@1;) + end + ) + (func (;3;) (type 1) (param i32) (result i32) + try (result i32) ;; label = @1 + throw $e0 + catch_all + local.get 0 + i32.eqz + if ;; label = @2 + rethrow 1 (;@1;) + end + i32.const 23 + end + ) + (func (;4;) (type 1) (param i32) (result i32) + try (result i32) ;; label = @1 + throw $e1 + catch $e1 + try (result i32) ;; label = @2 + throw $e0 + catch $e0 + local.get 0 + i32.const 0 + i32.eq + if ;; label = @3 + rethrow 1 (;@2;) + end + local.get 0 + i32.const 1 + i32.eq + if ;; label = @3 + rethrow 2 (;@1;) + end + i32.const 23 + end + end + ) + (func (;5;) (type 1) (param i32) (result i32) + try (result i32) ;; label = @1 + throw $e0 + catch $e0 + try (result i32) ;; label = @2 + local.get 0 + i32.eqz + if ;; label = @3 + rethrow 2 (;@1;) + end + i32.const 42 + catch $e0 + i32.const 23 + end + end + ) + (func (;6;) (type 0) + try ;; label = @1 + throw $e0 + catch $e0 + i32.const 1 + rethrow 0 (;@1;) + end + ) + (tag $e0 (;0;) (type 0)) + (tag $e1 (;1;) (type 0)) + (export "catch-rethrow-0" (func 0)) + (export "catch-rethrow-1" (func 1)) + (export "catchall-rethrow-0" (func 2)) + (export "catchall-rethrow-1" (func 3)) + (export "rethrow-nested" (func 4)) + (export "rethrow-recatch" (func 5)) + (export "rethrow-stack-polymorphism" (func 6)) +) diff --git a/tests/snapshots/local/legacy-exceptions/throw.wast.json b/tests/snapshots/local/legacy-exceptions/throw.wast.json new file mode 100644 index 0000000000..bbffce788a --- /dev/null +++ b/tests/snapshots/local/legacy-exceptions/throw.wast.json @@ -0,0 +1,131 @@ +{ + "source_filename": "tests/local/legacy-exceptions/throw.wast", + "commands": [ + { + "type": "module", + "line": 3, + "filename": "throw.0.wasm" + }, + { + "type": "assert_return", + "line": 42, + "action": { + "type": "invoke", + "field": "throw-if", + "args": [ + { + "type": "i32", + "value": "0" + } + ] + }, + "expected": [ + { + "type": "i32", + "value": "0" + } + ] + }, + { + "type": "assert_exception", + "line": 43, + "action": { + "type": "invoke", + "field": "throw-if", + "args": [ + { + "type": "i32", + "value": "10" + } + ] + } + }, + { + "type": "assert_exception", + "line": 44, + "action": { + "type": "invoke", + "field": "throw-if", + "args": [ + { + "type": "i32", + "value": "-1" + } + ] + } + }, + { + "type": "assert_exception", + "line": 46, + "action": { + "type": "invoke", + "field": "throw-param-f32", + "args": [ + { + "type": "f32", + "value": "1084227584" + } + ] + } + }, + { + "type": "assert_exception", + "line": 47, + "action": { + "type": "invoke", + "field": "throw-param-i64", + "args": [ + { + "type": "i64", + "value": "5" + } + ] + } + }, + { + "type": "assert_exception", + "line": 48, + "action": { + "type": "invoke", + "field": "throw-param-f64", + "args": [ + { + "type": "f64", + "value": "4617315517961601024" + } + ] + } + }, + { + "type": "assert_return", + "line": 50, + "action": { + "type": "invoke", + "field": "test-throw-1-2", + "args": [] + }, + "expected": [] + }, + { + "type": "assert_invalid", + "line": 52, + "filename": "throw.1.wasm", + "text": "unknown tag 0", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 53, + "filename": "throw.2.wasm", + "text": "type mismatch: instruction requires [i32] but stack has []", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 55, + "filename": "throw.3.wasm", + "text": "type mismatch: instruction requires [i32] but stack has [i64]", + "module_type": "binary" + } + ] +} \ No newline at end of file diff --git a/tests/snapshots/local/legacy-exceptions/throw.wast/0.print b/tests/snapshots/local/legacy-exceptions/throw.wast/0.print new file mode 100644 index 0000000000..afaf56a81e --- /dev/null +++ b/tests/snapshots/local/legacy-exceptions/throw.wast/0.print @@ -0,0 +1,62 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (param i32))) + (type (;2;) (func (param f32))) + (type (;3;) (func (param i64))) + (type (;4;) (func (param f64))) + (type (;5;) (func (param i32 i32))) + (type (;6;) (func (param i32) (result i32))) + (func $throw-if (;0;) (type 6) (param i32) (result i32) + local.get 0 + i32.const 0 + i32.ne + if ;; label = @1 + throw $e0 + end + i32.const 0 + ) + (func (;1;) (type 2) (param f32) + local.get 0 + throw $e-f32 + ) + (func (;2;) (type 3) (param i64) + local.get 0 + throw $e-i64 + ) + (func (;3;) (type 4) (param f64) + local.get 0 + throw $e-f64 + ) + (func $throw-1-2 (;4;) (type 0) + i32.const 1 + i32.const 2 + throw $e-i32-i32 + ) + (func (;5;) (type 0) + try ;; label = @1 + call $throw-1-2 + catch $e-i32-i32 + i32.const 2 + i32.ne + if ;; label = @2 + unreachable + end + i32.const 1 + i32.ne + if ;; label = @2 + unreachable + end + end + ) + (tag $e0 (;0;) (type 0)) + (tag $e-i32 (;1;) (type 1) (param i32)) + (tag $e-f32 (;2;) (type 2) (param f32)) + (tag $e-i64 (;3;) (type 3) (param i64)) + (tag $e-f64 (;4;) (type 4) (param f64)) + (tag $e-i32-i32 (;5;) (type 5) (param i32 i32)) + (export "throw-if" (func $throw-if)) + (export "throw-param-f32" (func 1)) + (export "throw-param-i64" (func 2)) + (export "throw-param-f64" (func 3)) + (export "test-throw-1-2" (func 5)) +) diff --git a/tests/snapshots/local/legacy-exceptions/try_catch.wast.json b/tests/snapshots/local/legacy-exceptions/try_catch.wast.json new file mode 100644 index 0000000000..8b256d189b --- /dev/null +++ b/tests/snapshots/local/legacy-exceptions/try_catch.wast.json @@ -0,0 +1,599 @@ +{ + "source_filename": "tests/local/legacy-exceptions/try_catch.wast", + "commands": [ + { + "type": "module", + "line": 3, + "filename": "try_catch.0.wasm" + }, + { + "type": "register", + "line": 8, + "as": "test" + }, + { + "type": "module", + "line": 10, + "filename": "try_catch.1.wasm" + }, + { + "type": "assert_return", + "line": 213, + "action": { + "type": "invoke", + "field": "empty-catch", + "args": [] + }, + "expected": [] + }, + { + "type": "assert_return", + "line": 215, + "action": { + "type": "invoke", + "field": "simple-throw-catch", + "args": [ + { + "type": "i32", + "value": "0" + } + ] + }, + "expected": [ + { + "type": "i32", + "value": "23" + } + ] + }, + { + "type": "assert_return", + "line": 216, + "action": { + "type": "invoke", + "field": "simple-throw-catch", + "args": [ + { + "type": "i32", + "value": "1" + } + ] + }, + "expected": [ + { + "type": "i32", + "value": "42" + } + ] + }, + { + "type": "assert_trap", + "line": 218, + "action": { + "type": "invoke", + "field": "unreachable-not-caught", + "args": [] + }, + "text": "unreachable" + }, + { + "type": "assert_return", + "line": 220, + "action": { + "type": "invoke", + "field": "trap-in-callee", + "args": [ + { + "type": "i32", + "value": "7" + }, + { + "type": "i32", + "value": "2" + } + ] + }, + "expected": [ + { + "type": "i32", + "value": "3" + } + ] + }, + { + "type": "assert_trap", + "line": 221, + "action": { + "type": "invoke", + "field": "trap-in-callee", + "args": [ + { + "type": "i32", + "value": "1" + }, + { + "type": "i32", + "value": "0" + } + ] + }, + "text": "integer divide by zero" + }, + { + "type": "assert_return", + "line": 223, + "action": { + "type": "invoke", + "field": "catch-complex-1", + "args": [ + { + "type": "i32", + "value": "0" + } + ] + }, + "expected": [ + { + "type": "i32", + "value": "3" + } + ] + }, + { + "type": "assert_return", + "line": 224, + "action": { + "type": "invoke", + "field": "catch-complex-1", + "args": [ + { + "type": "i32", + "value": "1" + } + ] + }, + "expected": [ + { + "type": "i32", + "value": "4" + } + ] + }, + { + "type": "assert_exception", + "line": 225, + "action": { + "type": "invoke", + "field": "catch-complex-1", + "args": [ + { + "type": "i32", + "value": "2" + } + ] + } + }, + { + "type": "assert_return", + "line": 227, + "action": { + "type": "invoke", + "field": "catch-complex-2", + "args": [ + { + "type": "i32", + "value": "0" + } + ] + }, + "expected": [ + { + "type": "i32", + "value": "3" + } + ] + }, + { + "type": "assert_return", + "line": 228, + "action": { + "type": "invoke", + "field": "catch-complex-2", + "args": [ + { + "type": "i32", + "value": "1" + } + ] + }, + "expected": [ + { + "type": "i32", + "value": "4" + } + ] + }, + { + "type": "assert_exception", + "line": 229, + "action": { + "type": "invoke", + "field": "catch-complex-2", + "args": [ + { + "type": "i32", + "value": "2" + } + ] + } + }, + { + "type": "assert_return", + "line": 231, + "action": { + "type": "invoke", + "field": "throw-catch-param-i32", + "args": [ + { + "type": "i32", + "value": "0" + } + ] + }, + "expected": [ + { + "type": "i32", + "value": "0" + } + ] + }, + { + "type": "assert_return", + "line": 232, + "action": { + "type": "invoke", + "field": "throw-catch-param-i32", + "args": [ + { + "type": "i32", + "value": "1" + } + ] + }, + "expected": [ + { + "type": "i32", + "value": "1" + } + ] + }, + { + "type": "assert_return", + "line": 233, + "action": { + "type": "invoke", + "field": "throw-catch-param-i32", + "args": [ + { + "type": "i32", + "value": "10" + } + ] + }, + "expected": [ + { + "type": "i32", + "value": "10" + } + ] + }, + { + "type": "assert_return", + "line": 235, + "action": { + "type": "invoke", + "field": "throw-catch-param-f32", + "args": [ + { + "type": "f32", + "value": "1084227584" + } + ] + }, + "expected": [ + { + "type": "f32", + "value": "1084227584" + } + ] + }, + { + "type": "assert_return", + "line": 236, + "action": { + "type": "invoke", + "field": "throw-catch-param-f32", + "args": [ + { + "type": "f32", + "value": "1093140480" + } + ] + }, + "expected": [ + { + "type": "f32", + "value": "1093140480" + } + ] + }, + { + "type": "assert_return", + "line": 238, + "action": { + "type": "invoke", + "field": "throw-catch-param-i64", + "args": [ + { + "type": "i64", + "value": "5" + } + ] + }, + "expected": [ + { + "type": "i64", + "value": "5" + } + ] + }, + { + "type": "assert_return", + "line": 239, + "action": { + "type": "invoke", + "field": "throw-catch-param-i64", + "args": [ + { + "type": "i64", + "value": "0" + } + ] + }, + "expected": [ + { + "type": "i64", + "value": "0" + } + ] + }, + { + "type": "assert_return", + "line": 240, + "action": { + "type": "invoke", + "field": "throw-catch-param-i64", + "args": [ + { + "type": "i64", + "value": "-1" + } + ] + }, + "expected": [ + { + "type": "i64", + "value": "-1" + } + ] + }, + { + "type": "assert_return", + "line": 242, + "action": { + "type": "invoke", + "field": "throw-catch-param-f64", + "args": [ + { + "type": "f64", + "value": "4617315517961601024" + } + ] + }, + "expected": [ + { + "type": "f64", + "value": "4617315517961601024" + } + ] + }, + { + "type": "assert_return", + "line": 243, + "action": { + "type": "invoke", + "field": "throw-catch-param-f64", + "args": [ + { + "type": "f64", + "value": "4622100592565682176" + } + ] + }, + "expected": [ + { + "type": "f64", + "value": "4622100592565682176" + } + ] + }, + { + "type": "assert_return", + "line": 245, + "action": { + "type": "invoke", + "field": "catch-param-i32", + "args": [ + { + "type": "i32", + "value": "5" + } + ] + }, + "expected": [ + { + "type": "i32", + "value": "5" + } + ] + }, + { + "type": "assert_return", + "line": 247, + "action": { + "type": "invoke", + "field": "catch-imported", + "args": [] + }, + "expected": [ + { + "type": "i32", + "value": "2" + } + ] + }, + { + "type": "assert_return", + "line": 249, + "action": { + "type": "invoke", + "field": "catchless-try", + "args": [ + { + "type": "i32", + "value": "0" + } + ] + }, + "expected": [ + { + "type": "i32", + "value": "0" + } + ] + }, + { + "type": "assert_return", + "line": 250, + "action": { + "type": "invoke", + "field": "catchless-try", + "args": [ + { + "type": "i32", + "value": "1" + } + ] + }, + "expected": [ + { + "type": "i32", + "value": "1" + } + ] + }, + { + "type": "assert_exception", + "line": 252, + "action": { + "type": "invoke", + "field": "return-call-in-try-catch", + "args": [] + } + }, + { + "type": "assert_exception", + "line": 253, + "action": { + "type": "invoke", + "field": "return-call-indirect-in-try-catch", + "args": [] + } + }, + { + "type": "assert_return", + "line": 255, + "action": { + "type": "invoke", + "field": "break-try-catch", + "args": [] + }, + "expected": [] + }, + { + "type": "assert_return", + "line": 256, + "action": { + "type": "invoke", + "field": "break-try-catch_all", + "args": [] + }, + "expected": [] + }, + { + "type": "module", + "line": 258, + "filename": "try_catch.2.wasm" + }, + { + "type": "assert_return", + "line": 276, + "action": { + "type": "invoke", + "field": "imported-mismatch", + "args": [] + }, + "expected": [ + { + "type": "i32", + "value": "3" + } + ] + }, + { + "type": "assert_invalid", + "line": 297, + "filename": "try_catch.3.wasm", + "text": "type mismatch: instruction requires [i32] but stack has []", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 299, + "filename": "try_catch.4.wasm", + "text": "type mismatch: instruction requires [i32] but stack has [i64]", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 301, + "filename": "try_catch.5.wasm", + "text": "type mismatch: block requires [] but stack has [i32]", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 303, + "filename": "try_catch.6.wasm", + "text": "type mismatch: instruction requires [i32] but stack has [i64]", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 308, + "filename": "try_catch.7.wasm", + "text": "type mismatch: block requires [] but stack has [i32]", + "module_type": "binary" + } + ] +} \ No newline at end of file diff --git a/tests/snapshots/local/legacy-exceptions/try_catch.wast/0.print b/tests/snapshots/local/legacy-exceptions/try_catch.wast/0.print new file mode 100644 index 0000000000..121840d85f --- /dev/null +++ b/tests/snapshots/local/legacy-exceptions/try_catch.wast/0.print @@ -0,0 +1,9 @@ +(module + (type (;0;) (func)) + (func (;0;) (type 0) + throw $e0 + ) + (tag $e0 (;0;) (type 0)) + (export "e0" (tag 0)) + (export "throw" (func 0)) +) diff --git a/tests/snapshots/local/legacy-exceptions/try_catch.wast/2.print b/tests/snapshots/local/legacy-exceptions/try_catch.wast/2.print new file mode 100644 index 0000000000..dc973cca06 --- /dev/null +++ b/tests/snapshots/local/legacy-exceptions/try_catch.wast/2.print @@ -0,0 +1,229 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (param i32))) + (type (;2;) (func (param f32))) + (type (;3;) (func (param i64))) + (type (;4;) (func (param f64))) + (type (;5;) (func (param i32) (result i32))) + (type (;6;) (func (param i32 i32) (result i32))) + (type (;7;) (func (param f32) (result f32))) + (type (;8;) (func (param i64) (result i64))) + (type (;9;) (func (param f64) (result f64))) + (type (;10;) (func (result i32))) + (import "test" "e0" (tag $imported-e0 (;0;) (type 0))) + (import "test" "throw" (func $imported-throw (;0;) (type 0))) + (func $throw-if (;1;) (type 5) (param i32) (result i32) + local.get 0 + i32.const 0 + i32.ne + if ;; label = @1 + throw $e0 + end + i32.const 0 + ) + (func (;2;) (type 0) + try ;; label = @1 + catch $e0 + end + ) + (func (;3;) (type 5) (param i32) (result i32) + try (result i32) ;; label = @1 + local.get 0 + i32.eqz + if ;; label = @2 + throw $e0 + end + i32.const 42 + catch $e0 + i32.const 23 + end + ) + (func (;4;) (type 0) + try ;; label = @1 + unreachable + catch_all + end + ) + (func $div (;5;) (type 6) (param i32 i32) (result i32) + local.get 0 + local.get 1 + i32.div_u + ) + (func (;6;) (type 6) (param i32 i32) (result i32) + try (result i32) ;; label = @1 + local.get 0 + local.get 1 + call $div + catch_all + i32.const 11 + end + ) + (func (;7;) (type 5) (param i32) (result i32) + try (result i32) ;; label = @1 + try (result i32) ;; label = @2 + local.get 0 + i32.eqz + if ;; label = @3 + throw $e0 + else + local.get 0 + i32.const 1 + i32.eq + if ;; label = @4 + throw $e1 + else + throw $e2 + end + end + i32.const 2 + catch $e0 + i32.const 3 + end + catch $e1 + i32.const 4 + end + ) + (func (;8;) (type 5) (param i32) (result i32) + try (result i32) ;; label = @1 + local.get 0 + i32.eqz + if ;; label = @2 + throw $e0 + else + local.get 0 + i32.const 1 + i32.eq + if ;; label = @3 + throw $e1 + else + throw $e2 + end + end + i32.const 2 + catch $e0 + i32.const 3 + catch $e1 + i32.const 4 + end + ) + (func (;9;) (type 5) (param i32) (result i32) + try (result i32) ;; label = @1 + local.get 0 + throw $e-i32 + i32.const 2 + catch $e-i32 + return + end + ) + (func (;10;) (type 7) (param f32) (result f32) + try (result f32) ;; label = @1 + local.get 0 + throw $e-f32 + f32.const 0x0p+0 (;=0;) + catch $e-f32 + return + end + ) + (func (;11;) (type 8) (param i64) (result i64) + try (result i64) ;; label = @1 + local.get 0 + throw $e-i64 + i64.const 2 + catch $e-i64 + return + end + ) + (func (;12;) (type 9) (param f64) (result f64) + try (result f64) ;; label = @1 + local.get 0 + throw $e-f64 + f64.const 0x0p+0 (;=0;) + catch $e-f64 + return + end + ) + (func $throw-param-i32 (;13;) (type 1) (param i32) + local.get 0 + throw $e-i32 + ) + (func (;14;) (type 5) (param i32) (result i32) + try (result i32) ;; label = @1 + i32.const 0 + local.get 0 + call $throw-param-i32 + catch $e-i32 + end + ) + (func (;15;) (type 10) (result i32) + try (result i32) ;; label = @1 + i32.const 1 + call $imported-throw + catch $imported-e0 + i32.const 2 + end + ) + (func (;16;) (type 5) (param i32) (result i32) + try (result i32) ;; label = @1 + try (result i32) ;; label = @2 + local.get 0 + call $throw-if + end + catch $e0 + i32.const 1 + end + ) + (func $throw-void (;17;) (type 0) + throw $e0 + ) + (func (;18;) (type 0) + try ;; label = @1 + return_call $throw-void + catch $e0 + end + ) + (func (;19;) (type 0) + try ;; label = @1 + i32.const 0 + return_call_indirect (type 0) + catch $e0 + end + ) + (func (;20;) (type 0) + try ;; label = @1 + br 0 (;@1;) + catch $e0 + end + ) + (func (;21;) (type 0) + try ;; label = @1 + br 0 (;@1;) + catch_all + end + ) + (table (;0;) 1 1 funcref) + (tag $e0 (;1;) (type 0)) + (tag $e1 (;2;) (type 0)) + (tag $e2 (;3;) (type 0)) + (tag $e-i32 (;4;) (type 1) (param i32)) + (tag $e-f32 (;5;) (type 2) (param f32)) + (tag $e-i64 (;6;) (type 3) (param i64)) + (tag $e-f64 (;7;) (type 4) (param f64)) + (export "empty-catch" (func 2)) + (export "simple-throw-catch" (func 3)) + (export "unreachable-not-caught" (func 4)) + (export "trap-in-callee" (func 6)) + (export "catch-complex-1" (func 7)) + (export "catch-complex-2" (func 8)) + (export "throw-catch-param-i32" (func 9)) + (export "throw-catch-param-f32" (func 10)) + (export "throw-catch-param-i64" (func 11)) + (export "throw-catch-param-f64" (func 12)) + (export "catch-param-i32" (func 14)) + (export "catch-imported" (func 15)) + (export "catchless-try" (func 16)) + (export "return-call-in-try-catch" (func 18)) + (export "return-call-indirect-in-try-catch" (func 19)) + (export "break-try-catch" (func 20)) + (export "break-try-catch_all" (func 21)) + (elem (;0;) (i32.const 0) func $throw-void) +) diff --git a/tests/snapshots/local/legacy-exceptions/try_catch.wast/33.print b/tests/snapshots/local/legacy-exceptions/try_catch.wast/33.print new file mode 100644 index 0000000000..8210510b56 --- /dev/null +++ b/tests/snapshots/local/legacy-exceptions/try_catch.wast/33.print @@ -0,0 +1,19 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (result i32))) + (import "test" "throw" (func $imported-throw (;0;) (type 0))) + (func (;1;) (type 1) (result i32) + try (result i32) ;; label = @1 + try (result i32) ;; label = @2 + i32.const 1 + call $imported-throw + catch $e0 + i32.const 2 + end + catch_all + i32.const 3 + end + ) + (tag $e0 (;0;) (type 0)) + (export "imported-mismatch" (func 1)) +) diff --git a/tests/snapshots/local/legacy-exceptions/try_delegate.wast.json b/tests/snapshots/local/legacy-exceptions/try_delegate.wast.json new file mode 100644 index 0000000000..2ba6f88788 --- /dev/null +++ b/tests/snapshots/local/legacy-exceptions/try_delegate.wast.json @@ -0,0 +1,325 @@ +{ + "source_filename": "tests/local/legacy-exceptions/try_delegate.wast", + "commands": [ + { + "type": "module", + "line": 3, + "filename": "try_delegate.0.wasm" + }, + { + "type": "assert_return", + "line": 219, + "action": { + "type": "invoke", + "field": "delegate-no-throw", + "args": [] + }, + "expected": [ + { + "type": "i32", + "value": "1" + } + ] + }, + { + "type": "assert_return", + "line": 221, + "action": { + "type": "invoke", + "field": "delegate-throw", + "args": [ + { + "type": "i32", + "value": "0" + } + ] + }, + "expected": [ + { + "type": "i32", + "value": "1" + } + ] + }, + { + "type": "assert_return", + "line": 222, + "action": { + "type": "invoke", + "field": "delegate-throw", + "args": [ + { + "type": "i32", + "value": "1" + } + ] + }, + "expected": [ + { + "type": "i32", + "value": "2" + } + ] + }, + { + "type": "assert_exception", + "line": 224, + "action": { + "type": "invoke", + "field": "delegate-throw-no-catch", + "args": [] + } + }, + { + "type": "assert_return", + "line": 226, + "action": { + "type": "invoke", + "field": "delegate-merge", + "args": [ + { + "type": "i32", + "value": "1" + }, + { + "type": "i32", + "value": "0" + } + ] + }, + "expected": [ + { + "type": "i32", + "value": "2" + } + ] + }, + { + "type": "assert_exception", + "line": 227, + "action": { + "type": "invoke", + "field": "delegate-merge", + "args": [ + { + "type": "i32", + "value": "2" + }, + { + "type": "i32", + "value": "0" + } + ] + } + }, + { + "type": "assert_return", + "line": 228, + "action": { + "type": "invoke", + "field": "delegate-merge", + "args": [ + { + "type": "i32", + "value": "0" + }, + { + "type": "i32", + "value": "1" + } + ] + }, + "expected": [ + { + "type": "i32", + "value": "2" + } + ] + }, + { + "type": "assert_exception", + "line": 229, + "action": { + "type": "invoke", + "field": "delegate-merge", + "args": [ + { + "type": "i32", + "value": "0" + }, + { + "type": "i32", + "value": "2" + } + ] + } + }, + { + "type": "assert_return", + "line": 230, + "action": { + "type": "invoke", + "field": "delegate-merge", + "args": [ + { + "type": "i32", + "value": "0" + }, + { + "type": "i32", + "value": "0" + } + ] + }, + "expected": [ + { + "type": "i32", + "value": "1" + } + ] + }, + { + "type": "assert_return", + "line": 232, + "action": { + "type": "invoke", + "field": "delegate-skip", + "args": [] + }, + "expected": [ + { + "type": "i32", + "value": "3" + } + ] + }, + { + "type": "assert_return", + "line": 234, + "action": { + "type": "invoke", + "field": "delegate-to-block", + "args": [] + }, + "expected": [ + { + "type": "i32", + "value": "1" + } + ] + }, + { + "type": "assert_return", + "line": 235, + "action": { + "type": "invoke", + "field": "delegate-to-catch", + "args": [] + }, + "expected": [ + { + "type": "i32", + "value": "1" + } + ] + }, + { + "type": "assert_exception", + "line": 237, + "action": { + "type": "invoke", + "field": "delegate-to-caller-trivial", + "args": [] + } + }, + { + "type": "assert_exception", + "line": 238, + "action": { + "type": "invoke", + "field": "delegate-to-caller-skipping", + "args": [] + } + }, + { + "type": "assert_return", + "line": 240, + "action": { + "type": "invoke", + "field": "delegate-correct-targets", + "args": [] + }, + "expected": [ + { + "type": "i32", + "value": "1" + } + ] + }, + { + "type": "assert_exception", + "line": 242, + "action": { + "type": "invoke", + "field": "return-call-in-try-delegate", + "args": [] + } + }, + { + "type": "assert_exception", + "line": 243, + "action": { + "type": "invoke", + "field": "return-call-indirect-in-try-delegate", + "args": [] + } + }, + { + "type": "assert_return", + "line": 245, + "action": { + "type": "invoke", + "field": "break-try-delegate", + "args": [] + }, + "expected": [] + }, + { + "type": "assert_return", + "line": 247, + "action": { + "type": "invoke", + "field": "break-and-call-throw", + "args": [] + }, + "expected": [ + { + "type": "i32", + "value": "1" + } + ] + }, + { + "type": "assert_return", + "line": 248, + "action": { + "type": "invoke", + "field": "break-and-throw", + "args": [] + }, + "expected": [ + { + "type": "i32", + "value": "1" + } + ] + }, + { + "type": "assert_invalid", + "line": 273, + "filename": "try_delegate.1.wasm", + "text": "unknown label", + "module_type": "binary" + } + ] +} \ No newline at end of file diff --git a/tests/snapshots/local/legacy-exceptions/try_delegate.wast/0.print b/tests/snapshots/local/legacy-exceptions/try_delegate.wast/0.print new file mode 100644 index 0000000000..7144255ea7 --- /dev/null +++ b/tests/snapshots/local/legacy-exceptions/try_delegate.wast/0.print @@ -0,0 +1,227 @@ +(module + (type (;0;) (func)) + (type (;1;) (func (result i32))) + (type (;2;) (func (param i32))) + (type (;3;) (func (param i32) (result i32))) + (type (;4;) (func (param i32 i32) (result i32))) + (func (;0;) (type 1) (result i32) + try (result i32) ;; label = @1 + try (result i32) ;; label = @2 + i32.const 1 + delegate 0 (;@1;) + catch $e0 + i32.const 2 + end + ) + (func $throw-if (;1;) (type 2) (param i32) + local.get 0 + if ;; label = @1 + throw $e0 + else + end + ) + (func (;2;) (type 3) (param i32) (result i32) + try (result i32) ;; label = @1 + try (result i32) ;; label = @2 + local.get 0 + call $throw-if + i32.const 1 + delegate 0 (;@1;) + catch $e0 + i32.const 2 + end + ) + (func (;3;) (type 1) (result i32) + try (result i32) ;; label = @1 + try (result i32) ;; label = @2 + try (result i32) ;; label = @3 + throw $e0 + i32.const 1 + delegate 1 (;@1;) + catch $e0 + i32.const 2 + end + catch $e0 + i32.const 3 + end + ) + (func (;4;) (type 1) (result i32) + try (result i32) ;; label = @1 + block ;; label = @2 + try ;; label = @3 + throw $e0 + delegate 0 (;@2;) + end + i32.const 0 + catch_all + i32.const 1 + end + ) + (func (;5;) (type 1) (result i32) + try (result i32) ;; label = @1 + try ;; label = @2 + throw $e0 + catch $e0 + try ;; label = @3 + rethrow 1 (;@2;) + delegate 0 (;@2;) + end + i32.const 0 + catch_all + i32.const 1 + end + ) + (func (;6;) (type 0) + try ;; label = @1 + throw $e0 + delegate 0 + ) + (func (;7;) (type 0) + try ;; label = @1 + try ;; label = @2 + throw $e0 + delegate 1 + catch_all + end + ) + (func $select-tag (;8;) (type 2) (param i32) + block ;; label = @1 + block ;; label = @2 + block ;; label = @3 + local.get 0 + br_table 0 (;@3;) 1 (;@2;) 2 (;@1;) + end + return + end + throw $e0 + end + throw $e1 + ) + (func (;9;) (type 4) (param i32 i32) (result i32) + try (result i32) ;; label = @1 + local.get 0 + call $select-tag + try (result i32) ;; label = @2 + local.get 1 + call $select-tag + i32.const 1 + delegate 0 (;@1;) + catch $e0 + i32.const 2 + end + ) + (func (;10;) (type 1) (result i32) + try (result i32) ;; label = @1 + try (result i32) ;; label = @2 + throw $e0 + i32.const 1 + delegate 0 (;@1;) + catch $e1 + i32.const 2 + end + ) + (func (;11;) (type 1) (result i32) + try (result i32) ;; label = @1 + try ;; label = @2 + try ;; label = @3 + try ;; label = @4 + try ;; label = @5 + try ;; label = @6 + throw $e0 + delegate 1 (;@4;) + catch_all + unreachable + end + delegate 1 (;@2;) + catch_all + unreachable + end + catch_all + try ;; label = @3 + throw $e0 + delegate 0 (;@2;) + end + unreachable + catch_all + i32.const 1 + end + ) + (func $throw-void (;12;) (type 0) + throw $e0 + ) + (func (;13;) (type 0) + try ;; label = @1 + try ;; label = @2 + return_call $throw-void + delegate 0 (;@1;) + catch $e0 + end + ) + (func (;14;) (type 0) + try ;; label = @1 + try ;; label = @2 + i32.const 0 + return_call_indirect (type 0) + delegate 0 (;@1;) + catch $e0 + end + ) + (func (;15;) (type 0) + try ;; label = @1 + br 0 (;@1;) + delegate 0 + ) + (func (;16;) (type 1) (result i32) + try (result i32) ;; label = @1 + try (result i32) ;; label = @2 + block ;; label = @3 + try ;; label = @4 + br 1 (;@3;) + delegate 2 (;@1;) + end + call $throw-void + i32.const 0 + catch $e0 + i32.const 1 + end + catch $e0 + i32.const 2 + end + ) + (func (;17;) (type 1) (result i32) + try (result i32) ;; label = @1 + try (result i32) ;; label = @2 + block ;; label = @3 + try ;; label = @4 + br 1 (;@3;) + delegate 2 (;@1;) + end + throw $e0 + i32.const 0 + catch $e0 + i32.const 1 + end + catch $e0 + i32.const 2 + end + ) + (table (;0;) 1 1 funcref) + (tag $e0 (;0;) (type 0)) + (tag $e1 (;1;) (type 0)) + (export "delegate-no-throw" (func 0)) + (export "delegate-throw" (func 2)) + (export "delegate-skip" (func 3)) + (export "delegate-to-block" (func 4)) + (export "delegate-to-catch" (func 5)) + (export "delegate-to-caller-trivial" (func 6)) + (export "delegate-to-caller-skipping" (func 7)) + (export "delegate-merge" (func 9)) + (export "delegate-throw-no-catch" (func 10)) + (export "delegate-correct-targets" (func 11)) + (export "return-call-in-try-delegate" (func 13)) + (export "return-call-indirect-in-try-delegate" (func 14)) + (export "break-try-delegate" (func 15)) + (export "break-and-call-throw" (func 16)) + (export "break-and-throw" (func 17)) + (elem (;0;) (i32.const 0) func $throw-void) +) diff --git a/tests/snapshots/local/missing-features/tables.wast.json b/tests/snapshots/local/missing-features/tables.wast.json new file mode 100644 index 0000000000..5e06332b77 --- /dev/null +++ b/tests/snapshots/local/missing-features/tables.wast.json @@ -0,0 +1,12 @@ +{ + "source_filename": "tests/local/missing-features/tables.wast", + "commands": [ + { + "type": "assert_invalid", + "line": 2, + "filename": "tables.0.wasm", + "text": "shared tables require the shared-everything-threads proposal", + "module_type": "binary" + } + ] +} \ No newline at end of file diff --git a/tests/snapshots/local/shared-everything-threads/array.wast.json b/tests/snapshots/local/shared-everything-threads/array.wast.json index 03bf81d778..5118986647 100644 --- a/tests/snapshots/local/shared-everything-threads/array.wast.json +++ b/tests/snapshots/local/shared-everything-threads/array.wast.json @@ -55,6 +55,377 @@ "type": "module", "line": 72, "filename": "array.8.wasm" + }, + { + "type": "module", + "line": 118, + "filename": "array.9.wasm" + }, + { + "type": "module", + "line": 126, + "filename": "array.10.wasm" + }, + { + "type": "module", + "line": 134, + "filename": "array.11.wasm" + }, + { + "type": "module", + "line": 142, + "filename": "array.12.wasm" + }, + { + "type": "module", + "line": 150, + "filename": "array.13.wasm" + }, + { + "type": "module", + "line": 158, + "filename": "array.14.wasm" + }, + { + "type": "module", + "line": 166, + "filename": "array.15.wasm" + }, + { + "type": "module", + "line": 174, + "filename": "array.16.wasm" + }, + { + "type": "module", + "line": 182, + "filename": "array.17.wasm" + }, + { + "type": "module", + "line": 190, + "filename": "array.18.wasm" + }, + { + "type": "module", + "line": 198, + "filename": "array.19.wasm" + }, + { + "type": "module", + "line": 206, + "filename": "array.20.wasm" + }, + { + "type": "module", + "line": 214, + "filename": "array.21.wasm" + }, + { + "type": "module", + "line": 222, + "filename": "array.22.wasm" + }, + { + "type": "module", + "line": 230, + "filename": "array.23.wasm" + }, + { + "type": "module", + "line": 239, + "filename": "array.24.wasm" + }, + { + "type": "module", + "line": 248, + "filename": "array.25.wasm" + }, + { + "type": "module", + "line": 257, + "filename": "array.26.wasm" + }, + { + "type": "module", + "line": 266, + "filename": "array.27.wasm" + }, + { + "type": "module", + "line": 275, + "filename": "array.28.wasm" + }, + { + "type": "module", + "line": 284, + "filename": "array.29.wasm" + }, + { + "type": "module", + "line": 293, + "filename": "array.30.wasm" + }, + { + "type": "module", + "line": 302, + "filename": "array.31.wasm" + }, + { + "type": "module", + "line": 311, + "filename": "array.32.wasm" + }, + { + "type": "module", + "line": 320, + "filename": "array.33.wasm" + }, + { + "type": "module", + "line": 329, + "filename": "array.34.wasm" + }, + { + "type": "module", + "line": 338, + "filename": "array.35.wasm" + }, + { + "type": "module", + "line": 347, + "filename": "array.36.wasm" + }, + { + "type": "module", + "line": 356, + "filename": "array.37.wasm" + }, + { + "type": "module", + "line": 365, + "filename": "array.38.wasm" + }, + { + "type": "module", + "line": 374, + "filename": "array.39.wasm" + }, + { + "type": "module", + "line": 383, + "filename": "array.40.wasm" + }, + { + "type": "module", + "line": 392, + "filename": "array.41.wasm" + }, + { + "type": "module", + "line": 401, + "filename": "array.42.wasm" + }, + { + "type": "module", + "line": 410, + "filename": "array.43.wasm" + }, + { + "type": "module", + "line": 419, + "filename": "array.44.wasm" + }, + { + "type": "module", + "line": 428, + "filename": "array.45.wasm" + }, + { + "type": "module", + "line": 437, + "filename": "array.46.wasm" + }, + { + "type": "module", + "line": 446, + "filename": "array.47.wasm" + }, + { + "type": "module", + "line": 455, + "filename": "array.48.wasm" + }, + { + "type": "module", + "line": 464, + "filename": "array.49.wasm" + }, + { + "type": "module", + "line": 473, + "filename": "array.50.wasm" + }, + { + "type": "module", + "line": 482, + "filename": "array.51.wasm" + }, + { + "type": "module", + "line": 491, + "filename": "array.52.wasm" + }, + { + "type": "module", + "line": 500, + "filename": "array.53.wasm" + }, + { + "type": "module", + "line": 509, + "filename": "array.54.wasm" + }, + { + "type": "module", + "line": 518, + "filename": "array.55.wasm" + }, + { + "type": "module", + "line": 527, + "filename": "array.56.wasm" + }, + { + "type": "module", + "line": 536, + "filename": "array.57.wasm" + }, + { + "type": "module", + "line": 545, + "filename": "array.58.wasm" + }, + { + "type": "module", + "line": 554, + "filename": "array.59.wasm" + }, + { + "type": "module", + "line": 564, + "filename": "array.60.wasm" + }, + { + "type": "module", + "line": 574, + "filename": "array.61.wasm" + }, + { + "type": "module", + "line": 584, + "filename": "array.62.wasm" + }, + { + "type": "module", + "line": 594, + "filename": "array.63.wasm" + }, + { + "type": "module", + "line": 604, + "filename": "array.64.wasm" + }, + { + "type": "assert_invalid", + "line": 615, + "filename": "array.65.wasm", + "text": "packed storage type", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 625, + "filename": "array.66.wasm", + "text": "non-packed storage type", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 635, + "filename": "array.67.wasm", + "text": "non-packed storage type", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 645, + "filename": "array.68.wasm", + "text": "non-packed storage type", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 655, + "filename": "array.69.wasm", + "text": "non-packed storage type", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 665, + "filename": "array.70.wasm", + "text": "invalid type", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 676, + "filename": "array.71.wasm", + "text": "invalid type", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 687, + "filename": "array.72.wasm", + "text": "invalid type", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 698, + "filename": "array.73.wasm", + "text": "invalid type", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 709, + "filename": "array.74.wasm", + "text": "invalid type", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 720, + "filename": "array.75.wasm", + "text": "invalid type", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 731, + "filename": "array.76.wasm", + "text": "invalid type", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 743, + "filename": "array.77.wasm", + "text": "invalid type", + "module_type": "binary" } ] } \ No newline at end of file diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/10.print b/tests/snapshots/local/shared-everything-threads/array.wast/10.print new file mode 100644 index 0000000000..f733e00572 --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/10.print @@ -0,0 +1,10 @@ +(module + (type $a (;0;) (shared(array (mut i64)))) + (type (;1;) (func (param (ref null $a) i32) (result i64))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (result i64) + local.get $x + local.get $y + array.atomic.get seq_cst $a + ) + (export "array-atomic-get-i64-seq_cst" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/11.print b/tests/snapshots/local/shared-everything-threads/array.wast/11.print new file mode 100644 index 0000000000..76dbd3ecb7 --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/11.print @@ -0,0 +1,10 @@ +(module + (type $a (;0;) (shared(array (mut (ref null (shared any)))))) + (type (;1;) (func (param (ref null $a) i32) (result (ref null (shared any))))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (result (ref null (shared any))) + local.get $x + local.get $y + array.atomic.get seq_cst $a + ) + (export "array-atomic-get-anyref-seq_cst" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/12.print b/tests/snapshots/local/shared-everything-threads/array.wast/12.print new file mode 100644 index 0000000000..5cf5608397 --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/12.print @@ -0,0 +1,10 @@ +(module + (type $a (;0;) (shared(array (mut i32)))) + (type (;1;) (func (param (ref null $a) i32) (result i32))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (result i32) + local.get $x + local.get $y + array.atomic.get acq_rel $a + ) + (export "array-atomic-get-i32-acq_rel" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/13.print b/tests/snapshots/local/shared-everything-threads/array.wast/13.print new file mode 100644 index 0000000000..b4b3919e6f --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/13.print @@ -0,0 +1,10 @@ +(module + (type $a (;0;) (shared(array (mut i64)))) + (type (;1;) (func (param (ref null $a) i32) (result i64))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (result i64) + local.get $x + local.get $y + array.atomic.get acq_rel $a + ) + (export "array-atomic-get-i64-acq_rel" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/14.print b/tests/snapshots/local/shared-everything-threads/array.wast/14.print new file mode 100644 index 0000000000..189c2ea090 --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/14.print @@ -0,0 +1,10 @@ +(module + (type $a (;0;) (shared(array (mut (ref null (shared any)))))) + (type (;1;) (func (param (ref null $a) i32) (result (ref null (shared any))))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (result (ref null (shared any))) + local.get $x + local.get $y + array.atomic.get acq_rel $a + ) + (export "array-atomic-get-anyref-acq_rel" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/15.print b/tests/snapshots/local/shared-everything-threads/array.wast/15.print new file mode 100644 index 0000000000..00e0b30082 --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/15.print @@ -0,0 +1,10 @@ +(module + (type $a (;0;) (shared(array (mut i8)))) + (type (;1;) (func (param (ref null $a) i32) (result i32))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (result i32) + local.get $x + local.get $y + array.atomic.get_s seq_cst $a + ) + (export "array-atomic-get_s-i8-seq_cst" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/16.print b/tests/snapshots/local/shared-everything-threads/array.wast/16.print new file mode 100644 index 0000000000..82d7db16b1 --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/16.print @@ -0,0 +1,10 @@ +(module + (type $a (;0;) (shared(array (mut i16)))) + (type (;1;) (func (param (ref null $a) i32) (result i32))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (result i32) + local.get $x + local.get $y + array.atomic.get_s seq_cst $a + ) + (export "array-atomic-get_s-i16-seq_cst" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/17.print b/tests/snapshots/local/shared-everything-threads/array.wast/17.print new file mode 100644 index 0000000000..0794e77851 --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/17.print @@ -0,0 +1,10 @@ +(module + (type $a (;0;) (shared(array (mut i8)))) + (type (;1;) (func (param (ref null $a) i32) (result i32))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (result i32) + local.get $x + local.get $y + array.atomic.get_s acq_rel $a + ) + (export "array-atomic-get_s-i8-acq_rel" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/18.print b/tests/snapshots/local/shared-everything-threads/array.wast/18.print new file mode 100644 index 0000000000..f7a27cdcd8 --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/18.print @@ -0,0 +1,10 @@ +(module + (type $a (;0;) (shared(array (mut i16)))) + (type (;1;) (func (param (ref null $a) i32) (result i32))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (result i32) + local.get $x + local.get $y + array.atomic.get_s acq_rel $a + ) + (export "array-atomic-get_s-i16-acq_rel" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/19.print b/tests/snapshots/local/shared-everything-threads/array.wast/19.print new file mode 100644 index 0000000000..2ccc59945c --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/19.print @@ -0,0 +1,10 @@ +(module + (type $a (;0;) (shared(array (mut i8)))) + (type (;1;) (func (param (ref null $a) i32) (result i32))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (result i32) + local.get $x + local.get $y + array.atomic.get_u seq_cst $a + ) + (export "array-atomic-get_u-i8-seq_cst" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/20.print b/tests/snapshots/local/shared-everything-threads/array.wast/20.print new file mode 100644 index 0000000000..144068c536 --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/20.print @@ -0,0 +1,10 @@ +(module + (type $a (;0;) (shared(array (mut i16)))) + (type (;1;) (func (param (ref null $a) i32) (result i32))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (result i32) + local.get $x + local.get $y + array.atomic.get_u seq_cst $a + ) + (export "array-atomic-get_u-i16-seq_cst" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/21.print b/tests/snapshots/local/shared-everything-threads/array.wast/21.print new file mode 100644 index 0000000000..e5bed640b9 --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/21.print @@ -0,0 +1,10 @@ +(module + (type $a (;0;) (shared(array (mut i8)))) + (type (;1;) (func (param (ref null $a) i32) (result i32))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (result i32) + local.get $x + local.get $y + array.atomic.get_u acq_rel $a + ) + (export "array-atomic-get_u-i8-acq_rel" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/22.print b/tests/snapshots/local/shared-everything-threads/array.wast/22.print new file mode 100644 index 0000000000..069d3eb673 --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/22.print @@ -0,0 +1,10 @@ +(module + (type $a (;0;) (shared(array (mut i16)))) + (type (;1;) (func (param (ref null $a) i32) (result i32))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (result i32) + local.get $x + local.get $y + array.atomic.get_u acq_rel $a + ) + (export "array-atomic-get_u-i16-acq_rel" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/23.print b/tests/snapshots/local/shared-everything-threads/array.wast/23.print new file mode 100644 index 0000000000..b1727c3227 --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/23.print @@ -0,0 +1,11 @@ +(module + (type $a (;0;) (shared(array (mut i8)))) + (type (;1;) (func (param (ref null $a) i32 i32))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i32) + local.get $x + local.get $y + local.get $z + array.atomic.set seq_cst $a + ) + (export "array-atomic-set-i8-seq_cst" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/24.print b/tests/snapshots/local/shared-everything-threads/array.wast/24.print new file mode 100644 index 0000000000..95641f947b --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/24.print @@ -0,0 +1,11 @@ +(module + (type $a (;0;) (shared(array (mut i16)))) + (type (;1;) (func (param (ref null $a) i32 i32))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i32) + local.get $x + local.get $y + local.get $z + array.atomic.set seq_cst $a + ) + (export "array-atomic-set-i16-seq_cst" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/25.print b/tests/snapshots/local/shared-everything-threads/array.wast/25.print new file mode 100644 index 0000000000..b8e21b1aa8 --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/25.print @@ -0,0 +1,11 @@ +(module + (type $a (;0;) (shared(array (mut i32)))) + (type (;1;) (func (param (ref null $a) i32 i32))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i32) + local.get $x + local.get $y + local.get $z + array.atomic.set seq_cst $a + ) + (export "array-atomic-set-i32-seq_cst" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/26.print b/tests/snapshots/local/shared-everything-threads/array.wast/26.print new file mode 100644 index 0000000000..6e11fb3a41 --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/26.print @@ -0,0 +1,11 @@ +(module + (type $a (;0;) (shared(array (mut i64)))) + (type (;1;) (func (param (ref null $a) i32 i64))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i64) + local.get $x + local.get $y + local.get $z + array.atomic.set seq_cst $a + ) + (export "array-atomic-set-i64-seq_cst" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/27.print b/tests/snapshots/local/shared-everything-threads/array.wast/27.print new file mode 100644 index 0000000000..db65bed132 --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/27.print @@ -0,0 +1,11 @@ +(module + (type $a (;0;) (shared(array (mut (ref null (shared any)))))) + (type (;1;) (func (param (ref null $a) i32 (ref null (shared any))))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z (ref null (shared any))) + local.get $x + local.get $y + local.get $z + array.atomic.set seq_cst $a + ) + (export "array-atomic-set-anyref-seq_cst" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/28.print b/tests/snapshots/local/shared-everything-threads/array.wast/28.print new file mode 100644 index 0000000000..941e3f0d84 --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/28.print @@ -0,0 +1,11 @@ +(module + (type $a (;0;) (shared(array (mut i8)))) + (type (;1;) (func (param (ref null $a) i32 i32))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i32) + local.get $x + local.get $y + local.get $z + array.atomic.set acq_rel $a + ) + (export "array-atomic-set-i8-acq_rel" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/29.print b/tests/snapshots/local/shared-everything-threads/array.wast/29.print new file mode 100644 index 0000000000..4e3d7c91cd --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/29.print @@ -0,0 +1,11 @@ +(module + (type $a (;0;) (shared(array (mut i16)))) + (type (;1;) (func (param (ref null $a) i32 i32))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i32) + local.get $x + local.get $y + local.get $z + array.atomic.set acq_rel $a + ) + (export "array-atomic-set-i16-acq_rel" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/30.print b/tests/snapshots/local/shared-everything-threads/array.wast/30.print new file mode 100644 index 0000000000..17aec3ab82 --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/30.print @@ -0,0 +1,11 @@ +(module + (type $a (;0;) (shared(array (mut i32)))) + (type (;1;) (func (param (ref null $a) i32 i32))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i32) + local.get $x + local.get $y + local.get $z + array.atomic.set acq_rel $a + ) + (export "array-atomic-set-i32-acq_rel" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/31.print b/tests/snapshots/local/shared-everything-threads/array.wast/31.print new file mode 100644 index 0000000000..43139589ed --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/31.print @@ -0,0 +1,11 @@ +(module + (type $a (;0;) (shared(array (mut i64)))) + (type (;1;) (func (param (ref null $a) i32 i64))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i64) + local.get $x + local.get $y + local.get $z + array.atomic.set acq_rel $a + ) + (export "array-atomic-set-i64-acq_rel" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/32.print b/tests/snapshots/local/shared-everything-threads/array.wast/32.print new file mode 100644 index 0000000000..ed1acbaf33 --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/32.print @@ -0,0 +1,11 @@ +(module + (type $a (;0;) (shared(array (mut (ref null (shared any)))))) + (type (;1;) (func (param (ref null $a) i32 (ref null (shared any))))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z (ref null (shared any))) + local.get $x + local.get $y + local.get $z + array.atomic.set acq_rel $a + ) + (export "array-atomic-set-anyref-acq_rel" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/33.print b/tests/snapshots/local/shared-everything-threads/array.wast/33.print new file mode 100644 index 0000000000..d230670ccd --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/33.print @@ -0,0 +1,11 @@ +(module + (type $a (;0;) (shared(array (mut i32)))) + (type (;1;) (func (param (ref null $a) i32 i32) (result i32))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i32) (result i32) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.add seq_cst $a + ) + (export "array-atomic-rmw.add-i32-seq_cst" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/34.print b/tests/snapshots/local/shared-everything-threads/array.wast/34.print new file mode 100644 index 0000000000..28ea109420 --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/34.print @@ -0,0 +1,11 @@ +(module + (type $a (;0;) (shared(array (mut i64)))) + (type (;1;) (func (param (ref null $a) i32 i64) (result i64))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i64) (result i64) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.add seq_cst $a + ) + (export "array-atomic-rmw.add-i64-seq_cst" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/35.print b/tests/snapshots/local/shared-everything-threads/array.wast/35.print new file mode 100644 index 0000000000..8cc27f279f --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/35.print @@ -0,0 +1,11 @@ +(module + (type $a (;0;) (shared(array (mut i32)))) + (type (;1;) (func (param (ref null $a) i32 i32) (result i32))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i32) (result i32) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.add acq_rel $a + ) + (export "array-atomic-rmw.add-i32-acq_rel" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/36.print b/tests/snapshots/local/shared-everything-threads/array.wast/36.print new file mode 100644 index 0000000000..3be7d18db2 --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/36.print @@ -0,0 +1,11 @@ +(module + (type $a (;0;) (shared(array (mut i64)))) + (type (;1;) (func (param (ref null $a) i32 i64) (result i64))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i64) (result i64) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.add acq_rel $a + ) + (export "array-atomic-rmw.add-i64-acq_rel" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/37.print b/tests/snapshots/local/shared-everything-threads/array.wast/37.print new file mode 100644 index 0000000000..36af9d868b --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/37.print @@ -0,0 +1,11 @@ +(module + (type $a (;0;) (shared(array (mut i32)))) + (type (;1;) (func (param (ref null $a) i32 i32) (result i32))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i32) (result i32) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.sub seq_cst $a + ) + (export "array-atomic-rmw.sub-i32-seq_cst" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/38.print b/tests/snapshots/local/shared-everything-threads/array.wast/38.print new file mode 100644 index 0000000000..5bb94f29a1 --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/38.print @@ -0,0 +1,11 @@ +(module + (type $a (;0;) (shared(array (mut i64)))) + (type (;1;) (func (param (ref null $a) i32 i64) (result i64))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i64) (result i64) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.sub seq_cst $a + ) + (export "array-atomic-rmw.sub-i64-seq_cst" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/39.print b/tests/snapshots/local/shared-everything-threads/array.wast/39.print new file mode 100644 index 0000000000..0b4badbb86 --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/39.print @@ -0,0 +1,11 @@ +(module + (type $a (;0;) (shared(array (mut i32)))) + (type (;1;) (func (param (ref null $a) i32 i32) (result i32))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i32) (result i32) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.sub acq_rel $a + ) + (export "array-atomic-rmw.sub-i32-acq_rel" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/40.print b/tests/snapshots/local/shared-everything-threads/array.wast/40.print new file mode 100644 index 0000000000..ba01772628 --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/40.print @@ -0,0 +1,11 @@ +(module + (type $a (;0;) (shared(array (mut i64)))) + (type (;1;) (func (param (ref null $a) i32 i64) (result i64))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i64) (result i64) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.sub acq_rel $a + ) + (export "array-atomic-rmw.sub-i64-acq_rel" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/41.print b/tests/snapshots/local/shared-everything-threads/array.wast/41.print new file mode 100644 index 0000000000..5c61030757 --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/41.print @@ -0,0 +1,11 @@ +(module + (type $a (;0;) (shared(array (mut i32)))) + (type (;1;) (func (param (ref null $a) i32 i32) (result i32))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i32) (result i32) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.and seq_cst $a + ) + (export "array-atomic-rmw.and-i32-seq_cst" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/42.print b/tests/snapshots/local/shared-everything-threads/array.wast/42.print new file mode 100644 index 0000000000..2edfd317cf --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/42.print @@ -0,0 +1,11 @@ +(module + (type $a (;0;) (shared(array (mut i64)))) + (type (;1;) (func (param (ref null $a) i32 i64) (result i64))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i64) (result i64) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.and seq_cst $a + ) + (export "array-atomic-rmw.and-i64-seq_cst" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/43.print b/tests/snapshots/local/shared-everything-threads/array.wast/43.print new file mode 100644 index 0000000000..9a6e89fc15 --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/43.print @@ -0,0 +1,11 @@ +(module + (type $a (;0;) (shared(array (mut i32)))) + (type (;1;) (func (param (ref null $a) i32 i32) (result i32))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i32) (result i32) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.and acq_rel $a + ) + (export "array-atomic-rmw.and-i32-acq_rel" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/44.print b/tests/snapshots/local/shared-everything-threads/array.wast/44.print new file mode 100644 index 0000000000..f82346cddb --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/44.print @@ -0,0 +1,11 @@ +(module + (type $a (;0;) (shared(array (mut i64)))) + (type (;1;) (func (param (ref null $a) i32 i64) (result i64))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i64) (result i64) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.and acq_rel $a + ) + (export "array-atomic-rmw.and-i64-acq_rel" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/45.print b/tests/snapshots/local/shared-everything-threads/array.wast/45.print new file mode 100644 index 0000000000..59adfe733b --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/45.print @@ -0,0 +1,11 @@ +(module + (type $a (;0;) (shared(array (mut i32)))) + (type (;1;) (func (param (ref null $a) i32 i32) (result i32))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i32) (result i32) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.or seq_cst $a + ) + (export "array-atomic-rmw.or-i32-seq_cst" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/46.print b/tests/snapshots/local/shared-everything-threads/array.wast/46.print new file mode 100644 index 0000000000..13dd111893 --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/46.print @@ -0,0 +1,11 @@ +(module + (type $a (;0;) (shared(array (mut i64)))) + (type (;1;) (func (param (ref null $a) i32 i64) (result i64))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i64) (result i64) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.or seq_cst $a + ) + (export "array-atomic-rmw.or-i64-seq_cst" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/47.print b/tests/snapshots/local/shared-everything-threads/array.wast/47.print new file mode 100644 index 0000000000..ffca25c496 --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/47.print @@ -0,0 +1,11 @@ +(module + (type $a (;0;) (shared(array (mut i32)))) + (type (;1;) (func (param (ref null $a) i32 i32) (result i32))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i32) (result i32) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.or acq_rel $a + ) + (export "array-atomic-rmw.or-i32-acq_rel" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/48.print b/tests/snapshots/local/shared-everything-threads/array.wast/48.print new file mode 100644 index 0000000000..94fbc49ce6 --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/48.print @@ -0,0 +1,11 @@ +(module + (type $a (;0;) (shared(array (mut i64)))) + (type (;1;) (func (param (ref null $a) i32 i64) (result i64))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i64) (result i64) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.or acq_rel $a + ) + (export "array-atomic-rmw.or-i64-acq_rel" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/49.print b/tests/snapshots/local/shared-everything-threads/array.wast/49.print new file mode 100644 index 0000000000..0e6016a7ab --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/49.print @@ -0,0 +1,11 @@ +(module + (type $a (;0;) (shared(array (mut i32)))) + (type (;1;) (func (param (ref null $a) i32 i32) (result i32))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i32) (result i32) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.xor seq_cst $a + ) + (export "array-atomic-rmw.xor-i32-seq_cst" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/50.print b/tests/snapshots/local/shared-everything-threads/array.wast/50.print new file mode 100644 index 0000000000..446233a0e1 --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/50.print @@ -0,0 +1,11 @@ +(module + (type $a (;0;) (shared(array (mut i64)))) + (type (;1;) (func (param (ref null $a) i32 i64) (result i64))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i64) (result i64) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.xor seq_cst $a + ) + (export "array-atomic-rmw.xor-i64-seq_cst" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/51.print b/tests/snapshots/local/shared-everything-threads/array.wast/51.print new file mode 100644 index 0000000000..7867026121 --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/51.print @@ -0,0 +1,11 @@ +(module + (type $a (;0;) (shared(array (mut i32)))) + (type (;1;) (func (param (ref null $a) i32 i32) (result i32))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i32) (result i32) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.xor acq_rel $a + ) + (export "array-atomic-rmw.xor-i32-acq_rel" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/52.print b/tests/snapshots/local/shared-everything-threads/array.wast/52.print new file mode 100644 index 0000000000..1e8eb5b9ef --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/52.print @@ -0,0 +1,11 @@ +(module + (type $a (;0;) (shared(array (mut i64)))) + (type (;1;) (func (param (ref null $a) i32 i64) (result i64))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i64) (result i64) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.xor acq_rel $a + ) + (export "array-atomic-rmw.xor-i64-acq_rel" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/53.print b/tests/snapshots/local/shared-everything-threads/array.wast/53.print new file mode 100644 index 0000000000..71e2c7a8c2 --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/53.print @@ -0,0 +1,11 @@ +(module + (type $a (;0;) (shared(array (mut i32)))) + (type (;1;) (func (param (ref null $a) i32 i32) (result i32))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i32) (result i32) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.xchg seq_cst $a + ) + (export "array-atomic-rmw.xchg-i32-seq_cst" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/54.print b/tests/snapshots/local/shared-everything-threads/array.wast/54.print new file mode 100644 index 0000000000..1770c9685c --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/54.print @@ -0,0 +1,11 @@ +(module + (type $a (;0;) (shared(array (mut i64)))) + (type (;1;) (func (param (ref null $a) i32 i64) (result i64))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i64) (result i64) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.xchg seq_cst $a + ) + (export "array-atomic-rmw.xchg-i64-seq_cst" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/55.print b/tests/snapshots/local/shared-everything-threads/array.wast/55.print new file mode 100644 index 0000000000..6ca3ea8062 --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/55.print @@ -0,0 +1,11 @@ +(module + (type $a (;0;) (shared(array (mut (ref null (shared any)))))) + (type (;1;) (func (param (ref null $a) i32 (ref null (shared any))) (result (ref null (shared any))))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z (ref null (shared any))) (result (ref null (shared any))) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.xchg seq_cst $a + ) + (export "array-atomic-rmw.xchg-anyref-seq_cst" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/56.print b/tests/snapshots/local/shared-everything-threads/array.wast/56.print new file mode 100644 index 0000000000..2a03171eae --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/56.print @@ -0,0 +1,11 @@ +(module + (type $a (;0;) (shared(array (mut i32)))) + (type (;1;) (func (param (ref null $a) i32 i32) (result i32))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i32) (result i32) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.xchg acq_rel $a + ) + (export "array-atomic-rmw.xchg-i32-acq_rel" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/57.print b/tests/snapshots/local/shared-everything-threads/array.wast/57.print new file mode 100644 index 0000000000..618521206b --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/57.print @@ -0,0 +1,11 @@ +(module + (type $a (;0;) (shared(array (mut i64)))) + (type (;1;) (func (param (ref null $a) i32 i64) (result i64))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i64) (result i64) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.xchg acq_rel $a + ) + (export "array-atomic-rmw.xchg-i64-acq_rel" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/58.print b/tests/snapshots/local/shared-everything-threads/array.wast/58.print new file mode 100644 index 0000000000..2670aba692 --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/58.print @@ -0,0 +1,11 @@ +(module + (type $a (;0;) (shared(array (mut (ref null (shared any)))))) + (type (;1;) (func (param (ref null $a) i32 (ref null (shared any))) (result (ref null (shared any))))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z (ref null (shared any))) (result (ref null (shared any))) + local.get $x + local.get $y + local.get $z + array.atomic.rmw.xchg acq_rel $a + ) + (export "array-atomic-rmw.xchg-anyref-acq_rel" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/59.print b/tests/snapshots/local/shared-everything-threads/array.wast/59.print new file mode 100644 index 0000000000..9b4ed0eced --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/59.print @@ -0,0 +1,12 @@ +(module + (type $a (;0;) (shared(array (mut i32)))) + (type (;1;) (func (param (ref null $a) i32 i32 i32) (result i32))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i32) (param $A i32) (result i32) + local.get $x + local.get $y + local.get $z + local.get $A + array.atomic.rmw.cmpxchg seq_cst $a + ) + (export "array-atomic-rmw.cmpxchg-i32-seq_cst" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/60.print b/tests/snapshots/local/shared-everything-threads/array.wast/60.print new file mode 100644 index 0000000000..f485f7a7e3 --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/60.print @@ -0,0 +1,12 @@ +(module + (type $a (;0;) (shared(array (mut i64)))) + (type (;1;) (func (param (ref null $a) i32 i64 i64) (result i64))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i64) (param $A i64) (result i64) + local.get $x + local.get $y + local.get $z + local.get $A + array.atomic.rmw.cmpxchg seq_cst $a + ) + (export "array-atomic-rmw.cmpxchg-i64-seq_cst" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/61.print b/tests/snapshots/local/shared-everything-threads/array.wast/61.print new file mode 100644 index 0000000000..c9be7ed8c2 --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/61.print @@ -0,0 +1,12 @@ +(module + (type $a (;0;) (shared(array (mut (ref null (shared eq)))))) + (type (;1;) (func (param (ref null $a) i32 (ref null (shared eq)) (ref null (shared eq))) (result (ref null (shared eq))))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z (ref null (shared eq))) (param $A (ref null (shared eq))) (result (ref null (shared eq))) + local.get $x + local.get $y + local.get $z + local.get $A + array.atomic.rmw.cmpxchg seq_cst $a + ) + (export "array-atomic-rmw.cmpxchg-eqref-seq_cst" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/62.print b/tests/snapshots/local/shared-everything-threads/array.wast/62.print new file mode 100644 index 0000000000..15e7ca30d3 --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/62.print @@ -0,0 +1,12 @@ +(module + (type $a (;0;) (shared(array (mut i32)))) + (type (;1;) (func (param (ref null $a) i32 i32 i32) (result i32))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i32) (param $A i32) (result i32) + local.get $x + local.get $y + local.get $z + local.get $A + array.atomic.rmw.cmpxchg acq_rel $a + ) + (export "array-atomic-rmw.cmpxchg-i32-acq_rel" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/63.print b/tests/snapshots/local/shared-everything-threads/array.wast/63.print new file mode 100644 index 0000000000..7bce20ede1 --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/63.print @@ -0,0 +1,12 @@ +(module + (type $a (;0;) (shared(array (mut i64)))) + (type (;1;) (func (param (ref null $a) i32 i64 i64) (result i64))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z i64) (param $A i64) (result i64) + local.get $x + local.get $y + local.get $z + local.get $A + array.atomic.rmw.cmpxchg acq_rel $a + ) + (export "array-atomic-rmw.cmpxchg-i64-acq_rel" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/64.print b/tests/snapshots/local/shared-everything-threads/array.wast/64.print new file mode 100644 index 0000000000..d61185983f --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/64.print @@ -0,0 +1,12 @@ +(module + (type $a (;0;) (shared(array (mut (ref null (shared eq)))))) + (type (;1;) (func (param (ref null $a) i32 (ref null (shared eq)) (ref null (shared eq))) (result (ref null (shared eq))))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (param $z (ref null (shared eq))) (param $A (ref null (shared eq))) (result (ref null (shared eq))) + local.get $x + local.get $y + local.get $z + local.get $A + array.atomic.rmw.cmpxchg acq_rel $a + ) + (export "array-atomic-rmw.cmpxchg-eqref-acq_rel" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/array.wast/9.print b/tests/snapshots/local/shared-everything-threads/array.wast/9.print new file mode 100644 index 0000000000..f3d308bd71 --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/array.wast/9.print @@ -0,0 +1,10 @@ +(module + (type $a (;0;) (shared(array (mut i32)))) + (type (;1;) (func (param (ref null $a) i32) (result i32))) + (func (;0;) (type 1) (param $x (ref null $a)) (param $y i32) (result i32) + local.get $x + local.get $y + array.atomic.get seq_cst $a + ) + (export "array-atomic-get-i32-seq_cst" (func 0)) +) diff --git a/tests/snapshots/local/shared-everything-threads/struct.wast.json b/tests/snapshots/local/shared-everything-threads/struct.wast.json index 97900a0eba..106b265ca1 100644 --- a/tests/snapshots/local/shared-everything-threads/struct.wast.json +++ b/tests/snapshots/local/shared-everything-threads/struct.wast.json @@ -55,6 +55,102 @@ "type": "module", "line": 72, "filename": "struct.8.wasm" + }, + { + "type": "module", + "line": 95, + "filename": "struct.9.wasm" + }, + { + "type": "assert_invalid", + "line": 322, + "filename": "struct.10.wasm", + "text": "non-packed storage type", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 331, + "filename": "struct.11.wasm", + "text": "non-packed storage types", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 340, + "filename": "struct.12.wasm", + "text": "non-packed storage types", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 349, + "filename": "struct.13.wasm", + "text": "non-packed storage types", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 358, + "filename": "struct.14.wasm", + "text": "non-packed storage types", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 367, + "filename": "struct.15.wasm", + "text": "invalid type", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 377, + "filename": "struct.16.wasm", + "text": "invalid type", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 387, + "filename": "struct.17.wasm", + "text": "invalid type", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 397, + "filename": "struct.18.wasm", + "text": "invalid type", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 407, + "filename": "struct.19.wasm", + "text": "invalid type", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 417, + "filename": "struct.20.wasm", + "text": "invalid type", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 427, + "filename": "struct.21.wasm", + "text": "invalid type", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 438, + "filename": "struct.22.wasm", + "text": "invalid type", + "module_type": "binary" } ] } \ No newline at end of file diff --git a/tests/snapshots/local/shared-everything-threads/struct.wast/9.print b/tests/snapshots/local/shared-everything-threads/struct.wast/9.print new file mode 100644 index 0000000000..7987e5e408 --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/struct.wast/9.print @@ -0,0 +1,343 @@ +(module + (type $s (;0;) (shared(struct (field $i8 (mut i8)) (field $i16 (mut i16)) (field $i32 (mut i32)) (field $i64 (mut i64)) (field $anyref (mut (ref null (shared any)))) (field $eqref (mut (ref null (shared eq))))))) + (type (;1;) (func (param (ref null $s)) (result i32))) + (type (;2;) (func (param (ref null $s)) (result i64))) + (type (;3;) (func (param (ref null $s)) (result (ref null (shared any))))) + (type (;4;) (func (param (ref null $s) i32))) + (type (;5;) (func (param (ref null $s) i64))) + (type (;6;) (func (param (ref null $s) (ref null (shared any))))) + (type (;7;) (func (param (ref null $s) i32) (result i32))) + (type (;8;) (func (param (ref null $s) i64) (result i64))) + (type (;9;) (func (param (ref null $s) (ref null (shared any))) (result (ref null (shared any))))) + (type (;10;) (func (param (ref null $s) i32 i32) (result i32))) + (type (;11;) (func (param (ref null $s) i64 i64) (result i64))) + (type (;12;) (func (param (ref null $s) (ref null (shared eq)) (ref null (shared eq))) (result (ref null (shared eq))))) + (func (;0;) (type 1) (param $x (ref null $s)) (result i32) + local.get $x + struct.atomic.get seq_cst $s $i32 + ) + (func (;1;) (type 2) (param $x (ref null $s)) (result i64) + local.get $x + struct.atomic.get seq_cst $s $i64 + ) + (func (;2;) (type 3) (param $x (ref null $s)) (result (ref null (shared any))) + local.get $x + struct.atomic.get seq_cst $s $anyref + ) + (func (;3;) (type 1) (param $x (ref null $s)) (result i32) + local.get $x + struct.atomic.get acq_rel $s $i32 + ) + (func (;4;) (type 2) (param $x (ref null $s)) (result i64) + local.get $x + struct.atomic.get acq_rel $s $i64 + ) + (func (;5;) (type 3) (param $x (ref null $s)) (result (ref null (shared any))) + local.get $x + struct.atomic.get acq_rel $s $anyref + ) + (func (;6;) (type 1) (param $x (ref null $s)) (result i32) + local.get $x + struct.atomic.get_s seq_cst $s $i8 + ) + (func (;7;) (type 1) (param $x (ref null $s)) (result i32) + local.get $x + struct.atomic.get_s seq_cst $s $i16 + ) + (func (;8;) (type 1) (param $x (ref null $s)) (result i32) + local.get $x + struct.atomic.get_s acq_rel $s $i8 + ) + (func (;9;) (type 1) (param $x (ref null $s)) (result i32) + local.get $x + struct.atomic.get_s acq_rel $s $i16 + ) + (func (;10;) (type 1) (param $x (ref null $s)) (result i32) + local.get $x + struct.atomic.get_u seq_cst $s $i8 + ) + (func (;11;) (type 1) (param $x (ref null $s)) (result i32) + local.get $x + struct.atomic.get_u seq_cst $s $i16 + ) + (func (;12;) (type 1) (param $x (ref null $s)) (result i32) + local.get $x + struct.atomic.get_u acq_rel $s $i8 + ) + (func (;13;) (type 1) (param $x (ref null $s)) (result i32) + local.get $x + struct.atomic.get_u acq_rel $s $i16 + ) + (func (;14;) (type 4) (param $x (ref null $s)) (param $y i32) + local.get $x + local.get $y + struct.atomic.set seq_cst $s $i8 + ) + (func (;15;) (type 4) (param $x (ref null $s)) (param $y i32) + local.get $x + local.get $y + struct.atomic.set seq_cst $s $i16 + ) + (func (;16;) (type 4) (param $x (ref null $s)) (param $y i32) + local.get $x + local.get $y + struct.atomic.set seq_cst $s $i32 + ) + (func (;17;) (type 5) (param $x (ref null $s)) (param $y i64) + local.get $x + local.get $y + struct.atomic.set seq_cst $s $i64 + ) + (func (;18;) (type 6) (param $x (ref null $s)) (param $y (ref null (shared any))) + local.get $x + local.get $y + struct.atomic.set seq_cst $s $anyref + ) + (func (;19;) (type 4) (param $x (ref null $s)) (param $y i32) + local.get $x + local.get $y + struct.atomic.set acq_rel $s $i8 + ) + (func (;20;) (type 4) (param $x (ref null $s)) (param $y i32) + local.get $x + local.get $y + struct.atomic.set acq_rel $s $i16 + ) + (func (;21;) (type 4) (param $x (ref null $s)) (param $y i32) + local.get $x + local.get $y + struct.atomic.set acq_rel $s $i32 + ) + (func (;22;) (type 5) (param $x (ref null $s)) (param $y i64) + local.get $x + local.get $y + struct.atomic.set acq_rel $s $i64 + ) + (func (;23;) (type 6) (param $x (ref null $s)) (param $y (ref null (shared any))) + local.get $x + local.get $y + struct.atomic.set acq_rel $s $anyref + ) + (func (;24;) (type 7) (param $x (ref null $s)) (param $y i32) (result i32) + local.get $x + local.get $y + struct.atomic.rmw.add seq_cst $s $i32 + ) + (func (;25;) (type 8) (param $x (ref null $s)) (param $y i64) (result i64) + local.get $x + local.get $y + struct.atomic.rmw.add seq_cst $s $i64 + ) + (func (;26;) (type 7) (param $x (ref null $s)) (param $y i32) (result i32) + local.get $x + local.get $y + struct.atomic.rmw.add acq_rel $s $i32 + ) + (func (;27;) (type 8) (param $x (ref null $s)) (param $y i64) (result i64) + local.get $x + local.get $y + struct.atomic.rmw.add acq_rel $s $i64 + ) + (func (;28;) (type 7) (param $x (ref null $s)) (param $y i32) (result i32) + local.get $x + local.get $y + struct.atomic.rmw.sub seq_cst $s $i32 + ) + (func (;29;) (type 8) (param $x (ref null $s)) (param $y i64) (result i64) + local.get $x + local.get $y + struct.atomic.rmw.sub seq_cst $s $i64 + ) + (func (;30;) (type 7) (param $x (ref null $s)) (param $y i32) (result i32) + local.get $x + local.get $y + struct.atomic.rmw.sub acq_rel $s $i32 + ) + (func (;31;) (type 8) (param $x (ref null $s)) (param $y i64) (result i64) + local.get $x + local.get $y + struct.atomic.rmw.sub acq_rel $s $i64 + ) + (func (;32;) (type 7) (param $x (ref null $s)) (param $y i32) (result i32) + local.get $x + local.get $y + struct.atomic.rmw.and seq_cst $s $i32 + ) + (func (;33;) (type 8) (param $x (ref null $s)) (param $y i64) (result i64) + local.get $x + local.get $y + struct.atomic.rmw.and seq_cst $s $i64 + ) + (func (;34;) (type 7) (param $x (ref null $s)) (param $y i32) (result i32) + local.get $x + local.get $y + struct.atomic.rmw.and acq_rel $s $i32 + ) + (func (;35;) (type 8) (param $x (ref null $s)) (param $y i64) (result i64) + local.get $x + local.get $y + struct.atomic.rmw.and acq_rel $s $i64 + ) + (func (;36;) (type 7) (param $x (ref null $s)) (param $y i32) (result i32) + local.get $x + local.get $y + struct.atomic.rmw.or seq_cst $s $i32 + ) + (func (;37;) (type 8) (param $x (ref null $s)) (param $y i64) (result i64) + local.get $x + local.get $y + struct.atomic.rmw.or seq_cst $s $i64 + ) + (func (;38;) (type 7) (param $x (ref null $s)) (param $y i32) (result i32) + local.get $x + local.get $y + struct.atomic.rmw.or acq_rel $s $i32 + ) + (func (;39;) (type 8) (param $x (ref null $s)) (param $y i64) (result i64) + local.get $x + local.get $y + struct.atomic.rmw.or acq_rel $s $i64 + ) + (func (;40;) (type 7) (param $x (ref null $s)) (param $y i32) (result i32) + local.get $x + local.get $y + struct.atomic.rmw.xor seq_cst $s $i32 + ) + (func (;41;) (type 8) (param $x (ref null $s)) (param $y i64) (result i64) + local.get $x + local.get $y + struct.atomic.rmw.xor seq_cst $s $i64 + ) + (func (;42;) (type 7) (param $x (ref null $s)) (param $y i32) (result i32) + local.get $x + local.get $y + struct.atomic.rmw.xor acq_rel $s $i32 + ) + (func (;43;) (type 8) (param $x (ref null $s)) (param $y i64) (result i64) + local.get $x + local.get $y + struct.atomic.rmw.xor acq_rel $s $i64 + ) + (func (;44;) (type 7) (param $x (ref null $s)) (param $y i32) (result i32) + local.get $x + local.get $y + struct.atomic.rmw.xchg seq_cst $s $i32 + ) + (func (;45;) (type 8) (param $x (ref null $s)) (param $y i64) (result i64) + local.get $x + local.get $y + struct.atomic.rmw.xchg seq_cst $s $i64 + ) + (func (;46;) (type 9) (param $x (ref null $s)) (param $y (ref null (shared any))) (result (ref null (shared any))) + local.get $x + local.get $y + struct.atomic.rmw.xchg seq_cst $s $anyref + ) + (func (;47;) (type 7) (param $x (ref null $s)) (param $y i32) (result i32) + local.get $x + local.get $y + struct.atomic.rmw.xchg acq_rel $s $i32 + ) + (func (;48;) (type 8) (param $x (ref null $s)) (param $y i64) (result i64) + local.get $x + local.get $y + struct.atomic.rmw.xchg acq_rel $s $i64 + ) + (func (;49;) (type 9) (param $x (ref null $s)) (param $y (ref null (shared any))) (result (ref null (shared any))) + local.get $x + local.get $y + struct.atomic.rmw.xchg acq_rel $s $anyref + ) + (func (;50;) (type 10) (param $x (ref null $s)) (param $y i32) (param $z i32) (result i32) + local.get $x + local.get $y + local.get $z + struct.atomic.rmw.cmpxchg seq_cst $s $i32 + ) + (func (;51;) (type 11) (param $x (ref null $s)) (param $y i64) (param $z i64) (result i64) + local.get $x + local.get $y + local.get $z + struct.atomic.rmw.cmpxchg seq_cst $s $i64 + ) + (func (;52;) (type 12) (param $x (ref null $s)) (param $y (ref null (shared eq))) (param $z (ref null (shared eq))) (result (ref null (shared eq))) + local.get $x + local.get $y + local.get $z + struct.atomic.rmw.cmpxchg seq_cst $s $eqref + ) + (func (;53;) (type 10) (param $x (ref null $s)) (param $y i32) (param $z i32) (result i32) + local.get $x + local.get $y + local.get $z + struct.atomic.rmw.cmpxchg acq_rel $s $i32 + ) + (func (;54;) (type 11) (param $x (ref null $s)) (param $y i64) (param $z i64) (result i64) + local.get $x + local.get $y + local.get $z + struct.atomic.rmw.cmpxchg acq_rel $s $i64 + ) + (func (;55;) (type 12) (param $x (ref null $s)) (param $y (ref null (shared eq))) (param $z (ref null (shared eq))) (result (ref null (shared eq))) + local.get $x + local.get $y + local.get $z + struct.atomic.rmw.cmpxchg acq_rel $s $eqref + ) + (export "struct-atomic-get-i32-seq_cst" (func 0)) + (export "struct-atomic-get-i64-seq_cst" (func 1)) + (export "struct-atomic-get-anyref-seq_cst" (func 2)) + (export "struct-atomic-get-i32-acq_rel" (func 3)) + (export "struct-atomic-get-i64-acq_rel" (func 4)) + (export "struct-atomic-get-anyref-acq_rel" (func 5)) + (export "struct-atomic-get_s-i8-seq_cst" (func 6)) + (export "struct-atomic-get_s-i16-seq_cst" (func 7)) + (export "struct-atomic-get_s-i8-acq_rel" (func 8)) + (export "struct-atomic-get_s-i16-acq_rel" (func 9)) + (export "struct-atomic-get_u-i8-seq_cst" (func 10)) + (export "struct-atomic-get_u-i16-seq_cst" (func 11)) + (export "struct-atomic-get_u-i8-acq_rel" (func 12)) + (export "struct-atomic-get_u-i16-acq_rel" (func 13)) + (export "struct-atomic-set-i8-seq_cst" (func 14)) + (export "struct-atomic-set-i16-seq_cst" (func 15)) + (export "struct-atomic-set-i32-seq_cst" (func 16)) + (export "struct-atomic-set-i64-seq_cst" (func 17)) + (export "struct-atomic-set-anyref-seq_cst" (func 18)) + (export "struct-atomic-set-i8-acq_rel" (func 19)) + (export "struct-atomic-set-i16-acq_rel" (func 20)) + (export "struct-atomic-set-i32-acq_rel" (func 21)) + (export "struct-atomic-set-i64-acq_rel" (func 22)) + (export "struct-atomic-set-anyref-acq_rel" (func 23)) + (export "struct-atomic-rmw.add-i32-seq_cst" (func 24)) + (export "struct-atomic-rmw.add-i64-seq_cst" (func 25)) + (export "struct-atomic-rmw.add-i32-acq_rel" (func 26)) + (export "struct-atomic-rmw.add-i64-acq_rel" (func 27)) + (export "struct-atomic-rmw.sub-i32-seq_cst" (func 28)) + (export "struct-atomic-rmw.sub-i64-seq_cst" (func 29)) + (export "struct-atomic-rmw.sub-i32-acq_rel" (func 30)) + (export "struct-atomic-rmw.sub-i64-acq_rel" (func 31)) + (export "struct-atomic-rmw.and-i32-seq_cst" (func 32)) + (export "struct-atomic-rmw.and-i64-seq_cst" (func 33)) + (export "struct-atomic-rmw.and-i32-acq_rel" (func 34)) + (export "struct-atomic-rmw.and-i64-acq_rel" (func 35)) + (export "struct-atomic-rmw.or-i32-seq_cst" (func 36)) + (export "struct-atomic-rmw.or-i64-seq_cst" (func 37)) + (export "struct-atomic-rmw.or-i32-acq_rel" (func 38)) + (export "struct-atomic-rmw.or-i64-acq_rel" (func 39)) + (export "struct-atomic-rmw.xor-i32-seq_cst" (func 40)) + (export "struct-atomic-rmw.xor-i64-seq_cst" (func 41)) + (export "struct-atomic-rmw.xor-i32-acq_rel" (func 42)) + (export "struct-atomic-rmw.xor-i64-acq_rel" (func 43)) + (export "struct-atomic-rmw.xchg-i32-seq_cst" (func 44)) + (export "struct-atomic-rmw.xchg-i64-seq_cst" (func 45)) + (export "struct-atomic-rmw.xchg-anyref-seq_cst" (func 46)) + (export "struct-atomic-rmw.xchg-i32-acq_rel" (func 47)) + (export "struct-atomic-rmw.xchg-i64-acq_rel" (func 48)) + (export "struct-atomic-rmw.xchg-anyref-acq_rel" (func 49)) + (export "struct-atomic-rmw.cmpxchg-i32-seq_cst" (func 50)) + (export "struct-atomic-rmw.cmpxchg-i64-seq_cst" (func 51)) + (export "struct-atomic-rmw.cmpxchg-eqref-seq_cst" (func 52)) + (export "struct-atomic-rmw.cmpxchg-i32-acq_rel" (func 53)) + (export "struct-atomic-rmw.cmpxchg-i64-acq_rel" (func 54)) + (export "struct-atomic-rmw.cmpxchg-eqref-acq_rel" (func 55)) +) diff --git a/tests/snapshots/local/shared-everything-threads/table.wast.json b/tests/snapshots/local/shared-everything-threads/table.wast.json new file mode 100644 index 0000000000..13a852f325 --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/table.wast.json @@ -0,0 +1,67 @@ +{ + "source_filename": "tests/local/shared-everything-threads/table.wast", + "commands": [ + { + "type": "module", + "line": 3, + "filename": "table.0.wasm" + }, + { + "type": "module", + "line": 17, + "filename": "table.1.wasm" + }, + { + "type": "assert_malformed", + "line": 22, + "filename": "table.2.wat", + "text": "unexpected token", + "module_type": "text" + }, + { + "type": "assert_malformed", + "line": 26, + "filename": "table.3.wat", + "text": "unexpected token", + "module_type": "text" + }, + { + "type": "assert_malformed", + "line": 32, + "filename": "table.4.wat", + "text": "unexpected token", + "module_type": "text" + }, + { + "type": "assert_invalid", + "line": 36, + "filename": "table.5.wasm", + "text": "shared tables must have a shared element type", + "module_type": "binary" + }, + { + "type": "assert_invalid", + "line": 40, + "filename": "table.6.wasm", + "text": "shared tables must have a shared element type", + "module_type": "binary" + }, + { + "type": "module", + "line": 46, + "filename": "table.7.wasm" + }, + { + "type": "module", + "line": 115, + "filename": "table.8.wasm" + }, + { + "type": "assert_invalid", + "line": 167, + "filename": "table.9.wasm", + "text": "invalid type", + "module_type": "binary" + } + ] +} \ No newline at end of file diff --git a/tests/snapshots/local/shared-everything-threads/table.wast/0.print b/tests/snapshots/local/shared-everything-threads/table.wast/0.print new file mode 100644 index 0000000000..80ca77635d --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/table.wast/0.print @@ -0,0 +1,8 @@ +(module + (import "spectest" "table_ref" (table (;0;) shared 1 (ref null (shared func)))) + (import "spectest" "table_ref_with_max" (table (;1;) shared 1 1 (ref null (shared func)))) + (table (;2;) shared 1 (ref null (shared func))) + (table (;3;) shared 1 1 (ref null (shared func))) + (table (;4;) shared 1 1 (ref null (shared func))) + (elem (;0;) (table 4) (i32.const 0) (ref null (shared func)) (ref.null (shared func))) +) diff --git a/tests/snapshots/local/shared-everything-threads/table.wast/1.print b/tests/snapshots/local/shared-everything-threads/table.wast/1.print new file mode 100644 index 0000000000..56e5cf89be --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/table.wast/1.print @@ -0,0 +1,3 @@ +(module + (import "spectest" "table_ref" (table (;0;) 1 (ref null (shared func)))) +) diff --git a/tests/snapshots/local/shared-everything-threads/table.wast/7.print b/tests/snapshots/local/shared-everything-threads/table.wast/7.print new file mode 100644 index 0000000000..033089a8b9 --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/table.wast/7.print @@ -0,0 +1,104 @@ +(module + (type (;0;) (func (param i32) (result (ref null (shared eq))))) + (type (;1;) (func (param i32 (ref null (shared eq))))) + (type (;2;) (func (param i32 (ref null (shared eq))) (result (ref null (shared eq))))) + (type (;3;) (func (param i32 (ref null (shared eq)) (ref null (shared eq))) (result (ref null (shared eq))))) + (import "spectest" "table_eq" (table $a (;0;) shared 1 (ref null (shared eq)))) + (func (;0;) (type 0) (param $x i32) (result (ref null (shared eq))) + local.get $x + table.atomic.get seq_cst $a + ) + (func (;1;) (type 0) (param $x i32) (result (ref null (shared eq))) + local.get $x + table.atomic.get seq_cst $b + ) + (func (;2;) (type 0) (param $x i32) (result (ref null (shared eq))) + local.get $x + table.atomic.get acq_rel $a + ) + (func (;3;) (type 0) (param $x i32) (result (ref null (shared eq))) + local.get $x + table.atomic.get acq_rel $b + ) + (func (;4;) (type 1) (param $x i32) (param $y (ref null (shared eq))) + local.get $x + local.get $y + table.atomic.set seq_cst $a + ) + (func (;5;) (type 1) (param $x i32) (param $y (ref null (shared eq))) + local.get $x + local.get $y + table.atomic.set seq_cst $b + ) + (func (;6;) (type 1) (param $x i32) (param $y (ref null (shared eq))) + local.get $x + local.get $y + table.atomic.set acq_rel $a + ) + (func (;7;) (type 1) (param $x i32) (param $y (ref null (shared eq))) + local.get $x + local.get $y + table.atomic.set acq_rel $b + ) + (func (;8;) (type 2) (param $x i32) (param $y (ref null (shared eq))) (result (ref null (shared eq))) + local.get $x + local.get $y + table.atomic.rmw.xchg seq_cst $a + ) + (func (;9;) (type 2) (param $x i32) (param $y (ref null (shared eq))) (result (ref null (shared eq))) + local.get $x + local.get $y + table.atomic.rmw.xchg seq_cst $b + ) + (func (;10;) (type 2) (param $x i32) (param $y (ref null (shared eq))) (result (ref null (shared eq))) + local.get $x + local.get $y + table.atomic.rmw.xchg acq_rel $a + ) + (func (;11;) (type 2) (param $x i32) (param $y (ref null (shared eq))) (result (ref null (shared eq))) + local.get $x + local.get $y + table.atomic.rmw.xchg acq_rel $b + ) + (func (;12;) (type 3) (param $x i32) (param $y (ref null (shared eq))) (param $z (ref null (shared eq))) (result (ref null (shared eq))) + local.get $x + local.get $y + local.get $z + table.atomic.rmw.cmpxchg seq_cst $a + ) + (func (;13;) (type 3) (param $x i32) (param $y (ref null (shared eq))) (param $z (ref null (shared eq))) (result (ref null (shared eq))) + local.get $x + local.get $y + local.get $z + table.atomic.rmw.cmpxchg seq_cst $b + ) + (func (;14;) (type 3) (param $x i32) (param $y (ref null (shared eq))) (param $z (ref null (shared eq))) (result (ref null (shared eq))) + local.get $x + local.get $y + local.get $z + table.atomic.rmw.cmpxchg acq_rel $a + ) + (func (;15;) (type 3) (param $x i32) (param $y (ref null (shared eq))) (param $z (ref null (shared eq))) (result (ref null (shared eq))) + local.get $x + local.get $y + local.get $z + table.atomic.rmw.cmpxchg acq_rel $b + ) + (table $b (;1;) shared 1 (ref null (shared eq))) + (export "table-atomic-get-eq-seq_cst-$a" (func 0)) + (export "table-atomic-get-eq-seq_cst-$b" (func 1)) + (export "table-atomic-get-eq-acq_rel-$a" (func 2)) + (export "table-atomic-get-eq-acq_rel-$b" (func 3)) + (export "table-atomic-set-eq-seq_cst-$a" (func 4)) + (export "table-atomic-set-eq-seq_cst-$b" (func 5)) + (export "table-atomic-set-eq-acq_rel-$a" (func 6)) + (export "table-atomic-set-eq-acq_rel-$b" (func 7)) + (export "table-atomic-rmw.xchg-eq-seq_cst-$a" (func 8)) + (export "table-atomic-rmw.xchg-eq-seq_cst-$b" (func 9)) + (export "table-atomic-rmw.xchg-eq-acq_rel-$a" (func 10)) + (export "table-atomic-rmw.xchg-eq-acq_rel-$b" (func 11)) + (export "table-atomic-rmw.cmpxchg-eq-seq_cst-$a" (func 12)) + (export "table-atomic-rmw.cmpxchg-eq-seq_cst-$b" (func 13)) + (export "table-atomic-rmw.cmpxchg-eq-acq_rel-$a" (func 14)) + (export "table-atomic-rmw.cmpxchg-eq-acq_rel-$b" (func 15)) +) diff --git a/tests/snapshots/local/shared-everything-threads/table.wast/8.print b/tests/snapshots/local/shared-everything-threads/table.wast/8.print new file mode 100644 index 0000000000..e921f4e848 --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/table.wast/8.print @@ -0,0 +1,75 @@ +(module + (type (;0;) (func (param i32) (result (ref null (shared any))))) + (type (;1;) (func (param i32 (ref null (shared any))))) + (type (;2;) (func (param i32 (ref null (shared any))) (result (ref null (shared any))))) + (import "spectest" "table_any" (table $a (;0;) shared 1 (ref null (shared any)))) + (func (;0;) (type 0) (param $x i32) (result (ref null (shared any))) + local.get $x + table.atomic.get seq_cst $a + ) + (func (;1;) (type 0) (param $x i32) (result (ref null (shared any))) + local.get $x + table.atomic.get seq_cst $b + ) + (func (;2;) (type 0) (param $x i32) (result (ref null (shared any))) + local.get $x + table.atomic.get acq_rel $a + ) + (func (;3;) (type 0) (param $x i32) (result (ref null (shared any))) + local.get $x + table.atomic.get acq_rel $b + ) + (func (;4;) (type 1) (param $x i32) (param $y (ref null (shared any))) + local.get $x + local.get $y + table.atomic.set seq_cst $a + ) + (func (;5;) (type 1) (param $x i32) (param $y (ref null (shared any))) + local.get $x + local.get $y + table.atomic.set seq_cst $b + ) + (func (;6;) (type 1) (param $x i32) (param $y (ref null (shared any))) + local.get $x + local.get $y + table.atomic.set acq_rel $a + ) + (func (;7;) (type 1) (param $x i32) (param $y (ref null (shared any))) + local.get $x + local.get $y + table.atomic.set acq_rel $b + ) + (func (;8;) (type 2) (param $x i32) (param $y (ref null (shared any))) (result (ref null (shared any))) + local.get $x + local.get $y + table.atomic.rmw.xchg seq_cst $a + ) + (func (;9;) (type 2) (param $x i32) (param $y (ref null (shared any))) (result (ref null (shared any))) + local.get $x + local.get $y + table.atomic.rmw.xchg seq_cst $b + ) + (func (;10;) (type 2) (param $x i32) (param $y (ref null (shared any))) (result (ref null (shared any))) + local.get $x + local.get $y + table.atomic.rmw.xchg acq_rel $a + ) + (func (;11;) (type 2) (param $x i32) (param $y (ref null (shared any))) (result (ref null (shared any))) + local.get $x + local.get $y + table.atomic.rmw.xchg acq_rel $b + ) + (table $b (;1;) shared 1 (ref null (shared any))) + (export "table-atomic-get-any-seq_cst-$a" (func 0)) + (export "table-atomic-get-any-seq_cst-$b" (func 1)) + (export "table-atomic-get-any-acq_rel-$a" (func 2)) + (export "table-atomic-get-any-acq_rel-$b" (func 3)) + (export "table-atomic-set-any-seq_cst-$a" (func 4)) + (export "table-atomic-set-any-seq_cst-$b" (func 5)) + (export "table-atomic-set-any-acq_rel-$a" (func 6)) + (export "table-atomic-set-any-acq_rel-$b" (func 7)) + (export "table-atomic-rmw.xchg-any-seq_cst-$a" (func 8)) + (export "table-atomic-rmw.xchg-any-seq_cst-$b" (func 9)) + (export "table-atomic-rmw.xchg-any-acq_rel-$a" (func 10)) + (export "table-atomic-rmw.xchg-any-acq_rel-$b" (func 11)) +)