summaryrefslogtreecommitdiffstats
path: root/js/src/jit-test/tests/wasm/tables.js
blob: d8defeb9c8681282ef406350bf5ea4144196d422 (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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
load(libdir + 'wasm.js');

const Module = WebAssembly.Module;
const Instance = WebAssembly.Instance;
const Table = WebAssembly.Table;
const Memory = WebAssembly.Memory;
const RuntimeError = WebAssembly.RuntimeError;

var callee = i => `(func $f${i} (result i32) (i32.const ${i}))`;

wasmFailValidateText(`(module (elem (i32.const 0) $f0) ${callee(0)})`, /table index out of range/);
wasmFailValidateText(`(module (table 10 anyfunc) (elem (i32.const 0) 0))`, /table element out of range/);
wasmFailValidateText(`(module (table 10 anyfunc) (func) (elem (i32.const 0) 0 1))`, /table element out of range/);
wasmFailValidateText(`(module (table 10 anyfunc) (func) (elem (f32.const 0) 0) ${callee(0)})`, /type mismatch/);

assertErrorMessage(() => wasmEvalText(`(module (table 10 anyfunc) (elem (i32.const 10) $f0) ${callee(0)})`), RangeError, /elem segment does not fit/);
assertErrorMessage(() => wasmEvalText(`(module (table 10 anyfunc) (elem (i32.const 8) $f0 $f0 $f0) ${callee(0)})`), RangeError, /elem segment does not fit/);
wasmEvalText(`(module (table 0 anyfunc) (func) (elem (i32.const 0x10001)))`);

assertErrorMessage(() => wasmEvalText(`(module (table 10 anyfunc) (import "globals" "a" (global i32)) (elem (get_global 0) $f0) ${callee(0)})`, {globals:{a:10}}), RangeError, /elem segment does not fit/);
assertErrorMessage(() => wasmEvalText(`(module (table 10 anyfunc) (import "globals" "a" (global i32)) (elem (get_global 0) $f0 $f0 $f0) ${callee(0)})`, {globals:{a:8}}), RangeError, /elem segment does not fit/);

assertEq(new Module(wasmTextToBinary(`(module (table 10 anyfunc) (elem (i32.const 1) $f0 $f0) (elem (i32.const 0) $f0) ${callee(0)})`)) instanceof Module, true);
assertEq(new Module(wasmTextToBinary(`(module (table 10 anyfunc) (elem (i32.const 1) $f0 $f0) (elem (i32.const 2) $f0) ${callee(0)})`)) instanceof Module, true);
wasmEvalText(`(module (table 10 anyfunc) (import "globals" "a" (global i32)) (elem (i32.const 1) $f0 $f0) (elem (get_global 0) $f0) ${callee(0)})`, {globals:{a:0}});
wasmEvalText(`(module (table 10 anyfunc) (import "globals" "a" (global i32)) (elem (get_global 0) $f0 $f0) (elem (i32.const 2) $f0) ${callee(0)})`, {globals:{a:1}});

var m = new Module(wasmTextToBinary(`
    (module
        (import "globals" "table" (table 10 anyfunc))
        (import "globals" "a" (global i32))
        (elem (get_global 0) $f0 $f0)
        ${callee(0)})
`));
var tbl = new Table({initial:50, element:"anyfunc"});
assertEq(new Instance(m, {globals:{a:20, table:tbl}}) instanceof Instance, true);
assertErrorMessage(() => new Instance(m, {globals:{a:50, table:tbl}}), RangeError, /elem segment does not fit/);

var caller = `(type $v2i (func (result i32))) (func $call (param $i i32) (result i32) (call_indirect $v2i (get_local $i))) (export "call" $call)`
var callee = i => `(func $f${i} (type $v2i) (i32.const ${i}))`;

var call = wasmEvalText(`(module (table 10 anyfunc) ${callee(0)} ${caller})`).exports.call;
assertErrorMessage(() => call(0), RuntimeError, /indirect call to null/);
assertErrorMessage(() => call(10), RuntimeError, /index out of bounds/);

var call = wasmEvalText(`(module (table 10 anyfunc) (elem (i32.const 0)) ${callee(0)} ${caller})`).exports.call;
assertErrorMessage(() => call(0), RuntimeError, /indirect call to null/);
assertErrorMessage(() => call(10), RuntimeError, /index out of bounds/);

var call = wasmEvalText(`(module (table 10 anyfunc) (elem (i32.const 0) $f0) ${callee(0)} ${caller})`).exports.call;
assertEq(call(0), 0);
assertErrorMessage(() => call(1), RuntimeError, /indirect call to null/);
assertErrorMessage(() => call(2), RuntimeError, /indirect call to null/);
assertErrorMessage(() => call(10), RuntimeError, /index out of bounds/);

var call = wasmEvalText(`(module (table 10 anyfunc) (elem (i32.const 1) $f0 $f1) (elem (i32.const 4) $f0 $f2) ${callee(0)} ${callee(1)} ${callee(2)} ${caller})`).exports.call;
assertErrorMessage(() => call(0), RuntimeError, /indirect call to null/);
assertEq(call(1), 0);
assertEq(call(2), 1);
assertErrorMessage(() => call(3), RuntimeError, /indirect call to null/);
assertEq(call(4), 0);
assertEq(call(5), 2);
assertErrorMessage(() => call(6), RuntimeError, /indirect call to null/);
assertErrorMessage(() => call(10), RuntimeError, /index out of bounds/);

var imports = {a:{b:()=>42}};
var call = wasmEvalText(`(module (table 10 anyfunc) (elem (i32.const 0) $f0 $f1 $f2) ${callee(0)} (import "a" "b" (func $f1)) (import "a" "b" (func $f2 (result i32))) ${caller})`, imports).exports.call;
assertEq(call(0), 0);
assertErrorMessage(() => call(1), RuntimeError, /indirect call signature mismatch/);
assertEq(call(2), 42);

var tbl = new Table({initial:3, element:"anyfunc"});
var call = wasmEvalText(`(module (import "a" "b" (table 3 anyfunc)) (export "tbl" table) (elem (i32.const 0) $f0 $f1) ${callee(0)} ${callee(1)} ${caller})`, {a:{b:tbl}}).exports.call;
assertEq(call(0), 0);
assertEq(call(1), 1);
assertEq(tbl.get(0)(), 0);
assertEq(tbl.get(1)(), 1);
assertErrorMessage(() => call(2), RuntimeError, /indirect call to null/);
assertEq(tbl.get(2), null);

var exp = wasmEvalText(`(module (import "a" "b" (table 3 anyfunc)) (export "tbl" table) (elem (i32.const 2) $f2) ${callee(2)} ${caller})`, {a:{b:tbl}}).exports;
assertEq(exp.tbl, tbl);
assertEq(exp.call(0), 0);
assertEq(exp.call(1), 1);
assertEq(exp.call(2), 2);
assertEq(call(0), 0);
assertEq(call(1), 1);
assertEq(call(2), 2);
assertEq(tbl.get(0)(), 0);
assertEq(tbl.get(1)(), 1);
assertEq(tbl.get(2)(), 2);

var exp1 = wasmEvalText(`(module (table 10 anyfunc) (export "tbl" table) (elem (i32.const 0) $f0 $f0) ${callee(0)} (export "f0" $f0) ${caller})`).exports
assertEq(exp1.tbl.get(0), exp1.f0);
assertEq(exp1.tbl.get(1), exp1.f0);
assertEq(exp1.tbl.get(2), null);
assertEq(exp1.call(0), 0);
assertEq(exp1.call(1), 0);
assertErrorMessage(() => exp1.call(2), RuntimeError, /indirect call to null/);
var exp2 = wasmEvalText(`(module (import "a" "b" (table 10 anyfunc)) (export "tbl" table) (elem (i32.const 1) $f1 $f1) ${callee(1)} (export "f1" $f1) ${caller})`, {a:{b:exp1.tbl}}).exports
assertEq(exp1.tbl, exp2.tbl);
assertEq(exp2.tbl.get(0), exp1.f0);
assertEq(exp2.tbl.get(1), exp2.f1);
assertEq(exp2.tbl.get(2), exp2.f1);
assertEq(exp1.call(0), 0);
assertEq(exp1.call(1), 1);
assertEq(exp1.call(2), 1);
assertEq(exp2.call(0), 0);
assertEq(exp2.call(1), 1);
assertEq(exp2.call(2), 1);

var tbl = new Table({initial:3, element:"anyfunc"});
var e1 = wasmEvalText(`(module (func $f (result i32) (i32.const 42)) (export "f" $f))`).exports;
var e2 = wasmEvalText(`(module (func $g (result f32) (f32.const 10)) (export "g" $g))`).exports;
var e3 = wasmEvalText(`(module (func $h (result i32) (i32.const 13)) (export "h" $h))`).exports;
tbl.set(0, e1.f);
tbl.set(1, e2.g);
tbl.set(2, e3.h);
var e4 = wasmEvalText(`(module (import "a" "b" (table 3 anyfunc)) ${caller})`, {a:{b:tbl}}).exports;
assertEq(e4.call(0), 42);
assertErrorMessage(() => e4.call(1), RuntimeError, /indirect call signature mismatch/);
assertEq(e4.call(2), 13);

var m = new Module(wasmTextToBinary(`(module
    (type $i2i (func (param i32) (result i32)))
    (import "a" "mem" (memory 1))
    (import "a" "tbl" (table 10 anyfunc))
    (import $imp "a" "imp" (result i32))
    (func $call (param $i i32) (result i32)
        (i32.add
            (call $imp)
            (i32.add
                (i32.load (i32.const 0))
                (if i32 (i32.eqz (get_local $i))
                    (then (i32.const 0))
                    (else
                        (set_local $i (i32.sub (get_local $i) (i32.const 1)))
                        (call_indirect $i2i (get_local $i) (get_local $i)))))))
    (export "call" $call)
)`));
var failTime = false;
var tbl = new Table({initial:10, element:"anyfunc"});
var mem1 = new Memory({initial:1});
var e1 = new Instance(m, {a:{mem:mem1, tbl, imp() {if (failTime) throw new Error("ohai"); return 1}}}).exports;
tbl.set(0, e1.call);
var mem2 = new Memory({initial:1});
var e2 = new Instance(m, {a:{mem:mem2, tbl, imp() {return 10} }}).exports;
tbl.set(1, e2.call);
var mem3 = new Memory({initial:1});
var e3 = new Instance(m, {a:{mem:mem3, tbl, imp() {return 100} }}).exports;
new Int32Array(mem1.buffer)[0] = 1000;
new Int32Array(mem2.buffer)[0] = 10000;
new Int32Array(mem3.buffer)[0] = 100000;
assertEq(e3.call(2), 111111);
failTime = true;
assertErrorMessage(() => e3.call(2), Error, "ohai");

// Call signatures are matched structurally:

var call = wasmEvalText(`(module
    (type $v2i1 (func (result i32)))
    (type $v2i2 (func (result i32)))
    (type $i2v (func (param i32)))
    (table anyfunc (elem $a $b $c))
    (func $a (type $v2i1) (i32.const 0))
    (func $b (type $v2i2) (i32.const 1))
    (func $c (type $i2v))
    (func $call (param i32) (result i32) (call_indirect $v2i1 (get_local 0)))
    (export "call" $call)
)`).exports.call;
assertEq(call(0), 0);
assertEq(call(1), 1);
assertErrorMessage(() => call(2), RuntimeError, /indirect call signature mismatch/);

var call = wasmEvalText(`(module
    (type $A (func (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (result i32)))
    (type $B (func (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (result i32)))
    (type $C (func (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (result i32)))
    (type $D (func (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (result i32)))
    (type $E (func (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (result i32)))
    (type $F (func (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (result i32)))
    (type $G (func (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (param i32) (result i32)))
    (table anyfunc (elem $a $b $c $d $e $f $g))
    (func $a (type $A) (get_local 7))
    (func $b (type $B) (get_local 8))
    (func $c (type $C) (get_local 9))
    (func $d (type $D) (get_local 10))
    (func $e (type $E) (get_local 11))
    (func $f (type $F) (get_local 12))
    (func $g (type $G) (get_local 13))
    (func $call (param i32) (result i32)
        (call_indirect $A (i32.const 0) (i32.const 0) (i32.const 0) (i32.const 0) (i32.const 0) (i32.const 0) (i32.const 0) (i32.const 42) (get_local 0)))
    (export "call" $call)
)`).exports.call;
assertEq(call(0), 42);
for (var i = 1; i < 7; i++)
    assertErrorMessage(() => call(i), RuntimeError, /indirect call signature mismatch/);
assertErrorMessage(() => call(7), RuntimeError, /index out of bounds/);