Bug 1511958 - part 4, tests for Wasm I64<->BigInt draft
authorAsumu Takikawa <asumu@igalia.com>
Thu, 05 Dec 2019 02:52:25 +0000
changeset 2517408 f17297a6e22c63ff1c3cc93224107345acae91fe
parent 2517407 c12cd9a18b984531ad2e6c5d0ff5b3f81c71e52d
child 2517409 1d3d9411ba9be1cff5ee11b117b10676b796357b
push id460517
push userreviewbot
push dateThu, 05 Dec 2019 02:52:52 +0000
treeherdertry@1b2d78f9463f [default view] [failures only]
bugs1511958
milestone73.0a1
Bug 1511958 - part 4, tests for Wasm I64<->BigInt This commit adds tests for the I64 to BigInt interop for Wasm's JS API. Differential Diff: PHID-DIFF-tclcv7v36tsjvi6kneiz
js/src/jit-test/tests/wasm/bigint/bigint.js
js/src/jit-test/tests/wasm/bigint/directives.txt
js/src/jit-test/tests/wasm/bigint/stubs.js
js/src/jit-test/tests/wasm/ion-error-i64.js
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/bigint/bigint.js
@@ -0,0 +1,188 @@
+// Used to ensure tests will trigger Wasm Jit stub code.
+var threshold = 2 * getJitCompilerOptions()["ion.warmup.trigger"] + 10;
+function testWithJit(f) {
+  for (var i=0; i < threshold; i++) {
+    f();
+  }
+}
+
+function testRet() {
+  var f = wasmEvalText(`(module
+    (func (export "f") (result i64) (i64.const 66))
+  )`).exports.f;
+
+  testWithJit(() => {
+    assertEq(typeof f(), "bigint", "should return a bigint");
+    assertEq(f(), 66n, "should return the correct value");
+  });
+}
+
+function testRetPlus() {
+  var f = wasmEvalText(`(module
+    (func (export "f") (result i64)
+      (i64.const 66)
+      (i64.const 1)
+      (i64.add)
+    )
+  )`).exports.f;
+
+  testWithJit(() => {
+    assertEq(f(), 66n + 1n);
+  });
+}
+
+function testId() {
+  var exports = wasmEvalText(`(module
+    (func (export "f") (param i64 i64) (result i64)
+      (local.get 0)
+    )
+    (func (export "f2") (param i64 i64) (result i64)
+      (local.get 1)
+    )
+  )`).exports;
+  var f = exports.f;
+  var f2 = exports.f2;
+
+  testWithJit(() => {
+    assertEq(f(0n, 1n), 0n);
+    assertEq(f(-0n, 1n), -0n);
+    assertEq(f(123n, 1n), 123n);
+    assertEq(f(-123n, 1n), -123n);
+    assertEq(f(2n ** 63n, 1n), - (2n ** 63n));
+    assertEq(f(2n ** 64n + 123n, 1n), 123n);
+    assertEq(f("5", 1n), 5n);
+
+    assertEq(f2(1n, 0n), 0n);
+    assertEq(f2(1n, -0n), -0n);
+    assertEq(f2(1n, 123n), 123n);
+    assertEq(f2(1n, -123n), -123n);
+    assertEq(f2(1n, 2n ** 63n), - (2n ** 63n));
+    assertEq(f2(1n, 2n ** 64n + 123n), 123n);
+    assertEq(f2(1n, "5"), 5n);
+
+    assertThrowsInstanceOf(() => f(5, 1n), TypeError);
+    assertThrowsInstanceOf(() => f2(1n, 5), TypeError);
+  });
+}
+
+function testIdPlus() {
+  var f = wasmEvalText(`(module
+    (func (export "f") (param i64) (result i64)
+      (i64.const 8)
+      (get_local 0)
+      (i64.add)
+    )
+  )`).exports.f;
+
+  testWithJit(() => {
+    assertEq(f(0n), 0n + 8n);
+    assertEq(f(147n), 147n + 8n);
+  });
+}
+
+// Test functions with many parameters to stress ABI cases.
+function testManyArgs() {
+  var f = wasmEvalText(`(module
+    (func (export "f")
+      (param i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64 i64)
+      (result i64)
+      (get_local 0)
+      (get_local 1)
+      (get_local 2)
+      (get_local 3)
+      (get_local 4)
+      (get_local 5)
+      (get_local 6)
+      (get_local 7)
+      (get_local 8)
+      (get_local 9)
+      (get_local 10)
+      (get_local 11)
+      (get_local 12)
+      (get_local 13)
+      (i64.add)
+      (i64.add)
+      (i64.add)
+      (i64.add)
+      (i64.add)
+      (i64.add)
+      (i64.add)
+      (i64.add)
+      (i64.add)
+      (i64.add)
+      (i64.add)
+      (i64.add)
+      (i64.add)
+    )
+  )`).exports.f;
+
+  testWithJit(() => {
+    assertEq(f(1n, 1n, 1n, 1n, 1n, 1n, 1n, 1n, 1n, 1n, 1n, 1n, 1n, 1n), 14n);
+  });
+}
+
+// Test import and re-export.
+function testImportExport() {
+    var f1 = wasmEvalText(`(module
+      (import "i64" "func" (param i64))
+      (export "f" 0)
+    )`, {i64: { func(b) { assertEq(b, 42n); } },}).exports.f;
+
+    var f2 = wasmEvalText(`(module
+      (import "i64" "func" (param i64) (result i64))
+      (export "f" 0)
+    )`, {i64: { func(n) { return n + 1n } },}).exports.f;
+
+    var f3 = wasmEvalText(`(module
+      (import $i64 "" "i64" (param i64) (result i64))
+      (func (export "f") (param i64) (result i64)
+        (get_local 0)
+        (call $i64))
+    )`, {"":{i64: (n)=>{ return n + 1n }}}).exports.f;
+
+    var f4 = wasmEvalText(`(module
+      (import "i64" "func" (result i64))
+      (export "f" 0)
+    )`, {i64: { func() {} },}).exports.f;
+
+    testWithJit(() => {
+      assertEq(f1(42n), undefined);
+      assertEq(f2(42n), 43n);
+      assertEq(f3(42n), 43n);
+      assertErrorMessage(() => f4(42), TypeError, "not a BigInt");
+    });
+}
+
+// Test that a mixture of I64 and other argument types works.
+function testMixedArgs() {
+    var f = wasmEvalText(`(module
+    (func (export "f")
+      (param i64 f32 f64 i32 i64)
+      (result i64)
+      (get_local 1)
+      (i64.trunc_s/f32)
+      (get_local 2)
+      (i64.trunc_s/f64)
+      (i64.add)
+      (get_local 3)
+      (i64.extend_i32_u)
+      (i64.add)
+      (get_local 0)
+      (i64.add)
+      (get_local 4)
+      (i64.add)
+    )
+  )`).exports.f;
+
+  testWithJit(() => {
+    assertEq(f(1n, 1.3, 1.7, 1, 1n), 5n);
+  });
+}
+
+testRet();
+testRetPlus();
+testId();
+testIdPlus();
+testManyArgs();
+testImportExport();
+testMixedArgs();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/bigint/directives.txt
@@ -0,0 +1,1 @@
+|jit-test| test-also=--wasm-compiler=ion; test-also=--wasm-compiler=baseline; test-also=--test-wasm-await-tier2; skip-if: !wasmBigIntEnabled(); --wasm-bigint; include:wasm.js
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/bigint/stubs.js
@@ -0,0 +1,125 @@
+// This is similar to the corresponding JIT exit stub test in the
+// wasm/import-export.js file, but it also tests BigInt cases.
+(function testImportJitExit() {
+    let options = getJitCompilerOptions();
+    if (!options['baseline.enable'])
+        return;
+
+    let baselineTrigger = options['baseline.warmup.trigger'];
+
+    let valueToConvert = 0;
+    function ffi(n) {if (n == 1337n) { return BigInt(valueToConvert); }; return 42n; }
+
+    // This case is intended to test that the I64 to BigInt argument
+    // filling for the JIT exit stub does not interfere with the other
+    // argument registers. It's important that the BigInt argument comes
+    // first (to test that it doesn't clobber the subsequent ones).
+    function ffi2(n, x1, x2, x3, x4, x5, x6) {
+        return 42n + BigInt(x1) + BigInt(x2) + BigInt(x3) +
+            BigInt(x4) + BigInt(x5) + BigInt(x6); }
+
+    // This case is for testing issues with potential GC.
+    function ffi3(n1, n2, n3, n4) { return n3; }
+
+    // Baseline compile ffis.
+    for (let i = baselineTrigger + 1; i --> 0;) {
+        ffi(BigInt(i));
+        ffi2(BigInt(i), i, i, i, i, i, i);
+        ffi3(BigInt(i), BigInt(i), BigInt(i), BigInt(i));
+    }
+
+    let imports = {
+        a: {
+            ffi,
+            ffi2,
+            ffi3
+        }
+    };
+
+    ex = wasmEvalText(`(module
+        (import $ffi "a" "ffi" (param i64) (result i64))
+        (import $ffi2 "a" "ffi2" (param i64 i32 i32 i32 i32 i32 i32) (result i64))
+        (import $ffi3 "a" "ffi3" (param i64 i64 i64 i64) (result i64))
+
+        (func (export "callffi") (param i64) (result i64)
+         local.get 0
+         call $ffi
+        )
+
+        (func (export "callffi2") (param i32 i64) (result i64)
+         local.get 1
+         local.get 0
+         local.get 0
+         local.get 0
+         local.get 0
+         local.get 0
+         local.get 0
+         call $ffi2
+        )
+
+        (func (export "callffi3") (param i64 i64 i64 i64) (result i64)
+          local.get 0
+          local.get 1
+          local.get 2
+          local.get 3
+          call $ffi3
+        )
+    )`, imports).exports;
+
+    // Enable the jit exit for each JS callee.
+    assertEq(ex.callffi(0n), 42n);
+    assertEq(ex.callffi2(2, 0n), 54n);
+    assertEq(ex.callffi3(0n, 1n, 2n, 3n), 2n);
+
+    // Test the jit exit under normal conditions.
+    assertEq(ex.callffi(0n), 42n);
+    assertEq(ex.callffi(1337n), 0n);
+    assertEq(ex.callffi2(2, 0n), 54n);
+    assertEq(ex.callffi3(0n, 1n, 2n, 3n), 2n);
+
+    // Test the jit exit with GC stress in order to ensure that
+    // any trigger of GC in the stub do not cause errors.
+    if (this.gczeal) {
+        this.gczeal(2, 1); // Collect on every allocation
+    }
+    for ( let i=0; i < 1000; i++ ) {
+        assertEq(ex.callffi3(0n, 1n, 2n, 3n), 2n);
+    }
+})();
+
+// Test JIT entry stub
+if (wasmBigIntEnabled()) {
+    (function testJitEntry() {
+        let options = getJitCompilerOptions();
+        if (!options["baseline.enable"]) return;
+
+        let baselineTrigger = options["baseline.warmup.trigger"];
+
+        i = wasmEvalText(
+            `(module
+        (func (export "foo") (param i64) (result i64)
+         local.get 0
+         i64.const 1
+         i64.add
+         return
+        )
+    )`,
+            {}
+        ).exports;
+
+        function caller(n) {
+            return i.foo(42n);
+        }
+
+        // Baseline compile ffis.
+        for (let i = baselineTrigger + 1; i-- > 0; ) {
+            caller(i);
+        }
+
+        // Enable the jit entry.
+        assertEq(caller(0), 43n);
+
+        // Test the jit exit under normal conditions.
+        assertEq(caller(0), 43n);
+    })();
+}
--- a/js/src/jit-test/tests/wasm/ion-error-i64.js
+++ b/js/src/jit-test/tests/wasm/ion-error-i64.js
@@ -1,9 +1,9 @@
-// |jit-test| skip-if: !getJitCompilerOptions()['baseline.enable']
+// |jit-test| skip-if: !getJitCompilerOptions()['baseline.enable'] || wasmBigIntEnabled()
 // These tests need at least baseline to make sense.
 
 const { nextLineNumber, startProfiling, endProfiling, assertEqPreciseStacks } = WasmHelpers;
 
 const options = getJitCompilerOptions();
 const TRIGGER = options['ion.warmup.trigger'] + 10;
 const ITER = 2 * TRIGGER;
 const EXCEPTION_ITER = ITER - 2;
@@ -27,17 +27,17 @@ var instance = wasmEvalText(`(module
      local.get 1
      i64.add
     )
 )`).exports;
 
 (function() {
     // In ion-eager mode, make sure we don't try to inline a function that
     // takes or returns i64 arguments.
-    assertErrorMessage(() => instance.add_two_i64(0, 1), TypeError, /cannot pass i64 to or from JS/);
+    assertErrorMessage(() => instance.add_two_i64(0n, 1n), TypeError, /cannot pass i64 to or from JS/);
 })();
 
 enableGeckoProfiling();
 
 var callToMain;
 
 function main() {
     var arrayCallLine = nextLineNumber(13);