// |jit-test| --setpref=wasm_gc=true; 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/);