Skip to content

Commit dc89132

Browse files
authored
Fix Unsubtyping on array and struct cmpxchg (#8469)
Struct and array cmpxchg operations allow the accessed field to be a shared or unshared eqref, but subtype-exprs.h was assuming that if it was a reference, it would be a subtype of unshared eqref only. Fix it to account for shared types as well.
1 parent 216ea0b commit dc89132

2 files changed

Lines changed: 94 additions & 4 deletions

File tree

src/ir/subtype-exprs.h

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -368,8 +368,12 @@ struct SubtypingDiscoverer : public OverriddenVisitor<SubType> {
368368
}
369369
const auto& fields = curr->ref->type.getHeapType().getStruct().fields;
370370
auto type = fields[curr->index].type;
371-
self()->noteSubtype(curr->expected,
372-
type.isRef() ? Type(HeapType::eq, Nullable) : type);
371+
Type expectedType = type;
372+
if (type.isRef()) {
373+
expectedType =
374+
Type(HeapTypes::eq.getBasic(type.getHeapType().getShared()), Nullable);
375+
}
376+
self()->noteSubtype(curr->expected, expectedType);
373377
self()->noteSubtype(curr->replacement, type);
374378
}
375379
void visitStructWait(StructWait* curr) {}
@@ -445,8 +449,12 @@ struct SubtypingDiscoverer : public OverriddenVisitor<SubType> {
445449
return;
446450
}
447451
auto type = curr->ref->type.getHeapType().getArray().element.type;
448-
self()->noteSubtype(curr->expected,
449-
type.isRef() ? Type(HeapType::eq, Nullable) : type);
452+
Type expectedType = type;
453+
if (type.isRef()) {
454+
expectedType =
455+
Type(HeapTypes::eq.getBasic(type.getHeapType().getShared()), Nullable);
456+
}
457+
self()->noteSubtype(curr->expected, expectedType);
450458
self()->noteSubtype(curr->replacement, type);
451459
}
452460
void visitRefAs(RefAs* curr) {
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
;; NOTE: Assertions have been generated by update_lit_checks.py and should not be edited.
2+
;; RUN: wasm-opt %s -all --closed-world --unsubtyping -S -o - | filecheck %s
3+
4+
(module
5+
;; CHECK: (rec
6+
;; CHECK-NEXT: (type $array-unshared (array (mut eqref)))
7+
8+
;; CHECK: (type $array-shared (shared (array (mut (ref null (shared eq))))))
9+
10+
;; CHECK: (type $struct-unshared (struct (field (mut eqref))))
11+
12+
;; CHECK: (type $struct-shared (struct (field (mut (ref null (shared eq))))))
13+
(type $struct-shared (struct (field (mut (ref null (shared eq))))))
14+
(type $struct-unshared (struct (field (mut eqref))))
15+
16+
(type $array-shared (shared (array (mut (ref null (shared eq))))))
17+
(type $array-unshared (array (mut eqref)))
18+
19+
;; CHECK: (func $struct-shared-eq (type $7) (param $struct (ref $struct-shared)) (param $eq (ref null (shared eq))) (result (ref null (shared eq)))
20+
;; CHECK-NEXT: (struct.atomic.rmw.cmpxchg $struct-shared 0
21+
;; CHECK-NEXT: (local.get $struct)
22+
;; CHECK-NEXT: (local.get $eq)
23+
;; CHECK-NEXT: (local.get $eq)
24+
;; CHECK-NEXT: )
25+
;; CHECK-NEXT: )
26+
(func $struct-shared-eq (param $struct (ref $struct-shared)) (param $eq (ref null (shared eq))) (result (ref null (shared eq)))
27+
(struct.atomic.rmw.cmpxchg $struct-shared 0
28+
(local.get $struct)
29+
(local.get $eq)
30+
(local.get $eq)
31+
)
32+
)
33+
34+
;; CHECK: (func $struct-unshared-eq (type $6) (param $struct (ref $struct-unshared)) (param $eq eqref) (result eqref)
35+
;; CHECK-NEXT: (struct.atomic.rmw.cmpxchg $struct-unshared 0
36+
;; CHECK-NEXT: (local.get $struct)
37+
;; CHECK-NEXT: (local.get $eq)
38+
;; CHECK-NEXT: (local.get $eq)
39+
;; CHECK-NEXT: )
40+
;; CHECK-NEXT: )
41+
(func $struct-unshared-eq (param $struct (ref $struct-unshared)) (param $eq eqref) (result eqref)
42+
(struct.atomic.rmw.cmpxchg $struct-unshared 0
43+
(local.get $struct)
44+
(local.get $eq)
45+
(local.get $eq)
46+
)
47+
)
48+
49+
;; CHECK: (func $array-shared-eq (type $5) (param $array (ref $array-shared)) (param $eq (ref null (shared eq))) (result (ref null (shared eq)))
50+
;; CHECK-NEXT: (array.atomic.rmw.cmpxchg $array-shared
51+
;; CHECK-NEXT: (local.get $array)
52+
;; CHECK-NEXT: (i32.const 0)
53+
;; CHECK-NEXT: (local.get $eq)
54+
;; CHECK-NEXT: (local.get $eq)
55+
;; CHECK-NEXT: )
56+
;; CHECK-NEXT: )
57+
(func $array-shared-eq (param $array (ref $array-shared)) (param $eq (ref null (shared eq))) (result (ref null (shared eq)))
58+
(array.atomic.rmw.cmpxchg $array-shared
59+
(local.get $array)
60+
(i32.const 0)
61+
(local.get $eq)
62+
(local.get $eq)
63+
)
64+
)
65+
66+
;; CHECK: (func $array-unshared-eq (type $4) (param $array (ref $array-unshared)) (param $eq eqref) (result eqref)
67+
;; CHECK-NEXT: (array.atomic.rmw.cmpxchg $array-unshared
68+
;; CHECK-NEXT: (local.get $array)
69+
;; CHECK-NEXT: (i32.const 0)
70+
;; CHECK-NEXT: (local.get $eq)
71+
;; CHECK-NEXT: (local.get $eq)
72+
;; CHECK-NEXT: )
73+
;; CHECK-NEXT: )
74+
(func $array-unshared-eq (param $array (ref $array-unshared)) (param $eq eqref) (result eqref)
75+
(array.atomic.rmw.cmpxchg $array-unshared
76+
(local.get $array)
77+
(i32.const 0)
78+
(local.get $eq)
79+
(local.get $eq)
80+
)
81+
)
82+
)

0 commit comments

Comments
 (0)