Skip to content

Commit 99e54a0

Browse files
authored
StringLowering: Fix up nulls written to struct.new fields (#6306)
1 parent 5ef1aba commit 99e54a0

File tree

2 files changed

+111
-46
lines changed

2 files changed

+111
-46
lines changed

src/passes/StringLowering.cpp

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -423,24 +423,44 @@ struct StringLowering : public StringGathering {
423423
}
424424
}
425425

426-
// Additional hacks.
426+
// Additional hacks: We fix up a none that should be noext. Before the
427+
// lowering we can use none for stringref, but after we must use noext as
428+
// the two do not share a bottom type.
429+
//
430+
// The code here and in the visitors below is course wildly insufficient
431+
// (we need selects and blocks and all other joins, and not just nulls,
432+
// etc.) but in practice this is enough for now. TODO extend as needed
433+
void ensureNullIsExt(Expression* curr) {
434+
if (auto* null = curr->dynCast<RefNull>()) {
435+
null->finalize(HeapType::noext);
436+
}
437+
}
438+
439+
bool isExt(Type type) {
440+
return type.isRef() && type.getHeapType() == HeapType::ext;
441+
}
427442

428443
void visitIf(If* curr) {
429-
// Before the lowering we could have one arm be a ref.null none and the
430-
// other a stringref; after the lowering that is invalid, because the
431-
// string is now extern, which has no shared ancestor with none. Fix
432-
// that up manually in the simple case of an if arm with a null by
433-
// correcting the null's type. This is of course wildly insufficient (we
434-
// need selects and blocks and all other joins) but in practice this is
435-
// enough for now. TODO extend as needed
436-
if (curr->type.isRef() && curr->type.getHeapType() == HeapType::ext) {
437-
auto fixArm = [](Expression* arm) {
438-
if (auto* null = arm->dynCast<RefNull>()) {
439-
null->finalize(HeapType::noext);
440-
}
441-
};
442-
fixArm(curr->ifTrue);
443-
fixArm(curr->ifFalse);
444+
// If the if outputs an ext, fix up the arms to contain proper nulls for
445+
// that type.
446+
if (isExt(curr->type)) {
447+
ensureNullIsExt(curr->ifTrue);
448+
ensureNullIsExt(curr->ifFalse);
449+
}
450+
}
451+
452+
void visitStructNew(StructNew* curr) {
453+
if (curr->type == Type::unreachable || curr->operands.empty()) {
454+
return;
455+
}
456+
457+
// If we write a none into an ext field, fix that.
458+
auto& fields = curr->type.getHeapType().getStruct().fields;
459+
assert(curr->operands.size() == fields.size());
460+
for (Index i = 0; i < fields.size(); i++) {
461+
if (isExt(fields[i].type)) {
462+
ensureNullIsExt(curr->operands[i]);
463+
}
444464
}
445465
}
446466
};

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

Lines changed: 75 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515

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

18+
;; CHECK: (type $struct-of-string (struct (field externref) (field i32) (field anyref)))
19+
(type $struct-of-string (struct (field stringref) (field i32) (field anyref)))
20+
1821
;; CHECK: (type $struct-of-array (struct (field (ref $0))))
1922
(type $struct-of-array (struct (field (ref $array16))))
2023

@@ -34,58 +37,60 @@
3437
(type $array16 (array (mut i16)))
3538
)
3639

37-
;; CHECK: (type $11 (func (param externref) (result externref)))
38-
3940
;; CHECK: (type $12 (func (param externref) (result externref)))
4041

41-
;; CHECK: (type $13 (func (param externref) (result i32)))
42+
;; CHECK: (type $13 (func (param externref) (result externref)))
4243

43-
;; CHECK: (type $14 (func (param externref externref) (result i32)))
44+
;; CHECK: (type $14 (func (param externref) (result i32)))
4445

45-
;; CHECK: (type $15 (func (param externref (ref $0)) (result i32)))
46+
;; CHECK: (type $15 (func (param externref externref) (result i32)))
4647

47-
;; CHECK: (type $16 (func (param (ref $0))))
48+
;; CHECK: (type $16 (func (param externref (ref $0)) (result i32)))
4849

49-
;; CHECK: (type $17 (func (param externref externref externref externref)))
50+
;; CHECK: (type $17 (func (param (ref $0))))
5051

51-
;; CHECK: (type $18 (func (param (ref null $0) i32 i32) (result (ref extern))))
52+
;; CHECK: (type $18 (func (param externref externref externref externref)))
5253

53-
;; CHECK: (type $19 (func (param i32) (result (ref extern))))
54+
;; CHECK: (type $19 (func (param (ref null $0) i32 i32) (result (ref extern))))
5455

55-
;; CHECK: (type $20 (func (param externref (ref null $0) i32) (result i32)))
56+
;; CHECK: (type $20 (func (param i32) (result (ref extern))))
5657

