Skip to content

Commit 2aa7672

Browse files
authored
threads: add tests for ref.i31_shared (#1728)
* threads: add tests for `ref.i31_shared` This change brings in Binaryen's existing [`shared-i31.wast`] test, with the commented-out parts that Binaryen does not yet support enabled here. To get this to pass in `wasm-tools`, we add the ability to parse `ref.i31_shared` as a constant expression in WAST. [`shared-i31.wast`]: https://github.com/WebAssembly/binaryen/blob/main/test/spec/shared-i31.wast * review: validate constant expressions for shared-everything-threads
1 parent 5068b3a commit 2aa7672

12 files changed

Lines changed: 1738 additions & 6 deletions

File tree

crates/wasmparser/src/validator/core.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,20 @@ impl ModuleState {
344344
}
345345
}
346346

347+
fn validate_shared_everything_threads(&mut self, op: &str) -> Result<()> {
348+
if self.features.shared_everything_threads() {
349+
Ok(())
350+
} else {
351+
Err(BinaryReaderError::new(
352+
format!(
353+
"constant expression required: non-constant operator: {}",
354+
op
355+
),
356+
self.offset,
357+
))
358+
}
359+
}
360+
347361
fn validate_global(&mut self, index: u32) -> Result<()> {
348362
let module = &self.resources.module;
349363
let global = module.global_at(index, self.offset)?;
@@ -479,6 +493,10 @@ impl ModuleState {
479493
$self.validate_gc("ref.i31")?;
480494
$self.validator().visit_ref_i31()
481495
}};
496+
(@visit $self:ident visit_ref_i31_shared) => {{
497+
$self.validate_shared_everything_threads("ref.i31_shared")?;
498+
$self.validator().visit_ref_i31_shared()
499+
}};
482500

483501
// `global.get` is a valid const expression for imported, immutable
484502
// globals.

crates/wast/src/core/wast.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ pub enum WastRetCore<'a> {
9090
RefStruct,
9191
/// A non-null i31ref is expected.
9292
RefI31,
93+
/// A non-null, shared i31ref is expected.
94+
RefI31Shared,
9395

