Skip to content

Commit 36d2093

Browse files
authored
StringLowering: Properly handle nullable inputs to StringAs (#6307)
StringAs's output must be non-nullable, so add a cast.
1 parent 99e54a0 commit 36d2093

File tree

2 files changed

+47
-6
lines changed

2 files changed

+47
-6
lines changed

src/passes/StringLowering.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "ir/module-utils.h"
3636
#include "ir/names.h"
3737
#include "ir/type-updating.h"
38+
#include "ir/utils.h"
3839
#include "pass.h"
3940
#include "support/json.h"
4041
#include "wasm-builder.h"
@@ -360,7 +361,13 @@ struct StringLowering : public StringGathering {
360361
void visitStringAs(StringAs* curr) {
361362
// There is no difference between strings and views with imported
362363
// strings: they are all just JS strings, so no conversion is needed.
363-
replaceCurrent(curr->ref);
364+
// However, we must keep the same nullability: the output of StringAs
365+
// must be non-nullable.
366+
auto* ref = curr->ref;
367+
if (ref->type.isNullable()) {
368+
ref = Builder(*getModule()).makeRefAs(RefAsNonNull, ref);
369+
}
370+
replaceCurrent(ref);
364371
}
365372

366373
void visitStringEncode(StringEncode* curr) {
@@ -468,6 +475,9 @@ struct StringLowering : public StringGathering {
468475
Replacer replacer(*this);
469476
replacer.run(getPassRunner(), module);
470477
replacer.walkModuleCode(module);
478+
479+
// ReFinalize to apply changes to parents.
480+
ReFinalize().run(getPassRunner(), module);
471481
}
472482
};
473483

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

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949

5050
;; CHECK: (type $17 (func (param (ref $0))))
5151

52-
;; CHECK: (type $18 (func (param externref externref externref externref)))
52+
;; CHECK: (type $18 (func (param externref (ref extern) externref externref externref (ref extern))))
5353

5454
;; CHECK: (type $19 (func (param (ref null $0) i32 i32) (result (ref extern))))
5555

@@ -90,22 +90,38 @@
9090

9191
;; CHECK: (export "export.2" (func $exported-string-receiver))
9292

93-
;; CHECK: (func $string.as (type $18) (param $a externref) (param $b externref) (param $c externref) (param $d externref)
93+
;; CHECK: (func $string.as (type $18) (param $a externref) (param $a_nn (ref extern)) (param $b externref) (param $c externref) (param $d externref) (param $nn_view (ref extern))
9494
;; CHECK-NEXT: (local.set $b
95-
;; CHECK-NEXT: (local.get $a)
95+
;; CHECK-NEXT: (ref.as_non_null
96+
;; CHECK-NEXT: (local.get $a)
97+
;; CHECK-NEXT: )
9698
;; CHECK-NEXT: )
9799
;; CHECK-NEXT: (local.set $c
98-
;; CHECK-NEXT: (local.get $a)
100+
;; CHECK-NEXT: (ref.as_non_null
101+
;; CHECK-NEXT: (local.get $a)
102+
;; CHECK-NEXT: )
99103
;; CHECK-NEXT: )
100104
;; CHECK-NEXT: (local.set $d
101-
;; CHECK-NEXT: (local.get $a)
105+
;; CHECK-NEXT: (ref.as_non_null
106+
;; CHECK-NEXT: (local.get $a)
107+
;; CHECK-NEXT: )
108+
;; CHECK-NEXT: )
109+
;; CHECK-NEXT: (local.set $nn_view
110+
;; CHECK-NEXT: (ref.as_non_null
111+
;; CHECK-NEXT: (local.get $a)
112+
;; CHECK-NEXT: )
113+
;; CHECK-NEXT: )
114+
;; CHECK-NEXT: (local.set $nn_view
115+
;; CHECK-NEXT: (local.get $a_nn)
102116
;; CHECK-NEXT: )
103117
;; CHECK-NEXT: )
104118
(func $string.as
105119
(param $a stringref)
120+
(param $a_nn (ref string))
106121
(param $b stringview_wtf8)
107122
(param $c stringview_wtf16)
108123
(param $d stringview_iter)
124+
(param $nn_view (ref stringview_wtf16))
109125
;; These operations all vanish in the lowering, as they all become extref
110126
;; (JS strings).
111127
(local.set $b
@@ -123,6 +139,21 @@
123139
(local.get $a)
124140
)
125141
)
142+
;; The input is nullable, and string.as casts to non-null, so we will need
143+
;; to keep a cast here in order to validate. (We also add a cast in all the
144+
;; above as the inputs are nullable, but this is the only one that will
145+
;; fail to validate. Other opts can remove the above ones.)
146+
(local.set $nn_view
147+
(string.as_wtf16
148+
(local.get $a)
149+
)
150+
)
151+
;; The input is already non-nullable here, so no cast is needed.
152+
(local.set $nn_view
153+
(string.as_wtf16
154+
(local.get $a_nn)
155+
)
156+
)
126157
)
127158

128159
;; CHECK: (func $string.new.gc (type $17) (param $array16 (ref $0))

0 commit comments

Comments
 (0)