Skip to content

Commit 3ec1024

Browse files
authored
GUFA: Fix handling of public tags (#7278)
When a tag is imported or exported, it might be written to (an exception thrown with a value in the tag) from the outside, so we should not assume it is unreachable.
1 parent 7198f0e commit 3ec1024

2 files changed

Lines changed: 172 additions & 0 deletions

File tree

src/ir/possible-contents.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2309,6 +2309,26 @@ Flower::Flower(Module& wasm, const PassOptions& options)
23092309
}
23102310
}
23112311

2312+
// Exported/imported tags are modifiable from the outside. TODO: should that
2313+
// not be possible in closed world?
2314+
std::unordered_set<Name> publicTags;
2315+
for (auto& tag : wasm.tags) {
2316+
if (tag->imported()) {
2317+
publicTags.insert(tag->name);
2318+
}
2319+
}
2320+
for (auto& ex : wasm.exports) {
2321+
if (ex->kind == ExternalKind::Tag) {
2322+
publicTags.insert(ex->value);
2323+
}
2324+
}
2325+
for (auto tag : publicTags) {
2326+
auto params = wasm.getTag(tag)->params();
2327+
for (Index i = 0; i < params.size(); i++) {
2328+
roots[TagLocation{tag, i}] = PossibleContents::fromType(params[i]);
2329+
}
2330+
}
2331+
23122332
#ifdef POSSIBLE_CONTENTS_DEBUG
23132333
std::cout << "struct phase\n";
23142334
#endif

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

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,3 +146,155 @@
146146
)
147147
)
148148
)
149+
150+
;; Imported tags may be written to from places we do not see.
151+
(module
152+
;; CHECK: (type $0 (func (param i32)))
153+
154+
;; CHECK: (type $1 (func))
155+
156+
;; CHECK: (import "fuzzing-support" "throw" (func $throw (type $0) (param i32)))
157+
(import "fuzzing-support" "throw" (func $throw (param i32)))
158+
;; CHECK: (import "fuzzing-support" "tag" (tag $tag (type $0) (param i32)))
159+
(import "fuzzing-support" "tag" (tag $tag (param i32)))
160+
161+
;; CHECK: (export "func" (func $func))
162+
163+
;; CHECK: (func $func (type $1)
164+
;; CHECK-NEXT: (try
165+
;; CHECK-NEXT: (do
166+
;; CHECK-NEXT: (call $throw
167+
;; CHECK-NEXT: (i32.const 1)
168+
;; CHECK-NEXT: )
169+
;; CHECK-NEXT: )
170+
;; CHECK-NEXT: (catch $tag
171+
;; CHECK-NEXT: (drop
172+
;; CHECK-NEXT: (pop i32)
173+
;; CHECK-NEXT: )
174+
;; CHECK-NEXT: )
175+
;; CHECK-NEXT: )
176+
;; CHECK-NEXT: )
177+
(func $func (export "func")
178+
(try
179+
(do
180+
(call $throw
181+
(i32.const 1)
182+
)
183+
)
184+
(catch $tag
185+
;; If we thought no value was possible to pop here (if no exception were
186+
;; created of this tag) then we'd put an unreachable after it. As it is
187+
;; imported, a value might be there, so we do not.
188+
(drop
189+
(pop i32)
190+
)
191+
)
192+
)
193+
)
194+
)
195+
196+
;; As above, but with an exported tag. Also test a tag with multiple params.
197+
(module
198+
;; CHECK: (type $0 (func (param i32 f64)))
199+
200+
;; CHECK: (type $1 (func (param i32)))
201+
202+
;; CHECK: (type $2 (func))
203+
204+
;; CHECK: (import "fuzzing-support" "throw" (func $throw (type $1) (param i32)))
205+
(import "fuzzing-support" "throw" (func $throw (param i32)))
206+
207+
;; CHECK: (tag $tag (type $0) (param i32 f64))
208+
(tag $tag (param i32 f64))
209+
210+
;; CHECK: (export "func" (func $func))
211+
212+
;; CHECK: (export "tag" (tag $tag))
213+
(export "tag" (tag $tag))
214+
215+
;; CHECK: (func $func (type $2)
216+
;; CHECK-NEXT: (try
217+
;; CHECK-NEXT: (do
218+
;; CHECK-NEXT: (call $throw
219+
;; CHECK-NEXT: (i32.const 1)
220+
;; CHECK-NEXT: )
221+
;; CHECK-NEXT: )
222+
;; CHECK-NEXT: (catch $tag
223+
;; CHECK-NEXT: (tuple.drop 2
224+
;; CHECK-NEXT: (pop (tuple i32 f64))
225+
;; CHECK-NEXT: )
226+
;; CHECK-NEXT: )
227+
;; CHECK-NEXT: )
228+
;; CHECK-NEXT: )
229+
(func $func (export "func")
230+
(try
231+
(do
232+
(call $throw
233+
(i32.const 1)
234+
)
235+
)
236+
(catch $tag
237+
;; Once more, we do not optimize to unreachable here.
238+
(tuple.drop 2
239+
(pop (tuple i32 f64))
240+
)
241+
)
242+
)
243+
)
244+
)
245+
246+
;; Private tags are optimizable.
247+
(module
248+
;; CHECK: (type $0 (func (param i32)))
249+
250+
;; CHECK: (type $1 (func))
251+
252+
;; CHECK: (import "fuzzing-support" "throw" (func $throw (type $0) (param i32)))
253+
(import "fuzzing-support" "throw" (func $throw (param i32)))
254+
255+
;; CHECK: (tag $tag (type $0) (param i32))
256+
(tag $tag (param i32))
257+
258+
;; CHECK: (export "func" (func $func))
259+
260+
;; CHECK: (func $func (type $1)
261+
;; CHECK-NEXT: (local $0 i32)
262+
;; CHECK-NEXT: (try
263+
;; CHECK-NEXT: (do
264+
;; CHECK-NEXT: (call $throw
265+
;; CHECK-NEXT: (i32.const 1)
266+
;; CHECK-NEXT: )
267+
;; CHECK-NEXT: )
268+
;; CHECK-NEXT: (catch $tag
269+
;; CHECK-NEXT: (local.set $0
270+
;; CHECK-NEXT: (pop i32)
271+
;; CHECK-NEXT: )
272+
;; CHECK-NEXT: (drop
273+
;; CHECK-NEXT: (block
274+
;; CHECK-NEXT: (drop
275+
;; CHECK-NEXT: (local.get $0)
276+
;; CHECK-NEXT: )
277+
;; CHECK-NEXT: (unreachable)
278+
;; CHECK-NEXT: )
279+
;; CHECK-NEXT: )
280+
;; CHECK-NEXT: )
281+
;; CHECK-NEXT: )
282+
;; CHECK-NEXT: )
283+
(func $func (export "func")
284+
(try
285+
(do
286+
(call $throw
287+
(i32.const 1)
288+
)
289+
)
290+
(catch $tag
291+
;; The tag is neither imported nor exported, so we can optimize to
292+
;; unreachable.
293+
(drop
294+
(pop i32)
295+
)
296+
)
297+
)
298+
)
299+
)
300+

0 commit comments

Comments
 (0)