From d99b51d8ae09b267a12b573734f9eaee3807a129 Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Thu, 7 Nov 2024 14:17:37 -0800 Subject: [PATCH] threads: add validation for global constant expressions Previously, it was possible to use an unshared global to initialize a shared global, table element. This change makes that invalid by propagating sharedness in to the constant expression validator. --- crates/wasmparser/src/validator/core.rs | 54 +++++++-- .../shared-everything-threads/globals.wast | 12 ++ .../shared-everything-threads/tables.wast | 17 +++ .../globals.wast.json | 113 ++++++++++-------- .../globals.wast/1.print | 4 + .../globals.wast/{23.print => 25.print} | 0 .../globals.wast/{24.print => 26.print} | 0 .../globals.wast/30.print | 3 +- .../globals.wast/{28.print => 32.print} | 3 +- .../globals.wast/{3.print => 5.print} | 0 .../tables.wast.json | 33 +++-- .../tables.wast/{8.print => 10.print} | 0 .../tables.wast/7.print | 106 +--------------- .../tables.wast/9.print | 104 ++++++++++++++++ 14 files changed, 275 insertions(+), 174 deletions(-) create mode 100644 tests/snapshots/local/shared-everything-threads/globals.wast/1.print rename tests/snapshots/local/shared-everything-threads/globals.wast/{23.print => 25.print} (100%) rename tests/snapshots/local/shared-everything-threads/globals.wast/{24.print => 26.print} (100%) rename tests/snapshots/local/shared-everything-threads/globals.wast/{28.print => 32.print} (69%) rename tests/snapshots/local/shared-everything-threads/globals.wast/{3.print => 5.print} (100%) rename tests/snapshots/local/shared-everything-threads/tables.wast/{8.print => 10.print} (100%) create mode 100644 tests/snapshots/local/shared-everything-threads/tables.wast/9.print diff --git a/crates/wasmparser/src/validator/core.rs b/crates/wasmparser/src/validator/core.rs index 68e56c5552..4ac44a71e4 100644 --- a/crates/wasmparser/src/validator/core.rs +++ b/crates/wasmparser/src/validator/core.rs @@ -133,7 +133,13 @@ impl ModuleState { ) -> Result<()> { self.module .check_global_type(&mut global.ty, features, types, offset)?; - self.check_const_expr(&global.init_expr, global.ty.content_type, features, types)?; + self.check_const_expr( + &global.init_expr, + global.ty.content_type, + global.ty.shared, + features, + types, + )?; self.module.assert_mut().globals.push(global.ty); Ok(()) } @@ -162,7 +168,13 @@ impl ModuleState { the function-references proposal" ); } - self.check_const_expr(expr, table.ty.element_type.into(), features, types)?; + self.check_const_expr( + expr, + table.ty.element_type.into(), + table.ty.shared, + features, + types, + )?; } } self.module.assert_mut().tables.push(table.ty); @@ -182,8 +194,8 @@ impl ModuleState { memory_index, offset_expr, } => { - let ty = self.module.memory_at(memory_index, offset)?.index_type(); - self.check_const_expr(&offset_expr, ty, features, types) + let ty = self.module.memory_at(memory_index, offset)?; + self.check_const_expr(&offset_expr, ty.index_type(), ty.shared, features, types) } } } @@ -195,8 +207,8 @@ impl ModuleState { types: &TypeList, offset: usize, ) -> Result<()> { - // the `funcref` value type is allowed all the way back to the MVP, so - // don't check it here + // The `funcref` value type is allowed all the way back to the MVP, so + // don't check it here. let element_ty = match &mut e.items { crate::ElementItems::Functions(_) => RefType::FUNC, crate::ElementItems::Expressions(ty, _) => { @@ -221,8 +233,13 @@ impl ModuleState { offset, )); } - - self.check_const_expr(&offset_expr, table.index_type(), features, types)?; + self.check_const_expr( + &offset_expr, + table.index_type(), + table.shared, + features, + types, + )?; } ElementKind::Passive | ElementKind::Declared => { if !features.bulk_memory() { @@ -256,8 +273,18 @@ impl ModuleState { } crate::ElementItems::Expressions(ty, reader) => { validate_count(reader.count())?; + let shared = match ty.heap_type() { + HeapType::Abstract { shared, .. } => shared, + HeapType::Concrete(unpacked_index) => { + if let Some(id) = unpacked_index.as_core_type_id() { + types[id].composite_type.shared + } else { + todo!() + } + } + }; for expr in reader { - self.check_const_expr(&expr?, ValType::Ref(ty), features, types)?; + self.check_const_expr(&expr?, ValType::Ref(ty), shared, features, types)?; } } } @@ -269,6 +296,7 @@ impl ModuleState { &mut self, expr: &ConstExpr<'_>, expected_ty: ValType, + shared: bool, features: &WasmFeatures, types: &TypeList, ) -> Result<()> { @@ -286,6 +314,7 @@ impl ModuleState { module: &mut self.module, }, features, + shared, }; let mut ops = expr.get_operators_reader(); @@ -309,6 +338,7 @@ impl ModuleState { resources: OperatorValidatorResources<'a>, order: Order, features: &'a WasmFeatures, + shared: bool, } impl VisitConstOperator<'_> { @@ -374,6 +404,12 @@ impl ModuleState { self.offset, )); } + if self.shared && !global.shared { + return Err(BinaryReaderError::new( + "invalid type: constant expression must be shared", + self.offset, + )); + } Ok(()) } diff --git a/tests/local/shared-everything-threads/globals.wast b/tests/local/shared-everything-threads/globals.wast index 857a0bda7a..c69950d56f 100644 --- a/tests/local/shared-everything-threads/globals.wast +++ b/tests/local/shared-everything-threads/globals.wast @@ -26,6 +26,18 @@ (global (shared mut v128) (v128.const i64x2 0 0)) ) +;; Check that we can only use shared globals to initialize other shared globals. +(module + (global $a (shared i32) (i32.const 0)) + (global $b (shared i32) (global.get $a)) +) +(assert_invalid + (module + (global $a i32 (i32.const 0)) + (global $b (shared i32) (global.get $a)) + ) + "invalid type") + (assert_malformed (module quote "(global (mut shared i64) (i64.const -1))") "unexpected token") diff --git a/tests/local/shared-everything-threads/tables.wast b/tests/local/shared-everything-threads/tables.wast index d293a29203..b9bb2a60de 100644 --- a/tests/local/shared-everything-threads/tables.wast +++ b/tests/local/shared-everything-threads/tables.wast @@ -42,6 +42,23 @@ (table shared 0 (ref $t))) "shared tables must have a shared element type") +;; A shared table must be initialized from shared objects. +(module + (type $f (shared (func))) + (global $g (shared (ref null $f)) (ref.null $f)) + (table $t shared 1 (ref null $f)) + (elem (ref null $f) (global.get $g)) +) +(assert_invalid + (module + (type $f (shared (func))) + (global $g (ref null $f) (ref.null $f)) + (table $t shared 1 (ref null $f)) + ;; When we initialize a shared element, everything must be shared, including + ;; the used global. + (elem (ref null $f) (global.get $g))) + "invalid type") + ;; Check `table.atomic.*` instructions. (module (;eq;) (table $a (import "spectest" "table_eq") shared 1 (ref null (shared eq))) diff --git a/tests/snapshots/local/shared-everything-threads/globals.wast.json b/tests/snapshots/local/shared-everything-threads/globals.wast.json index 75f4d83c24..b760c01701 100644 --- a/tests/snapshots/local/shared-everything-threads/globals.wast.json +++ b/tests/snapshots/local/shared-everything-threads/globals.wast.json @@ -8,208 +8,221 @@ "module_type": "binary" }, { - "type": "assert_malformed", + "type": "module", "line": 30, - "filename": "globals.1.wat", - "module_type": "text", - "text": "unexpected token" + "filename": "globals.1.wasm", + "module_type": "binary" }, { "type": "assert_invalid", - "line": 34, + "line": 35, "filename": "globals.2.wasm", "module_type": "binary", - "text": "shared value type" + "text": "invalid type" }, { - "type": "module", - "line": 38, - "filename": "globals.3.wasm", - "module_type": "binary" + "type": "assert_malformed", + "line": 42, + "filename": "globals.3.wat", + "module_type": "text", + "text": "unexpected token" }, { "type": "assert_invalid", - "line": 51, + "line": 46, "filename": "globals.4.wasm", "module_type": "binary", - "text": "global is immutable" + "text": "shared value type" }, { - "type": "assert_invalid", - "line": 58, + "type": "module", + "line": 50, "filename": "globals.5.wasm", - "module_type": "binary", - "text": "invalid type" + "module_type": "binary" }, { "type": "assert_invalid", - "line": 65, + "line": 63, "filename": "globals.6.wasm", "module_type": "binary", - "text": "invalid type" + "text": "global is immutable" }, { "type": "assert_invalid", - "line": 72, + "line": 70, "filename": "globals.7.wasm", "module_type": "binary", "text": "invalid type" }, { "type": "assert_invalid", - "line": 79, + "line": 77, "filename": "globals.8.wasm", "module_type": "binary", "text": "invalid type" }, { "type": "assert_invalid", - "line": 86, + "line": 84, "filename": "globals.9.wasm", "module_type": "binary", "text": "invalid type" }, { "type": "assert_invalid", - "line": 93, + "line": 91, "filename": "globals.10.wasm", "module_type": "binary", "text": "invalid type" }, { "type": "assert_invalid", - "line": 100, + "line": 98, "filename": "globals.11.wasm", "module_type": "binary", "text": "invalid type" }, { "type": "assert_invalid", - "line": 107, + "line": 105, "filename": "globals.12.wasm", "module_type": "binary", "text": "invalid type" }, { "type": "assert_invalid", - "line": 114, + "line": 112, "filename": "globals.13.wasm", "module_type": "binary", "text": "invalid type" }, { "type": "assert_invalid", - "line": 121, + "line": 119, "filename": "globals.14.wasm", "module_type": "binary", "text": "invalid type" }, { "type": "assert_invalid", - "line": 128, + "line": 126, "filename": "globals.15.wasm", "module_type": "binary", "text": "invalid type" }, { "type": "assert_invalid", - "line": 135, + "line": 133, "filename": "globals.16.wasm", "module_type": "binary", "text": "invalid type" }, { "type": "assert_invalid", - "line": 142, + "line": 140, "filename": "globals.17.wasm", "module_type": "binary", "text": "invalid type" }, { "type": "assert_invalid", - "line": 149, + "line": 147, "filename": "globals.18.wasm", "module_type": "binary", "text": "invalid type" }, { "type": "assert_invalid", - "line": 156, + "line": 154, "filename": "globals.19.wasm", "module_type": "binary", "text": "invalid type" }, { "type": "assert_invalid", - "line": 163, + "line": 161, "filename": "globals.20.wasm", "module_type": "binary", "text": "invalid type" }, { "type": "assert_invalid", - "line": 170, + "line": 168, "filename": "globals.21.wasm", "module_type": "binary", "text": "invalid type" }, { "type": "assert_invalid", - "line": 177, + "line": 175, "filename": "globals.22.wasm", "module_type": "binary", "text": "invalid type" }, { - "type": "module", - "line": 184, + "type": "assert_invalid", + "line": 182, "filename": "globals.23.wasm", + "module_type": "binary", + "text": "invalid type" + }, + { + "type": "assert_invalid", + "line": 189, + "filename": "globals.24.wasm", + "module_type": "binary", + "text": "invalid type" + }, + { + "type": "module", + "line": 196, + "filename": "globals.25.wasm", "module_type": "binary" }, { "type": "module", - "line": 277, - "filename": "globals.24.wasm", + "line": 289, + "filename": "globals.26.wasm", "module_type": "binary" }, { "type": "assert_invalid", - "line": 371, - "filename": "globals.25.wasm", + "line": 383, + "filename": "globals.27.wasm", "module_type": "binary", "text": "invalid type: `global.atomic.rmw.*` only allows `i32` and `i64`" }, { "type": "assert_invalid", - "line": 382, - "filename": "globals.26.wasm", + "line": 394, + "filename": "globals.28.wasm", "module_type": "binary", "text": "global index out of bounds" }, { "type": "assert_invalid", - "line": 390, - "filename": "globals.27.wasm", + "line": 402, + "filename": "globals.29.wasm", "module_type": "binary", "text": "invalid type: `global.atomic.rmw.xchg` only allows `i32`, `i64` and subtypes of `anyref`" }, { "type": "module", - "line": 400, - "filename": "globals.28.wasm", + "line": 412, + "filename": "globals.30.wasm", "module_type": "binary" }, { "type": "assert_invalid", - "line": 410, - "filename": "globals.29.wasm", + "line": 422, + "filename": "globals.31.wasm", "module_type": "binary", "text": "invalid type: `global.atomic.rmw.cmpxchg` only allows `i32`, `i64` and subtypes of `eqref`" }, { "type": "module", - "line": 421, - "filename": "globals.30.wasm", + "line": 433, + "filename": "globals.32.wasm", "module_type": "binary" } ] diff --git a/tests/snapshots/local/shared-everything-threads/globals.wast/1.print b/tests/snapshots/local/shared-everything-threads/globals.wast/1.print new file mode 100644 index 0000000000..96f6eefbb8 --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/globals.wast/1.print @@ -0,0 +1,4 @@ +(module + (global $a (;0;) (shared i32) i32.const 0) + (global $b (;1;) (shared i32) global.get $a) +) diff --git a/tests/snapshots/local/shared-everything-threads/globals.wast/23.print b/tests/snapshots/local/shared-everything-threads/globals.wast/25.print similarity index 100% rename from tests/snapshots/local/shared-everything-threads/globals.wast/23.print rename to tests/snapshots/local/shared-everything-threads/globals.wast/25.print diff --git a/tests/snapshots/local/shared-everything-threads/globals.wast/24.print b/tests/snapshots/local/shared-everything-threads/globals.wast/26.print similarity index 100% rename from tests/snapshots/local/shared-everything-threads/globals.wast/24.print rename to tests/snapshots/local/shared-everything-threads/globals.wast/26.print diff --git a/tests/snapshots/local/shared-everything-threads/globals.wast/30.print b/tests/snapshots/local/shared-everything-threads/globals.wast/30.print index f4aeb6f5da..e5522d46e8 100644 --- a/tests/snapshots/local/shared-everything-threads/globals.wast/30.print +++ b/tests/snapshots/local/shared-everything-threads/globals.wast/30.print @@ -3,8 +3,7 @@ (global $g (;0;) (mut eqref) ref.null eq) (func (;0;) (type 0) ref.null eq - ref.null eq - global.atomic.rmw.cmpxchg acq_rel $g + global.atomic.rmw.xchg acq_rel $g drop ) ) diff --git a/tests/snapshots/local/shared-everything-threads/globals.wast/28.print b/tests/snapshots/local/shared-everything-threads/globals.wast/32.print similarity index 69% rename from tests/snapshots/local/shared-everything-threads/globals.wast/28.print rename to tests/snapshots/local/shared-everything-threads/globals.wast/32.print index e5522d46e8..f4aeb6f5da 100644 --- a/tests/snapshots/local/shared-everything-threads/globals.wast/28.print +++ b/tests/snapshots/local/shared-everything-threads/globals.wast/32.print @@ -3,7 +3,8 @@ (global $g (;0;) (mut eqref) ref.null eq) (func (;0;) (type 0) ref.null eq - global.atomic.rmw.xchg acq_rel $g + ref.null eq + global.atomic.rmw.cmpxchg acq_rel $g drop ) ) diff --git a/tests/snapshots/local/shared-everything-threads/globals.wast/3.print b/tests/snapshots/local/shared-everything-threads/globals.wast/5.print similarity index 100% rename from tests/snapshots/local/shared-everything-threads/globals.wast/3.print rename to tests/snapshots/local/shared-everything-threads/globals.wast/5.print diff --git a/tests/snapshots/local/shared-everything-threads/tables.wast.json b/tests/snapshots/local/shared-everything-threads/tables.wast.json index fbfecb0c65..4ca999024c 100644 --- a/tests/snapshots/local/shared-everything-threads/tables.wast.json +++ b/tests/snapshots/local/shared-everything-threads/tables.wast.json @@ -55,36 +55,49 @@ "module_type": "binary" }, { - "type": "module", - "line": 115, + "type": "assert_invalid", + "line": 53, "filename": "tables.8.wasm", + "module_type": "binary", + "text": "invalid type" + }, + { + "type": "module", + "line": 63, + "filename": "tables.9.wasm", + "module_type": "binary" + }, + { + "type": "module", + "line": 132, + "filename": "tables.10.wasm", "module_type": "binary" }, { "type": "assert_invalid", - "line": 167, - "filename": "tables.9.wasm", + "line": 184, + "filename": "tables.11.wasm", "module_type": "binary", "text": "invalid type" }, { "type": "assert_invalid", - "line": 177, - "filename": "tables.10.wasm", + "line": 194, + "filename": "tables.12.wasm", "module_type": "binary", "text": "invalid type: `table.atomic.get` only allows subtypes of `anyref`" }, { "type": "assert_invalid", - "line": 187, - "filename": "tables.11.wasm", + "line": 204, + "filename": "tables.13.wasm", "module_type": "binary", "text": "invalid type: `table.atomic.set` only allows subtypes of `anyref`" }, { "type": "assert_invalid", - "line": 198, - "filename": "tables.12.wasm", + "line": 215, + "filename": "tables.14.wasm", "module_type": "binary", "text": "invalid type: `table.atomic.rmw.xchg` only allows subtypes of `anyref`" } diff --git a/tests/snapshots/local/shared-everything-threads/tables.wast/8.print b/tests/snapshots/local/shared-everything-threads/tables.wast/10.print similarity index 100% rename from tests/snapshots/local/shared-everything-threads/tables.wast/8.print rename to tests/snapshots/local/shared-everything-threads/tables.wast/10.print diff --git a/tests/snapshots/local/shared-everything-threads/tables.wast/7.print b/tests/snapshots/local/shared-everything-threads/tables.wast/7.print index a5cc97fc5e..a671d7d0d1 100644 --- a/tests/snapshots/local/shared-everything-threads/tables.wast/7.print +++ b/tests/snapshots/local/shared-everything-threads/tables.wast/7.print @@ -1,104 +1,6 @@ (module - (type (;0;) (func (param i32) (result (ref null (shared eq))))) - (type (;1;) (func (param i32 (ref null (shared eq))))) - (type (;2;) (func (param i32 (ref null (shared eq))) (result (ref null (shared eq))))) - (type (;3;) (func (param i32 (ref null (shared eq)) (ref null (shared eq))) (result (ref null (shared eq))))) - (import "spectest" "table_eq" (table $a (;0;) shared 1 (ref null (shared eq)))) - (table $b (;1;) shared 1 (ref null (shared eq))) - (export "table-atomic-get-eq-seq_cst-$a" (func 0)) - (export "table-atomic-get-eq-seq_cst-$b" (func 1)) - (export "table-atomic-get-eq-acq_rel-$a" (func 2)) - (export "table-atomic-get-eq-acq_rel-$b" (func 3)) - (export "table-atomic-set-eq-seq_cst-$a" (func 4)) - (export "table-atomic-set-eq-seq_cst-$b" (func 5)) - (export "table-atomic-set-eq-acq_rel-$a" (func 6)) - (export "table-atomic-set-eq-acq_rel-$b" (func 7)) - (export "table-atomic-rmw.xchg-eq-seq_cst-$a" (func 8)) - (export "table-atomic-rmw.xchg-eq-seq_cst-$b" (func 9)) - (export "table-atomic-rmw.xchg-eq-acq_rel-$a" (func 10)) - (export "table-atomic-rmw.xchg-eq-acq_rel-$b" (func 11)) - (export "table-atomic-rmw.cmpxchg-eq-seq_cst-$a" (func 12)) - (export "table-atomic-rmw.cmpxchg-eq-seq_cst-$b" (func 13)) - (export "table-atomic-rmw.cmpxchg-eq-acq_rel-$a" (func 14)) - (export "table-atomic-rmw.cmpxchg-eq-acq_rel-$b" (func 15)) - (func (;0;) (type 0) (param $x i32) (result (ref null (shared eq))) - local.get $x - table.atomic.get seq_cst $a - ) - (func (;1;) (type 0) (param $x i32) (result (ref null (shared eq))) - local.get $x - table.atomic.get seq_cst $b - ) - (func (;2;) (type 0) (param $x i32) (result (ref null (shared eq))) - local.get $x - table.atomic.get acq_rel $a - ) - (func (;3;) (type 0) (param $x i32) (result (ref null (shared eq))) - local.get $x - table.atomic.get acq_rel $b - ) - (func (;4;) (type 1) (param $x i32) (param $y (ref null (shared eq))) - local.get $x - local.get $y - table.atomic.set seq_cst $a - ) - (func (;5;) (type 1) (param $x i32) (param $y (ref null (shared eq))) - local.get $x - local.get $y - table.atomic.set seq_cst $b - ) - (func (;6;) (type 1) (param $x i32) (param $y (ref null (shared eq))) - local.get $x - local.get $y - table.atomic.set acq_rel $a - ) - (func (;7;) (type 1) (param $x i32) (param $y (ref null (shared eq))) - local.get $x - local.get $y - table.atomic.set acq_rel $b - ) - (func (;8;) (type 2) (param $x i32) (param $y (ref null (shared eq))) (result (ref null (shared eq))) - local.get $x - local.get $y - table.atomic.rmw.xchg seq_cst $a - ) - (func (;9;) (type 2) (param $x i32) (param $y (ref null (shared eq))) (result (ref null (shared eq))) - local.get $x - local.get $y - table.atomic.rmw.xchg seq_cst $b - ) - (func (;10;) (type 2) (param $x i32) (param $y (ref null (shared eq))) (result (ref null (shared eq))) - local.get $x - local.get $y - table.atomic.rmw.xchg acq_rel $a - ) - (func (;11;) (type 2) (param $x i32) (param $y (ref null (shared eq))) (result (ref null (shared eq))) - local.get $x - local.get $y - table.atomic.rmw.xchg acq_rel $b - ) - (func (;12;) (type 3) (param $x i32) (param $y (ref null (shared eq))) (param $z (ref null (shared eq))) (result (ref null (shared eq))) - local.get $x - local.get $y - local.get $z - table.atomic.rmw.cmpxchg seq_cst $a - ) - (func (;13;) (type 3) (param $x i32) (param $y (ref null (shared eq))) (param $z (ref null (shared eq))) (result (ref null (shared eq))) - local.get $x - local.get $y - local.get $z - table.atomic.rmw.cmpxchg seq_cst $b - ) - (func (;14;) (type 3) (param $x i32) (param $y (ref null (shared eq))) (param $z (ref null (shared eq))) (result (ref null (shared eq))) - local.get $x - local.get $y - local.get $z - table.atomic.rmw.cmpxchg acq_rel $a - ) - (func (;15;) (type 3) (param $x i32) (param $y (ref null (shared eq))) (param $z (ref null (shared eq))) (result (ref null (shared eq))) - local.get $x - local.get $y - local.get $z - table.atomic.rmw.cmpxchg acq_rel $b - ) + (type $f (;0;) (shared (func))) + (table $t (;0;) shared 1 (ref null $f)) + (global $g (;0;) (shared (ref null $f)) ref.null $f) + (elem (;0;) (ref null $f) (global.get $g)) ) diff --git a/tests/snapshots/local/shared-everything-threads/tables.wast/9.print b/tests/snapshots/local/shared-everything-threads/tables.wast/9.print new file mode 100644 index 0000000000..a5cc97fc5e --- /dev/null +++ b/tests/snapshots/local/shared-everything-threads/tables.wast/9.print @@ -0,0 +1,104 @@ +(module + (type (;0;) (func (param i32) (result (ref null (shared eq))))) + (type (;1;) (func (param i32 (ref null (shared eq))))) + (type (;2;) (func (param i32 (ref null (shared eq))) (result (ref null (shared eq))))) + (type (;3;) (func (param i32 (ref null (shared eq)) (ref null (shared eq))) (result (ref null (shared eq))))) + (import "spectest" "table_eq" (table $a (;0;) shared 1 (ref null (shared eq)))) + (table $b (;1;) shared 1 (ref null (shared eq))) + (export "table-atomic-get-eq-seq_cst-$a" (func 0)) + (export "table-atomic-get-eq-seq_cst-$b" (func 1)) + (export "table-atomic-get-eq-acq_rel-$a" (func 2)) + (export "table-atomic-get-eq-acq_rel-$b" (func 3)) + (export "table-atomic-set-eq-seq_cst-$a" (func 4)) + (export "table-atomic-set-eq-seq_cst-$b" (func 5)) + (export "table-atomic-set-eq-acq_rel-$a" (func 6)) + (export "table-atomic-set-eq-acq_rel-$b" (func 7)) + (export "table-atomic-rmw.xchg-eq-seq_cst-$a" (func 8)) + (export "table-atomic-rmw.xchg-eq-seq_cst-$b" (func 9)) + (export "table-atomic-rmw.xchg-eq-acq_rel-$a" (func 10)) + (export "table-atomic-rmw.xchg-eq-acq_rel-$b" (func 11)) + (export "table-atomic-rmw.cmpxchg-eq-seq_cst-$a" (func 12)) + (export "table-atomic-rmw.cmpxchg-eq-seq_cst-$b" (func 13)) + (export "table-atomic-rmw.cmpxchg-eq-acq_rel-$a" (func 14)) + (export "table-atomic-rmw.cmpxchg-eq-acq_rel-$b" (func 15)) + (func (;0;) (type 0) (param $x i32) (result (ref null (shared eq))) + local.get $x + table.atomic.get seq_cst $a + ) + (func (;1;) (type 0) (param $x i32) (result (ref null (shared eq))) + local.get $x + table.atomic.get seq_cst $b + ) + (func (;2;) (type 0) (param $x i32) (result (ref null (shared eq))) + local.get $x + table.atomic.get acq_rel $a + ) + (func (;3;) (type 0) (param $x i32) (result (ref null (shared eq))) + local.get $x + table.atomic.get acq_rel $b + ) + (func (;4;) (type 1) (param $x i32) (param $y (ref null (shared eq))) + local.get $x + local.get $y + table.atomic.set seq_cst $a + ) + (func (;5;) (type 1) (param $x i32) (param $y (ref null (shared eq))) + local.get $x + local.get $y + table.atomic.set seq_cst $b + ) + (func (;6;) (type 1) (param $x i32) (param $y (ref null (shared eq))) + local.get $x + local.get $y + table.atomic.set acq_rel $a + ) + (func (;7;) (type 1) (param $x i32) (param $y (ref null (shared eq))) + local.get $x + local.get $y + table.atomic.set acq_rel $b + ) + (func (;8;) (type 2) (param $x i32) (param $y (ref null (shared eq))) (result (ref null (shared eq))) + local.get $x + local.get $y + table.atomic.rmw.xchg seq_cst $a + ) + (func (;9;) (type 2) (param $x i32) (param $y (ref null (shared eq))) (result (ref null (shared eq))) + local.get $x + local.get $y + table.atomic.rmw.xchg seq_cst $b + ) + (func (;10;) (type 2) (param $x i32) (param $y (ref null (shared eq))) (result (ref null (shared eq))) + local.get $x + local.get $y + table.atomic.rmw.xchg acq_rel $a + ) + (func (;11;) (type 2) (param $x i32) (param $y (ref null (shared eq))) (result (ref null (shared eq))) + local.get $x + local.get $y + table.atomic.rmw.xchg acq_rel $b + ) + (func (;12;) (type 3) (param $x i32) (param $y (ref null (shared eq))) (param $z (ref null (shared eq))) (result (ref null (shared eq))) + local.get $x + local.get $y + local.get $z + table.atomic.rmw.cmpxchg seq_cst $a + ) + (func (;13;) (type 3) (param $x i32) (param $y (ref null (shared eq))) (param $z (ref null (shared eq))) (result (ref null (shared eq))) + local.get $x + local.get $y + local.get $z + table.atomic.rmw.cmpxchg seq_cst $b + ) + (func (;14;) (type 3) (param $x i32) (param $y (ref null (shared eq))) (param $z (ref null (shared eq))) (result (ref null (shared eq))) + local.get $x + local.get $y + local.get $z + table.atomic.rmw.cmpxchg acq_rel $a + ) + (func (;15;) (type 3) (param $x i32) (param $y (ref null (shared eq))) (param $z (ref null (shared eq))) (result (ref null (shared eq))) + local.get $x + local.get $y + local.get $z + table.atomic.rmw.cmpxchg acq_rel $b + ) +)