summaryrefslogtreecommitdiffstats
path: root/js/src/jit-test/tests/wasm/multi-value
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /js/src/jit-test/tests/wasm/multi-value
parentInitial commit. (diff)
downloadfirefox-esr-upstream.tar.xz
firefox-esr-upstream.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/jit-test/tests/wasm/multi-value')
-rw-r--r--js/src/jit-test/tests/wasm/multi-value/block-run.js268
-rw-r--r--js/src/jit-test/tests/wasm/multi-value/block-validate.js266
-rw-r--r--js/src/jit-test/tests/wasm/multi-value/call-js.js138
-rw-r--r--js/src/jit-test/tests/wasm/multi-value/call-ref.js81
-rw-r--r--js/src/jit-test/tests/wasm/multi-value/call-run.js120
-rw-r--r--js/src/jit-test/tests/wasm/multi-value/call-validate.js47
-rw-r--r--js/src/jit-test/tests/wasm/multi-value/directives.txt1
-rw-r--r--js/src/jit-test/tests/wasm/multi-value/ion-inlining.js14
-rw-r--r--js/src/jit-test/tests/wasm/multi-value/regress-1597200.js41
-rw-r--r--js/src/jit-test/tests/wasm/multi-value/regress-1621645-2.js19
-rw-r--r--js/src/jit-test/tests/wasm/multi-value/regress-1621645.js20
-rw-r--r--js/src/jit-test/tests/wasm/multi-value/regress-1628417.js11
-rw-r--r--js/src/jit-test/tests/wasm/multi-value/regress-1628426.js22
-rw-r--r--js/src/jit-test/tests/wasm/multi-value/regress-1628429.js6
-rw-r--r--js/src/jit-test/tests/wasm/multi-value/regress-1628499.js11
-rw-r--r--js/src/jit-test/tests/wasm/multi-value/regress-1629496.js9
-rw-r--r--js/src/jit-test/tests/wasm/multi-value/regress-1631423.js15
-rw-r--r--js/src/jit-test/tests/wasm/multi-value/regress-1661723.js23
18 files changed, 1112 insertions, 0 deletions
diff --git a/js/src/jit-test/tests/wasm/multi-value/block-run.js b/js/src/jit-test/tests/wasm/multi-value/block-run.js
new file mode 100644
index 0000000000..3b6689d2f9
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/multi-value/block-run.js
@@ -0,0 +1,268 @@
+wasmFullPass(`
+ (module
+ (func (export "run") (result i32)
+ (i32.add
+ (block (result i32 i32)
+ (i32.const 32)
+ (i32.const 10)))))`,
+ 42);
+
+wasmFullPass(`
+ (module
+ (func (export "run") (result i32)
+ (i32.const 32) (i32.const 10)
+ (block (param i32 i32) (result i32 i32))
+ (i32.add)))`,
+ 42);
+
+wasmFullPass(`
+ (module
+ (func (export "run") (result i32)
+ (i32.const 32)
+ (block (param i32) (result i32 i32)
+ (i32.const 10))
+ (i32.add)))`,
+ 42);
+
+wasmFullPass(`
+ (module
+ (func (export "run") (result i32)
+ (i32.add
+ (loop (result i32 i32)
+ (i32.const 32)
+ (i32.const 10)))))`,
+ 42);
+
+wasmFullPass(`
+ (module
+ (func (export "run") (result i32)
+ (i32.const 32) (i32.const 10)
+ (loop (param i32 i32) (result i32 i32))
+ (i32.add)))`,
+ 42);
+
+wasmFullPass(`
+ (module
+ (func (export "run") (result i32)
+ (i32.const 32)
+ (loop (param i32) (result i32 i32)
+ (i32.const 10))
+ (i32.add)))`,
+ 42);
+
+wasmFullPass(`
+ (module
+ (func (export "run") (result i32)
+ (i32.add
+ (block (result i32 i32)
+ (i32.const 32)
+ (i32.const 10)
+ (br 0)))))`,
+ 42);
+
+wasmFullPass(`
+ (module
+ (func (export "run") (result i32)
+ (i32.const 32)
+ (i32.const 10)
+ (block (param i32 i32) (result i32 i32)
+ (br 0))
+ (i32.add)))`,
+ 42);
+
+wasmFullPass(`
+ (module
+ (func (export "run") (result i32)
+ (i32.const 32)
+ (block (param i32) (result i32 i32)
+ (i32.const 10)
+ (br 0))
+ (i32.add)))`,
+ 42);
+
+wasmFullPass(`
+ (module
+ (func (export "run") (result i32)
+ (i32.add
+ (block (result i32 i32)
+ (i32.const 32)
+ (i32.const 10)
+ (block (param i32 i32) (result i32 i32)
+ (br 1))))))`,
+ 42);
+
+wasmFullPass(`
+ (module
+ (func (export "run") (result i32)
+ (i32.const 32)
+ (i32.const 10)
+ (block (param i32 i32) (result i32 i32)
+ (block (param i32 i32) (result i32 i32)
+ (br 1)))
+ (i32.add)))`,
+ 42);
+
+wasmFullPass(`
+ (module
+ (func (export "run") (result i32)
+ (i32.const 32)
+ (i32.const 10)
+ (block (param i32 i32) (result i32 i32)
+ (block (param i32 i32) (result i32 i32)
+ (br 0)))
+ (i32.add)))`,
+ 42);
+
+wasmFullPass(`
+ (module
+ (func (export "run") (result i32)
+ (i32.const 32)
+ (block (param i32) (result i32 i32)
+ (i32.const 10)
+ (block (param i32 i32) (result i32 i32)
+ (br 1)))
+ (i32.add)))`,
+ 42);
+
+wasmFullPass(`
+ (module
+ (func (export "run") (result i32)
+ (i32.const 32)
+ (i32.const 10)
+ (i32.const 1)
+ (if (param i32 i32) (result i32)
+ (then (i32.add))
+ (else (i32.sub)))))`,
+ 42);
+
+wasmFullPass(`
+ (module
+ (func (export "run") (result i32)
+ (i32.const 32)
+ (i32.const 10)
+ (i32.const 1)
+ (if (param i32 i32) (result i32 i32)
+ (then
+ (drop)
+ (drop)
+ (i32.const 10)
+ (i32.const 32)))
+ (i32.sub)))`,
+ -22);
+
+wasmFullPass(`
+ (module
+ (func (export "run") (result i32)
+ (i32.const 32)
+ (i32.const 10)
+ (i32.const 0)
+ (if (param i32 i32) (result i32 i32)
+ (then
+ (drop)
+ (drop)
+ (i32.const 10)
+ (i32.const 32)))
+ (i32.sub)))`,
+ 22);
+
+wasmFullPass(`
+ (module
+ (func (export "run") (result i32)
+ (i32.const 32)
+ (i32.const 10)
+ (i32.const 1)
+ (if (param i32 i32) (result i32 i32)
+ (then (return)))
+ (i32.sub)))`,
+ 10);
+
+wasmFullPass(`
+ (module
+ (func (export "run") (result i32)
+ (i32.const 32)
+ (i32.const 10)
+ (i32.const 0)
+ (if (param i32 i32) (result i32 i32)
+ (then (return)))
+ (i32.sub)))`,
+ 22);
+
+wasmFullPass(`
+ (module
+ (func (export "run") (result i32)
+ (i32.const 32)
+ (i32.const 10)
+ (i32.const 1)
+ (if (param i32 i32) (result i32 i32)
+ (then)
+ (else (return)))
+ (i32.sub)))`,
+ 22);
+
+wasmFullPass(`
+ (module
+ (func (export "run") (result i32)
+ (i32.const 32)
+ (i32.const 10)
+ (i32.const 0)
+ (if (param i32 i32) (result i32 i32)
+ (then)
+ (else (return)))
+ (i32.sub)))`,
+ 10);
+
+wasmFullPass(`
+ (module
+ (func (export "run") (result i32)
+ (local $i i32)
+ (i32.const 0) ;; sum
+ (i32.const 10) ;; i
+ (loop $loop (param i32 i32) (result i32)
+ (local.tee $i)
+ (i32.add) ;; sum = i + sum
+ (i32.sub (local.get $i) (i32.const 1))
+ (i32.eqz (local.tee $i))
+ (if (param i32) (result i32)
+ (then)
+ (else (local.get $i) (br $loop))))))`,
+ 55);
+
+wasmFullPass(`
+ (module
+ (func (export "run") (result i32)
+ (local i32)
+ i32.const 42
+ local.get 0
+ local.get 0
+ loop (param i32 i32 i32) (result i32)
+ drop
+ drop
+ end))`,
+ 42);
+
+wasmFullPass(`
+ (module
+ (func (export "run") (result i32)
+ (block (result i32 i32)
+ (i32.popcnt (i32.const 1))
+ (i32.popcnt (i32.const 3))
+ (block (param i32 i32)
+ (i32.const 6)
+ (i32.const 7)
+ (br 1))
+ (unreachable))
+ i32.add))`,
+ 13);
+
+wasmFullPass(`
+ (module
+ (func (export "run") (result i32)
+ (block (result i32 i32)
+ (i32.popcnt (i32.const 1))
+ (i32.popcnt (i32.const 3))
+ (block) ;; sync()
+ (i32.const 6)
+ (i32.const 7)
+ (br 0))
+ i32.add))`,
+ 13);
diff --git a/js/src/jit-test/tests/wasm/multi-value/block-validate.js b/js/src/jit-test/tests/wasm/multi-value/block-validate.js
new file mode 100644
index 0000000000..7845c016e3
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/multi-value/block-validate.js
@@ -0,0 +1,266 @@
+wasmValidateText(`
+ (module
+ (func (result i32)
+ (i32.add
+ (block (result i32 i32)
+ (i32.const 32)
+ (i32.const 10)))))`);
+
+wasmValidateText(`
+ (module
+ (func (result i32)
+ (i32.const 32) (i32.const 10)
+ (block (param i32 i32) (result i32 i32))
+ (i32.add)))`);
+
+wasmValidateText(`
+ (module
+ (func (result i32)
+ (i32.const 32)
+ (block (param i32) (result i32 i32)
+ (i32.const 10))
+ (i32.add)))`);
+
+wasmValidateText(`
+ (module
+ (func (result i32)
+ (i32.add
+ (loop (result i32 i32)
+ (i32.const 32)
+ (i32.const 10)))))`);
+
+wasmValidateText(`
+ (module
+ (func (result i32)
+ (i32.const 32) (i32.const 10)
+ (loop (param i32 i32) (result i32 i32))
+ (i32.add)))`);
+
+wasmValidateText(`
+ (module
+ (func (result i32)
+ (i32.const 32)
+ (loop (param i32) (result i32 i32)
+ (i32.const 10))
+ (i32.add)))`);
+
+wasmValidateText(`
+ (module
+ (func (result i32)
+ (i32.add
+ (block (result i32 i32)
+ (i32.const 32)
+ (i32.const 10)
+ (br 0)))))`);
+
+wasmValidateText(`
+ (module
+ (func (result i32)
+ (i32.const 32)
+ (i32.const 10)
+ (block (param i32 i32) (result i32 i32)
+ (br 0))
+ (i32.add)))`);
+
+wasmValidateText(`
+ (module
+ (func (result i32)
+ (i32.const 32)
+ (block (param i32) (result i32 i32)
+ (i32.const 10)
+ (br 0))
+ (i32.add)))`);
+
+wasmValidateText(`
+ (module
+ (func (result i32)
+ (i32.add
+ (block (result i32 i32)
+ (i32.const 32)
+ (i32.const 10)
+ (block (param i32 i32) (result i32 i32)
+ (br 1))))))`);
+
+wasmValidateText(`
+ (module
+ (func (result i32)
+ (i32.const 32)
+ (i32.const 10)
+ (block (param i32 i32) (result i32 i32)
+ (block (param i32 i32) (result i32 i32)
+ (br 1)))
+ (i32.add)))`);
+
+wasmValidateText(`
+ (module
+ (func (result i32)
+ (i32.const 32)
+ (i32.const 10)
+ (block (param i32 i32) (result i32 i32)
+ (block (param i32 i32) (result i32 i32)
+ (br 0)))
+ (i32.add)))`);
+
+wasmValidateText(`
+ (module
+ (func (result i32)
+ (i32.const 32)
+ (block (param i32) (result i32 i32)
+ (i32.const 10)
+ (block (param i32 i32) (result i32 i32)
+ (br 1)))
+ (i32.add)))`);
+
+wasmValidateText(`
+ (module
+ (func (result i32)
+ (i32.const 32)
+ (i32.const 10)
+ (i32.const 1)
+ (if (param i32 i32) (result i32)
+ (then (i32.add))
+ (else (i32.sub)))))`);
+
+wasmValidateText(`
+ (module
+ (func (result i32)
+ (i32.const 32)
+ (i32.const 10)
+ (i32.const 1)
+ (if (param i32 i32) (result i32 i32)
+ (then
+ (drop)
+ (drop)
+ (i32.const 10)
+ (i32.const 32)))
+ (i32.sub)))`);
+
+wasmValidateText(`
+ (module
+ (func (result i32)
+ (i32.const 32)
+ (i32.const 10)
+ (i32.const 1)
+ (if (param i32 i32) (result i32 i32)
+ (then (return)))
+ (i32.sub)))`);
+
+wasmValidateText(`
+ (module
+ (func (result i32)
+ (i32.const 32)
+ (i32.const 10)
+ (i32.const 1)
+ (if (param i32 i32) (result i32 i32)
+ (then)
+ (else (return)))
+ (i32.sub)))`);
+
+wasmValidateText(`
+ (module
+ (func (result i32)
+ (local $i i32)
+ (i32.const 0) ;; sum
+ (i32.const 10) ;; i
+ (loop $loop (param i32 i32) (result i32)
+ (local.tee $i)
+ (i32.add) ;; sum = i + sum
+ (i32.sub (local.get $i) (i32.const 1))
+ (local.tee $i)
+ (local.get $i)
+ (br_if $loop (i32.eqz))
+ (drop))))`);
+
+// Tests the encoding: with more than 64 function types, the block type encoded
+// as an uleb will create a confusion with the valtype; an sleb is required.
+
+wasmValidateText(`
+ (module
+ ${(function () {
+ s = "";
+ for ( let i=0; i < 64; i++ ) {
+ let t = [];
+ for ( let j=0; j < 6; j++ )
+ t.push(i & (1 << j) ? "i32" : "f32");
+ s += "(func (param " + t.join(" ") + "))\n";
+ }
+ return s;
+ })()}
+ (func (result i32)
+ (i32.add
+ (block (result i32 i32)
+ (i32.const 32)
+ (i32.const 10)))))`);
+
+wasmValidateText(`
+ (module
+ (func (result i32)
+ (block $B (result i32 i32)
+ (br $B (i32.const 1) (i32.const 2))
+ (i32.const 0x1337))
+ (drop)))`);
+
+wasmValidateText(`
+ (module
+ (func (result i32)
+ (block $B (result i32 i32)
+ (i32.const 1)
+ (br $B (i32.const 2))
+ (i32.const 0x1337))
+ (drop)))`);
+
+wasmValidateText(`
+ (module
+ (func (result i32)
+ (block $B (result i32 i32)
+ (i32.const 1)
+ (i32.const 2)
+ (br $B)
+ (i32.const 0x1337))
+ (drop)))`);
+
+wasmValidateText(`
+ (module
+ (func (param $cond i32) (result i32)
+ (block $B (result i32 i32)
+ (br_if $B (i32.const 1) (i32.const 2) (local.get $cond)))
+ (drop)))`);
+
+wasmValidateText(`
+ (module
+ (func (param $cond i32) (result i32)
+ (block $B (result i32 i32)
+ (i32.const 1)
+ (br_if $B (i32.const 2) (local.get $cond)))
+ (drop)))`);
+
+wasmValidateText(`
+ (module
+ (func (param $cond i32) (result i32)
+ (block $B (result i32 i32)
+ (i32.const 1)
+ (i32.const 2)
+ (br_if $B (local.get $cond)))
+ (drop)))`);
+
+wasmValidateText(`
+ (module
+ (func (param $cond i32) (result i32)
+ (block $B (result i32 i32)
+ (i32.const 1)
+ (i32.const 2)
+ (local.get $cond)
+ (br_if $B))
+ (drop)))`);
+
+wasmValidateText(`
+ (module
+ (func (param $index i32) (result i32)
+ (block $OUT (result i32)
+ (block $B1 (result i32 i32)
+ (block $B2 (result i32 i32)
+ (block $B3 (result i32 i32)
+ (br_table $B1 $B2 $B3 (i32.const 1) (i32.const 2) (local.get $index)))
+ (br $OUT (i32.add)))
+ (br $OUT (i32.sub)))
+ (br $OUT (i32.mul)))))`);
diff --git a/js/src/jit-test/tests/wasm/multi-value/call-js.js b/js/src/jit-test/tests/wasm/multi-value/call-js.js
new file mode 100644
index 0000000000..7af031e5f0
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/multi-value/call-js.js
@@ -0,0 +1,138 @@
+
+wasmFullPass(`
+ (module
+ (import "env" "f" (func $f (result i32 i32 i32)))
+ (func (export "run") (result i32)
+ (call $f)
+ i32.sub
+ i32.sub))`,
+ 42,
+ { env: { f: () => [52, 10, 0] } });
+
+wasmFullPass(`
+ (module
+ (import "env" "f" (func $f (result i64 i64 i64)))
+ (func (export "run") (result i64)
+ (call $f)
+ i64.sub
+ i64.sub))`,
+ 42n,
+ { env: { f: () => [52n, 10n, 0n] } });
+
+wasmFullPass(`
+ (module
+ (import "env" "f" (func $f (result f32 f32 f32)))
+ (func (export "run") (result i32)
+ (call $f)
+ f32.sub
+ f32.sub
+ i32.trunc_f32_s))`,
+ 42,
+ { env: { f: () => [52.25, 10.5, 0.25] } });
+
+wasmFullPass(`
+ (module
+ (import "env" "f" (func $f (result f64 f64 f64)))
+ (func (export "run") (result i32)
+ (call $f)
+ f64.sub
+ f64.sub
+ i32.trunc_f64_s))`,
+ 42,
+ { env: { f: () => [52.25, 10.5, 0.25] } });
+
+// Multiple values are returned as an iterable; it doesn't have to be an array.
+function expectMultiValuePass(f) {
+ wasmFullPass(`
+ (module
+ (import "env" "f" (func $f (result i32 i32 i32)))
+ (func (export "run") (result i32)
+ (call $f)
+ i32.sub
+ i32.sub))`,
+ 42,
+ { env: { f } });
+}
+function expectMultiValueError(f, type, pattern) {
+ let module = new WebAssembly.Module(wasmTextToBinary(`
+ (module
+ (import "env" "f" (func $f (result i32 i32 i32)))
+ (func (export "run") (result i32)
+ (call $f)
+ i32.sub
+ i32.sub))`));
+
+ let instance = new WebAssembly.Instance(module, { env: { f } } );
+ assertErrorMessage(() => instance.exports.run(), type, pattern);
+}
+
+expectMultiValuePass(() => [52, 10, 0]);
+expectMultiValuePass(() => [32, -10, 0]);
+expectMultiValuePass(() => [52.75, 10, 0.5]); // Values converted to i32 via ToInt32.
+expectMultiValuePass(() => [42, undefined, undefined]);
+expectMultiValuePass(() => (function*() { yield 52; yield 10; yield 0; })());
+expectMultiValuePass(() => (function*() { yield '52'; yield '10'; yield 0; })());
+
+// Multi-value result must be iterable.
+expectMultiValueError(() => 1, TypeError, /iterable/);
+expectMultiValueError(() => 1n, TypeError, /iterable/);
+
+// Check that the iterator's values are collected first, and that the
+// length of the result is correct.
+expectMultiValueError(() => [1], TypeError, /expected 3, got 1/);
+expectMultiValueError(() => [1n], TypeError, /expected 3, got 1/);
+expectMultiValueError(() => [52, 10, 0, 0], TypeError, /expected 3, got 4/);
+expectMultiValueError(() => (function*() { yield 52; yield 10; yield 0; yield 0; })(),
+ TypeError, /expected 3, got 4/);
+
+// Check that side effects from conversions are done in order.
+{
+ let calls = [];
+ function log(x) { calls.push(x); return x; }
+ function logged(x) { return { valueOf: () => log(x) } }
+ expectMultiValuePass(() => [logged(52), logged(10), logged(0)]);
+ assertEq(calls.join(','), '52,10,0');
+}
+
+function expectMultiValueResult(text, expected) {
+ let instance = wasmEvalText(text);
+ assertDeepEq(instance.exports.run(), expected);
+}
+
+expectMultiValueResult(`
+ (module
+ (func (export "run") (result i32 i32 i32)
+ (i32.const 0)
+ (i32.const 52)
+ (i32.const 10)))`, [0, 52, 10]);
+expectMultiValueResult(`
+ (module
+ (func (export "run") (result f32 f32 f32)
+ (f32.const 0.5)
+ (f32.const 52.5)
+ (f32.const 10.5)))`, [0.5, 52.5, 10.5]);
+expectMultiValueResult(`
+ (module
+ (func (export "run") (result f64 f64 f64)
+ (f64.const 0.5)
+ (f64.const 52.5)
+ (f64.const 10.5)))`, [0.5, 52.5, 10.5]);
+
+expectMultiValueResult(`
+ (module
+ (func (export "run") (result i32 i64 i32)
+ (i32.const 0)
+ (i64.const 52)
+ (i32.const 10)))`, [0, 52n, 10]);
+expectMultiValueResult(`
+ (module
+ (func (export "run") (result i64 i32 i64)
+ (i64.const 0)
+ (i32.const 52)
+ (i64.const 10)))`, [0n, 52, 10n]);
+expectMultiValueResult(`
+ (module
+ (func (export "run") (result i64 i64 i64)
+ (i64.const 0)
+ (i64.const 52)
+ (i64.const 10)))`, [0n, 52n, 10n]);
diff --git a/js/src/jit-test/tests/wasm/multi-value/call-ref.js b/js/src/jit-test/tests/wasm/multi-value/call-ref.js
new file mode 100644
index 0000000000..63b7eb271b
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/multi-value/call-ref.js
@@ -0,0 +1,81 @@
+let counter;
+function resetCounter() { counter = 0; }
+
+function boxNextInt() { return {val: counter++}; }
+function unboxInt(box) { return box.val; }
+function boxNextThreeInts() {
+ return [boxNextInt(), boxNextInt(), boxNextInt()];
+}
+function unboxThreeInts(x, y, z) {
+ return [unboxInt(x), unboxInt(y), unboxInt(z)];
+}
+
+function testAddNextThreeIntsInner(addNextThreeInts) {
+ resetCounter();
+ for (let n = 0; n < 100000; n += 3) {
+ assertEq(addNextThreeInts(), n * 3 + 3);
+ }
+}
+
+function testAddNextThreeInts(text, imports) {
+ let i = new WebAssembly.Instance(
+ new WebAssembly.Module(wasmTextToBinary(text)), { imports });
+
+ testAddNextThreeIntsInner(() => i.exports.addNextThreeInts());
+}
+
+testAddNextThreeInts(`
+ (module
+ (func $boxNextInt (import "imports" "boxNextInt")
+ (result externref))
+ (func $unboxInt (import "imports" "unboxInt")
+ (param externref) (result i32))
+
+ (func $boxNextThreeInts (result externref externref externref)
+ call $boxNextInt
+ call $boxNextInt
+ call $boxNextInt)
+
+ (func $unboxThreeInts (param externref externref externref) (result i32 i32 i32)
+ local.get 0
+ call $unboxInt
+ local.get 1
+ call $unboxInt
+ local.get 2
+ call $unboxInt)
+
+ (func $addNextThreeInts (export "addNextThreeInts") (result i32)
+ call $boxNextThreeInts
+ call $unboxThreeInts
+ i32.add
+ i32.add))`,
+ {boxNextInt, unboxInt});
+
+testAddNextThreeInts(`
+ (module
+ (func $boxNextThreeInts (import "imports" "boxNextThreeInts")
+ (result externref externref externref))
+ (func $unboxThreeInts (import "imports" "unboxThreeInts")
+ (param externref externref externref) (result i32 i32 i32))
+
+ (func $addNextThreeInts (export "addNextThreeInts") (result i32)
+ call $boxNextThreeInts
+ call $unboxThreeInts
+ i32.add
+ i32.add))`,
+ {boxNextThreeInts, unboxThreeInts});
+
+{
+ let i = wasmEvalText(`
+ (module
+ (func $boxNextThreeInts (import "imports" "boxNextThreeInts")
+ (result externref externref externref))
+
+ (func (export "boxNextThreeInts") (result externref externref externref)
+ call $boxNextThreeInts))`,
+ {imports: {boxNextThreeInts}});
+ testAddNextThreeIntsInner(() => {
+ let [a, b, c] = i.exports.boxNextThreeInts();
+ return unboxInt(a) + unboxInt(b) + unboxInt(c);
+ });
+}
diff --git a/js/src/jit-test/tests/wasm/multi-value/call-run.js b/js/src/jit-test/tests/wasm/multi-value/call-run.js
new file mode 100644
index 0000000000..67662a4af5
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/multi-value/call-run.js
@@ -0,0 +1,120 @@
+wasmFullPass(`
+ (module
+ (func (result i32 i32)
+ (i32.const 52)
+ (i32.const 10))
+ (func (export "run") (result i32)
+ (call 0)
+ i32.sub))`,
+ 42);
+
+wasmFullPass(`
+ (module
+ (func (param i32 i32) (result i32 i32)
+ (local.get 0)
+ (local.get 1))
+ (func (export "run") (result i32)
+ (i32.const 52)
+ (i32.const 10)
+ (call 0)
+ i32.sub))`,
+ 42);
+
+wasmFullPass(`
+ (module
+ (func (param i32 i32 i32 i32 i32
+ i32 i32 i32 i32 i32)
+ (result i32 i32)
+ (local.get 8)
+ (local.get 9))
+ (func (export "run") (result i32)
+ (i32.const 0)
+ (i32.const 1)
+ (i32.const 2)
+ (i32.const 3)
+ (i32.const 4)
+ (i32.const 5)
+ (i32.const 6)
+ (i32.const 7)
+ (i32.const 52)
+ (i32.const 10)
+ (call 0)
+ i32.sub))`,
+ 42);
+
+wasmFullPass(`
+ (module
+ (func (param i32 i32 i32 i32 i32
+ i32 i32 i32 i32 i32)
+ (result i32 i32)
+ (local i32 i32 i32 i32)
+ (local.get 8)
+ (local.get 9))
+ (func (export "run") (result i32)
+ (i32.const 0)
+ (i32.const 1)
+ (i32.const 2)
+ (i32.const 3)
+ (i32.const 4)
+ (i32.const 5)
+ (i32.const 6)
+ (i32.const 7)
+ (i32.const 52)
+ (i32.const 10)
+ (call 0)
+ i32.sub))`,
+ 42);
+
+wasmFullPass(`
+ (module
+ (func (param i32 i32 i32 i32 i32
+ i32 i32 i32 i32 i32)
+ (result i32 i32 i32)
+ (local i32 i32 i32 i32)
+ (local.get 7)
+ (local.get 8)
+ (local.get 9))
+ (func (export "run") (result i32)
+ (i32.const 0)
+ (i32.const 1)
+ (i32.const 2)
+ (i32.const 3)
+ (i32.const 4)
+ (i32.const 5)
+ (i32.const 6)
+ (i32.const 7)
+ (i32.const 52)
+ (i32.const 10)
+ (call 0)
+ i32.sub
+ i32.sub))`,
+ -35);
+
+wasmFullPass(`
+ (module
+ (func (param i32 i64 i32 i64 i32
+ i64 i32 i64 i32 i64)
+ (result i64 i32 i64)
+ (local i32 i64 i32 i64)
+ (local.get 7)
+ (local.get 8)
+ (local.get 9))
+ (func (export "run") (result i32)
+ (i32.const 0)
+ (i64.const 1)
+ (i32.const 2)
+ (i64.const 3)
+ (i32.const 4)
+ (i64.const 5)
+ (i32.const 6)
+ (i64.const 7)
+ (i32.const 52)
+ (i64.const 10)
+ (call 0)
+ i32.wrap_i64
+ i32.sub
+ i64.extend_i32_s
+ i64.sub
+ i32.wrap_i64))`,
+ -35);
+
diff --git a/js/src/jit-test/tests/wasm/multi-value/call-validate.js b/js/src/jit-test/tests/wasm/multi-value/call-validate.js
new file mode 100644
index 0000000000..513e11bc6e
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/multi-value/call-validate.js
@@ -0,0 +1,47 @@
+wasmValidateText(`
+ (module
+ (func (result i32 i32)
+ (i32.const 32)
+ (i32.const 10)))`);
+
+wasmValidateText(`
+ (module
+ (type $t (func (result i32 i32)))
+ (func (type $t)
+ (i32.const 32)
+ (i32.const 10)))`);
+
+wasmValidateText(`
+ (module
+ (func (result i32 i32)
+ (block (result i32 i32)
+ (i32.const 32)
+ (i32.const 10))))`);
+
+wasmValidateText(`
+ (module
+ (func $return-2 (result i32 i32)
+ (i32.const 32)
+ (i32.const 10))
+ (func $tail-call (result i32 i32)
+ (call 0)))`);
+
+wasmValidateText(`
+ (module
+ (func $return-2 (result i32 i32)
+ (i32.const 32)
+ (i32.const 10))
+ (func $add (result i32)
+ (call 0)
+ i32.add))`);
+
+wasmValidateText(`
+ (module
+ (func $return-2 (param i32 i32) (result i32 i32)
+ (local.get 0)
+ (local.get 1))
+ (func (export "run") (result i32)
+ (i32.const 32)
+ (i32.const 10)
+ (call 0)
+ i32.add))`);
diff --git a/js/src/jit-test/tests/wasm/multi-value/directives.txt b/js/src/jit-test/tests/wasm/multi-value/directives.txt
new file mode 100644
index 0000000000..f636e648ec
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/multi-value/directives.txt
@@ -0,0 +1 @@
+|jit-test| test-also=--wasm-compiler=optimizing; test-also=--wasm-compiler=baseline; test-also=--wasm-test-serialization; test-also=--test-wasm-await-tier2; test-also=--disable-wasm-huge-memory; skip-variant-if: --disable-wasm-huge-memory, !wasmHugeMemorySupported(); include:wasm.js
diff --git a/js/src/jit-test/tests/wasm/multi-value/ion-inlining.js b/js/src/jit-test/tests/wasm/multi-value/ion-inlining.js
new file mode 100644
index 0000000000..0d9a05214e
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/multi-value/ion-inlining.js
@@ -0,0 +1,14 @@
+
+let instance = wasmEvalText(`
+ (module
+ (func $f (export "f") (result i32 i32 i32)
+ (i32.const 0)
+ (i32.const 32)
+ (i32.const 10)))`);
+
+const options = getJitCompilerOptions();
+const jitThreshold = options['ion.warmup.trigger'] * 2 + 2;
+
+for (let i = 0; i < jitThreshold; i++) {
+ assertDeepEq(instance.exports.f(), [0, 32, 10]);
+}
diff --git a/js/src/jit-test/tests/wasm/multi-value/regress-1597200.js b/js/src/jit-test/tests/wasm/multi-value/regress-1597200.js
new file mode 100644
index 0000000000..542bd542ab
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/multi-value/regress-1597200.js
@@ -0,0 +1,41 @@
+new WebAssembly.Instance(new WebAssembly.Module(wasmTextToBinary(`
+(module
+ (func (export "main") (result i32)
+ (i32.const 1)
+ (i32.const 2)
+ (i32.const 3)
+ (loop (param i32 i32 i32)
+ (i32.popcnt)
+ (i32.const -63)
+ (br 0))
+ (unreachable)))`)));
+
+wasmFullPass(`
+(module
+ (func (export "run") (result i32)
+ (block (result i32 i32 i32)
+ (i32.const 41)
+ (i32.const 42)
+ (i32.const 43)
+ (loop (param i32 i32 i32)
+ (i32.eqz)
+ (i32.const -63)
+ (br 1))
+ (unreachable))
+ (drop)
+ (drop)))`,
+ 42);
+
+wasmFullPass(`
+(module
+ (func (export "run") (result i32)
+ (block (result i32 i32 i32)
+ (i32.popcnt (i32.const 0x0))
+ (i32.popcnt (i32.const 0xf))
+ (i32.popcnt (i32.const 0xff))
+ (i32.popcnt (i32.const 0xfff))
+ (block) ;; Force a sync().
+ (br 0))
+ (drop)
+ (drop)))`,
+ 4);
diff --git a/js/src/jit-test/tests/wasm/multi-value/regress-1621645-2.js b/js/src/jit-test/tests/wasm/multi-value/regress-1621645-2.js
new file mode 100644
index 0000000000..4ba4b3b116
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/multi-value/regress-1621645-2.js
@@ -0,0 +1,19 @@
+wasmFullPass(`
+ ;; Iterative factorial without locals.
+ (func $pick0 (param i64) (result i64 i64)
+ (local.get 0) (local.get 0)
+ )
+ (func $pick1 (param i64 i64) (result i64 i64 i64)
+ (local.get 0) (local.get 1) (local.get 0)
+ )
+ (func (export "run") (param i64) (result i64)
+ (i64.const 1) (local.get 0)
+ (loop $l (param i64 i64) (result i64)
+ (call $pick1) (call $pick1) (i64.mul)
+ (call $pick1) (i64.const 1) (i64.sub)
+ (call $pick0) (i64.const 0) (i64.gt_u)
+ (br_if $l)
+ (drop) (return)
+ )
+ )`,
+ 7034535277573963776n, {}, 25n);
diff --git a/js/src/jit-test/tests/wasm/multi-value/regress-1621645.js b/js/src/jit-test/tests/wasm/multi-value/regress-1621645.js
new file mode 100644
index 0000000000..dc9aaf264c
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/multi-value/regress-1621645.js
@@ -0,0 +1,20 @@
+wasmFullPass(`
+(module
+ (func $f (result i64 i64 i64 i64 i64
+ i64 i64 i64 i64 i64)
+ (i64.const 0)
+ (i64.const 1)
+ (i64.const 2)
+ (i64.const 3)
+ (i64.const 4)
+ (i64.const 5)
+ (i64.const 6)
+ (i64.const 7)
+ (i64.const 8)
+ (i64.const 9))
+ (func (export "run") (result i32)
+ (call $f)
+ (i64.add) (i64.add) (i64.add) (i64.add) (i64.add)
+ (i64.add) (i64.add) (i64.add) (i64.add)
+ (i32.wrap_i64)))`,
+ 45);
diff --git a/js/src/jit-test/tests/wasm/multi-value/regress-1628417.js b/js/src/jit-test/tests/wasm/multi-value/regress-1628417.js
new file mode 100644
index 0000000000..eb97b2116f
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/multi-value/regress-1628417.js
@@ -0,0 +1,11 @@
+let bytes = wasmTextToBinary(`
+ (module
+ (func $main (export "main") (result i32 i32)
+ (i32.const 1)
+ (i32.const 2)
+ (i32.const 0)
+ (br_table 0 0)))`);
+
+let instance = new WebAssembly.Instance(new WebAssembly.Module(bytes));
+
+instance.exports.main();
diff --git a/js/src/jit-test/tests/wasm/multi-value/regress-1628426.js b/js/src/jit-test/tests/wasm/multi-value/regress-1628426.js
new file mode 100644
index 0000000000..ffb13333c4
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/multi-value/regress-1628426.js
@@ -0,0 +1,22 @@
+// |jit-test| skip-if: !wasmDebuggingEnabled()
+var g20 = newGlobal({
+ newCompartment: true
+});
+g20.parent = this;
+g20.eval("Debugger(parent).onEnterFrame = function() {};");
+
+let bytes = wasmTextToBinary(`
+ (module
+ (func $dup (param i32) (result i32 i32)
+ (local.get 0)
+ (local.get 0)
+ (i32.const 2)
+ (i32.mul))
+ (func $main (export "main") (param i32 i32) (result i32)
+ (local.get 1)
+ (call $dup)
+ (i32.sub)))`);
+
+let instance = new WebAssembly.Instance(new WebAssembly.Module(bytes));
+
+assertEq(instance.exports.main(0, 1), -1)
diff --git a/js/src/jit-test/tests/wasm/multi-value/regress-1628429.js b/js/src/jit-test/tests/wasm/multi-value/regress-1628429.js
new file mode 100644
index 0000000000..3446e0bc8b
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/multi-value/regress-1628429.js
@@ -0,0 +1,6 @@
+let bytes = wasmTextToBinary(`
+ (module
+ (func $f (import "imports" "f") (param i32 i32) (result i32 i32)))`);
+
+new WebAssembly.Instance(new WebAssembly.Module(bytes),
+ { 'imports': { 'f': Uint16Array } });
diff --git a/js/src/jit-test/tests/wasm/multi-value/regress-1628499.js b/js/src/jit-test/tests/wasm/multi-value/regress-1628499.js
new file mode 100644
index 0000000000..e4360fcb9c
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/multi-value/regress-1628499.js
@@ -0,0 +1,11 @@
+let instance = wasmEvalText(`
+ (func $twoRefs (result externref externref)
+ (ref.null extern)
+ (ref.null extern))
+ (func $fourRefs (export "run") (result externref externref externref externref externref externref)
+ call $twoRefs
+ call $twoRefs
+ call $twoRefs)
+`);
+
+assertDeepEq(instance.exports.run(), [null, null, null, null, null, null])
diff --git a/js/src/jit-test/tests/wasm/multi-value/regress-1629496.js b/js/src/jit-test/tests/wasm/multi-value/regress-1629496.js
new file mode 100644
index 0000000000..220fcf8d3d
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/multi-value/regress-1629496.js
@@ -0,0 +1,9 @@
+let bytes = wasmTextToBinary(`
+ (module
+ (func $f (param) (result i32 i32)
+ (local i32)
+ (loop)
+ (i32.const 0)
+ (i32.const 1)))`);
+
+new WebAssembly.Instance(new WebAssembly.Module(bytes));
diff --git a/js/src/jit-test/tests/wasm/multi-value/regress-1631423.js b/js/src/jit-test/tests/wasm/multi-value/regress-1631423.js
new file mode 100644
index 0000000000..2460830dfd
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/multi-value/regress-1631423.js
@@ -0,0 +1,15 @@
+wasmEvalText(`
+ (module
+ (func $main (export "main")
+ (local i32)
+ i32.const 1
+ i32.const 2
+ i32.const 3
+ (loop (param i32 i32 i32)
+ local.get 0
+ i32.const 4
+ i32.const 5
+ i32.const 6
+ i32.const 7
+ br_if 0
+ unreachable)))`);
diff --git a/js/src/jit-test/tests/wasm/multi-value/regress-1661723.js b/js/src/jit-test/tests/wasm/multi-value/regress-1661723.js
new file mode 100644
index 0000000000..3248c13444
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/multi-value/regress-1661723.js
@@ -0,0 +1,23 @@
+let { exports } = new WebAssembly.Instance(
+ new WebAssembly.Module(wasmTextToBinary(`
+ (module
+ (func (import "module" "fn") (param f64 i32) (result i32 f64))
+ (func (export "f") (result i32)
+ f64.const 4.2
+ i32.const 7
+ call 0
+ drop
+ )
+ )
+ `)),
+ {
+ "module": {
+ fn(f32, i32) {
+ assertEq(f32, 4.2);
+ assertEq(i32, 7);
+ return [2, 7.3];
+ },
+ }
+ });
+
+assertEq(exports.f(), 2);