1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
|
// |jit-test| skip-if: !wasmFunctionReferencesEnabled()
// non-null values are subtype of null values
wasmValidateText(`(module
(func (param $a (ref extern))
local.get $a
(block (param (ref null extern))
drop
)
)
)`);
// null values are not subtype of non-null values
wasmFailValidateText(`(module
(func (param $a (ref null extern))
local.get $a
(block (param (ref extern))
drop
)
)
)`, /expression has type externref but expected \(ref extern\)/);
// can have non-defaultable local, but not use/get if unset.
wasmValidateText(`(module
(func (local (ref extern)))
)`);
wasmFailValidateText(`(module
(func (local (ref extern))
local.get 0
drop
)
)`, /local\.get read from unset local/);
wasmFailValidateText(`(module
(func
(local (ref extern))
unreachable
block
local.get 0
drop
end
)
)`, /local\.get read from unset local/);
wasmFailValidateText(`(module
(func (param funcref) (result funcref) (local (ref func))
block
local.get 0
ref.as_non_null
local.set 1
end
local.get 1
)
)`, /local\.get read from unset local/);
wasmValidateText(`(module
(func (param $r (ref extern))
(local $var (ref extern))
local.get $r
ref.as_non_null
local.set $var
block block block
local.get $var
drop
end end end
)
(func
(param (ref null func) (ref null func) (ref func))
(result funcref)
(local (ref func) i32 (ref func) (ref null func))
local.get 0
ref.as_non_null
local.tee 3
block
local.get 6
ref.as_non_null
local.set 5
end
local.get 2
drop
local.tee 5
)
)`);
wasmFailValidateText(`(module
(elem declare 0)
(func
(local (ref func))
i32.const 0
if
ref.func 0
local.set 0
else
local.get 0
drop
end
)
)`, /local\.get read from unset local/);
wasmValidateText(`(module
(elem declare 0)
(func (result funcref)
(local (ref func) (ref func))
i32.const 0
if (result funcref)
ref.func 0
local.set 0
local.get 0
else
ref.func 0
local.tee 1
local.get 1
drop
end
)
)`);
// exported funcs can't take null in non-nullable params
let {a} = wasmEvalText(`(module
(func (export "a") (param (ref extern)))
)`).exports;
assertErrorMessage(() => a(null), TypeError, /cannot pass null to non-nullable/);
for (let val of WasmNonNullExternrefValues) {
a(val);
}
// imported funcs can't return null in non-nullable results
function returnNull() {
return null;
}
function returnMultiNullReg() {
return [null, null];
}
function returnMultiNullStack() {
return [1, 2, 3, 4, 5, 6, 7, 8, null];
}
let {runNull, runMultiNullReg, runMultiNullStack} = wasmEvalText(`(module
(func $returnNull (import "" "returnNull") (result (ref extern)))
(func $returnMultiNullReg (import "" "returnMultiNullReg") (result (ref extern) (ref extern)))
(func $returnMultiNullStack (import "" "returnMultiNullStack") (result (ref extern) (ref extern) (ref extern) (ref extern) (ref extern) (ref extern) (ref extern) (ref extern) (ref extern)))
(func (export "runNull")
call $returnNull
unreachable
)
(func (export "runMultiNullReg")
call $returnMultiNullReg
unreachable
)
(func (export "runMultiNullStack")
call $returnMultiNullStack
unreachable
)
)`, { "": { returnNull, returnMultiNullReg, returnMultiNullStack } }).exports;
assertErrorMessage(() => runNull(), TypeError, /cannot pass null to non-nullable/);
assertErrorMessage(() => runMultiNullReg(), TypeError, /cannot pass null to non-nullable/);
assertErrorMessage(() => runMultiNullStack(), TypeError, /cannot pass null to non-nullable/);
{
// can have non-nullable globals
wasmEvalText(`(module
(func $f)
(elem declare $f)
(global (ref func) ref.func $f)
)`);
}
// cannot have non-nullable tables without initializer
wasmFailValidateText(`(module
(table (ref extern) (elem))
)`, /table with non-nullable references requires initializer/);
// Testing internal wasmLosslessInvoke to pass non-nullable as params and arguments.
let {t} = wasmEvalText(`(module
(func (export "t") (param (ref extern)) (result (ref extern))
(local (ref extern))
(local.set 1 (local.get 0))
(local.get 1)
)
)`).exports;
const ret = wasmLosslessInvoke(t, {test: 1});
assertEq(ret.value.test, 1);
|