summaryrefslogtreecommitdiffstats
path: root/js/src/jit-test/tests/wasm/tail-calls/return_call_ref.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jit-test/tests/wasm/tail-calls/return_call_ref.js')
-rw-r--r--js/src/jit-test/tests/wasm/tail-calls/return_call_ref.js94
1 files changed, 94 insertions, 0 deletions
diff --git a/js/src/jit-test/tests/wasm/tail-calls/return_call_ref.js b/js/src/jit-test/tests/wasm/tail-calls/return_call_ref.js
new file mode 100644
index 0000000000..c5f250a41c
--- /dev/null
+++ b/js/src/jit-test/tests/wasm/tail-calls/return_call_ref.js
@@ -0,0 +1,94 @@
+// |jit-test| --wasm-gc; skip-if: !wasmGcEnabled()
+var ins = wasmEvalText(`(module
+ (type $t (func (param i64 i64 funcref) (result i64)))
+ (elem declare func $fac-acc $fac-acc-broken)
+ (func $fac-acc (export "fac-acc") (param i64 i64 funcref) (result i64)
+ (if (result i64) (i64.eqz (local.get 0))
+ (then (local.get 1))
+ (else
+ (return_call $vis
+ (i64.sub (local.get 0) (i64.const 1))
+ (i64.mul (local.get 0) (local.get 1))
+ (local.get 2)
+ )
+ )
+ )
+ )
+ ;; same as $fac-acc but fails on i == 6
+ (func $fac-acc-broken (param i64 i64 funcref) (result i64)
+ (if (result i64) (i64.eqz (local.get 0))
+ (then (local.get 1))
+ (else
+ (return_call $vis
+ (i64.sub (local.get 0) (i64.const 1))
+ (i64.mul (local.get 0) (local.get 1))
+ (select (result funcref)
+ (ref.null func) (local.get 2)
+ (i64.eq (local.get 0) (i64.const 6)))
+ )
+ )
+ )
+ )
+ (func $vis (export "vis") (param i64 i64 funcref) (result i64)
+ local.get 0
+ local.get 1
+ local.get 2
+ local.get 2
+ ref.cast (ref null $t)
+ return_call_ref $t
+ )
+ (func $trap (export "trap") (param i64 i64 funcref) (result i64)
+ unreachable
+ )
+ (func (export "main") (param i64) (result i64)
+ (call $vis (local.get 0) (i64.const 1) (ref.func $fac-acc))
+ )
+ (func (export "main_null") (param i64) (result i64)
+ (return_call $vis (local.get 0) (i64.const 1) (ref.null $t))
+ )
+ (func (export "main_broken") (param i64) (result i64)
+ (return_call $vis (local.get 0) (i64.const 1) (ref.func $fac-acc-broken))
+ )
+)`);
+
+// Check return call via wasm function
+assertEq(ins.exports.main(5n), 120n);
+
+// Check return call directly via interpreter stub
+const fac = ins.exports["fac-acc"];
+const vis = ins.exports["vis"];
+assertEq(vis(4n, 1n, fac), 24n);
+
+// Calling into JavaScript (and back).
+if ("Function" in WebAssembly) {
+ const visFn = new WebAssembly.Function({
+ parameters: ["i64", "i64", "funcref"],
+ results: ["i64"]
+ }, function (i, n, fn) {
+ if (i <= 0n) {
+ return n;
+ }
+ return vis(i - 1n, i * n, fn);
+ });
+
+ assertEq(vis(3n, 1n, visFn), 6n);
+}
+
+// Check return call directly via jit stub
+check_stub1: {
+ let options = getJitCompilerOptions();
+ if (!options["baseline.enable"]) break check_stub1;
+ const check = function() {
+ vis(4n, 1n, fac);
+ };
+ for (let i = options["baseline.warmup.trigger"] + 1; i--;)
+ check();
+}
+
+// Handling traps.
+const trap = ins.exports["trap"];
+assertErrorMessage(() => vis(4n, 1n, trap), WebAssembly.RuntimeError, /unreachable executed/);
+const main_broken = ins.exports["main_broken"];
+assertErrorMessage(() => main_broken(8n), WebAssembly.RuntimeError, /dereferencing null pointer/);
+const main_null = ins.exports["main_null"];
+assertErrorMessage(() => main_null(5n), WebAssembly.RuntimeError, /dereferencing null pointer/);