Repository: bytecodealliance/wasm-tools
Pull request #1731 (2024-08-21 17:08:55)

Add a feature for disabling GC types
This commit adds support for a new wasm feature named `WasmFeatures::GC_TYPES`. This does not correspond to any upstream proposal and is intended for use in Wasmtime for disabling the runtime garbage collector at compile time. This serves as a finer-grained switch to disable the runtime dependency at validation time on a garbage collector without disabling all the features that were added in other proposals. For example the `reference-types` proposal also added support for multi-table which disabling a runtime garbage collector doesn't need to disable.


Patch:
diff --git a/crates/wasmparser/src/features.rs b/crates/wasmparser/src/features.rs
index 3f61ffcc..aa47eee0 100644
--- a/crates/wasmparser/src/features.rs
+++ b/crates/wasmparser/src/features.rs
@@ -126,7 +126,7 @@ define_wasm_features! {
         /// The WebAssembly multi memory proposal.
         pub multi_memory: MULTI_MEMORY(1 << 12) = true;
         /// The WebAssembly exception handling proposal.
-        pub exceptions: EXCEPTIONS(1 << 13) = false;
+        pub exceptions: EXCEPTIONS(1 << 13) = true;
         /// The WebAssembly memory64 proposal.
         pub memory64: MEMORY64(1 << 14) = false;
         /// The WebAssembly extended_const proposal.
@@ -134,11 +134,11 @@ define_wasm_features! {
         /// The WebAssembly component model proposal.
         pub component_model: COMPONENT_MODEL(1 << 16) = true;
         /// The WebAssembly typed function references proposal.
-        pub function_references: FUNCTION_REFERENCES(1 << 17) = false;
+        pub function_references: FUNCTION_REFERENCES(1 << 17) = true;
         /// The WebAssembly memory control proposal.
         pub memory_control: MEMORY_CONTROL(1 << 18) = false;
         /// The WebAssembly gc proposal.
-        pub gc: GC(1 << 19) = false;
+        pub gc: GC(1 << 19) = true;
         /// The WebAssembly [custom-page-sizes
         /// proposal](https://github.com/WebAssembly/custom-page-sizes).
         pub custom_page_sizes: CUSTOM_PAGE_SIZES(1 << 20) = false;
@@ -157,6 +157,23 @@ define_wasm_features! {
         /// 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 << 25) = false;
+        /// Whether or not gc types are enabled.
+        ///
+        /// This feature does not correspond to any WebAssembly proposal nor
+        /// concept in the specification itself. This is intended to assist
+        /// embedders in disabling support for GC types at validation time. For
+        /// example if an engine wants to support all of WebAssembly except
+        /// a runtime garbage collector it could disable this feature.
+        ///
+        /// This features is enabled by default and is used to gate types such
+        /// as `externref` or `anyref`. Note that the requisite WebAssembly
+        /// proposal must also be enabled for types like `externref`, meaning
+        /// that it requires both `REFERENCE_TYPES` and `GC_TYPE` to be enabled.
+        ///
+        /// Note that the `funcref` and `exnref` types are not gated by this
+        /// feature. Those are expected to not require a full garbage collector
+        /// so are not gated by this.
+        pub gc_types: GC_TYPES(1 << 26) = true;
     }
 }
 
@@ -164,7 +181,7 @@ impl WasmFeatures {
     /// Returns the feature set associated with the 1.0 version of the
     /// WebAssembly specification or the "MVP" feature set.
     pub fn wasm1() -> WasmFeatures {
-        WasmFeatures::FLOATS
+        WasmFeatures::FLOATS | WasmFeatures::GC_TYPES
     }
 
     /// Returns the feature set associated with the 2.0 version of the
diff --git a/crates/wasmparser/src/validator.rs b/crates/wasmparser/src/validator.rs
index 5425fad7..700130e5 100644
--- a/crates/wasmparser/src/validator.rs
+++ b/crates/wasmparser/src/validator.rs
@@ -251,6 +251,12 @@ impl WasmFeatures {
         }
         match r.heap_type() {
             HeapType::Concrete(_) => {
+                // Note that `self.gc_types()` is not checked here because
+                // concrete pointers to function types are allowed. GC types
+                // are disallowed by instead rejecting the definition of
+                // array/struct types and only allowing the definition of
+                // function types.
+
                 // Indexed types require either the function-references or gc
                 // proposal as gc implies function references here.
                 if self.function_references() || self.gc() {
@@ -266,6 +272,13 @@ impl WasmFeatures {
                         "shared reference types require the shared-everything-threads proposal",
                     );
                 }
+
+                // Apply the "gc-types" feature which disallows all heap types
+                // except exnref/funcref.
+                if !self.gc_types() && ty != Func && ty != Exn {
+                    return Err("gc types are disallowed but found type which requires gc");
+                }
+
                 match (ty, r.is_nullable()) {
                     // funcref/externref only require `reference-types`.
                     (Func, true) | (Extern, true) => Ok(()),
diff --git a/crates/wasmparser/src/validator/core.rs b/crates/wasmparser/src/validator/core.rs
index fbcdbcbb..75cb01c5 100644
--- a/crates/wasmparser/src/validator/core.rs
+++ b/crates/wasmparser/src/validator/core.rs
@@ -699,10 +699,16 @@ impl Module {
             }
             CompositeInnerType::Array(t) => {
                 if !features.gc() {
-                    return Err(BinaryReaderError::new(
+                    bail!(
+                        offset,
                         "array indexed types not supported without the gc feature",
+                    );
+                }
+                if !features.gc_types() {
+                    bail!(
                         offset,
-                    ));
+                        "cannot define array types when gc types are disabled",
+                    );
                 }
                 match &t.0.element_type {
                     StorageType::I8 | StorageType::I16 => {
@@ -713,10 +719,16 @@ impl Module {
             }
             CompositeInnerType::Struct(t) => {
                 if !features.gc() {
-                    return Err(BinaryReaderError::new(
+                    bail!(
+                        offset,
                         "struct indexed types not supported without the gc feature",
+                    );
+                }
+                if !features.gc_types() {
+                    bail!(
                         offset,
-                    ));
+                        "cannot define struct types when gc types are disabled",
+                    );
                 }
                 for ft in t.fields.iter() {
                     match &ft.element_type {
diff --git a/crates/wasmparser/src/validator/operators.rs b/crates/wasmparser/src/validator/operators.rs
index df984683..a387ab5b 100644
--- a/crates/wasmparser/src/validator/operators.rs
+++ b/crates/wasmparser/src/validator/operators.rs
@@ -23,10 +23,10 @@
 // the various methods here.
 
 use crate::{
-    limits::MAX_WASM_FUNCTION_LOCALS, AbstractHeapType, ArrayType, BinaryReaderError, BlockType,
-    BrTable, Catch, FieldType, FuncType, GlobalType, HeapType, Ieee32, Ieee64, MemArg, RefType,
-    Result, StorageType, StructType, SubType, TableType, TryTable, UnpackedIndex, ValType,
-    VisitOperator, WasmFeatures, WasmModuleResources, V128,
+    limits::MAX_WASM_FUNCTION_LOCALS, AbstractHeapType, BinaryReaderError, BlockType, BrTable,
+    Catch, FieldType, FuncType, GlobalType, HeapType, Ieee32, Ieee64, MemArg, RefType, Result,
+    StorageType, StructType, SubType, TableType, TryTable, UnpackedIndex, ValType, VisitOperator,
+    WasmFeatures, WasmModuleResources, V128,
 };
 use crate::{prelude::*, CompositeInnerType, Ordering};
 use core::ops::{Deref, DerefMut};
@@ -1199,10 +1199,8 @@ where
         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 {
+        let field = self.mutable_struct_field_at(struct_type_index, field_index)?;
+        let field_ty = match field.element_type {
             StorageType::Val(ValType::I32) => ValType::I32,
             StorageType::Val(ValType::I64) => ValType::I64,
             _ => bail!(
@@ -1220,8 +1218,8 @@ where
     /// 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 {
+        let field = self.mutable_array_type_at(type_index)?;
+        let elem_ty = match field.element_type {
             StorageType::Val(ValType::I32) => ValType::I32,
             StorageType::Val(ValType::I64) => ValType::I64,
             _ => bail!(
@@ -1279,10 +1277,25 @@ where
             })
     }
 
-    fn array_type_at(&self, at: u32) -> Result<&'resources ArrayType> {
+    fn mutable_struct_field_at(
+        &self,
+        struct_type_index: u32,
+        field_index: u32,
+    ) -> Result<FieldType> {
+        let field = self.struct_field_at(struct_type_index, field_index)?;
+        if !field.mutable {
+            bail!(
+                self.offset,
+                "invalid struct modification: struct field is immutable"
+            )
+        }
+        Ok(field)
+    }
+
+    fn array_type_at(&self, at: u32) -> Result<FieldType> {
         let sub_ty = self.sub_type_at(at)?;
         if let CompositeInnerType::Array(array_ty) = &sub_ty.composite_type.inner {
-            Ok(array_ty)
+            Ok(array_ty.0)
         } else {
             bail!(
                 self.offset,
@@ -1291,6 +1304,17 @@ where
         }
     }
 
+    fn mutable_array_type_at(&self, at: u32) -> Result<FieldType> {
+        let field = self.array_type_at(at)?;
+        if !field.mutable {
+            bail!(
+                self.offset,
+                "invalid array modification: array is immutable"
+            )
+        }
+        Ok(field)
+    }
+
     fn func_type_at(&self, at: u32) -> Result<&'resources FuncType> {
         let sub_ty = self.sub_type_at(at)?;
         if let CompositeInnerType::Func(func_ty) = &sub_ty.composite_type.inner {
@@ -3876,7 +3900,7 @@ where
         if field_ty.element_type.is_packed() {
             bail!(
                 self.offset,
-                "can only use struct.get with non-packed storage types"
+                "can only use struct `get` with non-packed storage types"
             )
         }
         self.pop_concrete_ref(true, struct_type_index)?;
@@ -3961,10 +3985,7 @@ where
         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 {
-            bail!(self.offset, "invalid struct.set: struct field is immutable")
-        }
+        let field_ty = self.mutable_struct_field_at(struct_type_index, field_index)?;
         self.pop_operand(Some(field_ty.element_type.unpack()))?;
         self.pop_concrete_ref(true, struct_type_index)?;
         Ok(())
@@ -4041,10 +4062,8 @@ where
         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 {
+        let field = self.mutable_struct_field_at(struct_type_index, field_index)?;
+        let is_valid_type = match field.element_type {
             StorageType::Val(ValType::I32) | StorageType::Val(ValType::I64) => true,
             StorageType::Val(v) => self
                 .resources
@@ -4057,7 +4076,7 @@ where
                 "invalid type: `struct.atomic.rmw.xchg` only allows `i32`, `i64` and subtypes of `anyref`"
             );
         }
-        let field_ty = field_ty.unpack();
+        let field_ty = field.element_type.unpack();
         self.pop_operand(Some(field_ty))?;
         self.pop_concrete_ref(true, struct_type_index)?;
         self.push_operand(field_ty)?;
@@ -4069,10 +4088,8 @@ where
         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 {
+        let field = self.mutable_struct_field_at(struct_type_index, field_index)?;
+        let is_valid_type = match field.element_type {
             StorageType::Val(ValType::I32) | StorageType::Val(ValType::I64) => true,
             StorageType::Val(v) => self
                 .resources
@@ -4085,7 +4102,7 @@ where
                 "invalid type: `struct.atomic.rmw.cmpxchg` only allows `i32`, `i64` and subtypes of `eqref`"
             );
         }
-        let field_ty = field_ty.unpack();
+        let field_ty = field.element_type.unpack();
         self.pop_operand(Some(field_ty))?;
         self.pop_operand(Some(field_ty))?;
         self.pop_concrete_ref(true, struct_type_index)?;
@@ -4095,12 +4112,12 @@ where
     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))?;
-        self.pop_operand(Some(array_ty.0.element_type.unpack()))?;
+        self.pop_operand(Some(array_ty.element_type.unpack()))?;
         self.push_concrete_ref(false, type_index)
     }
     fn visit_array_new_default(&mut self, type_index: u32) -> Self::Output {
         let ty = self.array_type_at(type_index)?;
-        let val_ty = ty.0.element_type.unpack();
+        let val_ty = ty.element_type.unpack();
         if !val_ty.is_defaultable() {
             bail!(
                 self.offset,
@@ -4112,7 +4129,7 @@ where
     }
     fn visit_array_new_fixed(&mut self, type_index: u32, n: u32) -> Self::Output {
         let array_ty = self.array_type_at(type_index)?;
-        let elem_ty = array_ty.0.element_type.unpack();
+        let elem_ty = array_ty.element_type.unpack();
         for _ in 0..n {
             self.pop_operand(Some(elem_ty))?;
         }
@@ -4120,7 +4137,7 @@ where
     }
     fn visit_array_new_data(&mut self, type_index: u32, data_index: u32) -> Self::Output {
         let array_ty = self.array_type_at(type_index)?;
-        let elem_ty = array_ty.0.element_type.unpack();
+        let elem_ty = array_ty.element_type.unpack();
         match elem_ty {
             ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => {}
             ValType::Ref(_) => bail!(
@@ -4139,7 +4156,7 @@ where
     }
     fn visit_array_new_elem(&mut self, type_index: u32, elem_index: u32) -> Self::Output {
         let array_ty = self.array_type_at(type_index)?;
-        let array_ref_ty = match array_ty.0.element_type.unpack() {
+        let array_ref_ty = match array_ty.element_type.unpack() {
             ValType::Ref(rt) => rt,
             ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => bail!(
                 self.offset,
@@ -4163,7 +4180,7 @@ where
     }
     fn visit_array_get(&mut self, type_index: u32) -> Self::Output {
         let array_ty = self.array_type_at(type_index)?;
-        let elem_ty = array_ty.0.element_type;
+        let elem_ty = array_ty.element_type;
         if elem_ty.is_packed() {
             bail!(
                 self.offset,
@@ -4177,7 +4194,7 @@ where
     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 elem_ty = self.array_type_at(type_index)?.element_type;
         let is_valid_type = match elem_ty {
             StorageType::Val(ValType::I32) | StorageType::Val(ValType::I64) => true,
             StorageType::Val(v) => self
@@ -4195,7 +4212,7 @@ where
     }
     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;
+        let elem_ty = array_ty.element_type;
         if !elem_ty.is_packed() {
             bail!(
                 self.offset,
@@ -4210,14 +4227,14 @@ where
         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,
+            self.array_type_at(type_index)?.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;
+        let elem_ty = array_ty.element_type;
         if !elem_ty.is_packed() {
             bail!(
                 self.offset,
@@ -4232,17 +4249,14 @@ where
         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,
+            self.array_type_at(type_index)?.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 {
-            bail!(self.offset, "invalid array.set: array is immutable")
-        }
-        self.pop_operand(Some(array_ty.0.element_type.unpack()))?;
+        let array_ty = self.mutable_array_type_at(type_index)?;
+        self.pop_operand(Some(array_ty.element_type.unpack()))?;
         self.pop_operand(Some(ValType::I32))?;
         self.pop_concrete_ref(true, type_index)?;
         Ok(())
@@ -4250,7 +4264,7 @@ where
     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 elem_ty = self.array_type_at(type_index)?.element_type;
         let is_valid_type = match elem_ty {
             StorageType::I8 | StorageType::I16 => true,
             StorageType::Val(ValType::I32) | StorageType::Val(ValType::I64) => true,
@@ -4271,26 +4285,17 @@ where
         self.push_operand(ValType::I32)
     }
     fn visit_array_fill(&mut self, array_type_index: u32) -> Self::Output {
-        let array_ty = self.array_type_at(array_type_index)?;
-        if !array_ty.0.mutable {
-            bail!(self.offset, "invalid array.fill: array is immutable");
-        }
+        let array_ty = self.mutable_array_type_at(array_type_index)?;
         self.pop_operand(Some(ValType::I32))?;
-        self.pop_operand(Some(array_ty.0.element_type.unpack()))?;
+        self.pop_operand(Some(array_ty.element_type.unpack()))?;
         self.pop_operand(Some(ValType::I32))?;
         self.pop_concrete_ref(true, array_type_index)?;
         Ok(())
     }
     fn visit_array_copy(&mut self, type_index_dst: u32, type_index_src: u32) -> Self::Output {
-        let array_ty_dst = self.array_type_at(type_index_dst)?;
-        if !array_ty_dst.0.mutable {
-            bail!(
-                self.offset,
-                "invalid array.copy: destination array is immutable"
-            );
-        }
+        let array_ty_dst = self.mutable_array_type_at(type_index_dst)?;
         let array_ty_src = self.array_type_at(type_index_src)?;
-        match (array_ty_dst.0.element_type, array_ty_src.0.element_type) {
+        match (array_ty_dst.element_type, array_ty_src.element_type) {
             (StorageType::I8, StorageType::I8) => {}
             (StorageType::I8, ty) => bail!(
                 self.offset,
@@ -4328,11 +4333,8 @@ where
         array_type_index: u32,
         array_data_index: u32,
     ) -> Self::Output {
-        let array_ty = self.array_type_at(array_type_index)?;
-        if !array_ty.0.mutable {
-            bail!(self.offset, "invalid array.init_data: array is immutable");
-        }
-        let val_ty = array_ty.0.element_type.unpack();
+        let array_ty = self.mutable_array_type_at(array_type_index)?;
+        let val_ty = array_ty.element_type.unpack();
         match val_ty {
             ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => {}
             ValType::Ref(_) => bail!(
@@ -4352,11 +4354,8 @@ where
         Ok(())
     }
     fn visit_array_init_elem(&mut self, type_index: u32, elem_index: u32) -> Self::Output {
-        let array_ty = self.array_type_at(type_index)?;
-        if !array_ty.0.mutable {
-            bail!(self.offset, "invalid array.init_data: array is immutable");
-        }
-        let array_ref_ty = match array_ty.0.element_type.unpack() {
+        let array_ty = self.mutable_array_type_at(type_index)?;
+        let array_ref_ty = match array_ty.element_type.unpack() {
             ValType::Ref(rt) => rt,
             ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 | ValType::V128 => bail!(
                 self.offset,
@@ -4400,8 +4399,8 @@ where
         _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 {
+        let field = self.mutable_array_type_at(type_index)?;
+        let is_valid_type = match field.element_type {
             StorageType::Val(ValType::I32) | StorageType::Val(ValType::I64) => true,
             StorageType::Val(v) => self
                 .resources
@@ -4414,7 +4413,7 @@ where
                 "invalid type: `array.atomic.rmw.xchg` only allows `i32`, `i64` and subtypes of `anyref`"
             );
         }
-        let elem_ty = elem_ty.unpack();
+        let elem_ty = field.element_type.unpack();
         self.pop_operand(Some(elem_ty))?;
         self.pop_operand(Some(ValType::I32))?;
         self.pop_concrete_ref(true, type_index)?;
@@ -4426,8 +4425,8 @@ where
         _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 {
+        let field = self.mutable_array_type_at(type_index)?;
+        let is_valid_type = match field.element_type {
             StorageType::Val(ValType::I32) | StorageType::Val(ValType::I64) => true,
             StorageType::Val(v) => self
                 .resources
@@ -4440,7 +4439,7 @@ where
                 "invalid type: `array.atomic.rmw.cmpxchg` only allows `i32`, `i64` and subtypes of `eqref`"
             );
         }
-        let elem_ty = elem_ty.unpack();
+        let elem_ty = field.element_type.unpack();
         self.pop_operand(Some(elem_ty))?;
         self.pop_operand(Some(elem_ty))?;
         self.pop_operand(Some(ValType::I32))?;


Test patch:
diff --git a/crates/wasm-smith/tests/common/mod.rs b/crates/wasm-smith/tests/common/mod.rs
index 8a238776..332fd0ca 100644
--- a/crates/wasm-smith/tests/common/mod.rs
+++ b/crates/wasm-smith/tests/common/mod.rs
@@ -2,7 +2,7 @@ use wasm_smith::Config;
 use wasmparser::{types::Types, Validator, WasmFeatures};
 
 pub fn parser_features_from_config(config: &Config) -> WasmFeatures {
-    let mut features = WasmFeatures::MUTABLE_GLOBAL | WasmFeatures::FLOATS;
+    let mut features = WasmFeatures::MUTABLE_GLOBAL | WasmFeatures::wasm1();
     features.set(
         WasmFeatures::SATURATING_FLOAT_TO_INT,
         config.saturating_float_to_int_enabled,
diff --git a/tests/cli/validate-unknown-features.wat.stderr b/tests/cli/validate-unknown-features.wat.stderr
index 7aed7b2c..3e0ccb84 100644
--- a/tests/cli/validate-unknown-features.wat.stderr
+++ b/tests/cli/validate-unknown-features.wat.stderr
@@ -1,4 +1,4 @@
 error: invalid value 'unknown' for '--features <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, component-model-multiple-returns, legacy-exceptions
+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, component-model-multiple-returns, legacy-exceptions, gc-types
 
 For more information, try '--help'.
diff --git a/tests/local/missing-features/gc/gc-types-disabled.wast b/tests/local/missing-features/gc/gc-types-disabled.wast
new file mode 100644
index 00000000..3cd59484
--- /dev/null
+++ b/tests/local/missing-features/gc/gc-types-disabled.wast
@@ -0,0 +1,32 @@
+(assert_invalid
+  (module
+    (type (func (result externref)))
+  )
+  "gc types are disallowed")
+
+(assert_invalid
+  (module
+    (type (func (result (ref any))))
+  )
+  "gc types are disallowed")
+
+(module
+  (table 1 funcref)
+)
+
+(module
+  (type $t (func))
+  (table 1 (ref null $t))
+)
+
+(assert_invalid
+  (module
+    (type (array i8))
+  )
+  "cannot define array types")
+
+(assert_invalid
+  (module
+    (type (struct))
+  )
+  "cannot define struct types")
diff --git a/tests/local/shared-everything-threads/arrays.wast b/tests/local/shared-everything-threads/arrays.wast
index aa041f96..b545b445 100644
--- a/tests/local/shared-everything-threads/arrays.wast
+++ b/tests/local/shared-everything-threads/arrays.wast
@@ -138,6 +138,80 @@
   (func (array.init_elem $funcs 0 (ref.null (shared none)) (i32.const 0) (i32.const 0) (i32.const 0)))
 )
 
+;; Check that field-modifying instructions only work on mutable fields.
+(assert_invalid
+  (module
+    (type $a (shared (array (ref (shared any)))))
+    (func (param $a (ref $a)) (param $ar (ref (shared any))) (result (ref (shared any)))
+      (array.atomic.set seq_cst $a (local.get $a) (i32.const 0) (local.get $ar))
+    )
+  )
+  "array is immutable"
+)
+(assert_invalid
+  (module
+    (type $a (shared (array i32)))
+    (func (param $a (ref $a)) (result i32)
+      (array.atomic.rmw.add seq_cst $a (local.get $a) (i32.const 0) (i32.const 1))
+    )
+  )
+  "array is immutable"
+)
+(assert_invalid
+  (module
+    (type $a (shared (array i64)))
+    (func (param $a (ref $a)) (result i64)
+      (array.atomic.rmw.sub seq_cst $a (local.get $a) (i32.const 0) (i64.const 1))
+    )
+  )
+  "array is immutable"
+)
+(assert_invalid
+  (module
+    (type $a (shared (array i32)))
+    (func (param $a (ref $a)) (result i32)
+      (array.atomic.rmw.and acq_rel $a (local.get $a) (i32.const 0) (i32.const 1))
+    )
+  )
+  "array is immutable"
+)
+(assert_invalid
+  (module
+    (type $a (shared (array i64)))
+    (func (param $a (ref $a)) (result i64)
+      (array.atomic.rmw.or acq_rel $a (local.get $a) (i32.const 0) (i64.const 1))
+    )
+  )
+  "array is immutable"
+)
+(assert_invalid
+  (module
+    (type $a (shared (array i32)))
+    (func (param $a (ref $a)) (result i32)
+      (array.atomic.rmw.xor seq_cst $a (local.get $a) (i32.const 0) (i32.const 1))
+    )
+  )
+  "array is immutable"
+)
+(assert_invalid
+  (module
+    (type $a (shared (array (ref (shared any)))))
+    (func (param $a (ref $a)) (param $ar (ref (shared any))) (result (ref (shared any)))
+      (array.atomic.rmw.xchg seq_cst $a (local.get $a) (i32.const 0) (local.get $ar))
+    )
+  )
+  "array is immutable"
+)
+(assert_invalid
+  (module
+    (type $a (shared (array (ref (shared eq)))))
+    (func (param $a (ref $a)) (param $e1 (ref (shared eq))) (param $e2 (ref (shared eq))) (result)
+      (array.atomic.rmw.cmpxchg acq_rel $a (local.get $a) (i32.const 0) (local.get $e1) (local.get $e2))
+    )
+  )
+  "array is immutable"
+)
+
 ;; Exhaustively check `array.atomic.rmw.*` instructions.
 (module (; get, i32, seq_cst ;)
   (type $a (shared (array (mut i32))))
diff --git a/tests/local/shared-everything-threads/structs.wast b/tests/local/shared-everything-threads/structs.wast
index 69274c24..240e1f87 100644
--- a/tests/local/shared-everything-threads/structs.wast
+++ b/tests/local/shared-everything-threads/structs.wast
@@ -99,6 +99,80 @@
   (func (struct.set $i8 0 (ref.null (shared none)) (i32.const 0)))
 )
 
+;; Check that field-modifying instructions only work on mutable fields.
+(assert_invalid
+  (module
+    (type $s (shared (struct (field (ref (shared any))))))
+    (func (param $s (ref $s)) (param $a (ref (shared any))) (result (ref (shared any)))
+      (struct.atomic.set seq_cst $s 0 (local.get $s) (local.get $a))
+    )
+  )
+  "field is immutable"
+)
+(assert_invalid
+  (module
+    (type $s (shared (struct (field i32))))
+    (func (param $s (ref $s)) (result i32)
+      (struct.atomic.rmw.add seq_cst $s 0 (local.get $s) (i32.const 1))
+    )
+  )
+  "field is immutable"
+)
+(assert_invalid
+  (module
+    (type $s (shared (struct (field i64))))
+    (func (param $s (ref $s)) (result i64)
+      (struct.atomic.rmw.sub seq_cst $s 0 (local.get $s) (i64.const 1))
+    )
+  )
+  "field is immutable"
+)
+(assert_invalid
+  (module
+    (type $s (shared (struct (field i32))))
+    (func (param $s (ref $s)) (result i32)
+      (struct.atomic.rmw.and acq_rel $s 0 (local.get $s) (i32.const 1))
+    )
+  )
+  "field is immutable"
+)
+(assert_invalid
+  (module
+    (type $s (shared (struct (field i64))))
+    (func (param $s (ref $s)) (result i64)
+      (struct.atomic.rmw.or acq_rel $s 0 (local.get $s) (i64.const 1))
+    )
+  )
+  "field is immutable"
+)
+(assert_invalid
+  (module
+    (type $s (shared (struct (field i32))))
+    (func (param $s (ref $s)) (result i32)
+      (struct.atomic.rmw.xor seq_cst $s 0 (local.get $s) (i32.const 1))
+    )
+  )
+  "field is immutable"
+)
+(assert_invalid
+  (module
+    (type $s (shared (struct (field (ref (shared any))))))
+    (func (param $s (ref $s)) (param $a (ref (shared any))) (result (ref (shared any)))
+      (struct.atomic.rmw.xchg seq_cst $s 0 (local.get $s) (local.get $a))
+    )
+  )
+  "field is immutable"
+)
+(assert_invalid
+  (module
+    (type $s (shared (struct (field (ref (shared eq))))))
+    (func (param $s (ref $s)) (param $e1 (ref (shared eq))) (param $e2 (ref (shared eq))) (result (ref (shared eq)))
+      (struct.atomic.rmw.cmpxchg acq_rel $s 0 (local.get $s) (local.get $e1) (local.get $e2))
+    )
+  )
+  "field is immutable"
+)
+
 ;; Exhaustively check `struct.atomic.rmw.*` instructions.
 (module
   (type $s (shared (struct
diff --git a/tests/roundtrip.rs b/tests/roundtrip.rs
index b10d56bf..63917769 100644
--- a/tests/roundtrip.rs
+++ b/tests/roundtrip.rs
@@ -598,8 +598,9 @@ impl TestState {
         for part in test.iter().filter_map(|t| t.to_str()) {
             match part {
                 "testsuite" => {
-                    features = WasmFeatures::default();
-                    features.remove(WasmFeatures::COMPONENT_MODEL);
+                    features = WasmFeatures::wasm2();
+                    features |= WasmFeatures::TAIL_CALL;
+                    features |= WasmFeatures::EXTENDED_CONST;
 
                     // NB: when these proposals are merged upstream in the spec
                     // repo then this should be removed. Currently this hasn't
@@ -609,9 +610,11 @@ impl TestState {
                     features.remove(WasmFeatures::THREADS);
                 }
                 "missing-features" => {
-                    features = WasmFeatures::empty() | WasmFeatures::FLOATS;
+                    features =
+                        WasmFeatures::empty() | WasmFeatures::FLOATS | WasmFeatures::GC_TYPES;
                 }
                 "floats-disabled.wast" => features.remove(WasmFeatures::FLOATS),
+                "gc-types-disabled.wast" => features.remove(WasmFeatures::GC_TYPES),
                 "threads" => {
                     features.insert(WasmFeatures::THREADS);
                     features.remove(WasmFeatures::BULK_MEMORY);
diff --git a/tests/snapshots/local/missing-features/gc/gc-types-disabled.wast.json b/tests/snapshots/local/missing-features/gc/gc-types-disabled.wast.json
new file mode 100644
index 00000000..3cec0176
--- /dev/null
+++ b/tests/snapshots/local/missing-features/gc/gc-types-disabled.wast.json
@@ -0,0 +1,43 @@
+{
+  "source_filename": "tests/local/missing-features/gc/gc-types-disabled.wast",
+  "commands": [
+    {
+      "type": "assert_invalid",
+      "line": 2,
+      "filename": "gc-types-disabled.0.wasm",
+      "text": "gc types are disallowed",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 8,
+      "filename": "gc-types-disabled.1.wasm",
+      "text": "gc types are disallowed",
+      "module_type": "binary"
+    },
+    {
+      "type": "module",
+      "line": 13,
+      "filename": "gc-types-disabled.2.wasm"
+    },
+    {
+      "type": "module",
+      "line": 17,
+      "filename": "gc-types-disabled.3.wasm"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 23,
+      "filename": "gc-types-disabled.4.wasm",
+      "text": "cannot define array types",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 29,
+      "filename": "gc-types-disabled.5.wasm",
+      "text": "cannot define struct types",
+      "module_type": "binary"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/tests/snapshots/local/missing-features/gc/gc-types-disabled.wast/2.print b/tests/snapshots/local/missing-features/gc/gc-types-disabled.wast/2.print
new file mode 100644
index 00000000..7f62195a
--- /dev/null
+++ b/tests/snapshots/local/missing-features/gc/gc-types-disabled.wast/2.print
@@ -0,0 +1,3 @@
+(module
+  (table (;0;) 1 funcref)
+)
diff --git a/tests/snapshots/local/missing-features/gc/gc-types-disabled.wast/3.print b/tests/snapshots/local/missing-features/gc/gc-types-disabled.wast/3.print
new file mode 100644
index 00000000..7e017d6d
--- /dev/null
+++ b/tests/snapshots/local/missing-features/gc/gc-types-disabled.wast/3.print
@@ -0,0 +1,4 @@
+(module
+  (type $t (;0;) (func))
+  (table (;0;) 1 (ref null $t))
+)
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast.json b/tests/snapshots/local/shared-everything-threads/arrays.wast.json
index 59172cb6..fb61bec7 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast.json
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast.json
@@ -62,263 +62,279 @@
       "filename": "arrays.9.wasm"
     },
     {
-      "type": "module",
-      "line": 142,
-      "filename": "arrays.10.wasm"
+      "type": "assert_invalid",
+      "line": 143,
+      "filename": "arrays.10.wasm",
+      "text": "array is immutable",
+      "module_type": "binary"
     },
     {
-      "type": "module",
-      "line": 150,
-      "filename": "arrays.11.wasm"
+      "type": "assert_invalid",
+      "line": 152,
+      "filename": "arrays.11.wasm",
+      "text": "array is immutable",
+      "module_type": "binary"
     },
     {
-      "type": "module",
-      "line": 158,
-      "filename": "arrays.12.wasm"
+      "type": "assert_invalid",
+      "line": 161,
+      "filename": "arrays.12.wasm",
+      "text": "array is immutable",
+      "module_type": "binary"
     },
     {
-      "type": "module",
-      "line": 166,
-      "filename": "arrays.13.wasm"
+      "type": "assert_invalid",
+      "line": 170,
+      "filename": "arrays.13.wasm",
+      "text": "array is immutable",
+      "module_type": "binary"
     },
     {
-      "type": "module",
-      "line": 174,
-      "filename": "arrays.14.wasm"
+      "type": "assert_invalid",
+      "line": 179,
+      "filename": "arrays.14.wasm",
+      "text": "array is immutable",
+      "module_type": "binary"
     },
     {
-      "type": "module",
-      "line": 182,
-      "filename": "arrays.15.wasm"
+      "type": "assert_invalid",
+      "line": 188,
+      "filename": "arrays.15.wasm",
+      "text": "array is immutable",
+      "module_type": "binary"
     },
     {
-      "type": "module",
-      "line": 190,
-      "filename": "arrays.16.wasm"
+      "type": "assert_invalid",
+      "line": 197,
+      "filename": "arrays.16.wasm",
+      "text": "array is immutable",
+      "module_type": "binary"
     },
     {
-      "type": "module",
-      "line": 198,
-      "filename": "arrays.17.wasm"
+      "type": "assert_invalid",
+      "line": 206,
+      "filename": "arrays.17.wasm",
+      "text": "array is immutable",
+      "module_type": "binary"
     },
     {
       "type": "module",
-      "line": 206,
+      "line": 216,
       "filename": "arrays.18.wasm"
     },
     {
       "type": "module",
-      "line": 214,
+      "line": 224,
       "filename": "arrays.19.wasm"
     },
     {
       "type": "module",
-      "line": 222,
+      "line": 232,
       "filename": "arrays.20.wasm"
     },
     {
       "type": "module",
-      "line": 230,
+      "line": 240,
       "filename": "arrays.21.wasm"
     },
     {
       "type": "module",
-      "line": 238,
+      "line": 248,
       "filename": "arrays.22.wasm"
     },
     {
       "type": "module",
-      "line": 246,
+      "line": 256,
       "filename": "arrays.23.wasm"
     },
     {
       "type": "module",
-      "line": 254,
+      "line": 264,
       "filename": "arrays.24.wasm"
     },
     {
       "type": "module",
-      "line": 263,
+      "line": 272,
       "filename": "arrays.25.wasm"
     },
     {
       "type": "module",
-      "line": 272,
+      "line": 280,
       "filename": "arrays.26.wasm"
     },
     {
       "type": "module",
-      "line": 281,
+      "line": 288,
       "filename": "arrays.27.wasm"
     },
     {
       "type": "module",
-      "line": 290,
+      "line": 296,
       "filename": "arrays.28.wasm"
     },
     {
       "type": "module",
-      "line": 299,
+      "line": 304,
       "filename": "arrays.29.wasm"
     },
     {
       "type": "module",
-      "line": 308,
+      "line": 312,
       "filename": "arrays.30.wasm"
     },
     {
       "type": "module",
-      "line": 317,
+      "line": 320,
       "filename": "arrays.31.wasm"
     },
     {
       "type": "module",
-      "line": 326,
+      "line": 328,
       "filename": "arrays.32.wasm"
     },
     {
       "type": "module",
-      "line": 335,
+      "line": 337,
       "filename": "arrays.33.wasm"
     },
     {
       "type": "module",
-      "line": 344,
+      "line": 346,
       "filename": "arrays.34.wasm"
     },
     {
       "type": "module",
-      "line": 353,
+      "line": 355,
       "filename": "arrays.35.wasm"
     },
     {
       "type": "module",
-      "line": 362,
+      "line": 364,
       "filename": "arrays.36.wasm"
     },
     {
       "type": "module",
-      "line": 371,
+      "line": 373,
       "filename": "arrays.37.wasm"
     },
     {
       "type": "module",
-      "line": 380,
+      "line": 382,
       "filename": "arrays.38.wasm"
     },
     {
       "type": "module",
-      "line": 389,
+      "line": 391,
       "filename": "arrays.39.wasm"
     },
     {
       "type": "module",
-      "line": 398,
+      "line": 400,
       "filename": "arrays.40.wasm"
     },
     {
       "type": "module",
-      "line": 407,
+      "line": 409,
       "filename": "arrays.41.wasm"
     },
     {
       "type": "module",
-      "line": 416,
+      "line": 418,
       "filename": "arrays.42.wasm"
     },
     {
       "type": "module",
-      "line": 425,
+      "line": 427,
       "filename": "arrays.43.wasm"
     },
     {
       "type": "module",
-      "line": 434,
+      "line": 436,
       "filename": "arrays.44.wasm"
     },
     {
       "type": "module",
-      "line": 443,
+      "line": 445,
       "filename": "arrays.45.wasm"
     },
     {
       "type": "module",
-      "line": 452,
+      "line": 454,
       "filename": "arrays.46.wasm"
     },
     {
       "type": "module",
-      "line": 461,
+      "line": 463,
       "filename": "arrays.47.wasm"
     },
     {
       "type": "module",
-      "line": 470,
+      "line": 472,
       "filename": "arrays.48.wasm"
     },
     {
       "type": "module",
-      "line": 479,
+      "line": 481,
       "filename": "arrays.49.wasm"
     },
     {
       "type": "module",
-      "line": 488,
+      "line": 490,
       "filename": "arrays.50.wasm"
     },
     {
       "type": "module",
-      "line": 497,
+      "line": 499,
       "filename": "arrays.51.wasm"
     },
     {
       "type": "module",
-      "line": 506,
+      "line": 508,
       "filename": "arrays.52.wasm"
     },
     {
       "type": "module",
-      "line": 515,
+      "line": 517,
       "filename": "arrays.53.wasm"
     },
     {
       "type": "module",
-      "line": 524,
+      "line": 526,
       "filename": "arrays.54.wasm"
     },
     {
       "type": "module",
-      "line": 533,
+      "line": 535,
       "filename": "arrays.55.wasm"
     },
     {
       "type": "module",
-      "line": 542,
+      "line": 544,
       "filename": "arrays.56.wasm"
     },
     {
       "type": "module",
-      "line": 551,
+      "line": 553,
       "filename": "arrays.57.wasm"
     },
     {
       "type": "module",
-      "line": 560,
+      "line": 562,
       "filename": "arrays.58.wasm"
     },
     {
       "type": "module",
-      "line": 569,
+      "line": 571,
       "filename": "arrays.59.wasm"
     },
     {
       "type": "module",
-      "line": 578,
+      "line": 580,
       "filename": "arrays.60.wasm"
     },
     {
       "type": "module",
-      "line": 588,
+      "line": 589,
       "filename": "arrays.61.wasm"
     },
     {
@@ -328,107 +344,147 @@
     },
     {
       "type": "module",
-      "line": 608,
+      "line": 607,
       "filename": "arrays.63.wasm"
     },
     {
       "type": "module",
-      "line": 618,
+      "line": 616,
       "filename": "arrays.64.wasm"
     },
     {
       "type": "module",
-      "line": 628,
+      "line": 625,
       "filename": "arrays.65.wasm"
     },
+    {
+      "type": "module",
+      "line": 634,
+      "filename": "arrays.66.wasm"
+    },
+    {
+      "type": "module",
+      "line": 643,
+      "filename": "arrays.67.wasm"
+    },
+    {
+      "type": "module",
+      "line": 652,
+      "filename": "arrays.68.wasm"
+    },
+    {
+      "type": "module",
+      "line": 662,
+      "filename": "arrays.69.wasm"
+    },
+    {
+      "type": "module",
+      "line": 672,
+      "filename": "arrays.70.wasm"
+    },
+    {
+      "type": "module",
+      "line": 682,
+      "filename": "arrays.71.wasm"
+    },
+    {
+      "type": "module",
+      "line": 692,
+      "filename": "arrays.72.wasm"
+    },
+    {
+      "type": "module",
+      "line": 702,
+      "filename": "arrays.73.wasm"
+    },
     {
       "type": "assert_invalid",
-      "line": 639,
-      "filename": "arrays.66.wasm",
+      "line": 713,
+      "filename": "arrays.74.wasm",
       "text": "packed storage type",
       "module_type": "binary"
     },
     {
       "type": "assert_invalid",
-      "line": 649,
-      "filename": "arrays.67.wasm",
+      "line": 723,
+      "filename": "arrays.75.wasm",
       "text": "non-packed storage type",
       "module_type": "binary"
     },
     {
       "type": "assert_invalid",
-      "line": 659,
-      "filename": "arrays.68.wasm",
+      "line": 733,
+      "filename": "arrays.76.wasm",
       "text": "non-packed storage type",
       "module_type": "binary"
     },
     {
       "type": "assert_invalid",
-      "line": 669,
-      "filename": "arrays.69.wasm",
+      "line": 743,
+      "filename": "arrays.77.wasm",
       "text": "non-packed storage type",
       "module_type": "binary"
     },
     {
       "type": "assert_invalid",
-      "line": 679,
-      "filename": "arrays.70.wasm",
+      "line": 753,
+      "filename": "arrays.78.wasm",
       "text": "non-packed storage type",
       "module_type": "binary"
     },
     {
       "type": "assert_invalid",
-      "line": 689,
-      "filename": "arrays.71.wasm",
+      "line": 763,
+      "filename": "arrays.79.wasm",
       "text": "invalid type",
       "module_type": "binary"
     },
     {
       "type": "assert_invalid",
-      "line": 700,
-      "filename": "arrays.72.wasm",
+      "line": 774,
+      "filename": "arrays.80.wasm",
       "text": "invalid type",
       "module_type": "binary"
     },
     {
       "type": "assert_invalid",
-      "line": 711,
-      "filename": "arrays.73.wasm",
+      "line": 785,
+      "filename": "arrays.81.wasm",
       "text": "invalid type",
       "module_type": "binary"
     },
     {
       "type": "assert_invalid",
-      "line": 722,
-      "filename": "arrays.74.wasm",
+      "line": 796,
+      "filename": "arrays.82.wasm",
       "text": "invalid type",
       "module_type": "binary"
     },
     {
       "type": "assert_invalid",
-      "line": 733,
-      "filename": "arrays.75.wasm",
+      "line": 807,
+      "filename": "arrays.83.wasm",
       "text": "invalid type",
       "module_type": "binary"
     },
     {
       "type": "assert_invalid",
-      "line": 744,
-      "filename": "arrays.76.wasm",
+      "line": 818,
+      "filename": "arrays.84.wasm",
       "text": "invalid type",
       "module_type": "binary"
     },
     {
       "type": "assert_invalid",
-      "line": 755,
-      "filename": "arrays.77.wasm",
+      "line": 829,
+      "filename": "arrays.85.wasm",
       "text": "invalid type",
       "module_type": "binary"
     },
     {
       "type": "assert_invalid",
-      "line": 767,
-      "filename": "arrays.78.wasm",
+      "line": 841,
+      "filename": "arrays.86.wasm",
       "text": "invalid type",
       "module_type": "binary"
     }
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/10.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/10.print
deleted file mode 100644
index f3d308bd..00000000
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/10.print
+++ /dev/null
@@ -1,10 +0,0 @@
-(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/arrays.wast/11.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/11.print
deleted file mode 100644
index f733e005..00000000
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/11.print
+++ /dev/null
@@ -1,10 +0,0 @@
-(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/arrays.wast/12.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/12.print
deleted file mode 100644
index 76dbd3ec..00000000
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/12.print
+++ /dev/null
@@ -1,10 +0,0 @@
-(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/arrays.wast/13.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/13.print
deleted file mode 100644
index 5cf56083..00000000
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/13.print
+++ /dev/null
@@ -1,10 +0,0 @@
-(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/arrays.wast/14.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/14.print
deleted file mode 100644
index b4b3919e..00000000
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/14.print
+++ /dev/null
@@ -1,10 +0,0 @@
-(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/arrays.wast/15.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/15.print
deleted file mode 100644
index 189c2ea0..00000000
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/15.print
+++ /dev/null
@@ -1,10 +0,0 @@
-(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/arrays.wast/16.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/16.print
deleted file mode 100644
index 00e0b300..00000000
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/16.print
+++ /dev/null
@@ -1,10 +0,0 @@
-(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/arrays.wast/17.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/17.print
deleted file mode 100644
index 82d7db16..00000000
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/17.print
+++ /dev/null
@@ -1,10 +0,0 @@
-(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/arrays.wast/18.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/18.print
index 0794e778..f3d308bd 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/18.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/18.print
@@ -1,10 +1,10 @@
 (module
-  (type $a (;0;) (shared(array (mut i8))))
+  (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_s acq_rel $a
+    array.atomic.get seq_cst $a
   )
-  (export "array-atomic-get_s-i8-acq_rel" (func 0))
+  (export "array-atomic-get-i32-seq_cst" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/19.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/19.print
index f7a27cdc..f733e005 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/19.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/19.print
@@ -1,10 +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)
+  (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_s acq_rel $a
+    array.atomic.get seq_cst $a
   )
-  (export "array-atomic-get_s-i16-acq_rel" (func 0))
+  (export "array-atomic-get-i64-seq_cst" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/20.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/20.print
index 2ccc5994..76dbd3ec 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/20.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/20.print
@@ -1,10 +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)
+  (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_u seq_cst $a
+    array.atomic.get seq_cst $a
   )
-  (export "array-atomic-get_u-i8-seq_cst" (func 0))
+  (export "array-atomic-get-anyref-seq_cst" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/21.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/21.print
index 144068c5..5cf56083 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/21.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/21.print
@@ -1,10 +1,10 @@
 (module
-  (type $a (;0;) (shared(array (mut i16))))
+  (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_u seq_cst $a
+    array.atomic.get acq_rel $a
   )
-  (export "array-atomic-get_u-i16-seq_cst" (func 0))
+  (export "array-atomic-get-i32-acq_rel" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/22.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/22.print
index e5bed640..b4b3919e 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/22.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/22.print
@@ -1,10 +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)
+  (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_u acq_rel $a
+    array.atomic.get acq_rel $a
   )
-  (export "array-atomic-get_u-i8-acq_rel" (func 0))
+  (export "array-atomic-get-i64-acq_rel" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/23.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/23.print
index 069d3eb6..189c2ea0 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/23.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/23.print
@@ -1,10 +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)
+  (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_u acq_rel $a
+    array.atomic.get acq_rel $a
   )
-  (export "array-atomic-get_u-i16-acq_rel" (func 0))
+  (export "array-atomic-get-anyref-acq_rel" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/24.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/24.print
index b1727c32..00e0b300 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/24.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/24.print
@@ -1,11 +1,10 @@
 (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)
+  (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
-    local.get $z
-    array.atomic.set seq_cst $a
+    array.atomic.get_s seq_cst $a
   )
-  (export "array-atomic-set-i8-seq_cst" (func 0))
+  (export "array-atomic-get_s-i8-seq_cst" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/25.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/25.print
index 95641f94..82d7db16 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/25.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/25.print
@@ -1,11 +1,10 @@
 (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)
+  (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
-    local.get $z
-    array.atomic.set seq_cst $a
+    array.atomic.get_s seq_cst $a
   )
-  (export "array-atomic-set-i16-seq_cst" (func 0))
+  (export "array-atomic-get_s-i16-seq_cst" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/26.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/26.print
index b8e21b1a..0794e778 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/26.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/26.print
@@ -1,11 +1,10 @@
 (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)
+  (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
-    local.get $z
-    array.atomic.set seq_cst $a
+    array.atomic.get_s acq_rel $a
   )
-  (export "array-atomic-set-i32-seq_cst" (func 0))
+  (export "array-atomic-get_s-i8-acq_rel" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/27.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/27.print
index 6e11fb3a..f7a27cdc 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/27.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/27.print
@@ -1,11 +1,10 @@
 (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)
+  (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
-    local.get $z
-    array.atomic.set seq_cst $a
+    array.atomic.get_s acq_rel $a
   )
-  (export "array-atomic-set-i64-seq_cst" (func 0))
+  (export "array-atomic-get_s-i16-acq_rel" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/28.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/28.print
index db65bed1..2ccc5994 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/28.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/28.print
@@ -1,11 +1,10 @@
 (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)))
+  (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
-    local.get $z
-    array.atomic.set seq_cst $a
+    array.atomic.get_u seq_cst $a
   )
-  (export "array-atomic-set-anyref-seq_cst" (func 0))
+  (export "array-atomic-get_u-i8-seq_cst" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/29.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/29.print
index 941e3f0d..144068c5 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/29.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/29.print
@@ -1,11 +1,10 @@
 (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)
+  (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
-    local.get $z
-    array.atomic.set acq_rel $a
+    array.atomic.get_u seq_cst $a
   )
-  (export "array-atomic-set-i8-acq_rel" (func 0))
+  (export "array-atomic-get_u-i16-seq_cst" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/30.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/30.print
index 4e3d7c91..e5bed640 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/30.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/30.print
@@ -1,11 +1,10 @@
 (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)
+  (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
-    local.get $z
-    array.atomic.set acq_rel $a
+    array.atomic.get_u acq_rel $a
   )
-  (export "array-atomic-set-i16-acq_rel" (func 0))
+  (export "array-atomic-get_u-i8-acq_rel" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/31.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/31.print
index 17aec3ab..069d3eb6 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/31.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/31.print
@@ -1,11 +1,10 @@
 (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)
+  (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
-    local.get $z
-    array.atomic.set acq_rel $a
+    array.atomic.get_u acq_rel $a
   )
-  (export "array-atomic-set-i32-acq_rel" (func 0))
+  (export "array-atomic-get_u-i16-acq_rel" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/32.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/32.print
index 43139589..b1727c32 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/32.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/32.print
@@ -1,11 +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)
+  (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
+    array.atomic.set seq_cst $a
   )
-  (export "array-atomic-set-i64-acq_rel" (func 0))
+  (export "array-atomic-set-i8-seq_cst" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/33.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/33.print
index ed1acbaf..95641f94 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/33.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/33.print
@@ -1,11 +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)))
+  (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
+    array.atomic.set seq_cst $a
   )
-  (export "array-atomic-set-anyref-acq_rel" (func 0))
+  (export "array-atomic-set-i16-seq_cst" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/34.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/34.print
index d230670c..b8e21b1a 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/34.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/34.print
@@ -1,11 +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)
+  (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.rmw.add seq_cst $a
+    array.atomic.set seq_cst $a
   )
-  (export "array-atomic-rmw.add-i32-seq_cst" (func 0))
+  (export "array-atomic-set-i32-seq_cst" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/35.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/35.print
index 28ea1094..6e11fb3a 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/35.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/35.print
@@ -1,11 +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)
+  (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.rmw.add seq_cst $a
+    array.atomic.set seq_cst $a
   )
-  (export "array-atomic-rmw.add-i64-seq_cst" (func 0))
+  (export "array-atomic-set-i64-seq_cst" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/36.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/36.print
index 8cc27f27..db65bed1 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/36.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/36.print
@@ -1,11 +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)
+  (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.rmw.add acq_rel $a
+    array.atomic.set seq_cst $a
   )
-  (export "array-atomic-rmw.add-i32-acq_rel" (func 0))
+  (export "array-atomic-set-anyref-seq_cst" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/37.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/37.print
index 3be7d18d..941e3f0d 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/37.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/37.print
@@ -1,11 +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)
+  (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.rmw.add acq_rel $a
+    array.atomic.set acq_rel $a
   )
-  (export "array-atomic-rmw.add-i64-acq_rel" (func 0))
+  (export "array-atomic-set-i8-acq_rel" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/38.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/38.print
index 36af9d86..4e3d7c91 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/38.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/38.print
@@ -1,11 +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)
+  (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.rmw.sub seq_cst $a
+    array.atomic.set acq_rel $a
   )
-  (export "array-atomic-rmw.sub-i32-seq_cst" (func 0))
+  (export "array-atomic-set-i16-acq_rel" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/39.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/39.print
index 5bb94f29..17aec3ab 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/39.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/39.print
@@ -1,11 +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)
+  (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.rmw.sub seq_cst $a
+    array.atomic.set acq_rel $a
   )
-  (export "array-atomic-rmw.sub-i64-seq_cst" (func 0))
+  (export "array-atomic-set-i32-acq_rel" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/40.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/40.print
index 0b4badbb..43139589 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/40.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/40.print
@@ -1,11 +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)
+  (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.rmw.sub acq_rel $a
+    array.atomic.set acq_rel $a
   )
-  (export "array-atomic-rmw.sub-i32-acq_rel" (func 0))
+  (export "array-atomic-set-i64-acq_rel" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/41.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/41.print
index ba017726..ed1acbaf 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/41.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/41.print
@@ -1,11 +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)
+  (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.rmw.sub acq_rel $a
+    array.atomic.set acq_rel $a
   )
-  (export "array-atomic-rmw.sub-i64-acq_rel" (func 0))
+  (export "array-atomic-set-anyref-acq_rel" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/42.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/42.print
index 5c610307..d230670c 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/42.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/42.print
@@ -5,7 +5,7 @@
     local.get $x
     local.get $y
     local.get $z
-    array.atomic.rmw.and seq_cst $a
+    array.atomic.rmw.add seq_cst $a
   )
-  (export "array-atomic-rmw.and-i32-seq_cst" (func 0))
+  (export "array-atomic-rmw.add-i32-seq_cst" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/43.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/43.print
index 2edfd317..28ea1094 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/43.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/43.print
@@ -5,7 +5,7 @@
     local.get $x
     local.get $y
     local.get $z
-    array.atomic.rmw.and seq_cst $a
+    array.atomic.rmw.add seq_cst $a
   )
-  (export "array-atomic-rmw.and-i64-seq_cst" (func 0))
+  (export "array-atomic-rmw.add-i64-seq_cst" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/44.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/44.print
index 9a6e89fc..8cc27f27 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/44.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/44.print
@@ -5,7 +5,7 @@
     local.get $x
     local.get $y
     local.get $z
-    array.atomic.rmw.and acq_rel $a
+    array.atomic.rmw.add acq_rel $a
   )
-  (export "array-atomic-rmw.and-i32-acq_rel" (func 0))
+  (export "array-atomic-rmw.add-i32-acq_rel" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/45.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/45.print
index f82346cd..3be7d18d 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/45.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/45.print
@@ -5,7 +5,7 @@
     local.get $x
     local.get $y
     local.get $z
-    array.atomic.rmw.and acq_rel $a
+    array.atomic.rmw.add acq_rel $a
   )
-  (export "array-atomic-rmw.and-i64-acq_rel" (func 0))
+  (export "array-atomic-rmw.add-i64-acq_rel" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/46.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/46.print
index 59adfe73..36af9d86 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/46.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/46.print
@@ -5,7 +5,7 @@
     local.get $x
     local.get $y
     local.get $z
-    array.atomic.rmw.or seq_cst $a
+    array.atomic.rmw.sub seq_cst $a
   )
-  (export "array-atomic-rmw.or-i32-seq_cst" (func 0))
+  (export "array-atomic-rmw.sub-i32-seq_cst" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/47.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/47.print
index 13dd1118..5bb94f29 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/47.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/47.print
@@ -5,7 +5,7 @@
     local.get $x
     local.get $y
     local.get $z
-    array.atomic.rmw.or seq_cst $a
+    array.atomic.rmw.sub seq_cst $a
   )
-  (export "array-atomic-rmw.or-i64-seq_cst" (func 0))
+  (export "array-atomic-rmw.sub-i64-seq_cst" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/48.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/48.print
index ffca25c4..0b4badbb 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/48.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/48.print
@@ -5,7 +5,7 @@
     local.get $x
     local.get $y
     local.get $z
-    array.atomic.rmw.or acq_rel $a
+    array.atomic.rmw.sub acq_rel $a
   )
-  (export "array-atomic-rmw.or-i32-acq_rel" (func 0))
+  (export "array-atomic-rmw.sub-i32-acq_rel" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/49.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/49.print
index 94fbc49c..ba017726 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/49.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/49.print
@@ -5,7 +5,7 @@
     local.get $x
     local.get $y
     local.get $z
-    array.atomic.rmw.or acq_rel $a
+    array.atomic.rmw.sub acq_rel $a
   )
-  (export "array-atomic-rmw.or-i64-acq_rel" (func 0))
+  (export "array-atomic-rmw.sub-i64-acq_rel" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/50.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/50.print
index 0e6016a7..5c610307 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/50.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/50.print
@@ -5,7 +5,7 @@
     local.get $x
     local.get $y
     local.get $z
-    array.atomic.rmw.xor seq_cst $a
+    array.atomic.rmw.and seq_cst $a
   )
-  (export "array-atomic-rmw.xor-i32-seq_cst" (func 0))
+  (export "array-atomic-rmw.and-i32-seq_cst" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/51.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/51.print
index 446233a0..2edfd317 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/51.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/51.print
@@ -5,7 +5,7 @@
     local.get $x
     local.get $y
     local.get $z
-    array.atomic.rmw.xor seq_cst $a
+    array.atomic.rmw.and seq_cst $a
   )
-  (export "array-atomic-rmw.xor-i64-seq_cst" (func 0))
+  (export "array-atomic-rmw.and-i64-seq_cst" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/52.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/52.print
index 78670261..9a6e89fc 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/52.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/52.print
@@ -5,7 +5,7 @@
     local.get $x
     local.get $y
     local.get $z
-    array.atomic.rmw.xor acq_rel $a
+    array.atomic.rmw.and acq_rel $a
   )
-  (export "array-atomic-rmw.xor-i32-acq_rel" (func 0))
+  (export "array-atomic-rmw.and-i32-acq_rel" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/53.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/53.print
index 1e8eb5b9..f82346cd 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/53.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/53.print
@@ -5,7 +5,7 @@
     local.get $x
     local.get $y
     local.get $z
-    array.atomic.rmw.xor acq_rel $a
+    array.atomic.rmw.and acq_rel $a
   )
-  (export "array-atomic-rmw.xor-i64-acq_rel" (func 0))
+  (export "array-atomic-rmw.and-i64-acq_rel" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/54.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/54.print
index 71e2c7a8..59adfe73 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/54.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/54.print
@@ -5,7 +5,7 @@
     local.get $x
     local.get $y
     local.get $z
-    array.atomic.rmw.xchg seq_cst $a
+    array.atomic.rmw.or seq_cst $a
   )
-  (export "array-atomic-rmw.xchg-i32-seq_cst" (func 0))
+  (export "array-atomic-rmw.or-i32-seq_cst" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/55.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/55.print
index 1770c968..13dd1118 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/55.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/55.print
@@ -5,7 +5,7 @@
     local.get $x
     local.get $y
     local.get $z
-    array.atomic.rmw.xchg seq_cst $a
+    array.atomic.rmw.or seq_cst $a
   )
-  (export "array-atomic-rmw.xchg-i64-seq_cst" (func 0))
+  (export "array-atomic-rmw.or-i64-seq_cst" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/56.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/56.print
index 6ca3ea80..ffca25c4 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/56.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/56.print
@@ -1,11 +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)))
+  (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
+    array.atomic.rmw.or acq_rel $a
   )
-  (export "array-atomic-rmw.xchg-anyref-seq_cst" (func 0))
+  (export "array-atomic-rmw.or-i32-acq_rel" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/57.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/57.print
index 2a03171e..94fbc49c 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/57.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/57.print
@@ -1,11 +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)
+  (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
+    array.atomic.rmw.or acq_rel $a
   )
-  (export "array-atomic-rmw.xchg-i32-acq_rel" (func 0))
+  (export "array-atomic-rmw.or-i64-acq_rel" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/58.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/58.print
index 61852120..0e6016a7 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/58.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/58.print
@@ -1,11 +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)
+  (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
+    array.atomic.rmw.xor seq_cst $a
   )
-  (export "array-atomic-rmw.xchg-i64-acq_rel" (func 0))
+  (export "array-atomic-rmw.xor-i32-seq_cst" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/59.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/59.print
index 2670aba6..446233a0 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/59.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/59.print
@@ -1,11 +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)))
+  (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
+    array.atomic.rmw.xor seq_cst $a
   )
-  (export "array-atomic-rmw.xchg-anyref-acq_rel" (func 0))
+  (export "array-atomic-rmw.xor-i64-seq_cst" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/60.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/60.print
index 9b4ed0ec..78670261 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/60.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/60.print
@@ -1,12 +1,11 @@
 (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)
+  (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
-    local.get $A
-    array.atomic.rmw.cmpxchg seq_cst $a
+    array.atomic.rmw.xor acq_rel $a
   )
-  (export "array-atomic-rmw.cmpxchg-i32-seq_cst" (func 0))
+  (export "array-atomic-rmw.xor-i32-acq_rel" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/61.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/61.print
index f485f7a7..1e8eb5b9 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/61.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/61.print
@@ -1,12 +1,11 @@
 (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)
+  (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
-    local.get $A
-    array.atomic.rmw.cmpxchg seq_cst $a
+    array.atomic.rmw.xor acq_rel $a
   )
-  (export "array-atomic-rmw.cmpxchg-i64-seq_cst" (func 0))
+  (export "array-atomic-rmw.xor-i64-acq_rel" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/62.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/62.print
index c9be7ed8..71e2c7a8 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/62.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/62.print
@@ -1,12 +1,11 @@
 (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)))
+  (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
-    local.get $A
-    array.atomic.rmw.cmpxchg seq_cst $a
+    array.atomic.rmw.xchg seq_cst $a
   )
-  (export "array-atomic-rmw.cmpxchg-eqref-seq_cst" (func 0))
+  (export "array-atomic-rmw.xchg-i32-seq_cst" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/63.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/63.print
index 15e7ca30..1770c968 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/63.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/63.print
@@ -1,12 +1,11 @@
 (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)
+  (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
-    local.get $A
-    array.atomic.rmw.cmpxchg acq_rel $a
+    array.atomic.rmw.xchg seq_cst $a
   )
-  (export "array-atomic-rmw.cmpxchg-i32-acq_rel" (func 0))
+  (export "array-atomic-rmw.xchg-i64-seq_cst" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/64.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/64.print
index 7bce20ed..6ca3ea80 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/64.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/64.print
@@ -1,12 +1,11 @@
 (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)
+  (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
-    local.get $A
-    array.atomic.rmw.cmpxchg acq_rel $a
+    array.atomic.rmw.xchg seq_cst $a
   )
-  (export "array-atomic-rmw.cmpxchg-i64-acq_rel" (func 0))
+  (export "array-atomic-rmw.xchg-anyref-seq_cst" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/65.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/65.print
index d6118598..2a03171e 100644
--- a/tests/snapshots/local/shared-everything-threads/arrays.wast/65.print
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/65.print
@@ -1,12 +1,11 @@
 (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)))
+  (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
-    local.get $A
-    array.atomic.rmw.cmpxchg acq_rel $a
+    array.atomic.rmw.xchg acq_rel $a
   )
-  (export "array-atomic-rmw.cmpxchg-eqref-acq_rel" (func 0))
+  (export "array-atomic-rmw.xchg-i32-acq_rel" (func 0))
 )
diff --git a/tests/snapshots/local/shared-everything-threads/arrays.wast/66.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/66.print
new file mode 100644
index 00000000..61852120
--- /dev/null
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/66.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/arrays.wast/67.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/67.print
new file mode 100644
index 00000000..2670aba6
--- /dev/null
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/67.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/arrays.wast/68.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/68.print
new file mode 100644
index 00000000..9b4ed0ec
--- /dev/null
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/68.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/arrays.wast/69.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/69.print
new file mode 100644
index 00000000..f485f7a7
--- /dev/null
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/69.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/arrays.wast/70.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/70.print
new file mode 100644
index 00000000..c9be7ed8
--- /dev/null
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/70.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/arrays.wast/71.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/71.print
new file mode 100644
index 00000000..15e7ca30
--- /dev/null
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/71.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/arrays.wast/72.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/72.print
new file mode 100644
index 00000000..7bce20ed
--- /dev/null
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/72.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/arrays.wast/73.print b/tests/snapshots/local/shared-everything-threads/arrays.wast/73.print
new file mode 100644
index 00000000..d6118598
--- /dev/null
+++ b/tests/snapshots/local/shared-everything-threads/arrays.wast/73.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/structs.wast.json b/tests/snapshots/local/shared-everything-threads/structs.wast.json
index 2cc841de..0a68ac7d 100644
--- a/tests/snapshots/local/shared-everything-threads/structs.wast.json
+++ b/tests/snapshots/local/shared-everything-threads/structs.wast.json
@@ -62,98 +62,154 @@
       "filename": "structs.9.wasm"
     },
     {
-      "type": "module",
-      "line": 103,
-      "filename": "structs.10.wasm"
+      "type": "assert_invalid",
+      "line": 104,
+      "filename": "structs.10.wasm",
+      "text": "field is immutable",
+      "module_type": "binary"
     },
     {
       "type": "assert_invalid",
-      "line": 330,
+      "line": 113,
       "filename": "structs.11.wasm",
-      "text": "non-packed storage type",
+      "text": "field is immutable",
       "module_type": "binary"
     },
     {
       "type": "assert_invalid",
-      "line": 339,
+      "line": 122,
       "filename": "structs.12.wasm",
-      "text": "non-packed storage types",
+      "text": "field is immutable",
       "module_type": "binary"
     },
     {
       "type": "assert_invalid",
-      "line": 348,
+      "line": 131,
       "filename": "structs.13.wasm",
-      "text": "non-packed storage types",
+      "text": "field is immutable",
       "module_type": "binary"
     },
     {
       "type": "assert_invalid",
-      "line": 357,
+      "line": 140,
       "filename": "structs.14.wasm",
-      "text": "non-packed storage types",
+      "text": "field is immutable",
       "module_type": "binary"
     },
     {
       "type": "assert_invalid",
-      "line": 366,
+      "line": 149,
       "filename": "structs.15.wasm",
-      "text": "non-packed storage types",
+      "text": "field is immutable",
       "module_type": "binary"
     },
     {
       "type": "assert_invalid",
-      "line": 375,
+      "line": 158,
       "filename": "structs.16.wasm",
-      "text": "invalid type",
+      "text": "field is immutable",
       "module_type": "binary"
     },
     {
       "type": "assert_invalid",
-      "line": 385,
+      "line": 167,
       "filename": "structs.17.wasm",
+      "text": "field is immutable",
+      "module_type": "binary"
+    },
+    {
+      "type": "module",
+      "line": 177,
+      "filename": "structs.18.wasm"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 404,
+      "filename": "structs.19.wasm",
+      "text": "non-packed storage type",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 413,
+      "filename": "structs.20.wasm",
+      "text": "non-packed storage types",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 422,
+      "filename": "structs.21.wasm",
+      "text": "non-packed storage types",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 431,
+      "filename": "structs.22.wasm",
+      "text": "non-packed storage types",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 440,
+      "filename": "structs.23.wasm",
+      "text": "non-packed storage types",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 449,
+      "filename": "structs.24.wasm",
       "text": "invalid type",
       "module_type": "binary"
     },
     {
       "type": "assert_invalid",
-      "line": 395,
-      "filename": "structs.18.wasm",
+      "line": 459,
+      "filename": "structs.25.wasm",
       "text": "invalid type",
       "module_type": "binary"
     },
     {
       "type": "assert_invalid",
-      "line": 405,
-      "filename": "structs.19.wasm",
+      "line": 469,
+      "filename": "structs.26.wasm",
       "text": "invalid type",
       "module_type": "binary"
     },
     {
       "type": "assert_invalid",
-      "line": 415,
-      "filename": "structs.20.wasm",
+      "line": 479,
+      "filename": "structs.27.wasm",
       "text": "invalid type",
       "module_type": "binary"
     },
     {
       "type": "assert_invalid",
-      "line": 425,
-      "filename": "structs.21.wasm",
+      "line": 489,
+      "filename": "structs.28.wasm",
       "text": "invalid type",
       "module_type": "binary"
     },
     {
       "type": "assert_invalid",
-      "line": 435,
-      "filename": "structs.22.wasm",
+      "line": 499,
+      "filename": "structs.29.wasm",
       "text": "invalid type",
       "module_type": "binary"
     },
     {
       "type": "assert_invalid",
-      "line": 446,
-      "filename": "structs.23.wasm",
+      "line": 509,
+      "filename": "structs.30.wasm",
+      "text": "invalid type",
+      "module_type": "binary"
+    },
+    {
+      "type": "assert_invalid",
+      "line": 520,
+      "filename": "structs.31.wasm",
       "text": "invalid type",
       "module_type": "binary"
     }