summaryrefslogtreecommitdiffstats
path: root/js/src/jit-test/tests/wasm/tail-calls/return_call_ref.js
blob: 947da02ef50a198e74232abd44602895fee97edb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
// |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/);