9496
Either(Vec<WastRetCore<'a>>),
9597
}
@@ -111,6 +113,7 @@ static RETS: &[(&str, fn(Parser<'_>) -> Result<WastRetCore<'_>>)] = {
111113
("ref.array", |_| Ok(RefArray)),
112114
("ref.struct", |_| Ok(RefStruct)),
113115
("ref.i31", |_| Ok(RefI31)),
116+
("ref.i31_shared", |_| Ok(RefI31Shared)),
114117
("either", |p| {
115118
p.depth_check()?;
116119
let mut cases = Vec::new();

src/bin/wasm-tools/json_from_wast.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,7 @@ impl<'a> JsonBuilder<'a> {
462462
RefArray => json::Const::ArrayRef,
463463
RefStruct => json::Const::StructRef,
464464
RefI31 => json::Const::I31Ref,
465+
RefI31Shared => json::Const::I31RefShared,
465466
Either(either) => json::Const::Either {
466467
values: either
467468
.into_iter()
@@ -676,6 +677,7 @@ mod json {
676677
ArrayRef,
677678
StructRef,
678679
I31Ref,
680+
I31RefShared,
679681
// (ref.null none)
680682
NullRef,
681683
// (ref.null nofunc)
Lines changed: 228 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,230 @@
11
(module
2-
(func (result (ref null (shared i31)))
3-
(ref.i31_shared (i32.const 0))
4-
)
2+
(func (export "new") (param $i i32) (result (ref (shared i31)))
3+
(ref.i31_shared (local.get $i))
4+
)
5+
6+
(func (export "get_u") (param $i i32) (result i32)
7+
(i31.get_u (ref.i31_shared (local.get $i)))
8+
)
9+
(func (export "get_s") (param $i i32) (result i32)
10+
(i31.get_s (ref.i31_shared (local.get $i)))
11+
)
12+
13+
(func (export "get_u-null") (result i32)
14+
(i31.get_u (ref.null (shared i31)))
15+
)
16+
(func (export "get_s-null") (result i32)
17+
(i31.get_u (ref.null (shared i31)))
18+
)
19+
20+
(global $i (ref (shared i31)) (ref.i31_shared (i32.const 2)))
21+
(global $m (mut (ref (shared i31))) (ref.i31_shared (i32.const 3)))
22+
23+
(func (export "get_globals") (result i32 i32)
24+
(i31.get_u (global.get $i))
25+
(i31.get_u (global.get $m))
26+
)
27+
28+
(func (export "set_global") (param i32)
29+
(global.set $m (ref.i31_shared (local.get 0)))
30+
)
531
)
32+
33+
(assert_return (invoke "new" (i32.const 1)) (ref.i31_shared))
34+
35+
(assert_return (invoke "get_u" (i32.const 0)) (i32.const 0))
36+
(assert_return (invoke "get_u" (i32.const 100)) (i32.const 100))
37+
(assert_return (invoke "get_u" (i32.const -1)) (i32.const 0x7fff_ffff))
38+
(assert_return (invoke "get_u" (i32.const 0x3fff_ffff)) (i32.const 0x3fff_ffff))
39+
(assert_return (invoke "get_u" (i32.const 0x4000_0000)) (i32.const 0x4000_0000))
40+
(assert_return (invoke "get_u" (i32.const 0x7fff_ffff)) (i32.const 0x7fff_ffff))
41+
(assert_return (invoke "get_u" (i32.const 0xaaaa_aaaa)) (i32.const 0x2aaa_aaaa))
42+
(assert_return (invoke "get_u" (i32.const 0xcaaa_aaaa)) (i32.const 0x4aaa_aaaa))
43+
44+
(assert_return (invoke "get_s" (i32.const 0)) (i32.const 0))
45+
(assert_return (invoke "get_s" (i32.const 100)) (i32.const 100))
46+
(assert_return (invoke "get_s" (i32.const -1)) (i32.const -1))
47+
(assert_return (invoke "get_s" (i32.const 0x3fff_ffff)) (i32.const 0x3fff_ffff))
48+
(assert_return (invoke "get_s" (i32.const 0x4000_0000)) (i32.const -0x4000_0000))
49+
(assert_return (invoke "get_s" (i32.const 0x7fff_ffff)) (i32.const -1))
50+
(assert_return (invoke "get_s" (i32.const 0xaaaa_aaaa)) (i32.const 0x2aaa_aaaa))
51+
(assert_return (invoke "get_s" (i32.const 0xcaaa_aaaa)) (i32.const 0xcaaa_aaaa))
52+
53+
(assert_trap (invoke "get_u-null") "null i31 reference")
54+
(assert_trap (invoke "get_s-null") "null i31 reference")
55+
56+
(assert_return (invoke "get_globals") (i32.const 2) (i32.const 3))
57+
58+
(invoke "set_global" (i32.const 1234))
59+
(assert_return (invoke "get_globals") (i32.const 2) (i32.const 1234))
60+
61+
(module $tables_of_i31ref
62+
(table $table 3 10 (ref null (shared i31)))
63+
(elem (table $table) (i32.const 0) (ref null (shared i31))
64+
(item (ref.i31_shared (i32.const 999)))
65+
(item (ref.i31_shared (i32.const 888)))
66+
(item (ref.i31_shared (i32.const 777))))
67+
68+
(func (export "size") (result i32)
69+
table.size $table
70+
)
71+
72+
(func (export "get") (param i32) (result i32)
73+
(i31.get_u (table.get $table (local.get 0)))
74+
)
75+
76+
(func (export "grow") (param i32 i32) (result i32)
77+
(table.grow $table (ref.i31_shared (local.get 1)) (local.get 0))
78+
)
79+
80+
(func (export "fill") (param i32 i32 i32)
81+
(table.fill $table (local.get 0) (ref.i31_shared (local.get 1)) (local.get 2))
82+
)
83+
84+
(func (export "copy") (param i32 i32 i32)
85+
(table.copy $table $table (local.get 0) (local.get 1) (local.get 2))
86+
)
87+
88+
(elem $elem (ref null (shared i31)) (item (ref.i31_shared (i32.const 123)))
89+
(item (ref.i31_shared (i32.const 456)))
90+
(item (ref.i31_shared (i32.const 789))))
91+
(func (export "init") (param i32 i32 i32)
92+
(table.init $table $elem (local.get 0) (local.get 1) (local.get 2))
93+
)
94+
)
95+
96+
;; Initial state.
97+
(assert_return (invoke "size") (i32.const 3))
98+
(assert_return (invoke "get" (i32.const 0)) (i32.const 999))
99+
(assert_return (invoke "get" (i32.const 1)) (i32.const 888))
100+
(assert_return (invoke "get" (i32.const 2)) (i32.const 777))
101+
102+
;; Grow from size 3 to size 5.
103+
(assert_return (invoke "grow" (i32.const 2) (i32.const 333)) (i32.const 3))
104+
(assert_return (invoke "size") (i32.const 5))
105+
(assert_return (invoke "get" (i32.const 3)) (i32.const 333))
106+
(assert_return (invoke "get" (i32.const 4)) (i32.const 333))
107+
108+
;; Fill table[2..4] = 111.
109+
(invoke "fill" (i32.const 2) (i32.const 111) (i32.const 2))
110+
(assert_return (invoke "get" (i32.const 2)) (i32.const 111))
111+
(assert_return (invoke "get" (i32.const 3)) (i32.const 111))
112+
113+
;; Copy from table[0..2] to table[3..5].
114+
(invoke "copy" (i32.const 3) (i32.const 0) (i32.const 2))
115+
(assert_return (invoke "get" (i32.const 3)) (i32.const 999))
116+
(assert_return (invoke "get" (i32.const 4)) (i32.const 888))
117+
118+
;; Initialize the passive element at table[1..4].
119+
(invoke "init" (i32.const 1) (i32.const 0) (i32.const 3))
120+
(assert_return (invoke "get" (i32.const 1)) (i32.const 123))
121+
(assert_return (invoke "get" (i32.const 2)) (i32.const 456))
122+
(assert_return (invoke "get" (i32.const 3)) (i32.const 789))
123+
124+
(module $env
125+
(global (export "g") i32 (i32.const 42))
126+
)
127+
(register "env")
128+
129+
(module $i31ref_of_global_table_initializer
130+
(global $g (import "env" "g") i32)
131+
(table $t 3 3 (ref (shared i31)) (ref.i31_shared (global.get $g)))
132+
(func (export "get") (param i32) (result i32)
133+
(i31.get_u (local.get 0) (table.get $t))
134+
)
135+
)
136+
137+
(assert_return (invoke "get" (i32.const 0)) (i32.const 42))
138+
(assert_return (invoke "get" (i32.const 1)) (i32.const 42))
139+
(assert_return (invoke "get" (i32.const 2)) (i32.const 42))
140+
141+
(module $i31ref_of_global_global_initializer
142+
(global $g0 (import "env" "g") i32)
143+
(global $g1 (ref null (shared i31)) (ref.i31_shared (global.get $g0)))
144+
(func (export "get") (result i32)
145+
(i31.get_u (global.get $g1))
146+
)
147+
)
148+
149+
(assert_return (invoke "get") (i32.const 42))
150+
151+
(module $anyref_global_of_i31ref
152+
(global $c (ref null (shared any)) (ref.i31_shared (i32.const 1234)))
153+
(global $m (mut (ref null (shared any))) (ref.i31_shared (i32.const 5678)))
154+
155+
(func (export "get_globals") (result i32 i32)
156+
(i31.get_u (ref.cast (ref null (shared i31)) (global.get $c)))
157+
(i31.get_u (ref.cast (ref null (shared i31)) (global.get $m)))
158+
)
159+
160+
(func (export "set_global") (param i32)
161+
(global.set $m (ref.i31_shared (local.get 0)))
162+
)
163+
)
164+
165+
(assert_return (invoke "get_globals") (i32.const 1234) (i32.const 5678))
166+
(invoke "set_global" (i32.const 0))
167+
(assert_return (invoke "get_globals") (i32.const 1234) (i32.const 0))
168+
169+
(module $anyref_table_of_i31ref
170+
(table $table 3 10 (ref null (shared any)))
171+
(elem (table $table) (i32.const 0) (ref null (shared i31))
172+
(item (ref.i31_shared (i32.const 999)))
173+
(item (ref.i31_shared (i32.const 888)))
174+
(item (ref.i31_shared (i32.const 777))))
175+
176+
(func (export "size") (result i32)
177+
table.size $table
178+
)
179+
180+
(func (export "get") (param i32) (result i32)
181+
(i31.get_u (ref.cast (ref null (shared i31)) (table.get $table (local.get 0))))
182+
)
183+
184+
(func (export "grow") (param i32 i32) (result i32)
185+
(table.grow $table (ref.i31_shared (local.get 1)) (local.get 0))
186+
)
187+
188+
(func (export "fill") (param i32 i32 i32)
189+
(table.fill $table (local.get 0) (ref.i31_shared (local.get 1)) (local.get 2))
190+
)
191+
192+
(func (export "copy") (param i32 i32 i32)
193+
(table.copy $table $table (local.get 0) (local.get 1) (local.get 2))
194+
)
195+
196+
(elem $elem (ref null (shared i31)) (item (ref.i31_shared (i32.const 123)))
197+
(item (ref.i31_shared (i32.const 456)))
198+
(item (ref.i31_shared (i32.const 789))))
199+
(func (export "init") (param i32 i32 i32)
200+
(table.init $table $elem (local.get 0) (local.get 1) (local.get 2))
201+
)
202+
)
203+
204+
;; Initial state.
205+
(assert_return (invoke "size") (i32.const 3))
206+
(assert_return (invoke "get" (i32.const 0)) (i32.const 999))
207+
(assert_return (invoke "get" (i32.const 1)) (i32.const 888))
208+
(assert_return (invoke "get" (i32.const 2)) (i32.const 777))
209+
210+
;; Grow from size 3 to size 5.
211+
(assert_return (invoke "grow" (i32.const 2) (i32.const 333)) (i32.const 3))
212+
(assert_return (invoke "size") (i32.const 5))
213+
(assert_return (invoke "get" (i32.const 3)) (i32.const 333))
214+
(assert_return (invoke "get" (i32.const 4)) (i32.const 333))
215+
216+
;; Fill table[2..4] = 111.
217+
(invoke "fill" (i32.const 2) (i32.const 111) (i32.const 2))
218+
(assert_return (invoke "get" (i32.const 2)) (i32.const 111))
219+
(assert_return (invoke "get" (i32.const 3)) (i32.const 111))
220+
221+
;; Copy from table[0..2] to table[3..5].
222+
(invoke "copy" (i32.const 3) (i32.const 0) (i32.const 2))
223+
(assert_return (invoke "get" (i32.const 3)) (i32.const 999))
224+
(assert_return (invoke "get" (i32.const 4)) (i32.const 888))
225+
226+
;; Initialize the passive element at table[1..4].
227+
(invoke "init" (i32.const 1) (i32.const 0) (i32.const 3))
228+
(assert_return (invoke "get" (i32.const 1)) (i32.const 123))
229+
(assert_return (invoke "get" (i32.const 2)) (i32.const 456))
230+
(assert_return (invoke "get" (i32.const 3)) (i32.const 789))

0 commit comments

Comments
 (0)