Skip to content

Commit 32a2782

Browse files
authored
StringLowering: Hack around if issue with bottom types (#6303)
Replacing the string heap type with extern is dangerous as they do not share top/bottom types. In practice this works out almost everywhere except for a few ifs, which we can fix up as a hack for now.
1 parent cdc9ad9 commit 32a2782

File tree

2 files changed

+98
-28
lines changed

2 files changed

+98
-28
lines changed

src/passes/StringLowering.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,27 @@ struct StringLowering : public StringGathering {
406406
WASM_UNREACHABLE("TODO: all string.slice*");
407407
}
408408
}
409+
410+
// Additional hacks.
411+
412+
void visitIf(If* curr) {
413+
// Before the lowering we could have one arm be a ref.null none and the
414+
// other a stringref; after the lowering that is invalid, because the
415+
// string is now extern, which has no shared ancestor with none. Fix
416+
// that up manually in the simple case of an if arm with a null by
417+
// correcting the null's type. This is of course wildly insufficient (we
418+
// need selects and blocks and all other joins) but in practice this is
419+
// enough for now. TODO extend as needed
420+
if (curr->type.isRef() && curr->type.getHeapType() == HeapType::ext) {
421+
auto fixArm = [](Expression* arm) {
422+
if (auto* null = arm->dynCast<RefNull>()) {
423+
null->finalize(HeapType::noext);
424+
}
425+
};
426+
fixArm(curr->ifTrue);
427+
fixArm(curr->ifFalse);
428+
}
429+
}
409430
};
410431

411432
Replacer replacer(*this);

test/lit/passes/string-lowering-instructions.wast

Lines changed: 77 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -15,56 +15,58 @@
1515

1616
;; CHECK: (type $4 (func (param externref) (result externref)))
1717

18-
;; CHECK: (type $5 (func (param externref) (result i32)))
18+
;; CHECK: (type $5 (func (param externref) (result externref)))
1919

20-
;; CHECK: (type $6 (func (param externref externref) (result i32)))
20+
;; CHECK: (type $6 (func (param externref) (result i32)))
2121

22-
;; CHECK: (type $7 (func (param externref (ref $array16)) (result i32)))
22+
;; CHECK: (type $7 (func (param externref externref) (result i32)))
2323

24-
;; CHECK: (type $8 (func (param (ref $array16))))
24+
;; CHECK: (type $8 (func (param externref (ref $array16)) (result i32)))
2525

26-
;; CHECK: (type $9 (func (param externref externref externref externref)))
26+
;; CHECK: (type $9 (func (param (ref $array16))))
2727

28-
;; CHECK: (type $10 (func))
28+
;; CHECK: (type $10 (func (param externref externref externref externref)))
2929

30-
;; CHECK: (type $11 (func (param (ref null $array16) i32 i32) (result (ref extern))))
30+
;; CHECK: (type $11 (func))
3131

32-
;; CHECK: (type $12 (func (param i32) (result (ref extern))))
32+
;; CHECK: (type $12 (func (param (ref null $array16) i32 i32) (result (ref extern))))
3333

34-
;; CHECK: (type $13 (func (param externref (ref null $array16) i32) (result i32)))
34+
;; CHECK: (type $13 (func (param i32) (result (ref extern))))
3535

36-
;; CHECK: (type $14 (func (param externref) (result i32)))
36+
;; CHECK: (type $14 (func (param externref (ref null $array16) i32) (result i32)))
3737

38-
;; CHECK: (type $15 (func (param externref i32) (result i32)))
38+
;; CHECK: (type $15 (func (param externref) (result i32)))
3939

40-
;; CHECK: (type $16 (func (param externref i32 i32) (result (ref extern))))
40+
;; CHECK: (type $16 (func (param externref i32) (result i32)))
41+
42+
;; CHECK: (type $17 (func (param externref i32 i32) (result (ref extern))))
4143

4244
;; CHECK: (import "string.const" "0" (global $string.const_exported (ref extern)))
4345

44-
;; CHECK: (import "colliding" "name" (func $fromCodePoint (type $10)))
46+
;; CHECK: (import "colliding" "name" (func $fromCodePoint (type $11)))
4547
(import "colliding" "name" (func $fromCodePoint))
4648

