summaryrefslogtreecommitdiffstats
path: root/js/src/jit-test/tests/wasm/gc/i31ref.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jit-test/tests/wasm/gc/i31ref.js')
-rw-r--r--js/src/jit-test/tests/wasm/gc/i31ref.js164
1 files changed, 164 insertions, 0 deletions
diff --git a/js/src/jit-test/tests/wasm/gc/i31ref.js b/js/src/jit-test/tests/wasm/gc/i31ref.js
new file mode 100644
index 0000000000..65f2fccc3f
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/gc/i31ref.js
@@ -0,0 +1,164 @@
+// |jit-test| skip-if: !wasmGcEnabled()
+
+let InvalidI31Values = [
+ null,
+ Number.EPSILON,
+ Number.MAX_SAFE_INTEGER,
+ Number.MIN_SAFE_INTEGER,
+ Number.MIN_VALUE,
+ Number.MAX_VALUE,
+ Number.NaN,
+ -0,
+ // Number objects are not coerced
+ ...WasmI31refValues.map(n => new Number(n)),
+ // Non-integers are not valid
+ ...WasmI31refValues.map(n => n + 0.1),
+ ...WasmI31refValues.map(n => n + 0.5),
+ ...WasmI31refValues.map(n => n + 0.9)
+];
+
+// Return an equivalent JS number for if a JS number is converted to i31ref
+// and then zero extended back to 32-bits.
+function valueAsI31GetU(value) {
+ // Zero extending will drop the sign bit, if any
+ return value & 0x7fffffff;
+}
+
+let identity = (n) => n;
+
+let {
+ castFromAnyref,
+ castFromExternref,
+ refI31,
+ refI31Identity,
+ i31GetU,
+ i31GetS,
+ i31EqualsI31,
+ i31EqualsEq
+} = wasmEvalText(`(module
+ (func $identity (import "" "identity") (param anyref) (result anyref))
+
+ (func (export "castFromAnyref") (param anyref) (result i32)
+ local.get 0
+ ref.test (ref i31)
+ )
+ (func (export "castFromExternref") (param externref) (result i32)
+ local.get 0
+ any.convert_extern
+ ref.test (ref i31)
+ )
+ (func (export "refI31") (param i32) (result anyref)
+ local.get 0
+ ref.i31
+ )
+ (func (export "refI31Identity") (param i32) (result anyref)
+ local.get 0
+ ref.i31
+ call $identity
+ )
+ (func (export "i31GetU") (param i32) (result i32)
+ local.get 0
+ ref.i31
+ i31.get_u
+ )
+ (func (export "i31GetS") (param i32) (result i32)
+ local.get 0
+ ref.i31
+ i31.get_s
+ )
+ (func (export "i31EqualsI31") (param i32) (param i32) (result i32)
+ (ref.eq
+ (ref.i31 local.get 0)
+ (ref.i31 local.get 1)
+ )
+ )
+ (func (export "i31EqualsEq") (param i32) (param eqref) (result i32)
+ (ref.eq
+ (ref.i31 local.get 0)
+ local.get 1
+ )
+ )
+)`, {"": {identity}}).exports;
+
+// Test that wasm will represent JS number values that are 31-bit integers as
+// an i31ref
+for (let i of WasmI31refValues) {
+ assertEq(castFromAnyref(i), 1);
+ assertEq(castFromExternref(i), 1);
+}
+
+// Test that wasm will not represent a JS value that is not a 31-bit number as
+// an i31ref
+for (let i of InvalidI31Values) {
+ assertEq(castFromAnyref(i), 0);
+ assertEq(castFromExternref(i), 0);
+}
+
+// Test that we can roundtrip 31-bit integers through the i31ref type
+// faithfully.
+for (let i of WasmI31refValues) {
+ assertEq(refI31(i), i);
+ assertEq(refI31Identity(i), i);
+ assertEq(i31GetU(i), valueAsI31GetU(i));
+ assertEq(i31GetS(i), i);
+}
+
+// Test that i31ref values are truncated when given a 32-bit value
+for (let i of WasmI31refValues) {
+ let adjusted = i | 0x80000000;
+ assertEq(refI31(adjusted), i);
+}
+
+// Test that comparing identical i31 values works
+for (let a of WasmI31refValues) {
+ for (let b of WasmI31refValues) {
+ assertEq(!!i31EqualsI31(a, b), a === b);
+ }
+}
+
+// Test that an i31ref is never mistaken for a different kind of reference
+for (let a of WasmI31refValues) {
+ for (let b of WasmEqrefValues) {
+ assertEq(!!i31EqualsEq(a, b), a === b);
+ }
+}
+
+// Test that i32 values get wrapped correctly
+const bigI32Tests = [
+ {
+ input: MaxI31refValue + 1,
+ expected: MinI31refValue,
+ },
+ {
+ input: MinI31refValue - 1,
+ expected: MaxI31refValue,
+ },
+]
+for (const {input, expected} of bigI32Tests) {
+ const { get, getElem } = wasmEvalText(`(module
+ (func (export "get") (param i32) (result i32)
+ (i31.get_s (ref.i31 (local.get 0)))
+ )
+
+ (table i31ref (elem (item (ref.i31 (i32.const ${input})))))
+ (func (export "getElem") (result i32)
+ (i31.get_s (table.get 0 (i32.const 0)))
+ )
+ )`).exports;
+ assertEq(get(input), expected);
+ assertEq(getElem(), expected);
+}
+
+const { i31GetU_null, i31GetS_null } = wasmEvalText(`(module
+ (func (export "i31GetU_null") (result i32)
+ ref.null i31
+ i31.get_u
+ )
+ (func (export "i31GetS_null") (result i32)
+ ref.null i31
+ i31.get_s
+ )
+)`).exports;
+
+assertErrorMessage(() => i31GetU_null(), WebAssembly.RuntimeError, /dereferencing null pointer/);
+assertErrorMessage(() => i31GetS_null(), WebAssembly.RuntimeError, /dereferencing null pointer/);