summaryrefslogtreecommitdiffstats
path: root/js/src/jit-test/tests/wasm/ref-types/funcref.js
blob: 21ce95c0cbee7747d5d4188166a7bc00006af260 (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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
const {Module,Instance,Global,RuntimeError} = WebAssembly;

const badWasmFunc = /can only pass WebAssembly exported functions to funcref/;
const typeErr = /type mismatch/;


// Validation:

wasmFailValidateText(`(module (func (local externref funcref) (local.set 0 (local.get 1))))`, typeErr);
wasmEvalText(`(module (func (local funcref funcref) (local.set 0 (local.get 1))))`);
wasmEvalText(`(module (func (local funcref) (local.set 0 (ref.null func))))`);
wasmFailValidateText(`(module (func (local funcref externref) (local.set 0 (local.get 1))))`, typeErr);
wasmEvalText(`(module (global (mut funcref) (ref.null func)) (func (param funcref) (global.set 0 (local.get 0))))`);
wasmFailValidateText(`(module (global (mut externref) (ref.null extern)) (func (param funcref) (global.set 0 (local.get 0))))`, typeErr);
wasmFailValidateText(`(module (global (mut funcref) (ref.null func)) (func (param externref) (global.set 0 (local.get 0))))`, typeErr);
wasmEvalText(`(module (func (param funcref)) (func (param funcref) (call 0 (local.get 0))))`);
wasmFailValidateText(`(module (func (param externref)) (func (param funcref) (call 0 (local.get 0))))`, typeErr);
wasmFailValidateText(`(module (func (param funcref)) (func (param externref) (call 0 (local.get 0))))`, typeErr);
wasmEvalText(`(module (func (param funcref) (result funcref) (block (result funcref) (local.get 0) (br 0))))`);
wasmFailValidateText(`(module (func (param funcref) (result externref) (block (result externref) (local.get 0) (br 0))))`, typeErr);
wasmFailValidateText(`(module (func (param externref) (result externref) (block (result funcref) (local.get 0) (br 0))))`, typeErr);
wasmEvalText(`(module (func (param funcref funcref) (result funcref) (select (result funcref) (local.get 0) (local.get 1) (i32.const 0))))`);
wasmFailValidateText(`(module (func (param externref funcref) (result externref) (select (result externref) (local.get 0) (local.get 1) (i32.const 0))))`, typeErr);
wasmFailValidateText(`(module (func (param funcref externref) (result externref) (select (result externref)(local.get 0) (local.get 1) (i32.const 0))))`, typeErr);
wasmFailValidateText(`(module (func (param externref funcref) (result funcref) (select (result funcref) (local.get 0) (local.get 1) (i32.const 0))))`, typeErr);
wasmFailValidateText(`(module (func (param funcref externref) (result funcref) (select (result funcref) (local.get 0) (local.get 1) (i32.const 0))))`, typeErr);


// Runtime:

var m = new Module(wasmTextToBinary(`(module (func (export "wasmFun")))`));
const wasmFun1 = new Instance(m).exports.wasmFun;
const wasmFun2 = new Instance(m).exports.wasmFun;
const wasmFun3 = new Instance(m).exports.wasmFun;

var run = wasmEvalText(`(module
    (global (mut funcref) (ref.null func))
    (func (param $x funcref) (param $test i32) (result funcref)
      local.get $x
      global.get 0
      local.get $test
      select (result funcref)
    )
    (func (export "run") (param $a funcref) (param $b funcref) (param $c funcref) (param $test1 i32) (param $test2 i32) (result funcref)
      local.get $a
      global.set 0
      block (result funcref)
        local.get $b
        local.get $test1
        br_if 0
        drop
        local.get $c
      end
      local.get $test2
      call 0
    )
)`).exports.run;
assertEq(run(wasmFun1, wasmFun2, wasmFun3, false, false), wasmFun1);
assertEq(run(wasmFun1, wasmFun2, wasmFun3, true, false), wasmFun1);
assertEq(run(wasmFun1, wasmFun2, wasmFun3, true, true), wasmFun2);
assertEq(run(wasmFun1, wasmFun2, wasmFun3, false, true), wasmFun3);

var run = wasmEvalText(`(module
  (type $t0 (func (param externref) (result externref)))
  (type $t1 (func (param funcref) (result externref)))
  (type $t2 (func (param funcref funcref) (result externref)))
  (func $f0 (type $t0) ref.null extern)
  (func $f1 (type $t1) ref.null extern)
  (func $f2 (type $t2) ref.null extern)
  (table funcref (elem $f0 $f1 $f2))
  (func (export "run") (param i32 i32) (result externref)
    block $b2 block $b1 block $b0
      local.get 0
      br_table $b0 $b1 $b2
    end $b0
      ref.null extern
      local.get 1
      call_indirect (type $t0)
      return
    end $b1
      ref.null func
      local.get 1
      call_indirect (type $t1)
      return
    end $b2
      ref.null func
      ref.null func
      local.get 1
      call_indirect (type $t2)
      return
  )
)`).exports.run;

for (var i = 0; i < 3; i++) {
  for (var j = 0; j < 3; j++) {
    if (i == j)
      assertEq(run(i, j), null);
    else
      assertErrorMessage(() => run(i, j), RuntimeError, /indirect call signature mismatch/);
  }
}


// JS API:

const wasmFun = wasmEvalText(`(module (func (export "x")))`).exports.x;

var run = wasmEvalText(`(module (func (export "run") (param funcref) (result funcref) (local.get 0)))`).exports.run;
assertEq(run(wasmFun), wasmFun);
assertEq(run(null), null);
assertErrorMessage(() => run(() => {}), TypeError, badWasmFunc);

var importReturnValue;
var importFun = () => importReturnValue;
var run = wasmEvalText(`(module (func (import "" "i") (result funcref)) (func (export "run") (result funcref) (call 0)))`, {'':{i:importFun}}).exports.run;
importReturnValue = wasmFun;
assertEq(run(), wasmFun);
importReturnValue = null;
assertEq(run(), null);
importReturnValue = undefined;
assertErrorMessage(() => run(), TypeError, badWasmFunc);
importReturnValue = () => {};
assertErrorMessage(() => run(), TypeError, badWasmFunc);

var g = new Global({value:'anyfunc', mutable:true}, wasmFun);
assertEq(g.value, wasmFun);
g.value = null;
assertEq(g.value, null);
Math.sin();
assertErrorMessage(() => g.value = () => {}, TypeError, badWasmFunc);
var g = new Global({value:'anyfunc', mutable:true}, null);
assertEq(g.value, null);
g.value = wasmFun;
assertEq(g.value, wasmFun);
assertErrorMessage(() => new Global({value:'anyfunc'}, () => {}), TypeError, badWasmFunc);