Skip to content

Commit ea3e2ed

Browse files
authored
GUFA: In open world, public types can be written on the outside (#7992)
Mark their contents as unknown, so we do not misoptimize.
1 parent b7e895f commit ea3e2ed

File tree

3 files changed

+138
-6
lines changed

3 files changed

+138
-6
lines changed

src/ir/possible-contents.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2421,6 +2421,27 @@ Flower::Flower(Module& wasm, const PassOptions& options)
24212421
}
24222422
}
24232423

2424+
// In open world, public heap types may be written to from the outside.
2425+
if (!options.closedWorld) {
2426+
for (auto type : ModuleUtils::getPublicHeapTypes(wasm)) {
2427+
if (type.isStruct()) {
2428+
auto& fields = type.getStruct().fields;
2429+
for (Index i = 0; i < fields.size(); i++) {
2430+
roots[DataLocation{type, i}] =
2431+
PossibleContents::fromType(fields[i].type);
2432+
}
2433+
if (auto desc = type.getDescriptorType()) {
2434+
auto descType = Type(*desc, Nullable, Inexact);
2435+
roots[DataLocation{type, DataLocation::DescriptorIndex}] =
2436+
PossibleContents::fromType(descType);
2437+
}
2438+
} else if (type.isArray()) {
2439+
roots[DataLocation{type, 0}] =
2440+
PossibleContents::fromType(type.getArray().element.type);
2441+
}
2442+
}
2443+
}
2444+
24242445
#ifdef POSSIBLE_CONTENTS_DEBUG
24252446
std::cout << "struct phase\n";
24262447
#endif

test/lit/passes/gufa-cast-all-exact.wast

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -120,10 +120,22 @@
120120
(import "" "" (global $exact (ref (exact $foo))))
121121

