b832e117664130230fc80bfb130c1366a312e325
[WebKit-https.git] / JSTests / wasm / js-api / table.js
1 import Builder from '../Builder.js';
2 import * as assert from '../assert.js';
3
4 {
5     const builder = new Builder()
6         .Type().End()
7         .Import()
8             .Table("imp", "table", {initial: 20, element: "anyfunc"})
9         .End()
10         .Function().End()
11         .Table()
12             .Table({initial: 20, maximum: 30, element: "anyfunc"})
13         .End()
14         .Code()
15         .End();
16     assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 34 / 41: Cannot have more than one Table for now");
17 }
18
19 {
20     const builder = new Builder()
21         .Type().End()
22         .Function().End()
23         .Table()
24             // Table count is zero.
25         .End()
26         .Code()
27         .End();
28     new WebAssembly.Module(builder.WebAssembly().get());
29 }
30
31 {
32     const builder = new Builder()
33         .Type().End()
34         .Function().End()
35         .Table()
36             .Table({initial: 20, maximum: 30, element: "anyfunc"})
37             .Table({initial: 20, maximum: 30, element: "anyfunc"})
38         .End()
39         .Code()
40         .End();
41     assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 17 / 28: Table count of 2 is invalid, at most 1 is allowed for now (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')");
42 }
43
44 {
45     const builder = new Builder()
46         .Type().End()
47         .Function().End()
48         .Export()
49             .Function("foo")
50         .End()
51         .Code()
52             .Function("foo", {params: ["i32"]})
53                 .GetLocal(0)
54                 .CallIndirect(0, 0)
55             .End()
56         .End();
57     assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 4 / 7: call_indirect is only valid when a table is defined or imported, in function at index 0 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')");
58 }
59
60 {
61     const builder = new Builder()
62         .Type().End()
63         .Function().End()
64         .Table()
65             .Table({initial:20, element:"anyfunc"})
66         .End()
67         .Export()
68             .Function("foo")
69         .End()
70         .Code()
71             .Function("foo", {params: ["i32"]})
72                 .GetLocal(0)
73                 .CallIndirect(0, 1)
74             .End()
75         .End();
76     assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 6 / 7: call_indirect's 'reserved' varuint1 must be 0x0, in function at index 0 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')");
77 }
78
79 {
80     // Can't export an undefined table
81     const builder = new Builder()
82         .Type().End()
83         .Function().End()
84         .Export()
85             .Table("foo", 0)
86         .End()
87         .Code()
88         .End();
89     assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 23 / 26: can't export Table 0 there are 0 Tables");
90 }
91
92 {
93     // Can't export a table at index 1.
94     const builder = new Builder()
95         .Type().End()
96         .Function().End()
97         .Table()
98             .Table({initial: 20, maximum: 30, element: "anyfunc"})
99         .End()
100         .Export()
101             .Table("foo", 1)
102         .End()
103         .Code()
104         .End();
105     assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 30 / 33: can't export Table 1 there are 1 Tables");
106 }
107
108 function assertBadTable(tableDescription, message) {
109     const builder = new Builder()
110         .Type().End()
111         .Function().End()
112         .Table()
113             .Table(tableDescription)
114         .End()
115         .Code()
116         .End();
117     assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, message);
118 }
119
120 function assertBadTableImport(tableDescription, message) {
121     const builder = new Builder()
122         .Type().End()
123         .Import()
124             .Table("imp", "table", tableDescription)
125         .End()
126         .Function().End()
127         .Code()
128         .End();
129     assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, message);
130 }
131
132 {
133     let badDescriptions = [
134         [{initial: 10, element: "i32"},
135          "WebAssembly.Module doesn't parse at byte 18 / 23: Table type should be anyfunc, got -1 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
136          "WebAssembly.Module doesn't parse at byte 26 / 34: Table type should be anyfunc, got -1 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
137         [{initial: 10, element: "f32"},
138          "WebAssembly.Module doesn't parse at byte 18 / 23: Table type should be anyfunc, got -3 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
139          "WebAssembly.Module doesn't parse at byte 26 / 34: Table type should be anyfunc, got -3 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
140         [{initial: 10, element: "f64"},
141          "WebAssembly.Module doesn't parse at byte 18 / 23: Table type should be anyfunc, got -4 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
142          "WebAssembly.Module doesn't parse at byte 26 / 34: Table type should be anyfunc, got -4 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
143         [{initial: 10, element: "i64"},
144          "WebAssembly.Module doesn't parse at byte 18 / 23: Table type should be anyfunc, got -2 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
145          "WebAssembly.Module doesn't parse at byte 26 / 34: Table type should be anyfunc, got -2 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
146         [{initial: 10, maximum: 20, element: "i32"},
147          "WebAssembly.Module doesn't parse at byte 18 / 24: Table type should be anyfunc, got -1 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
148          "WebAssembly.Module doesn't parse at byte 26 / 35: Table type should be anyfunc, got -1 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
149         [{initial: 10, maximum: 20, element: "f32"},
150          "WebAssembly.Module doesn't parse at byte 18 / 24: Table type should be anyfunc, got -3 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
151          "WebAssembly.Module doesn't parse at byte 26 / 35: Table type should be anyfunc, got -3 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
152         [{initial: 10, maximum: 20, element: "f64"},
153          "WebAssembly.Module doesn't parse at byte 18 / 24: Table type should be anyfunc, got -4 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
154          "WebAssembly.Module doesn't parse at byte 26 / 35: Table type should be anyfunc, got -4 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
155         [{initial: 10, maximum: 20, element: "i64"},
156          "WebAssembly.Module doesn't parse at byte 18 / 24: Table type should be anyfunc, got -2 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
157          "WebAssembly.Module doesn't parse at byte 26 / 35: Table type should be anyfunc, got -2 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
158
159         [{initial: 10, maximum: 9, element: "anyfunc"},
160          "WebAssembly.Module doesn't parse at byte 21 / 24: resizable limits has a initial page count of 10 which is greater than its maximum 9 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
161          "WebAssembly.Module doesn't parse at byte 29 / 35: resizable limits has a initial page count of 10 which is greater than its maximum 9 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
162         [{initial: 1, maximum: 0, element: "anyfunc"},
163          "WebAssembly.Module doesn't parse at byte 21 / 24: resizable limits has a initial page count of 1 which is greater than its maximum 0 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
164          "WebAssembly.Module doesn't parse at byte 29 / 35: resizable limits has a initial page count of 1 which is greater than its maximum 0 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
165         [{initial: 2**32 - 1, maximum: 2**32 - 2, element: "anyfunc"},
166          "WebAssembly.Module doesn't parse at byte 29 / 32: resizable limits has a initial page count of 4294967295 which is greater than its maximum 4294967294 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
167          "WebAssembly.Module doesn't parse at byte 37 / 43: resizable limits has a initial page count of 4294967295 which is greater than its maximum 4294967294 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
168         [{initial: 2**31, element: "anyfunc"},
169          "WebAssembly.Module doesn't parse at byte 24 / 27: Table's initial page count of 2147483648 is too big, maximum 10000000 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
170          "WebAssembly.Module doesn't parse at byte 32 / 38: Table's initial page count of 2147483648 is too big, maximum 10000000 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
171     ];
172
173     for (const d of badDescriptions) {
174         assertBadTable(d[0], d[1]);
175         assertBadTableImport(d[0], d[2]);
176     }
177 }
178
179 {
180     const builder = new Builder()
181         .Type().End()
182         .Import()
183             .Table("imp", "table", {initial: 20, element: "anyfunc"})
184             .Table("imp", "table", {initial: 20, element: "anyfunc"})
185         .End()
186         .Function().End()
187         .Code()
188         .End();
189     assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 39 / 48: Cannot have more than one Table for now");
190 }
191
192
193 {
194     function assertBadTableInstance(tableDescription, table, message) {
195         const builder = new Builder()
196             .Type().End()
197             .Import()
198                 .Table("imp", "table", tableDescription)
199             .End()
200             .Function().End()
201             .Code()
202             .End();
203         const module = new WebAssembly.Module(builder.WebAssembly().get());
204         assert.throws(() => new WebAssembly.Instance(module, {imp: {table}}), WebAssembly.LinkError, message);
205     }
206
207     const badTables = [
208         [{initial: 100, maximum:100, element:"anyfunc"}, new WebAssembly.Table({initial:100, element: "anyfunc"}), "Table import imp:table does not have a 'maximum' but the module requires that it does (evaluating 'new WebAssembly.Instance(module, {imp: {table}})')"],
209         [{initial: 100, maximum:100, element:"anyfunc"}, new WebAssembly.Table({initial:100, maximum:101, element: "anyfunc"}), "Imported Table imp:table 'maximum' is larger than the module's expected 'maximum' (evaluating 'new WebAssembly.Instance(module, {imp: {table}})')"],
210         [{initial: 100, element:"anyfunc"}, new WebAssembly.Table({initial:10, element: "anyfunc"}), "Table import imp:table provided an 'initial' that is too small (evaluating 'new WebAssembly.Instance(module, {imp: {table}})')"],
211         [{initial: 10, element:"anyfunc"}, new WebAssembly.Table({initial:9, element: "anyfunc"}), "Table import imp:table provided an 'initial' that is too small (evaluating 'new WebAssembly.Instance(module, {imp: {table}})')"],
212     ];
213     for (const [d, t, m] of badTables) {
214         assertBadTableInstance(d, t, m);
215     }
216 }
217
218 assert.throws(() => WebAssembly.Table.prototype.grow(undefined), TypeError, `expected |this| value to be an instance of WebAssembly.Table`);
219
220 {
221     {
222         const table = new WebAssembly.Table({element: "anyfunc", initial: 20, maximum: 30});
223         assert.eq(20, table.grow(0));
224         assert.eq(20, table.length);
225         assert.eq(20, table.grow(1));
226         assert.eq(21, table.length);
227     }
228
229     {
230         const table = new WebAssembly.Table({element: "anyfunc", initial: 20, maximum: 30});
231         assert.eq(20, table.grow(10));
232         assert.eq(30, table.grow(0));
233         assert.throws(() => table.grow(1), RangeError, "WebAssembly.Table.prototype.grow could not grow the table");
234     }
235
236     {
237         const table = new WebAssembly.Table({element: "anyfunc", initial: 20});
238         let called = false;
239         table.grow({valueOf() { called = true; return 42; }});
240         assert.truthy(called);
241         assert.eq(62, table.length);
242     }
243
244     {
245         const table = new WebAssembly.Table({element: "anyfunc", initial: 20});
246         assert.throws(() => table.get(20), RangeError, "WebAssembly.Table.prototype.get expects an integer less than the length of the table");
247         for (let i = 0; i < 20; i++)
248             assert.eq(table.get(i), null);
249     }
250
251     {
252         const table = new WebAssembly.Table({element: "anyfunc", initial: 20});
253         assert.throws(() => table.set(20, null), RangeError, "WebAssembly.Table.prototype.set expects an integer less than the length of the table");
254         for (let i = 0; i < 20; i++)
255             table.set(i, null);
256     }
257
258     {
259         // This should not throw
260         new WebAssembly.Table({initial: 2**20, maximum: 2**32 - 1, element: "anyfunc"});
261     }
262 }
263
264 {
265
266     function assertBadTable(table) {
267         const builder = new Builder()
268             .Type().End()
269             .Import()
270                 .Table("imp", "table", {initial: 25, element: "anyfunc"})
271             .End()
272             .Function().End()
273             .Code()
274             .End();
275         const module = new WebAssembly.Module(builder.WebAssembly().get());
276         assert.throws(() => new WebAssembly.Instance(module, {imp: {table}}), WebAssembly.LinkError, "Table import imp:table is not an instance of WebAssembly.Table (evaluating 'new WebAssembly.Instance(module, {imp: {table}})')");
277     }
278     assertBadTable(25);
279     assertBadTable(new Object);
280     assertBadTable([]);
281     assertBadTable(new WebAssembly.Memory({initial:1}));
282 }
283
284 {
285     const builder = new Builder()
286         .Type().End()
287         .Import()
288             .Table("imp", "table", {initial: 25, element: "anyfunc"})
289         .End()
290         .Function().End()
291         .Export()
292             .Table("table", 0)
293             .Table("table2", 0)
294         .End()
295         .Code().End();
296
297     const module = new WebAssembly.Module(builder.WebAssembly().get());
298     const table = new WebAssembly.Table({element: "anyfunc", initial: 25});
299     const instance = new WebAssembly.Instance(module, {imp: {table}});
300     assert.truthy(table === instance.exports.table);
301     assert.truthy(table === instance.exports.table2);
302 }
303
304 {
305     const builder = new Builder()
306         .Type().End()
307         .Function().End()
308         .Table()
309             .Table({initial: 20, maximum: 30, element: "anyfunc"})
310         .End()
311         .Export()
312             .Table("table", 0)
313             .Table("table2", 0)
314         .End()
315         .Code().End();
316
317     const module = new WebAssembly.Module(builder.WebAssembly().get());
318     const instance = new WebAssembly.Instance(module);
319     assert.eq(instance.exports.table, instance.exports.table2);
320     assert.eq(instance.exports.table.length, 20);
321     assert.truthy(instance.exports.table instanceof WebAssembly.Table);
322 }