From 947c152652c57159ed39a59b9e8f0a060d741490 Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Mon, 8 Jul 2024 11:24:53 -0700 Subject: [PATCH 01/15] threads: add `shared` tables (#1649) * threads: add `shared` tables This change spreads `shared` attributes on to tables. As with #1480, this does not yet turn on fuzzing for `shared` things so the only checking is via the in-progress test suite in `tests/local/shared-everything-threads`. Implementing this raises an issue with the spec: the addition of `shared` in the text format means that inline table expressions (e.g., `(table (elem ...))`) are difficult to parse: the parser would potentially have to look past two tokens now, `shared` and `i32|i64` to see if a type appears that indicates we should be parsing an inline format. There are multiple options for what to do here; I opened an issue to figure this out at the spec level first ([#71]). [proposal]: https://github.com/WebAssembly/shared-everything-threads [#71]: https://github.com/WebAssembly/shared-everything-threads/issues/71 * Add a 'missing-features' test for `shared` tables * Add a negative test for indexed types --- crates/wasm-encoder/src/core/elements.rs | 1 + crates/wasm-encoder/src/core/tables.rs | 8 +++ crates/wasm-encoder/src/reencode.rs | 1 + crates/wasm-mutate/src/mutators/translate.rs | 1 + crates/wasm-smith/src/core.rs | 1 + crates/wasmparser/src/readers/core/tables.rs | 4 +- crates/wasmparser/src/readers/core/types.rs | 4 ++ crates/wasmparser/src/validator.rs | 1 + crates/wasmparser/src/validator/core.rs | 26 ++++++++-- crates/wasmparser/src/validator/types.rs | 24 +++++---- crates/wasmprinter/src/lib.rs | 3 ++ crates/wast/src/component/binary.rs | 1 + crates/wast/src/core/binary.rs | 3 ++ .../core/resolve/deinline_import_export.rs | 7 ++- crates/wast/src/core/table.rs | 25 +++++++--- crates/wast/src/core/types.rs | 5 +- crates/wit-component/src/encoding.rs | 1 + crates/wit-component/src/linking.rs | 2 + tests/cli/dump-llvm-object.wat.stdout | 2 +- tests/cli/dump/alias2.wat.stdout | 4 +- tests/cli/dump/module-types.wat.stdout | 2 +- tests/cli/dump/simple.wat.stdout | 2 +- tests/local/missing-features/tables.wast | 5 ++ .../shared-everything-threads/global.wast | 2 +- .../shared-everything-threads/table.wast | 43 ++++++++++++++++ tests/roundtrip.rs | 1 + .../local/missing-features/tables.wast.json | 12 +++++ .../shared-everything-threads/table.wast.json | 50 +++++++++++++++++++ .../table.wast/0.print | 8 +++ .../table.wast/1.print | 3 ++ 30 files changed, 220 insertions(+), 32 deletions(-) create mode 100644 tests/local/missing-features/tables.wast create mode 100644 tests/local/shared-everything-threads/table.wast create mode 100644 tests/snapshots/local/missing-features/tables.wast.json create mode 100644 tests/snapshots/local/shared-everything-threads/table.wast.json create mode 100644 tests/snapshots/local/shared-everything-threads/table.wast/0.print create mode 100644 tests/snapshots/local/shared-everything-threads/table.wast/1.print 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..c8fb29aa7f 100644 --- a/crates/wasm-encoder/src/reencode.rs +++ b/crates/wasm-encoder/src/reencode.rs @@ -1154,6 +1154,7 @@ pub mod utils { minimum: table_ty.initial, maximum: table_ty.maximum, table64: table_ty.table64, + shared: table_ty.shared, }) } 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/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/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/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..47fd4b0dd0 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; } 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/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/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/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/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/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/table.wast b/tests/local/shared-everything-threads/table.wast new file mode 100644 index 0000000000..0b4eedc2ce --- /dev/null +++ b/tests/local/shared-everything-threads/table.wast @@ -0,0 +1,43 @@ +;; 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") diff --git a/tests/roundtrip.rs b/tests/roundtrip.rs index 66fdc1e49b..6f1b64c779 100644 --- a/tests/roundtrip.rs +++ b/tests/roundtrip.rs @@ -717,6 +717,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/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/table.wast.json b/tests/snapshots/local/shared-everything-threads/table.wast.json new file mode 100644 index 0000000000..8c2bc6b10f --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/table.wast.json @@ -0,0 +1,50 @@ +{ + "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" + } + ] +} \ 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)))) +) From a2635eb91772d2de1607acbe14ff92ad16f25d33 Mon Sep 17 00:00:00 2001 From: Suhas Thalanki <54014218+thesuhas@users.noreply.github.com> Date: Tue, 9 Jul 2024 10:22:17 -0400 Subject: [PATCH 02/15] added conversions for component specific enums (#1655) * added conversions for component specific enums * added component_type_index * used correct type indices --- crates/wasm-encoder/src/reencode.rs | 193 ++++++++++++++++++++++++++++ 1 file changed, 193 insertions(+) diff --git a/crates/wasm-encoder/src/reencode.rs b/crates/wasm-encoder/src/reencode.rs index c8fb29aa7f..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, @@ -1620,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) From a265ec17ab8ee9081e9390387eafda7d92107f27 Mon Sep 17 00:00:00 2001 From: Guy Bedford Date: Wed, 10 Jul 2024 16:55:50 +0200 Subject: [PATCH 03/15] feat: support basic use syntax in interfaces and worlds (#1659) * feat: support basic use syntax in interfaces and worlds * fixup --- crates/wit-encoder/src/interface.rs | 11 ++++++- crates/wit-encoder/src/lib.rs | 2 ++ crates/wit-encoder/src/use_.rs | 44 ++++++++++++++++++++++++++++ crates/wit-encoder/src/world.rs | 9 +++++- crates/wit-encoder/tests/use.rs | 45 +++++++++++++++++++++++++++++ 5 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 crates/wit-encoder/src/use_.rs create mode 100644 crates/wit-encoder/tests/use.rs diff --git a/crates/wit-encoder/src/interface.rs b/crates/wit-encoder/src/interface.rs index 5641426c62..bf0827161c 100644 --- a/crates/wit-encoder/src/interface.rs +++ b/crates/wit-encoder/src/interface.rs @@ -1,6 +1,6 @@ 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)] pub struct Interface { @@ -34,6 +34,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 } @@ -51,6 +56,7 @@ impl Interface { #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum InterfaceItem { TypeDef(TypeDef), + Use(Use), Function(StandaloneFunc), } @@ -73,6 +79,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/use_.rs b/crates/wit-encoder/src/use_.rs new file mode 100644 index 0000000000..9322c15d6b --- /dev/null +++ b/crates/wit-encoder/src/use_.rs @@ -0,0 +1,44 @@ +use std::fmt; + +use crate::{Ident, Render}; + +/// Enable the union of a world with another world +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +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/world.rs b/crates/wit-encoder/src/world.rs index 7203524bb1..5f93320924 100644 --- a/crates/wit-encoder/src/world.rs +++ b/crates/wit-encoder/src/world.rs @@ -1,6 +1,6 @@ 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)] pub struct World { @@ -55,6 +55,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 +146,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(); @@ -173,6 +177,9 @@ pub enum WorldItem { /// Include type Include(Include), + + /// Use + Use(Use), } impl WorldItem { 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); +} From 3e58f7d2f459fcf0a7857cf18a7b2b60de16bc45 Mon Sep 17 00:00:00 2001 From: Guy Bedford Date: Thu, 11 Jul 2024 16:33:04 +0200 Subject: [PATCH 04/15] fix: f32, f64 encoding for wit-encoder (#1660) * fix: f32, f64 encoding for wit-encoder * fixup tests * handle escaping at write not create --- crates/wit-encoder/src/ident.rs | 14 ++++++-------- crates/wit-encoder/tests/type_defs.rs | 3 +++ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/crates/wit-encoder/src/ident.rs b/crates/wit-encoder/src/ident.rs index 4b7116f5ef..c336173c68 100644 --- a/crates/wit-encoder/src/ident.rs +++ b/crates/wit-encoder/src/ident.rs @@ -5,12 +5,7 @@ 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 +20,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 +35,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/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", From b6b5ad593d6ffdf6f0229aeb6d5281c522f57d80 Mon Sep 17 00:00:00 2001 From: Suhas Thalanki <54014218+thesuhas@users.noreply.github.com> Date: Thu, 11 Jul 2024 15:02:55 -0400 Subject: [PATCH 05/15] added from floating point to ieee trait (#1662) * added from floating point to ieee trait * fixed with little endian conversion --- crates/wasmparser/src/readers/core/operators.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) 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()) From d4bdb5bc294caea4f851940639e63039f6431716 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 11 Jul 2024 14:04:14 -0500 Subject: [PATCH 06/15] Improve the output of `wasm-tools component wit` (#1657) * Improve the `--out-dir` flag of `component wit` * Lift files in `deps` outside of their folders to be `deps/*.wit` instead of `deps/*/main.wit` since this structure is now supported. * Handle multi-package input documents by placing each package in the main folder. * Name the main wit file after the package name. * Add some tests for these cases. * Print all WIT packages by default This commit changes the output of `wasm-tools component wit` to by default output all WIT packages using the multi-package syntax implemented in #1577. This means that a complete view of the WIT will be seen when running this command instead of just the top-level world. * Fix build of fuzzer * Sanitize output to be more platform agnostic --- crates/wit-component/src/printing.rs | 19 +++++---- crates/wit-component/tests/components.rs | 2 +- crates/wit-component/tests/interfaces.rs | 2 +- crates/wit-component/tests/merge.rs | 2 +- fuzz/src/roundtrip_wit.rs | 2 +- src/bin/wasm-tools/component.rs | 39 +++++++++---------- src/lib.rs | 17 ++++---- tests/cli.rs | 16 +++++++- ...core-wasm-wit-multiple-packages.wit.stdout | 17 ++++++-- tests/cli/print-core-wasm-wit.wit.stdout | 17 ++++++-- .../wit-directory-output-in-deps-folder.wit | 14 +++++++ ...directory-output-in-deps-folder.wit.stdout | 3 ++ tests/cli/wit-directory-output-valid.wit | 14 +++++++ .../cli/wit-directory-output-valid.wit.stdout | 16 ++++++++ tests/cli/wit-directory-output.wit | 14 +++++++ tests/cli/wit-directory-output.wit.stdout | 2 + 16 files changed, 148 insertions(+), 48 deletions(-) create mode 100644 tests/cli/wit-directory-output-in-deps-folder.wit create mode 100644 tests/cli/wit-directory-output-in-deps-folder.wit.stdout create mode 100644 tests/cli/wit-directory-output-valid.wit create mode 100644 tests/cli/wit-directory-output-valid.wit.stdout create mode 100644 tests/cli/wit-directory-output.wit create mode 100644 tests/cli/wit-directory-output.wit.stdout diff --git a/crates/wit-component/src/printing.rs b/crates/wit-component/src/printing.rs index 28406a5023..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,9 +73,8 @@ impl WitPrinter { self.output.push_str(&format!("@{version}")); } - if has_multiple_packages { - self.output.push_str("{"); - self.output.indent += 1 + if print_package_in_curlies { + self.output.push_str(" {\n"); } else { self.print_semicolon(); self.output.push_str("\n\n"); @@ -96,9 +100,8 @@ impl WitPrinter { writeln!(&mut self.output, "}}")?; } - if has_multiple_packages { - self.output.push_str("}"); - self.output.indent -= 1 + 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 87c7ac2d4f..55a4cadd88 100644 --- a/crates/wit-component/tests/interfaces.rs +++ b/crates/wit-component/tests/interfaces.rs @@ -96,7 +96,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/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/fuzz/src/roundtrip_wit.rs b/fuzz/src/roundtrip_wit.rs index b15cd8c415..5cc6678265 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/bin/wasm-tools/component.rs b/src/bin/wasm-tools/component.rs index d546f82883..1b15b2f5a4 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)?; @@ -618,7 +616,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); @@ -641,28 +638,31 @@ 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 stem = if packages_with_same_name.len() == 1 { + pkg.name.name.clone() + } else { + let packages_with_same_namespace = + packages_with_same_name[&pkg.name.namespace]; + 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()); @@ -672,8 +672,7 @@ impl WitOpts { self.output.output( &self.general, Output::Wit { - resolve: &resolve, - ids: &main, + wit: &decoded, printer, }, )?; 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/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/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 From 3895cb78da9b0cade910bb598ac427938e890dcb Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 11 Jul 2024 14:20:33 -0500 Subject: [PATCH 07/15] Release wasm-tools 1.213.0 (#1663) [automatically-tag-and-release-this-commit] Co-authored-by: Auto Release Process --- Cargo.lock | 114 ++++++++++++++++++++--------------------- Cargo.toml | 32 ++++++------ crates/wast/Cargo.toml | 2 +- crates/wat/Cargo.toml | 2 +- 4 files changed, 75 insertions(+), 75 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7fa6f3e0f7..2d39c9f598 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", ] @@ -1564,7 +1564,7 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-compose" -version = "0.212.0" +version = "0.213.0" dependencies = [ "anyhow", "glob", @@ -1578,9 +1578,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 +1596,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 +1615,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 +1631,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 +1650,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 +1666,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,15 +1686,15 @@ 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", @@ -1718,18 +1718,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 +1741,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 +1757,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 +1797,7 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.212.0" +version = "0.213.0" dependencies = [ "ahash", "anyhow", @@ -1811,7 +1811,7 @@ dependencies = [ "rayon", "semver", "serde", - "wasm-encoder 0.212.0", + "wasm-encoder 0.213.0", "wast", "wat", ] @@ -1828,14 +1828,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 +2034,7 @@ dependencies = [ [[package]] name = "wast" -version = "212.0.0" +version = "213.0.0" dependencies = [ "anyhow", "bumpalo", @@ -2044,14 +2044,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 +2188,7 @@ dependencies = [ [[package]] name = "wit-component" -version = "0.212.0" +version = "0.213.0" dependencies = [ "anyhow", "bitflags", @@ -2201,19 +2201,19 @@ 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", @@ -2240,7 +2240,7 @@ dependencies = [ [[package]] name = "wit-parser" -version = "0.212.0" +version = "0.213.0" dependencies = [ "anyhow", "env_logger", @@ -2254,9 +2254,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 +2267,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 +2281,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..1ac79b1080 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 } 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/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" From 021389c149dc7fa0c0bac97c0bd84ffe4986d889 Mon Sep 17 00:00:00 2001 From: Damian <11998334+trzeciak@users.noreply.github.com> Date: Fri, 12 Jul 2024 16:18:12 +0200 Subject: [PATCH 08/15] Increase MAX_WASM_STRING_SIZE slightly (#1650) * Increase MAX_WASM_STRING_SIZE slightly * Revert "Increase MAX_WASM_STRING_SIZE slightly" This reverts commit 2f369476b94878b44f6102d431cc904c500ac572. * Reads a string of unlimited length during parse custom name section * Reads a string of unlimited length during parse custom name section --- crates/wasmparser/src/binary_reader.rs | 19 +++++++++++++++---- crates/wasmparser/src/readers/core/names.rs | 2 +- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/crates/wasmparser/src/binary_reader.rs b/crates/wasmparser/src/binary_reader.rs index 4df0029072..7f77662dcc 100644 --- a/crates/wasmparser/src/binary_reader.rs +++ b/crates/wasmparser/src/binary_reader.rs @@ -688,6 +688,14 @@ 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 @@ -701,10 +709,13 @@ 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. + 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] diff --git a/crates/wasmparser/src/readers/core/names.rs b/crates/wasmparser/src/readers/core/names.rs index 986e89506c..ef192acb91 100644 --- a/crates/wasmparser/src/readers/core/names.rs +++ b/crates/wasmparser/src/readers/core/names.rs @@ -33,7 +33,7 @@ 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()?; + let name = reader.read_unlimited_string()?; Ok(Naming { index, name }) } } From a63834a05df2cf9e448e4fc05379ccce45130984 Mon Sep 17 00:00:00 2001 From: Karthik Ganeshram Date: Fri, 12 Jul 2024 17:02:11 +0200 Subject: [PATCH 09/15] Handle multiple versions during `wasm-tools component wit` (#1665) * Handle multiple versions during `wasm-tools component wit` This commits makes sure that if a component depends on multiple versions of a package that it is handled correctly. It fixes the behavior by appending the version string in case there are multiple packages with the same name and namespaces specifically when there is only one namespace for the given package name. Signed-off-by: karthik2804 * add tests Signed-off-by: karthik2804 --------- Signed-off-by: karthik2804 --- src/bin/wasm-tools/component.rs | 13 +++++++++--- ...t-in-deps-folder-with-multiple-version.wit | 16 +++++++++++++++ ...ps-folder-with-multiple-version.wit.stdout | 20 +++++++++++++++++++ 3 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 tests/cli/wit-directory-output-in-deps-folder-with-multiple-version.wit create mode 100644 tests/cli/wit-directory-output-in-deps-folder-with-multiple-version.wit.stdout diff --git a/src/bin/wasm-tools/component.rs b/src/bin/wasm-tools/component.rs index 1b15b2f5a4..adc24f30d2 100644 --- a/src/bin/wasm-tools/component.rs +++ b/src/bin/wasm-tools/component.rs @@ -648,11 +648,18 @@ impl WitOpts { 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 { - pkg.name.name.clone() + 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 { - let packages_with_same_namespace = - packages_with_same_name[&pkg.name.namespace]; if packages_with_same_namespace == 1 { format!("{}:{}", pkg.name.namespace, pkg.name.name) } else { 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; + } +} From 00cc81c704c98028a299e651be5d65b0953b5d76 Mon Sep 17 00:00:00 2001 From: Damian <11998334+trzeciak@users.noreply.github.com> Date: Fri, 12 Jul 2024 17:26:58 +0200 Subject: [PATCH 10/15] Bring back legacy exception handling opcodes (#1661) * Bring back legacy exception handling opcodes under flag * Bring back legacy exception handling opcodes under flag (prepare place for tests) * Bring back legacy exception handling opcodes under flag (fixes) * Bring back legacy exception handling opcodes under flag (fixes) * Bring back legacy exception handling opcodes under flag (fixes) * Bring back legacy exception handling opcodes under flag (fixes) * Bring back legacy exception handling opcodes under flag (fixes) --- crates/wasmparser/src/features.rs | 7 ++ crates/wasmparser/src/lib.rs | 10 +- crates/wasmparser/src/validator/operators.rs | 108 +++++++++++++++--- src/bin/wasm-tools/validate.rs | 1 + tests/local/legacy-exceptions.wat | 17 +++ tests/roundtrip.rs | 8 +- .../local/legacy-exceptions.wat.print | 16 +++ 7 files changed, 145 insertions(+), 22 deletions(-) create mode 100644 tests/local/legacy-exceptions.wat create mode 100644 tests/snapshots/local/legacy-exceptions.wat.print 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..18183a4875 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 diff --git a/crates/wasmparser/src/validator/operators.rs b/crates/wasmparser/src/validator/operators.rs index e0f2c7aeef..824fe093a1 100644 --- a/crates/wasmparser/src/validator/operators.rs +++ b/crates/wasmparser/src/validator/operators.rs @@ -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> { @@ -1322,6 +1340,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 +1505,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()?; @@ -4124,6 +4128,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/src/bin/wasm-tools/validate.rs b/src/bin/wasm-tools/validate.rs index c0268ccb0d..fe402b1390 100644 --- a/src/bin/wasm-tools/validate.rs +++ b/src/bin/wasm-tools/validate.rs @@ -201,6 +201,7 @@ fn parse_features(arg: &str) -> Result { ("mutable-global", WasmFeatures::MUTABLE_GLOBAL), ("relaxed-simd", WasmFeatures::RELAXED_SIMD), ("gc", WasmFeatures::GC), + ("legacy-exceptions", WasmFeatures::LEGACY_EXCEPTIONS), ]; for part in arg.split(',').map(|s| s.trim()).filter(|s| !s.is_empty()) { diff --git a/tests/local/legacy-exceptions.wat b/tests/local/legacy-exceptions.wat new file mode 100644 index 0000000000..f923a69ae1 --- /dev/null +++ b/tests/local/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/roundtrip.rs b/tests/roundtrip.rs index 6f1b64c779..4a8e4f2b6a 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.wat" => 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" { diff --git a/tests/snapshots/local/legacy-exceptions.wat.print b/tests/snapshots/local/legacy-exceptions.wat.print new file mode 100644 index 0000000000..8ae9aa1a02 --- /dev/null +++ b/tests/snapshots/local/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)) +) From 56ee29dcb7aa671aab4174b7ae1022f0e9f4fcff Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 12 Jul 2024 10:50:23 -0500 Subject: [PATCH 11/15] Refactor handling of `--features` on the CLI (#1668) This commit uses the `bitflags::Flags` trait to refactor the parsing of the `--features` CLI flag to avoid needing to manually list out wasm features. This is something I at least always personally forget during reviews and such so it should make the CLI support more robust. --- Cargo.lock | 1 + Cargo.toml | 3 +- src/addr2line.rs | 2 +- src/bin/wasm-tools/validate.rs | 71 ++++++------------- tests/cli/validate-features.wat | 5 ++ tests/cli/validate-features.wat.stderr | 1 + tests/cli/validate-features2.wat | 6 ++ tests/cli/validate-unknown-features.wat | 4 ++ .../cli/validate-unknown-features.wat.stderr | 4 ++ 9 files changed, 45 insertions(+), 52 deletions(-) create mode 100644 tests/cli/validate-features.wat create mode 100644 tests/cli/validate-features.wat.stderr create mode 100644 tests/cli/validate-features2.wat create mode 100644 tests/cli/validate-unknown-features.wat create mode 100644 tests/cli/validate-unknown-features.wat.stderr diff --git a/Cargo.lock b/Cargo.lock index 2d39c9f598..7edaef94cf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1699,6 +1699,7 @@ dependencies = [ "addr2line", "anyhow", "arbitrary", + "bitflags", "clap", "clap_complete", "cpp_demangle", diff --git a/Cargo.toml b/Cargo.toml index 1ac79b1080..5a84f9266c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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/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/validate.rs b/src/bin/wasm-tools/validate.rs index fe402b1390..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,38 +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), - ("legacy-exceptions", WasmFeatures::LEGACY_EXCEPTIONS), - ]; + 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("-") { @@ -212,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/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'. From 8078b664bf1f710504e1c61243c8bc522ab5f40d Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 12 Jul 2024 11:05:06 -0500 Subject: [PATCH 12/15] Update some documentation about longer names (#1667) Adding some follow-up documentation to #1650 --- crates/wasmparser/src/binary_reader.rs | 6 ++++++ crates/wasmparser/src/readers/core/names.rs | 3 +++ 2 files changed, 9 insertions(+) diff --git a/crates/wasmparser/src/binary_reader.rs b/crates/wasmparser/src/binary_reader.rs index 7f77662dcc..c93187df5d 100644 --- a/crates/wasmparser/src/binary_reader.rs +++ b/crates/wasmparser/src/binary_reader.rs @@ -697,7 +697,9 @@ impl<'a> BinaryReader<'a> { } /// 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. @@ -713,6 +715,10 @@ impl<'a> BinaryReader<'a> { } /// 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); diff --git a/crates/wasmparser/src/readers/core/names.rs b/crates/wasmparser/src/readers/core/names.rs index ef192acb91..d53211ad8a 100644 --- a/crates/wasmparser/src/readers/core/names.rs +++ b/crates/wasmparser/src/readers/core/names.rs @@ -33,6 +33,9 @@ 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()?; + // 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 }) } From 4c7a005dca5ba873f0a1214c7a9d31ba70306517 Mon Sep 17 00:00:00 2001 From: Mendy Berger <12537668+MendyBerger@users.noreply.github.com> Date: Fri, 12 Jul 2024 12:20:17 -0400 Subject: [PATCH 13/15] Added serde support to wit-encoder (#1647) * Added serde support to wit-encoder * Added serde feature notes --- Cargo.lock | 8 ++++++-- crates/wit-encoder/Cargo.toml | 15 +++++++++++++++ crates/wit-encoder/src/docs.rs | 2 ++ crates/wit-encoder/src/enum_.rs | 4 ++++ crates/wit-encoder/src/flags.rs | 4 ++++ crates/wit-encoder/src/function.rs | 6 ++++++ crates/wit-encoder/src/ident.rs | 2 ++ crates/wit-encoder/src/include.rs | 2 ++ crates/wit-encoder/src/interface.rs | 4 ++++ crates/wit-encoder/src/package.rs | 6 ++++++ crates/wit-encoder/src/record.rs | 4 ++++ crates/wit-encoder/src/render.rs | 2 ++ crates/wit-encoder/src/resource.rs | 6 ++++++ crates/wit-encoder/src/result.rs | 2 ++ crates/wit-encoder/src/tuple.rs | 2 ++ crates/wit-encoder/src/ty.rs | 8 ++++++++ crates/wit-encoder/src/use_.rs | 2 ++ crates/wit-encoder/src/variant.rs | 2 ++ crates/wit-encoder/src/world.rs | 6 ++++++ 19 files changed, 85 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7edaef94cf..78ef44ca57 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" @@ -2219,6 +2222,7 @@ dependencies = [ "indoc", "pretty_assertions", "semver", + "serde", ] [[package]] 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 c336173c68..d0a2962743 100644 --- a/crates/wit-encoder/src/ident.rs +++ b/crates/wit-encoder/src/ident.rs @@ -1,6 +1,8 @@ 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 { 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 bf0827161c..a4b876110b 100644 --- a/crates/wit-encoder/src/interface.rs +++ b/crates/wit-encoder/src/interface.rs @@ -3,6 +3,8 @@ use std::fmt; 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, @@ -54,6 +56,8 @@ 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), 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 index 9322c15d6b..bb549adba6 100644 --- a/crates/wit-encoder/src/use_.rs +++ b/crates/wit-encoder/src/use_.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 Use { target: Ident, use_names_list: Vec<(String, Option)>, 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 5f93320924..d380f62be0 100644 --- a/crates/wit-encoder/src/world.rs +++ b/crates/wit-encoder/src/world.rs @@ -3,6 +3,8 @@ use std::fmt; 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, @@ -156,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), @@ -207,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, From bf282bb1054a58b7989b112de522674999d4af50 Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Fri, 12 Jul 2024 09:58:50 -0700 Subject: [PATCH 14/15] threads: add remaining instructions (#1664) * Add the `wast` instructions This refactors the way memory orderings are attached to instructions by introducing `Ordered`. This allows any kind of existing instruction argument to be wrapped up in its ordered equivalent, which is essentially what many of the shared-everything-threads instructions do. * Add the instructions everywhere else * Add tests * Fix formatting * Deduplicate validation of `struct|array.atomic.rmw.*` instructions --- crates/wasm-encoder/src/core/code.rs | 376 ++++++++++ crates/wasmparser/src/binary_reader.rs | 79 +++ crates/wasmparser/src/lib.rs | 27 + crates/wasmparser/src/validator/operators.rs | 472 ++++++++++++- crates/wasmprinter/src/operator.rs | 99 +++ crates/wast/src/core/binary.rs | 7 +- crates/wast/src/core/expr.rs | 68 +- crates/wast/src/core/resolve/names.rs | 58 +- .../shared-everything-threads/array.wast | 652 +++++++++++++++++- .../shared-everything-threads/struct.wast | 369 +++++++++- .../shared-everything-threads/table.wast | 131 ++++ .../shared-everything-threads/array.wast.json | 371 ++++++++++ .../array.wast/10.print | 10 + .../array.wast/11.print | 10 + .../array.wast/12.print | 10 + .../array.wast/13.print | 10 + .../array.wast/14.print | 10 + .../array.wast/15.print | 10 + .../array.wast/16.print | 10 + .../array.wast/17.print | 10 + .../array.wast/18.print | 10 + .../array.wast/19.print | 10 + .../array.wast/20.print | 10 + .../array.wast/21.print | 10 + .../array.wast/22.print | 10 + .../array.wast/23.print | 11 + .../array.wast/24.print | 11 + .../array.wast/25.print | 11 + .../array.wast/26.print | 11 + .../array.wast/27.print | 11 + .../array.wast/28.print | 11 + .../array.wast/29.print | 11 + .../array.wast/30.print | 11 + .../array.wast/31.print | 11 + .../array.wast/32.print | 11 + .../array.wast/33.print | 11 + .../array.wast/34.print | 11 + .../array.wast/35.print | 11 + .../array.wast/36.print | 11 + .../array.wast/37.print | 11 + .../array.wast/38.print | 11 + .../array.wast/39.print | 11 + .../array.wast/40.print | 11 + .../array.wast/41.print | 11 + .../array.wast/42.print | 11 + .../array.wast/43.print | 11 + .../array.wast/44.print | 11 + .../array.wast/45.print | 11 + .../array.wast/46.print | 11 + .../array.wast/47.print | 11 + .../array.wast/48.print | 11 + .../array.wast/49.print | 11 + .../array.wast/50.print | 11 + .../array.wast/51.print | 11 + .../array.wast/52.print | 11 + .../array.wast/53.print | 11 + .../array.wast/54.print | 11 + .../array.wast/55.print | 11 + .../array.wast/56.print | 11 + .../array.wast/57.print | 11 + .../array.wast/58.print | 11 + .../array.wast/59.print | 12 + .../array.wast/60.print | 12 + .../array.wast/61.print | 12 + .../array.wast/62.print | 12 + .../array.wast/63.print | 12 + .../array.wast/64.print | 12 + .../array.wast/9.print | 10 + .../struct.wast.json | 96 +++ .../struct.wast/9.print | 343 +++++++++ .../shared-everything-threads/table.wast.json | 17 + .../table.wast/7.print | 104 +++ .../table.wast/8.print | 75 ++ 73 files changed, 3879 insertions(+), 73 deletions(-) create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/10.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/11.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/12.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/13.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/14.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/15.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/16.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/17.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/18.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/19.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/20.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/21.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/22.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/23.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/24.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/25.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/26.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/27.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/28.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/29.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/30.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/31.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/32.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/33.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/34.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/35.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/36.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/37.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/38.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/39.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/40.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/41.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/42.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/43.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/44.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/45.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/46.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/47.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/48.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/49.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/50.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/51.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/52.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/53.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/54.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/55.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/56.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/57.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/58.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/59.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/60.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/61.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/62.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/63.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/64.print create mode 100644 tests/snapshots/local/shared-everything-threads/array.wast/9.print create mode 100644 tests/snapshots/local/shared-everything-threads/struct.wast/9.print create mode 100644 tests/snapshots/local/shared-everything-threads/table.wast/7.print create mode 100644 tests/snapshots/local/shared-everything-threads/table.wast/8.print 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/wasmparser/src/binary_reader.rs b/crates/wasmparser/src/binary_reader.rs index c93187df5d..3fa9a772c8 100644 --- a/crates/wasmparser/src/binary_reader.rs +++ b/crates/wasmparser/src/binary_reader.rs @@ -1727,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/lib.rs b/crates/wasmparser/src/lib.rs index 18183a4875..0b1c02db94 100644 --- a/crates/wasmparser/src/lib.rs +++ b/crates/wasmparser/src/lib.rs @@ -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/validator/operators.rs b/crates/wasmparser/src/validator/operators.rs index 824fe093a1..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 { @@ -758,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"); @@ -892,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) @@ -1173,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), @@ -1253,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()), @@ -1691,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 @@ -1718,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. @@ -3616,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 @@ -3640,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), @@ -3663,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()))?; @@ -3685,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() { @@ -3730,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() { @@ -3741,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() { @@ -3752,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 { @@ -3761,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))?; @@ -3843,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; @@ -3856,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; @@ -3869,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 { @@ -3879,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) @@ -3993,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 @@ -4064,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" ), }; @@ -4120,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) 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/src/core/binary.rs b/crates/wast/src/core/binary.rs index 47fd4b0dd0..5007c4255d 100644 --- a/crates/wast/src/core/binary.rs +++ b/crates/wast/src/core/binary.rs @@ -928,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/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/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/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 index 0b4eedc2ce..b733ec4c2b 100644 --- a/tests/local/shared-everything-threads/table.wast +++ b/tests/local/shared-everything-threads/table.wast @@ -41,3 +41,134 @@ (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/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 index 8c2bc6b10f..13a852f325 100644 --- a/tests/snapshots/local/shared-everything-threads/table.wast.json +++ b/tests/snapshots/local/shared-everything-threads/table.wast.json @@ -45,6 +45,23 @@ "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/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)) +) From 1cdafa768a961ad489d901d984c779fa67e0d0d1 Mon Sep 17 00:00:00 2001 From: Keith Winstein <208955+keithw@users.noreply.github.com> Date: Mon, 15 Jul 2024 07:46:12 -0700 Subject: [PATCH 15/15] Add unfolded versions of the legacy (v3) exception-handling tests (#1672) --- .../legacy-exceptions.wat | 0 tests/local/legacy-exceptions/rethrow.wast | 124 ++++ tests/local/legacy-exceptions/throw.wast | 56 ++ tests/local/legacy-exceptions/try_catch.wast | 309 +++++++++ .../local/legacy-exceptions/try_delegate.wast | 275 ++++++++ tests/roundtrip.rs | 2 +- .../legacy-exceptions.wat.print | 0 .../local/legacy-exceptions/rethrow.wast.json | 214 +++++++ .../legacy-exceptions/rethrow.wast/0.print | 98 +++ .../local/legacy-exceptions/throw.wast.json | 131 ++++ .../legacy-exceptions/throw.wast/0.print | 62 ++ .../legacy-exceptions/try_catch.wast.json | 599 ++++++++++++++++++ .../legacy-exceptions/try_catch.wast/0.print | 9 + .../legacy-exceptions/try_catch.wast/2.print | 229 +++++++ .../legacy-exceptions/try_catch.wast/33.print | 19 + .../legacy-exceptions/try_delegate.wast.json | 325 ++++++++++ .../try_delegate.wast/0.print | 227 +++++++ 17 files changed, 2678 insertions(+), 1 deletion(-) rename tests/local/{ => legacy-exceptions}/legacy-exceptions.wat (100%) create mode 100644 tests/local/legacy-exceptions/rethrow.wast create mode 100644 tests/local/legacy-exceptions/throw.wast create mode 100644 tests/local/legacy-exceptions/try_catch.wast create mode 100644 tests/local/legacy-exceptions/try_delegate.wast rename tests/snapshots/local/{ => legacy-exceptions}/legacy-exceptions.wat.print (100%) create mode 100644 tests/snapshots/local/legacy-exceptions/rethrow.wast.json create mode 100644 tests/snapshots/local/legacy-exceptions/rethrow.wast/0.print create mode 100644 tests/snapshots/local/legacy-exceptions/throw.wast.json create mode 100644 tests/snapshots/local/legacy-exceptions/throw.wast/0.print create mode 100644 tests/snapshots/local/legacy-exceptions/try_catch.wast.json create mode 100644 tests/snapshots/local/legacy-exceptions/try_catch.wast/0.print create mode 100644 tests/snapshots/local/legacy-exceptions/try_catch.wast/2.print create mode 100644 tests/snapshots/local/legacy-exceptions/try_catch.wast/33.print create mode 100644 tests/snapshots/local/legacy-exceptions/try_delegate.wast.json create mode 100644 tests/snapshots/local/legacy-exceptions/try_delegate.wast/0.print diff --git a/tests/local/legacy-exceptions.wat b/tests/local/legacy-exceptions/legacy-exceptions.wat similarity index 100% rename from tests/local/legacy-exceptions.wat rename to tests/local/legacy-exceptions/legacy-exceptions.wat 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/roundtrip.rs b/tests/roundtrip.rs index 4a8e4f2b6a..b788a81f3f 100644 --- a/tests/roundtrip.rs +++ b/tests/roundtrip.rs @@ -605,7 +605,7 @@ impl TestState { } "simd" => features.insert(WasmFeatures::SIMD), "exception-handling" => features.insert(WasmFeatures::EXCEPTIONS), - "legacy-exceptions.wat" => features.insert(WasmFeatures::LEGACY_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), diff --git a/tests/snapshots/local/legacy-exceptions.wat.print b/tests/snapshots/local/legacy-exceptions/legacy-exceptions.wat.print similarity index 100% rename from tests/snapshots/local/legacy-exceptions.wat.print rename to tests/snapshots/local/legacy-exceptions/legacy-exceptions.wat.print 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) +)