122122
;; CHECK: (func $get (type $1) (result i32)
123-
;; CHECK-NEXT: (unreachable)
123+
;; CHECK-NEXT: (struct.get $foo 0
124+
;; CHECK-NEXT: (select (result (ref null (exact $foo)))
125+
;; CHECK-NEXT: (global.get $exact)
126+
;; CHECK-NEXT: (ref.null none)
127+
;; CHECK-NEXT: (i32.const 0)
128+
;; CHECK-NEXT: )
129+
;; CHECK-NEXT: )
124130
;; CHECK-NEXT: )
125131
;; NO_CD: (func $get (type $1) (result i32)
126-
;; NO_CD-NEXT: (unreachable)
132+
;; NO_CD-NEXT: (struct.get $foo 0
133+
;; NO_CD-NEXT: (select (result (ref null (exact $foo)))
134+
;; NO_CD-NEXT: (global.get $exact)
135+
;; NO_CD-NEXT: (ref.null none)
136+
;; NO_CD-NEXT: (i32.const 0)
137+
;; NO_CD-NEXT: )
138+
;; NO_CD-NEXT: )
127139
;; NO_CD-NEXT: )
128140
(func $get (result i32)
129141
;; Regression test for a bug where exactness was not preserved when combining
@@ -220,20 +232,18 @@
220232
(import "" "" (global $null-exact (ref null (exact $foo))))
221233

222234
;; CHECK: (func $as-non-null (type $1) (result i32)
223-
;; CHECK-NEXT: (drop
235+
;; CHECK-NEXT: (struct.get $foo 0
224236
;; CHECK-NEXT: (ref.as_non_null
225237
;; CHECK-NEXT: (global.get $null-exact)
226238
;; CHECK-NEXT: )
227239
;; CHECK-NEXT: )
228-
;; CHECK-NEXT: (unreachable)
229240
;; CHECK-NEXT: )
230241
;; NO_CD: (func $as-non-null (type $1) (result i32)
231-
;; NO_CD-NEXT: (drop
242+
;; NO_CD-NEXT: (struct.get $foo 0
232243
;; NO_CD-NEXT: (ref.as_non_null
233244
;; NO_CD-NEXT: (global.get $null-exact)
234245
;; NO_CD-NEXT: )
235246
;; NO_CD-NEXT: )
236-
;; NO_CD-NEXT: (unreachable)
237247
;; NO_CD-NEXT: )
238248
(func $as-non-null (result i32)
239249
(struct.get $foo 0

test/lit/passes/gufa-closed-open.wast

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,104 @@
6666
)
6767
)
6868
)
69+
70+
;; Import a struct in a global.
71+
(module
72+
;; OPEND: (type $A (struct (field i32)))
73+
;; CLOSE: (type $A (struct (field i32)))
74+
(type $A (struct (field i32)))
75+
76+
;; OPEND: (type $1 (func (result i32)))
77+
78+
;; OPEND: (import "primary" "global" (global $import (ref null $A)))
79+
;; CLOSE: (type $1 (func (result i32)))
80+
81+
;; CLOSE: (import "primary" "global" (global $import (ref null $A)))
82+
(import "primary" "global" (global $import (ref null $A)))
83+
84+
;; OPEND: (func $read (type $1) (result i32)
85+
;; OPEND-NEXT: (struct.get $A 0
86+
;; OPEND-NEXT: (global.get $import)
87+
;; OPEND-NEXT: )
88+
;; OPEND-NEXT: )
89+
;; CLOSE: (func $read (type $1) (result i32)
90+
;; CLOSE-NEXT: (unreachable)
91+
;; CLOSE-NEXT: )
92+
(func $read (result i32)
93+
;; In closed world, we can assume no work happens on this struct outside, so
94+
;; it can only be null. In open world, we can do nothing here.
95+
(struct.get $A 0
96+
(global.get $import)
97+
)
98+
)
99+
)
100+
101+
;; Import an array.
102+
(module
103+
;; OPEND: (type $A (array (mut i32)))
104+
;; CLOSE: (type $A (array (mut i32)))
105+
(type $A (array (mut i32)))
106+
107+
;; OPEND: (type $1 (func (result i32)))
108+
109+
;; OPEND: (import "primary" "global" (global $import (ref null $A)))
110+
;; CLOSE: (type $1 (func (result i32)))
111+
112+
;; CLOSE: (import "primary" "global" (global $import (ref null $A)))
113+
(import "primary" "global" (global $import (ref null $A)))
114+
115+
;; OPEND: (func $read (type $1) (result i32)
116+
;; OPEND-NEXT: (array.get $A
117+
;; OPEND-NEXT: (global.get $import)
118+
;; OPEND-NEXT: (i32.const 0)
119+
;; OPEND-NEXT: )
120+
;; OPEND-NEXT: )
121+
;; CLOSE: (func $read (type $1) (result i32)
122+
;; CLOSE-NEXT: (unreachable)
123+
;; CLOSE-NEXT: )
124+
(func $read (result i32)
125+
;; We do not optimize in open world.
126+
(array.get $A
127+
(global.get $import)
128+
(i32.const 0)
129+
)
130+
)
131+
)
132+
133+
;; Import a struct with a descriptor.
134+
(module
135+
(rec
136+
;; OPEND: (rec
137+
;; OPEND-NEXT: (type $A (sub (descriptor $A.desc (struct))))
138+
;; CLOSE: (rec
139+
;; CLOSE-NEXT: (type $A (sub (descriptor $A.desc (struct))))
140+
(type $A (sub (descriptor $A.desc (struct))))
141+
;; OPEND: (type $A.desc (sub (describes $A (struct))))
142+
;; CLOSE: (type $A.desc (sub (describes $A (struct))))
143+
(type $A.desc (sub (describes $A (struct))))
144+
)
145+
146+
;; OPEND: (type $2 (func (result anyref)))
147+
148+
;; OPEND: (import "primary" "global" (global $import (ref null $A)))
149+
;; CLOSE: (type $2 (func (result anyref)))
150+
151+
;; CLOSE: (import "primary" "global" (global $import (ref null $A)))
152+
(import "primary" "global" (global $import (ref null $A)))
153+
154+
;; OPEND: (func $read (type $2) (result anyref)
155+
;; OPEND-NEXT: (ref.get_desc $A
156+
;; OPEND-NEXT: (global.get $import)
157+
;; OPEND-NEXT: )
158+
;; OPEND-NEXT: )
159+
;; CLOSE: (func $read (type $2) (result anyref)
160+
;; CLOSE-NEXT: (unreachable)
161+
;; CLOSE-NEXT: )
162+
(func $read (result anyref)
163+
;; We do not optimize in open world.
164+
(ref.get_desc $A
165+
(global.get $import)
166+
)
167+
)
168+
)
169+

0 commit comments

Comments
 (0)