57-
;; CHECK: (type $21 (func (param externref) (result i32)))
58+
;; CHECK: (type $21 (func (param externref (ref null $0) i32) (result i32)))
5859

59-
;; CHECK: (type $22 (func (param externref i32) (result i32)))
60+
;; CHECK: (type $22 (func (param externref) (result i32)))
6061

61-
;; CHECK: (type $23 (func (param externref i32 i32) (result (ref extern))))
62+
;; CHECK: (type $23 (func (param externref i32) (result i32)))
63+
64+
;; CHECK: (type $24 (func (param externref i32 i32) (result (ref extern))))
6265

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

68+
;; CHECK: (import "string.const" "1" (global $string.const_value (ref extern)))
69+
6570
;; CHECK: (import "colliding" "name" (func $fromCodePoint (type $1)))
6671
(import "colliding" "name" (func $fromCodePoint))
6772

68-
;; CHECK: (import "wasm:js-string" "fromCharCodeArray" (func $fromCharCodeArray (type $18) (param (ref null $0) i32 i32) (result (ref extern))))
73+
;; CHECK: (import "wasm:js-string" "fromCharCodeArray" (func $fromCharCodeArray (type $19) (param (ref null $0) i32 i32) (result (ref extern))))
6974

70-
;; CHECK: (import "wasm:js-string" "fromCodePoint" (func $fromCodePoint_16 (type $19) (param i32) (result (ref extern))))
75+
;; CHECK: (import "wasm:js-string" "fromCodePoint" (func $fromCodePoint_17 (type $20) (param i32) (result (ref extern))))
7176

72-
;; CHECK: (import "wasm:js-string" "intoCharCodeArray" (func $intoCharCodeArray (type $20) (param externref (ref null $0) i32) (result i32)))
77+
;; CHECK: (import "wasm:js-string" "intoCharCodeArray" (func $intoCharCodeArray (type $21) (param externref (ref null $0) i32) (result i32)))
7378

7479
;; CHECK: (import "wasm:js-string" "equals" (func $equals (type $2) (param externref externref) (result i32)))
7580

7681
;; CHECK: (import "wasm:js-string" "compare" (func $compare (type $2) (param externref externref) (result i32)))
7782

78-
;; CHECK: (import "wasm:js-string" "length" (func $length (type $21) (param externref) (result i32)))
83+
;; CHECK: (import "wasm:js-string" "length" (func $length (type $22) (param externref) (result i32)))
7984

80-
;; CHECK: (import "wasm:js-string" "codePointAt" (func $codePointAt (type $22) (param externref i32) (result i32)))
85+
;; CHECK: (import "wasm:js-string" "codePointAt" (func $codePointAt (type $23) (param externref i32) (result i32)))
8186

82-
;; CHECK: (import "wasm:js-string" "substring" (func $substring (type $23) (param externref i32 i32) (result (ref extern))))
87+
;; CHECK: (import "wasm:js-string" "substring" (func $substring (type $24) (param externref i32 i32) (result (ref extern))))
8388

8489
;; CHECK: (export "export.1" (func $exported-string-returner))
8590

8691
;; CHECK: (export "export.2" (func $exported-string-receiver))
8792

88-
;; CHECK: (func $string.as (type $17) (param $a externref) (param $b externref) (param $c externref) (param $d externref)
93+
;; CHECK: (func $string.as (type $18) (param $a externref) (param $b externref) (param $c externref) (param $d externref)
8994
;; CHECK-NEXT: (local.set $b
9095
;; CHECK-NEXT: (local.get $a)
9196
;; CHECK-NEXT: )
@@ -120,7 +125,7 @@
120125
)
121126
)
122127

