Skip to content

Commit 1434591

Browse files
authored
[threads] Fix shared ref.eq and disallow mixed-shareability (#6763)
Update the validator to reject mixed-shareability ref.eq, although this is still under discussion in WebAssembly/shared-everything-threads#76. Fix the implementation of `Literal::operator==` to work properly with shared i31ref.
1 parent 1e7be1e commit 1434591

File tree

5 files changed

+211
-3
lines changed

5 files changed

+211
-3
lines changed

scripts/fuzz_opt.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,7 @@ def is_git_repo():
360360
'shared-null.wast',
361361
'shared-absheaptype.wast',
362362
'type-ssa-shared.wast',
363+
'shared-ref_eq.wast',
363364
]
364365

365366

src/wasm/literal.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,8 @@ bool Literal::operator==(const Literal& other) const {
445445
if (type.isData()) {
446446
return gcData == other.gcData;
447447
}
448-
if (type.getHeapType() == HeapType::i31) {
448+
assert(type.getHeapType().isBasic());
449+
if (type.getHeapType().getBasic(Unshared) == HeapType::i31) {
449450
return i32 == other.i32;
450451
}
451452
WASM_UNREACHABLE("unexpected type");

src/wasm/wasm-validator.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2306,6 +2306,12 @@ void FunctionValidator::visitRefEq(RefEq* curr) {
23062306
eqref,
23072307
curr->right,
23082308
"ref.eq's right argument should be a subtype of eqref");
2309+
if (curr->left->type.isRef() && curr->right->type.isRef()) {
2310+
shouldBeEqual(curr->left->type.getHeapType().getShared(),
2311+
curr->right->type.getHeapType().getShared(),
2312+
curr,
2313+
"ref.eq operands must have the same shareability");
2314+
}
23092315
}
23102316

23112317
void FunctionValidator::visitTableGet(TableGet* curr) {

test/spec/shared-polymorphism.wast

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
;; references.
33
(module
44
(func (drop (ref.eq (ref.null (shared none)) (ref.null (shared none)))))
5-
(func (drop (ref.eq (ref.null (shared none)) (ref.null none))))
6-
(func (drop (ref.eq (ref.null none) (ref.null (shared none)))))
75

86
(func (param (ref null (shared i31))) (drop (i31.get_s (local.get 0))))
97
(func (param (ref null (shared i31))) (drop (i31.get_u (local.get 0))))

test/spec/shared-ref_eq.wast

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
(module
2+
(type $st (sub (shared (struct))))
3+
(type $st' (sub (shared (struct (field i32)))))
4+
(type $at (shared (array i8)))
5+
(type $st-sub1 (sub $st (shared (struct))))
6+
(type $st-sub2 (sub $st (shared (struct))))
7+
(type $st'-sub1 (sub $st' (shared (struct (field i32)))))
8+
(type $st'-sub2 (sub $st' (shared (struct (field i32)))))
9+
10+
(table 20 (ref null (shared eq)))
11+
12+
(func (export "init")
13+
(table.set (i32.const 0) (ref.null (shared eq)))
14+
(table.set (i32.const 1) (ref.null (shared i31)))
15+
(table.set (i32.const 2) (ref.i31_shared (i32.const 7)))
16+
(table.set (i32.const 3) (ref.i31_shared (i32.const 7)))
17+
(table.set (i32.const 4) (ref.i31_shared (i32.const 8)))
18+
(table.set (i32.const 5) (struct.new_default $st))
19+
(table.set (i32.const 6) (struct.new_default $st))
20+
(table.set (i32.const 7) (array.new_default $at (i32.const 0)))
21+
(table.set (i32.const 8) (array.new_default $at (i32.const 0)))
22+
)
23+
24+
(func (export "eq") (param $i i32) (param $j i32) (result i32)
25+
(ref.eq (table.get (local.get $i)) (table.get (local.get $j)))
26+
)
27+
)
28+
29+
(invoke "init")
30+
31+
(assert_return (invoke "eq" (i32.const 0) (i32.const 0)) (i32.const 1))
32+
(assert_return (invoke "eq" (i32.const 0) (i32.const 1)) (i32.const 1))
33+
(assert_return (invoke "eq" (i32.const 0) (i32.const 2)) (i32.const 0))
34+
(assert_return (invoke "eq" (i32.const 0) (i32.const 3)) (i32.const 0))
35+
(assert_return (invoke "eq" (i32.const 0) (i32.const 4)) (i32.const 0))
36+
(assert_return (invoke "eq" (i32.const 0) (i32.const 5)) (i32.const 0))
37+
(assert_return (invoke "eq" (i32.const 0) (i32.const 6)) (i32.const 0))
38+
(assert_return (invoke "eq" (i32.const 0) (i32.const 7)) (i32.const 0))
39+
(assert_return (invoke "eq" (i32.const 0) (i32.const 8)) (i32.const 0))
40+
41+
(assert_return (invoke "eq" (i32.const 1) (i32.const 0)) (i32.const 1))
42+
(assert_return (invoke "eq" (i32.const 1) (i32.const 1)) (i32.const 1))
43+
(assert_return (invoke "eq" (i32.const 1) (i32.const 2)) (i32.const 0))
44+
(assert_return (invoke "eq" (i32.const 1) (i32.const 3)) (i32.const 0))
45+
(assert_return (invoke "eq" (i32.const 1) (i32.const 4)) (i32.const 0))
46+
(assert_return (invoke "eq" (i32.const 1) (i32.const 5)) (i32.const 0))
47+
(assert_return (invoke "eq" (i32.const 1) (i32.const 6)) (i32.const 0))
48+
(assert_return (invoke "eq" (i32.const 1) (i32.const 7)) (i32.const 0))
49+
(assert_return (invoke "eq" (i32.const 1) (i32.const 8)) (i32.const 0))
50+
51+
(assert_return (invoke "eq" (i32.const 2) (i32.const 0)) (i32.const 0))
52+
(assert_return (invoke "eq" (i32.const 2) (i32.const 1)) (i32.const 0))
53+
(assert_return (invoke "eq" (i32.const 2) (i32.const 2)) (i32.const 1))
54+
(assert_return (invoke "eq" (i32.const 2) (i32.const 3)) (i32.const 1))
55+
(assert_return (invoke "eq" (i32.const 2) (i32.const 4)) (i32.const 0))
56+
(assert_return (invoke "eq" (i32.const 2) (i32.const 5)) (i32.const 0))
57+
(assert_return (invoke "eq" (i32.const 2) (i32.const 6)) (i32.const 0))
58+
(assert_return (invoke "eq" (i32.const 2) (i32.const 7)) (i32.const 0))
59+
(assert_return (invoke "eq" (i32.const 2) (i32.const 8)) (i32.const 0))
60+
61+
(assert_return (invoke "eq" (i32.const 3) (i32.const 0)) (i32.const 0))
62+
(assert_return (invoke "eq" (i32.const 3) (i32.const 1)) (i32.const 0))
63+
(assert_return (invoke "eq" (i32.const 3) (i32.const 2)) (i32.const 1))
64+
(assert_return (invoke "eq" (i32.const 3) (i32.const 3)) (i32.const 1))
65+
(assert_return (invoke "eq" (i32.const 3) (i32.const 4)) (i32.const 0))
66+
(assert_return (invoke "eq" (i32.const 3) (i32.const 5)) (i32.const 0))
67+
(assert_return (invoke "eq" (i32.const 3) (i32.const 6)) (i32.const 0))
68+
(assert_return (invoke "eq" (i32.const 3) (i32.const 7)) (i32.const 0))
69+
(assert_return (invoke "eq" (i32.const 3) (i32.const 8)) (i32.const 0))
70+
71+
(assert_return (invoke "eq" (i32.const 4) (i32.const 0)) (i32.const 0))
72+
(assert_return (invoke "eq" (i32.const 4) (i32.const 1)) (i32.const 0))
73+
(assert_return (invoke "eq" (i32.const 4) (i32.const 2)) (i32.const 0))
74+
(assert_return (invoke "eq" (i32.const 4) (i32.const 3)) (i32.const 0))
75+
(assert_return (invoke "eq" (i32.const 4) (i32.const 4)) (i32.const 1))
76+
(assert_return (invoke "eq" (i32.const 4) (i32.const 5)) (i32.const 0))
77+
(assert_return (invoke "eq" (i32.const 4) (i32.const 6)) (i32.const 0))
78+
(assert_return (invoke "eq" (i32.const 4) (i32.const 7)) (i32.const 0))
79+
(assert_return (invoke "eq" (i32.const 4) (i32.const 8)) (i32.const 0))
80+
81+
(assert_return (invoke "eq" (i32.const 5) (i32.const 0)) (i32.const 0))
82+
(assert_return (invoke "eq" (i32.const 5) (i32.const 1)) (i32.const 0))
83+
(assert_return (invoke "eq" (i32.const 5) (i32.const 2)) (i32.const 0))
84+
(assert_return (invoke "eq" (i32.const 5) (i32.const 3)) (i32.const 0))
85+
(assert_return (invoke "eq" (i32.const 5) (i32.const 4)) (i32.const 0))
86+
(assert_return (invoke "eq" (i32.const 5) (i32.const 5)) (i32.const 1))
87+
(assert_return (invoke "eq" (i32.const 5) (i32.const 6)) (i32.const 0))
88+
(assert_return (invoke "eq" (i32.const 5) (i32.const 7)) (i32.const 0))
89+
(assert_return (invoke "eq" (i32.const 5) (i32.const 8)) (i32.const 0))
90+
91+
(assert_return (invoke "eq" (i32.const 6) (i32.const 0)) (i32.const 0))
92+
(assert_return (invoke "eq" (i32.const 6) (i32.const 1)) (i32.const 0))
93+
(assert_return (invoke "eq" (i32.const 6) (i32.const 2)) (i32.const 0))
94+
(assert_return (invoke "eq" (i32.const 6) (i32.const 3)) (i32.const 0))
95+
(assert_return (invoke "eq" (i32.const 6) (i32.const 4)) (i32.const 0))
96+
(assert_return (invoke "eq" (i32.const 6) (i32.const 5)) (i32.const 0))
97+
(assert_return (invoke "eq" (i32.const 6) (i32.const 6)) (i32.const 1))
98+
(assert_return (invoke "eq" (i32.const 6) (i32.const 7)) (i32.const 0))
99+
(assert_return (invoke "eq" (i32.const 6) (i32.const 8)) (i32.const 0))
100+
101+
(assert_return (invoke "eq" (i32.const 7) (i32.const 0)) (i32.const 0))
102+
(assert_return (invoke "eq" (i32.const 7) (i32.const 1)) (i32.const 0))
103+
(assert_return (invoke "eq" (i32.const 7) (i32.const 2)) (i32.const 0))
104+
(assert_return (invoke "eq" (i32.const 7) (i32.const 3)) (i32.const 0))
105+
(assert_return (invoke "eq" (i32.const 7) (i32.const 4)) (i32.const 0))
106+
(assert_return (invoke "eq" (i32.const 7) (i32.const 5)) (i32.const 0))
107+
(assert_return (invoke "eq" (i32.const 7) (i32.const 6)) (i32.const 0))
108+
(assert_return (invoke "eq" (i32.const 7) (i32.const 7)) (i32.const 1))
109+
(assert_return (invoke "eq" (i32.const 7) (i32.const 8)) (i32.const 0))
110+
111+
(assert_return (invoke "eq" (i32.const 8) (i32.const 0)) (i32.const 0))
112+
(assert_return (invoke "eq" (i32.const 8) (i32.const 1)) (i32.const 0))
113+
(assert_return (invoke "eq" (i32.const 8) (i32.const 2)) (i32.const 0))
114+
(assert_return (invoke "eq" (i32.const 8) (i32.const 3)) (i32.const 0))
115+
(assert_return (invoke "eq" (i32.const 8) (i32.const 4)) (i32.const 0))
116+
(assert_return (invoke "eq" (i32.const 8) (i32.const 5)) (i32.const 0))
117+
(assert_return (invoke "eq" (i32.const 8) (i32.const 6)) (i32.const 0))
118+
(assert_return (invoke "eq" (i32.const 8) (i32.const 7)) (i32.const 0))
119+
(assert_return (invoke "eq" (i32.const 8) (i32.const 8)) (i32.const 1))
120+
121+
(assert_invalid
122+
(module
123+
(func (export "eq") (param $r (ref (shared any))) (result i32)
124+
(ref.eq (local.get $r) (local.get $r))
125+
)
126+
)
127+
"type mismatch"
128+
)
129+
(assert_invalid
130+
(module
131+
(func (export "eq") (param $r (ref null (shared any))) (result i32)
132+
(ref.eq (local.get $r) (local.get $r))
133+
)
134+
)
135+
"type mismatch"
136+
)
137+
(assert_invalid
138+
(module
139+
(func (export "eq") (param $r (ref null (shared func))) (result i32)
140+
(ref.eq (local.get $r) (local.get $r))
141+
)
142+
)
143+
"type mismatch"
144+
)
145+
(assert_invalid
146+
(module
147+
(func (export "eq") (param $r (ref null (shared func))) (result i32)
148+
(ref.eq (local.get $r) (local.get $r))
149+
)
150+
)
151+
"type mismatch"
152+
)
153+
(assert_invalid
154+
(module
155+
(func (export "eq") (param $r (ref (shared extern))) (result i32)
156+
(ref.eq (local.get $r) (local.get $r))
157+
)
158+
)
159+
"type mismatch"
160+
)
161+
(assert_invalid
162+
(module
163+
(func (export "eq") (param $r (ref null (shared extern))) (result i32)
164+
(ref.eq (local.get $r) (local.get $r))
165+
)
166+
)
167+
"type mismatch"
168+
)
169+
170+
;; Mixed shared / unshared eq
171+
(assert_invalid
172+
(module
173+
(func (export "eq") (param $r1 (ref eq)) (param $r2 (ref (shared eq))) (result i32)
174+
(ref.eq (local.get $r1) (local.get $r2))
175+
)
176+
)
177+
"type mismatch"
178+
)
179+
(assert_invalid
180+
(module
181+
(func (export "eq") (param $r1 (ref (shared eq))) (param $r2 (ref eq)) (result i32)
182+
(ref.eq (local.get $r1) (local.get $r2))
183+
)
184+
)
185+
"type mismatch"
186+
)
187+
(assert_invalid
188+
(module
189+
(func (export "eq") (param $r1 eqref) (param $r2 (ref null (shared eq))) (result i32)
190+
(ref.eq (local.get $r1) (local.get $r2))
191+
)
192+
)
193+
"type mismatch"
194+
)
195+
(assert_invalid
196+
(module
197+
(func (export "eq") (param $r1 (ref null (shared eq))) (param $r2 eqref) (result i32)
198+
(ref.eq (local.get $r1) (local.get $r2))
199+
)
200+
)
201+
"type mismatch"
202+
)

0 commit comments

Comments
 (0)