47-
;; CHECK: (import "wasm:js-string" "fromCharCodeArray" (func $fromCharCodeArray (type $11) (param (ref null $array16) i32 i32) (result (ref extern))))
49+
;; CHECK: (import "wasm:js-string" "fromCharCodeArray" (func $fromCharCodeArray (type $12) (param (ref null $array16) i32 i32) (result (ref extern))))
4850

49-
;; CHECK: (import "wasm:js-string" "fromCodePoint" (func $fromCodePoint_13 (type $12) (param i32) (result (ref extern))))
51+
;; CHECK: (import "wasm:js-string" "fromCodePoint" (func $fromCodePoint_15 (type $13) (param i32) (result (ref extern))))
5052

51-
;; CHECK: (import "wasm:js-string" "intoCharCodeArray" (func $intoCharCodeArray (type $13) (param externref (ref null $array16) i32) (result i32)))
53+
;; CHECK: (import "wasm:js-string" "intoCharCodeArray" (func $intoCharCodeArray (type $14) (param externref (ref null $array16) i32) (result i32)))
5254

5355
;; CHECK: (import "wasm:js-string" "equals" (func $equals (type $1) (param externref externref) (result i32)))
5456

5557
;; CHECK: (import "wasm:js-string" "compare" (func $compare (type $1) (param externref externref) (result i32)))
5658

57-
;; CHECK: (import "wasm:js-string" "length" (func $length (type $14) (param externref) (result i32)))
59+
;; CHECK: (import "wasm:js-string" "length" (func $length (type $15) (param externref) (result i32)))
5860

59-
;; CHECK: (import "wasm:js-string" "codePointAt" (func $codePointAt (type $15) (param externref i32) (result i32)))
61+
;; CHECK: (import "wasm:js-string" "codePointAt" (func $codePointAt (type $16) (param externref i32) (result i32)))
6062

61-
;; CHECK: (import "wasm:js-string" "substring" (func $substring (type $16) (param externref i32 i32) (result (ref extern))))
63+
;; CHECK: (import "wasm:js-string" "substring" (func $substring (type $17) (param externref i32 i32) (result (ref extern))))
6264

6365
;; CHECK: (export "export.1" (func $exported-string-returner))
6466

6567
;; CHECK: (export "export.2" (func $exported-string-receiver))
6668

67-
;; CHECK: (func $string.as (type $9) (param $a externref) (param $b externref) (param $c externref) (param $d externref)
69+
;; CHECK: (func $string.as (type $10) (param $a externref) (param $b externref) (param $c externref) (param $d externref)
6870
;; CHECK-NEXT: (local.set $b
6971
;; CHECK-NEXT: (local.get $a)
7072
;; CHECK-NEXT: )
@@ -99,7 +101,7 @@
99101
)
100102
)
101103

