[WASM-References] Rename anyfunc to funcref
[WebKit-https.git] / JSTests / wasm / js-api / call-indirect.js
1 import * as assert from '../assert.js';
2 import Builder from '../Builder.js';
3
4 const oneTable = () => {
5     const builder = (new Builder())
6         .Type().End()
7         .Import()
8             .Function("imp", "func", { params: ["i32"] })
9             .Table("imp", "table", { initial: 1, maximum: 1, element: "funcref"})
10         .End()
11         .Function().End()
12         .Export()
13             .Function("changeCounter")
14             .Function("callFunc")
15         .End()
16         .Code()
17             .Function("changeCounter", { params: ["i32", "i32"] })
18                 .I32Const(42)
19                 .GetLocal(0)
20                 .I32Add()
21                 .GetLocal(1)
22                 .CallIndirect(0, 0) // Calls table[0](param[0] + 42).
23             .End()
24             .Function("callFunc", { params: ["i32"] })
25                 .GetLocal(0)
26                 .Call(0) // Calls func(param[0] + 42)
27             .End()
28         .End();
29     const bin = builder.WebAssembly().get();
30     const module = new WebAssembly.Module(bin);
31     return module;
32 };
33
34 const multiTable = () => {
35     const builder = (new Builder())
36         .Type().End()
37         .Import()
38             .Function("imp", "func", { params: ["i32"] })
39             .Table("imp", "table0", { initial: 0, maximum: 0, element: "funcref"})
40             .Table("imp", "table", { initial: 1, maximum: 1, element: "funcref"})
41         .End()
42         .Function().End()
43         .Export()
44             .Function("changeCounter")
45             .Function("callFunc")
46         .End()
47         .Code()
48             .Function("changeCounter", { params: ["i32", "i32"] })
49                 .I32Const(42)
50                 .GetLocal(0)
51                 .I32Add()
52                 .GetLocal(1)
53                 .CallIndirect(0, 1) // Calls table[0](param[0] + 42).
54             .End()
55             .Function("callFunc", { params: ["i32"] })
56                 .GetLocal(0)
57                 .Call(0) // Calls func(param[0] + 42)
58             .End()
59         .End();
60     const bin = builder.WebAssembly().get();
61     const module = new WebAssembly.Module(bin);
62     return module;
63 };
64
65 for (const wasmModuleWhichImportJS of [oneTable, multiTable]) {
66
67 const makeTable = () => {
68     return new WebAssembly.Table({initial: 1, maximum: 1, element: "funcref"});
69 };
70
71 (function MonomorphicImport() {
72     let counter = 0;
73     const counterSetter = v => counter = v;
74     const table = makeTable();
75     const module = wasmModuleWhichImportJS();
76     const instance = new WebAssembly.Instance(module, { imp: { func: counterSetter, table, table0: new WebAssembly.Table({initial: 0, maximum: 0, element: "funcref"}) } });
77     table.set(0, instance.exports.callFunc);
78     for (let i = 0; i < 4096; ++i) {
79         // Invoke this a bunch of times to make sure the IC in the wasm -> JS stub works correctly.
80         instance.exports.changeCounter(i, 0);
81         assert.eq(counter, i + 42);
82     }
83 })();
84
85 (function Polyphic2Import() {
86     let counterA = 0;
87     let counterB = undefined;
88     const counterASetter = v => counterA = v;
89     const counterBSetter = v => counterB = { valueB: v };
90     const module = wasmModuleWhichImportJS();
91
92     const tableA = makeTable();
93     const instanceA = new WebAssembly.Instance(module, { imp: { func: counterASetter, table: tableA, table0: new WebAssembly.Table({initial: 0, maximum: 0, element: "funcref"}) } });
94     tableA.set(0, instanceA.exports.callFunc);
95
96     const tableB = makeTable();
97     const instanceB = new WebAssembly.Instance(module, { imp: { func: counterBSetter, table: tableB, table0: new WebAssembly.Table({initial: 0, maximum: 0, element: "funcref"}) } });
98     tableB.set(0, instanceB.exports.callFunc);
99     for (let i = 0; i < 2048; ++i) {
100         instanceA.exports.changeCounter(i, 0);
101         assert.isA(counterA, "number");
102         assert.eq(counterA, i + 42);
103         instanceB.exports.changeCounter(i, 0);
104         assert.isA(counterB, "object");
105         assert.eq(counterB.valueB, i + 42);
106     }
107 })();
108
109 (function VirtualImport() {
110     const counterSetters = [
111         v => counters[0] = v,
112         v => counters[1] = v + 1,
113         v => counters[2] = v + 2,
114         v => counters[3] = v + 3,
115         v => counters[4] = v + 4,
116         v => counters[5] = v + 5,
117         v => counters[6] = v + 6,
118         v => counters[7] = v + 7,
119         v => counters[8] = v + 8,
120         v => counters[9] = v + 9,
121     ];
122     const num = counterSetters.length;
123     let counters = counterSetters.map(() => 0);
124     assert.eq(counters.length, num);
125     const module = wasmModuleWhichImportJS();
126     let instances = [];
127     for (let i = 0; i < num; ++i) {
128         let table = makeTable();
129         instances[i] = new WebAssembly.Instance(module, { imp: { func: counterSetters[i], table, table0: new WebAssembly.Table({initial: 0, maximum: 0, element: "funcref"}) } });
130         table.set(0, instances[i].exports.callFunc);
131     }
132     for (let i = 0; i < 2048; ++i) {
133         for (let j = 0; j < num; ++j) {
134             instances[j].exports.changeCounter(i, 0);
135             assert.isA(counters[j], "number");
136             assert.eq(counters[j], i + 42 + j);
137         }
138     }
139 })();
140
141 }