1b844431ce65f91c4375325d5cae53dc8bc243c7
[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     new WebAssembly.Module(builder.WebAssembly().get())
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     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: 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: call_indirect's table index 1 invalid, limit is 1, in function at index 0 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')");
77 }
78
79 {
80     const builder = new Builder()
81         .Type().End()
82         .Function().End()
83         .Table()
84             .Table({initial:20, element:"anyfunc"})
85             .Table({initial:20, element:"anyfunc"})
86         .End()
87         .Export()
88             .Function("foo")
89         .End()
90         .Code()
91             .Function("foo", {params: ["i32"]})
92                 .GetLocal(0)
93                 .GetLocal(0)
94                 .CallIndirect(0, 1)
95             .End()
96         .End();
97     new WebAssembly.Module(builder.WebAssembly().get())
98 }
99
100 {
101     // Can't export an undefined table
102     const builder = new Builder()
103         .Type().End()
104         .Function().End()
105         .Export()
106             .Table("foo", 0)
107         .End()
108         .Code()
109         .End();
110     assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 23: can't export Table 0 there are 0 Tables");
111 }
112
113 {
114     // Can't export a table at index 1.
115     const builder = new Builder()
116         .Type().End()
117         .Function().End()
118         .Table()
119             .Table({initial: 20, maximum: 30, element: "anyfunc"})
120         .End()
121         .Export()
122             .Table("foo", 1)
123         .End()
124         .Code()
125         .End();
126     assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 30: can't export Table 1 there are 1 Tables");
127 }
128
129 function assertBadTable(tableDescription, message) {
130     const builder = new Builder()
131         .Type().End()
132         .Function().End()
133         .Table()
134             .Table(tableDescription)
135         .End()
136         .Code()
137         .End();
138     assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, message);
139 }
140
141 function assertBadTableImport(tableDescription, message) {
142     const builder = new Builder()
143         .Type().End()
144         .Import()
145             .Table("imp", "table", tableDescription)
146         .End()
147         .Function().End()
148         .Code()
149         .End();
150     assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, message);
151 }
152
153 {
154     let badDescriptions = [
155         [{initial: 10, element: "i32"},
156          "WebAssembly.Module doesn't parse at byte 18: Table type should be anyfunc or anyref, got -1 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
157          "WebAssembly.Module doesn't parse at byte 26: Table type should be anyfunc or anyref, got -1 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
158         [{initial: 10, element: "f32"},
159          "WebAssembly.Module doesn't parse at byte 18: Table type should be anyfunc or anyref, got -3 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
160          "WebAssembly.Module doesn't parse at byte 26: Table type should be anyfunc or anyref, got -3 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
161         [{initial: 10, element: "f64"},
162          "WebAssembly.Module doesn't parse at byte 18: Table type should be anyfunc or anyref, got -4 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
163          "WebAssembly.Module doesn't parse at byte 26: Table type should be anyfunc or anyref, got -4 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
164         [{initial: 10, element: "i64"},
165          "WebAssembly.Module doesn't parse at byte 18: Table type should be anyfunc or anyref, got -2 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
166          "WebAssembly.Module doesn't parse at byte 26: Table type should be anyfunc or anyref, got -2 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
167         [{initial: 10, maximum: 20, element: "i32"},
168          "WebAssembly.Module doesn't parse at byte 18: Table type should be anyfunc or anyref, got -1 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
169          "WebAssembly.Module doesn't parse at byte 26: Table type should be anyfunc or anyref, got -1 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
170         [{initial: 10, maximum: 20, element: "f32"},
171          "WebAssembly.Module doesn't parse at byte 18: Table type should be anyfunc or anyref, got -3 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
172          "WebAssembly.Module doesn't parse at byte 26: Table type should be anyfunc or anyref, got -3 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
173         [{initial: 10, maximum: 20, element: "f64"},
174          "WebAssembly.Module doesn't parse at byte 18: Table type should be anyfunc or anyref, got -4 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
175          "WebAssembly.Module doesn't parse at byte 26: Table type should be anyfunc or anyref, got -4 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
176         [{initial: 10, maximum: 20, element: "i64"},
177          "WebAssembly.Module doesn't parse at byte 18: Table type should be anyfunc or anyref, got -2 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
178          "WebAssembly.Module doesn't parse at byte 26: Table type should be anyfunc or anyref, got -2 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
179
180         [{initial: 10, maximum: 9, element: "anyfunc"},
181          "WebAssembly.Module doesn't parse at byte 21: resizable limits has a initial page count of 10 which is greater than its maximum 9 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
182          "WebAssembly.Module doesn't parse at byte 29: resizable limits has a initial page count of 10 which is greater than its maximum 9 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
183         [{initial: 1, maximum: 0, element: "anyfunc"},
184          "WebAssembly.Module doesn't parse at byte 21: resizable limits has a initial page count of 1 which is greater than its maximum 0 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
185          "WebAssembly.Module doesn't parse at byte 29: resizable limits has a initial page count of 1 which is greater than its maximum 0 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
186         [{initial: 2**32 - 1, maximum: 2**32 - 2, element: "anyfunc"},
187          "WebAssembly.Module doesn't parse at byte 29: resizable limits has a initial page count of 4294967295 which is greater than its maximum 4294967294 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
188          "WebAssembly.Module doesn't parse at byte 37: resizable limits has a initial page count of 4294967295 which is greater than its maximum 4294967294 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
189         [{initial: 2**31, element: "anyfunc"},
190          "WebAssembly.Module doesn't parse at byte 24: Table's initial page count of 2147483648 is too big, maximum 10000000 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
191          "WebAssembly.Module doesn't parse at byte 32: Table's initial page count of 2147483648 is too big, maximum 10000000 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
192     ];
193
194     for (const d of badDescriptions) {
195         assertBadTable(d[0], d[1]);
196         assertBadTableImport(d[0], d[2]);
197     }
198 }
199
200 {
201     const builder = new Builder()
202         .Type().End()
203         .Import()
204             .Table("imp", "table", {initial: 20, element: "anyfunc"})
205             .Table("imp", "table", {initial: 20, element: "anyfunc"})
206         .End()
207         .Function().End()
208         .Code()
209         .End();
210     new WebAssembly.Module(builder.WebAssembly().get())
211 }
212
213
214 {
215     function assertBadTableInstance(tableDescription, table, message) {
216         const builder = new Builder()
217             .Type().End()
218             .Import()
219                 .Table("imp", "table", tableDescription)
220             .End()
221             .Function().End()
222             .Code()
223             .End();
224         const module = new WebAssembly.Module(builder.WebAssembly().get());
225         assert.throws(() => new WebAssembly.Instance(module, {imp: {table}}), WebAssembly.LinkError, message);
226     }
227
228     const badTables = [
229         [{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}})')"],
230         [{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}})')"],
231         [{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}})')"],
232         [{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}})')"],
233     ];
234     for (const [d, t, m] of badTables) {
235         assertBadTableInstance(d, t, m);
236     }
237 }
238
239 assert.throws(() => WebAssembly.Table.prototype.grow(undefined), TypeError, `expected |this| value to be an instance of WebAssembly.Table`);
240
241 {
242     {
243         const table = new WebAssembly.Table({element: "anyfunc", initial: 20, maximum: 30});
244         assert.eq(20, table.grow(0));
245         assert.eq(20, table.length);
246         assert.eq(20, table.grow(1));
247         assert.eq(21, table.length);
248     }
249
250     {
251         const table = new WebAssembly.Table({element: "anyfunc", initial: 20, maximum: 30});
252         assert.eq(20, table.grow(10));
253         assert.eq(30, table.grow(0));
254         assert.throws(() => table.grow(1), RangeError, "WebAssembly.Table.prototype.grow could not grow the table");
255     }
256
257     {
258         const table = new WebAssembly.Table({element: "anyfunc", initial: 20});
259         let called = false;
260         table.grow({valueOf() { called = true; return 42; }});
261         assert.truthy(called);
262         assert.eq(62, table.length);
263     }
264
265     {
266         const table = new WebAssembly.Table({element: "anyfunc", initial: 20});
267         assert.throws(() => table.get(20), RangeError, "WebAssembly.Table.prototype.get expects an integer less than the length of the table");
268         for (let i = 0; i < 20; i++)
269             assert.eq(table.get(i), null);
270     }
271
272     {
273         const table = new WebAssembly.Table({element: "anyfunc", initial: 20});
274         assert.throws(() => table.set(20, null), RangeError, "WebAssembly.Table.prototype.set expects an integer less than the length of the table");
275         for (let i = 0; i < 20; i++)
276             table.set(i, null);
277     }
278
279     {
280         // This should not throw
281         new WebAssembly.Table({initial: 2**20, maximum: 2**32 - 1, element: "anyfunc"});
282     }
283 }
284
285 {
286
287     function assertBadTable(table) {
288         const builder = new Builder()
289             .Type().End()
290             .Import()
291                 .Table("imp", "table", {initial: 25, element: "anyfunc"})
292             .End()
293             .Function().End()
294             .Code()
295             .End();
296         const module = new WebAssembly.Module(builder.WebAssembly().get());
297         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}})')");
298     }
299     assertBadTable(25);
300     assertBadTable(new Object);
301     assertBadTable([]);
302     assertBadTable(new WebAssembly.Memory({initial:1}));
303 }
304
305 {
306     const builder = new Builder()
307         .Type().End()
308         .Import()
309             .Table("imp", "table", {initial: 25, element: "anyfunc"})
310         .End()
311         .Function().End()
312         .Export()
313             .Table("table", 0)
314             .Table("table2", 0)
315         .End()
316         .Code().End();
317
318     const module = new WebAssembly.Module(builder.WebAssembly().get());
319     const table = new WebAssembly.Table({element: "anyfunc", initial: 25});
320     const instance = new WebAssembly.Instance(module, {imp: {table}});
321     assert.truthy(table === instance.exports.table);
322     assert.truthy(table === instance.exports.table2);
323 }
324
325 {
326     const builder = new Builder()
327         .Type().End()
328         .Function().End()
329         .Table()
330             .Table({initial: 20, maximum: 30, element: "anyfunc"})
331         .End()
332         .Export()
333             .Table("table", 0)
334             .Table("table2", 0)
335         .End()
336         .Code().End();
337
338     const module = new WebAssembly.Module(builder.WebAssembly().get());
339     const instance = new WebAssembly.Instance(module);
340     assert.eq(instance.exports.table, instance.exports.table2);
341     assert.eq(instance.exports.table.length, 20);
342     assert.truthy(instance.exports.table instanceof WebAssembly.Table);
343 }
344
345 {
346     const builder = new Builder()
347         .Type().End()
348         .Function().End()
349         .Table()
350             .Table({initial: 0, maximum: 1, element: "anyfunc"})
351             .Table({initial: 20, maximum: 30, element: "anyfunc"})
352         .End()
353         .Export()
354             .Table("table0", 0)
355             .Table("table", 1)
356             .Table("table2", 1)
357         .End()
358         .Code().End();
359
360     const module = new WebAssembly.Module(builder.WebAssembly().get());
361     const instance = new WebAssembly.Instance(module);
362     assert.eq(instance.exports.table, instance.exports.table2);
363     assert.eq(instance.exports.table.length, 20);
364     assert.eq(instance.exports.table0.length, 0);
365     assert.truthy(instance.exports.table instanceof WebAssembly.Table);
366 }