102-
;; CHECK: (func $string.new.gc (type $8) (param $array16 (ref $array16))
104+
;; CHECK: (func $string.new.gc (type $9) (param $array16 (ref $array16))
103105
;; CHECK-NEXT: (drop
104106
;; CHECK-NEXT: (call $fromCharCodeArray
105107
;; CHECK-NEXT: (local.get $array16)
@@ -119,7 +121,7 @@
119121
)
120122

121123
;; CHECK: (func $string.from_code_point (type $3) (result externref)
122-
;; CHECK-NEXT: (call $fromCodePoint_13
124+
;; CHECK-NEXT: (call $fromCodePoint_15
123125
;; CHECK-NEXT: (i32.const 1)
124126
;; CHECK-NEXT: )
125127
;; CHECK-NEXT: )
@@ -129,7 +131,7 @@
129131
)
130132
)
131133

132-
;; CHECK: (func $string.encode (type $7) (param $ref externref) (param $array16 (ref $array16)) (result i32)
134+
;; CHECK: (func $string.encode (type $8) (param $ref externref) (param $array16 (ref $array16)) (result i32)
133135
;; CHECK-NEXT: (call $intoCharCodeArray
134136
;; CHECK-NEXT: (local.get $ref)
135137
;; CHECK-NEXT: (local.get $array16)
@@ -144,7 +146,7 @@
144146
)
145147
)
146148

147-
;; CHECK: (func $string.eq (type $6) (param $a externref) (param $b externref) (result i32)
149+
;; CHECK: (func $string.eq (type $7) (param $a externref) (param $b externref) (result i32)
148150
;; CHECK-NEXT: (call $equals
149151
;; CHECK-NEXT: (local.get $a)
150152
;; CHECK-NEXT: (local.get $b)
@@ -157,7 +159,7 @@
157159
)
158160
)
159161

160-
;; CHECK: (func $string.compare (type $6) (param $a externref) (param $b externref) (result i32)
162+
;; CHECK: (func $string.compare (type $7) (param $a externref) (param $b externref) (result i32)
161163
;; CHECK-NEXT: (call $compare
162164
;; CHECK-NEXT: (local.get $a)
163165
;; CHECK-NEXT: (local.get $b)
@@ -170,7 +172,7 @@
170172
)
171173
)
172174

173-
;; CHECK: (func $string.length (type $5) (param $ref externref) (result i32)
175+
;; CHECK: (func $string.length (type $6) (param $ref externref) (result i32)
174176
;; CHECK-NEXT: (call $length
175177
;; CHECK-NEXT: (local.get $ref)
176178
;; CHECK-NEXT: )
@@ -181,7 +183,7 @@
181183
)
182184
)
183185

184-
;; CHECK: (func $string.get_codeunit (type $5) (param $ref externref) (result i32)
186+
;; CHECK: (func $string.get_codeunit (type $6) (param $ref externref) (result i32)
185187
;; CHECK-NEXT: (call $codePointAt
186188
;; CHECK-NEXT: (local.get $ref)
187189
;; CHECK-NEXT: (i32.const 2)
@@ -194,7 +196,7 @@
194196
)
195197
)
196198

197-
;; CHECK: (func $string.slice (type $4) (param $ref externref) (result externref)
199+
;; CHECK: (func $string.slice (type $5) (param $ref externref) (result externref)
198200
;; CHECK-NEXT: (call $substring
199201
;; CHECK-NEXT: (local.get $ref)
200202
;; CHECK-NEXT: (i32.const 2)
@@ -209,6 +211,53 @@
209211
)
210212
)
211213

214+
;; CHECK: (func $if.string (type $4) (param $ref externref) (result externref)
215+
;; CHECK-NEXT: (if (result externref)
216+
;; CHECK-NEXT: (i32.const 0)
217+
;; CHECK-NEXT: (then
218+
;; CHECK-NEXT: (ref.null noextern)
219+
;; CHECK-NEXT: )
220+
;; CHECK-NEXT: (else
221+
;; CHECK-NEXT: (local.get $ref)
222+
;; CHECK-NEXT: )
223+
;; CHECK-NEXT: )
224+
;; CHECK-NEXT: )
225+
(func $if.string (param $ref stringref) (result stringref)
226+
(if (result stringref)
227+
(i32.const 0)
228+
(then
229+
(ref.null none) ;; this will turn into noextern
230+
)
231+
(else
232+
(local.get $ref)
233+
)
234+
)
235+
)
236+
237+
;; CHECK: (func $if.string.flip (type $4) (param $ref externref) (result externref)
238+
;; CHECK-NEXT: (if (result externref)
239+
;; CHECK-NEXT: (i32.const 0)
240+
;; CHECK-NEXT: (then
241+
;; CHECK-NEXT: (local.get $ref)
242+
;; CHECK-NEXT: )
243+
;; CHECK-NEXT: (else
244+
;; CHECK-NEXT: (ref.null noextern)
245+
;; CHECK-NEXT: )
246+
;; CHECK-NEXT: )
247+
;; CHECK-NEXT: )
248+
(func $if.string.flip (param $ref stringref) (result stringref)
249+
;; As above but with flipped arms.
250+
(if (result stringref)
251+
(i32.const 0)
252+
(then
253+
(local.get $ref)
254+
)
255+
(else
256+
(ref.null none)
257+
)
258+
)
259+
)
260+
212261
;; CHECK: (func $exported-string-returner (type $3) (result externref)
213262
;; CHECK-NEXT: (global.get $string.const_exported)
214263
;; CHECK-NEXT: )

0 commit comments

Comments
 (0)