Skip to content

Commit 2d96d57

Browse files
committed
Invert reference type null checks
1 parent 8bb0d88 commit 2d96d57

File tree

5 files changed

+111
-40
lines changed

5 files changed

+111
-40
lines changed

src/compiler.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9941,7 +9941,12 @@ export class Compiler extends DiagnosticEmitter {
99419941
case TypeKind.EQREF:
99429942
case TypeKind.DATAREF:
99439943
case TypeKind.I31REF: {
9944-
return module.ref_is(RefIsOp.RefIsNull, expr);
9944+
// Needs to be true when the ref is _not_ null.
9945+
// Therefore: 1 - <ref.is_null>
9946+
return type.size == 64
9947+
? module.binary(BinaryOp.SubI64, module.i64(1), module.ref_is(RefIsOp.RefIsNull, expr))
9948+
: module.binary(BinaryOp.SubI32, module.i32(1), module.ref_is(RefIsOp.RefIsNull, expr));
9949+
99459950
}
99469951
default: {
99479952
assert(false);

tests/compiler/features/reference-types.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ exports.preInstantiate = function(imports, exports) {
99
external: function(a) {
1010
return a;
1111
},
12+
somethingReal() {
13+
return {};
14+
},
15+
somethingNull() {
16+
return null;
17+
},
1218
someObject: {
1319
theKey: "Hello world!"
1420
},

tests/compiler/features/reference-types.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
{
22
"features": [
3-
"reference-types",
4-
"exception-handling",
5-
"gc"
3+
"reference-types"
64
],
75
"asc_flags": [
86
]

tests/compiler/features/reference-types.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// can use externref as a parameter or return type
22

33
export declare function external(a: externref): externref;
4+
export declare function somethingReal(): externref;
5+
export declare function somethingNull(): externref;
46

57
export function internal(a: externref): externref {
68
const b = external(a);
@@ -26,6 +28,44 @@ console.log(someObject);
2628
console.log(someKey);
2729
console.log(Reflect.get(someObject, someKey));
2830

31+
// Truthiness conversion
32+
if(!somethingReal()) {
33+
assert(false);
34+
}
35+
if(!somethingNull()) {
36+
// nop
37+
} else {
38+
assert(false);
39+
}
40+
if(somethingReal()) {
41+
// nop
42+
} else {
43+
assert(false);
44+
}
45+
if(somethingNull()) {
46+
assert(false);
47+
}
48+
49+
// Explicit null checks (don’t work yet)
50+
/*
51+
if(somethingReal() !== null) {
52+
// nop
53+
} else {
54+
assert(false);
55+
}
56+
if(somethingReal() === null) {
57+
assert(false);
58+
}
59+
if(somethingNull() === null) {
60+
// nop
61+
} else {
62+
assert(false);
63+
}
64+
if(somethingNull() !== null) {
65+
assert(false);
66+
}
67+
*/
68+
2969
// can represent and recognize 'null'
3070

3171
var funcGlobal: funcref;

tests/compiler/features/reference-types.untouched.wat

Lines changed: 58 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
(module
22
(type $none_=>_none (func))
3+
(type $none_=>_externref (func (result externref)))
34
(type $externref_=>_externref (func (param externref) (result externref)))
45
(type $externref_=>_none (func (param externref)))
56
(type $i32_i32_i32_i32_=>_none (func (param i32 i32 i32 i32)))
@@ -11,6 +12,8 @@
1112
(import "env" "abort" (func $~lib/builtins/abort (param i32 i32 i32 i32)))
1213
(import "console" "log" (func $~lib/bindings/console/log (param externref)))
1314
(import "Reflect" "get" (func $~lib/bindings/Reflect/get (param externref externref) (result externref)))
15+
(import "reference-types" "somethingReal" (func $features/reference-types/somethingReal (result externref)))
16+
(import "reference-types" "somethingNull" (func $features/reference-types/somethingNull (result externref)))
1417
(import "reference-types" "external" (func $features/reference-types/external (param externref) (result externref)))
1518
(memory $0 1)
1619
(data (i32.const 12) "L\00\00\00\00\00\00\00\00\00\00\00\01\00\00\006\00\00\00f\00e\00a\00t\00u\00r\00e\00s\00/\00r\00e\00f\00e\00r\00e\00n\00c\00e\00-\00t\00y\00p\00e\00s\00.\00t\00s\00\00\00\00\00\00\00")
@@ -26,6 +29,8 @@
2629
(global $~lib/memory/__stack_pointer (mut i32) (i32.const 16476))
2730
(global $~lib/memory/__heap_base i32 (i32.const 16476))
2831
(export "external" (func $features/reference-types/external))
32+
(export "somethingReal" (func $features/reference-types/somethingReal))
33+
(export "somethingNull" (func $features/reference-types/somethingNull))
2934
(export "internal" (func $features/reference-types/internal))
3035
(export "memory" (memory $0))
3136
(start $~start)
@@ -165,7 +170,6 @@
165170
nop
166171
)
167172
(func $start:features/reference-types
168-
(local $0 funcref)
169173
global.get $features/reference-types/someObject
170174
global.get $features/reference-types/someKey
171175
call $~lib/bindings/Reflect/has
@@ -175,7 +179,7 @@
175179
if
176180
i32.const 0
177181
i32.const 32
178-
i32.const 19
182+
i32.const 21
179183
i32.const 1
180184
call $~lib/builtins/abort
181185
unreachable
@@ -188,57 +192,75 @@
188192
global.get $features/reference-types/someKey
189193
call $~lib/bindings/Reflect/get
190194
call $~lib/bindings/console/log
191-
global.get $features/reference-types/funcGlobal
195+
i32.const 1
196+
call $features/reference-types/somethingReal
192197
ref.is_null
193-
i32.eqz
198+
i32.sub
194199
i32.eqz
195200
if
196201
i32.const 0
197-
i32.const 32
198-
i32.const 32
199-
i32.const 1
200-
call $~lib/builtins/abort
201-
unreachable
202+
i32.eqz
203+
if
204+
i32.const 0
205+
i32.const 32
206+
i32.const 33
207+
i32.const 3
208+
call $~lib/builtins/abort
209+
unreachable
210+
end
202211
end
203-
ref.null func
204-
global.set $features/reference-types/funcGlobal
205-
global.get $features/reference-types/funcGlobal
212+
i32.const 1
213+
call $features/reference-types/somethingNull
206214
ref.is_null
207-
i32.eqz
215+
i32.sub
208216
i32.eqz
209217
if
218+
nop
219+
else
210220
i32.const 0
211-
i32.const 32
212-
i32.const 34
213-
i32.const 1
214-
call $~lib/builtins/abort
215-
unreachable
221+
i32.eqz
222+
if
223+
i32.const 0
224+
i32.const 32
225+
i32.const 38
226+
i32.const 3
227+
call $~lib/builtins/abort
228+
unreachable
229+
end
216230
end
217-
ref.null func
218-
global.set $features/reference-types/funcGlobalInit
219-
global.get $features/reference-types/funcGlobalInit
231+
i32.const 1
232+
call $features/reference-types/somethingReal
220233
ref.is_null
221-
i32.eqz
222-
i32.eqz
234+
i32.sub
223235
if
236+
nop
237+
else
224238
i32.const 0
225-
i32.const 32
226-
i32.const 36
227-
i32.const 1
228-
call $~lib/builtins/abort
229-
unreachable
239+
i32.eqz
240+
if
241+
i32.const 0
242+
i32.const 32
243+
i32.const 43
244+
i32.const 3
245+
call $~lib/builtins/abort
246+
unreachable
247+
end
230248
end
231-
global.get $features/reference-types/externGlobal
249+
i32.const 1
250+
call $features/reference-types/somethingNull
232251
ref.is_null
233-
i32.eqz
234-
i32.eqz
252+
i32.sub
235253
if
236254
i32.const 0
237-
i32.const 32
238-
i32.const 39
239-
i32.const 1
240-
call $~lib/builtins/abort
241-
unreachable
255+
i32.eqz
256+
if
257+
i32.const 0
258+
i32.const 32
259+
i32.const 46
260+
i32.const 3
261+
call $~lib/builtins/abort
262+
unreachable
263+
end
242264
end
243265
ref.null extern
244266
global.set $features/reference-types/externGlobal

0 commit comments

Comments
 (0)