123-
;; CHECK: (func $string.new.gc (type $16) (param $array16 (ref $0))
128+
;; CHECK: (func $string.new.gc (type $17) (param $array16 (ref $0))
124129
;; CHECK-NEXT: (drop
125130
;; CHECK-NEXT: (call $fromCharCodeArray
126131
;; CHECK-NEXT: (local.get $array16)
@@ -140,7 +145,7 @@
140145
)
141146

142147
;; CHECK: (func $string.from_code_point (type $4) (result externref)
143-
;; CHECK-NEXT: (call $fromCodePoint_16
148+
;; CHECK-NEXT: (call $fromCodePoint_17
144149
;; CHECK-NEXT: (i32.const 1)
145150
;; CHECK-NEXT: )
146151
;; CHECK-NEXT: )
@@ -150,7 +155,7 @@
150155
)
151156
)
152157

153-
;; CHECK: (func $string.encode (type $15) (param $ref externref) (param $array16 (ref $0)) (result i32)
158+
;; CHECK: (func $string.encode (type $16) (param $ref externref) (param $array16 (ref $0)) (result i32)
154159
;; CHECK-NEXT: (call $intoCharCodeArray
155160
;; CHECK-NEXT: (local.get $ref)
156161
;; CHECK-NEXT: (local.get $array16)
@@ -165,7 +170,7 @@
165170
)
166171
)
167172

168-
;; CHECK: (func $string.eq (type $14) (param $a externref) (param $b externref) (result i32)
173+
;; CHECK: (func $string.eq (type $15) (param $a externref) (param $b externref) (result i32)
169174
;; CHECK-NEXT: (call $equals
170175
;; CHECK-NEXT: (local.get $a)
171176
;; CHECK-NEXT: (local.get $b)
@@ -178,7 +183,7 @@
178183
)
179184
)
180185

181-
;; CHECK: (func $string.compare (type $14) (param $a externref) (param $b externref) (result i32)
186+
;; CHECK: (func $string.compare (type $15) (param $a externref) (param $b externref) (result i32)
182187
;; CHECK-NEXT: (call $compare
183188
;; CHECK-NEXT: (local.get $a)
184189
;; CHECK-NEXT: (local.get $b)
@@ -191,7 +196,7 @@
191196
)
192197
)
193198

194-
;; CHECK: (func $string.length (type $13) (param $ref externref) (result i32)
199+
;; CHECK: (func $string.length (type $14) (param $ref externref) (result i32)
195200
;; CHECK-NEXT: (call $length
196201
;; CHECK-NEXT: (local.get $ref)
197202
;; CHECK-NEXT: )
@@ -202,7 +207,7 @@
202207
)
203208
)
204209

205-
;; CHECK: (func $string.get_codeunit (type $13) (param $ref externref) (result i32)
210+
;; CHECK: (func $string.get_codeunit (type $14) (param $ref externref) (result i32)
206211
;; CHECK-NEXT: (call $codePointAt
207212
;; CHECK-NEXT: (local.get $ref)
208213
;; CHECK-NEXT: (i32.const 2)
@@ -215,7 +220,7 @@
215220
)
216221
)
217222

218-
;; CHECK: (func $string.slice (type $12) (param $ref externref) (result externref)
223+
;; CHECK: (func $string.slice (type $13) (param $ref externref) (result externref)
219224
;; CHECK-NEXT: (call $substring
220225
;; CHECK-NEXT: (local.get $ref)
221226
;; CHECK-NEXT: (i32.const 2)
@@ -230,7 +235,7 @@
230235
)
231236
)
232237

233-
;; CHECK: (func $if.string (type $11) (param $ref externref) (result externref)
238+
;; CHECK: (func $if.string (type $12) (param $ref externref) (result externref)
234239
;; CHECK-NEXT: (if (result externref)
235240
;; CHECK-NEXT: (i32.const 0)
236241
;; CHECK-NEXT: (then
@@ -253,7 +258,7 @@
253258
)
254259
)
255260

256-
;; CHECK: (func $if.string.flip (type $11) (param $ref externref) (result externref)
261+
;; CHECK: (func $if.string.flip (type $12) (param $ref externref) (result externref)
257262
;; CHECK-NEXT: (if (result externref)
258263
;; CHECK-NEXT: (i32.const 0)
259264
;; CHECK-NEXT: (then
@@ -366,4 +371,44 @@
366371
)
367372
)
368373
)
374+
375+
;; CHECK: (func $struct-of-string (type $1)
376+
;; CHECK-NEXT: (drop
377+
;; CHECK-NEXT: (struct.new $struct-of-string
378+
;; CHECK-NEXT: (ref.null noextern)
379+
;; CHECK-NEXT: (i32.const 10)
380+
;; CHECK-NEXT: (ref.null none)
381+
;; CHECK-NEXT: )
382+
;; CHECK-NEXT: )
383+
;; CHECK-NEXT: (drop
384+
;; CHECK-NEXT: (struct.new $struct-of-string
385+
;; CHECK-NEXT: (global.get $string.const_value)
386+
;; CHECK-NEXT: (i32.const 10)
387+
;; CHECK-NEXT: (ref.null none)
388+
;; CHECK-NEXT: )
389+
;; CHECK-NEXT: )
390+
;; CHECK-NEXT: (drop
391+
;; CHECK-NEXT: (struct.new_default $struct-of-string)
392+
;; CHECK-NEXT: )
393+
;; CHECK-NEXT: )
394+
(func $struct-of-string
395+
;; Test lowering of struct fields from stringref to externref.
396+
(drop
397+
(struct.new $struct-of-string
398+
(ref.null none) ;; This null must be fixed to be ext.
399+
(i32.const 10)
400+
(ref.null none) ;; Nothing to do here (field remains anyref).
401+
)
402+
)
403+
(drop
404+
(struct.new $struct-of-string
405+
(string.const "value") ;; Nothing to do besides change to a global.
406+
(i32.const 10)
407+
(ref.null none)
408+
)
409+
)
410+
(drop
411+
(struct.new_default $struct-of-string) ;; Nothing to do here.
412+
)
413+
)
369414
)

0 commit comments

Comments
 (0)