09342312b5b4b3ddd682901ace71e51b60247543
[WebKit-https.git] / JSTests / wasm / self-test / test_BuilderJSON.js
1 import * as assert from '../assert.js';
2 import Builder from '../Builder.js';
3
4 const assertOpThrows = (opFn, message) => {
5     let f = (new Builder()).Code().Function();
6     assert.throws(opFn, Error, message, f);
7 };
8
9 (function EmptyModule() {
10     const b = new Builder();
11     const j = JSON.parse(b.json());
12     assert.notUndef(j.preamble);
13     assert.notUndef(j.preamble["magic number"]);
14     assert.notUndef(j.preamble.version);
15     assert.notUndef(j.section);
16     assert.eq(j.section.length, 0);
17 })();
18
19 (function CustomMagicNumber() {
20     const b = (new Builder()).setPreamble({ "magic number": 1337 });
21     const j = JSON.parse(b.json());
22     assert.eq(j.preamble["magic number"], 1337);
23     assert.notUndef(j.preamble.version);
24 })();
25
26 (function CustomVersion() {
27     const b = (new Builder()).setPreamble({ "version": 1337 });
28     const j = JSON.parse(b.json());
29     assert.eq(j.preamble["version"], 1337);
30     assert.notUndef(j.preamble.version);
31 })();
32
33 (function CustomSection() {
34     const b = new Builder();
35     b.Unknown("custom section")
36         .Byte(0x00)
37         .Byte(0x42)
38         .Byte(0xFF);
39     const j = JSON.parse(b.json());
40     assert.eq(j.section.length, 1);
41     assert.eq(j.section[0].name, "custom section");
42     assert.eq(j.section[0].data.length, 3);
43     assert.eq(j.section[0].data[0], 0x00);
44     assert.eq(j.section[0].data[1], 0x42);
45     assert.eq(j.section[0].data[2], 0xFF);
46 })();
47
48 (function CustomSectionAllBytes() {
49     const b = new Builder();
50     let u = b.Unknown("custom section");
51     for (let i = 0; i !== 0xFF + 1; ++i)
52         u.Byte(i);
53     const j = JSON.parse(b.json());
54     assert.eq(j.section[0].data.length, 256);
55     for (let i = 0; i !== 0xFF + 1; ++i)
56         assert.eq(j.section[0].data[i], i);
57 })();
58
59 (function CustomSectionInvalidByte() {
60     const b = new Builder();
61     let u = b.Unknown("custom section");
62     try {
63         u.Byte(0xFF + 1);
64     } catch (e) {
65         if (e instanceof RangeError) { return; }
66         throw new Error(`Expected a RangeError, got ${e}`);
67     }
68     throw new Error(`Expected to throw a RangeError`);
69 })();
70
71 (function TwoCustomSections() {
72     const b = new Builder();
73     b.Unknown("custom section")
74         .Byte(0x00)
75         .Byte(0x42)
76         .Byte(0xFF)
77     .End()
78     .Unknown("☃")
79         .Byte(0x11);
80     const j = JSON.parse(b.json());
81     assert.eq(j.section.length, 2);
82     assert.eq(j.section[0].name, "custom section");
83     assert.eq(j.section[0].data.length, 3);
84     assert.eq(j.section[1].name, "☃");
85     assert.eq(j.section[1].data.length, 1);
86     assert.eq(j.section[1].data[0], 0x11);
87 })();
88
89 (function EmptyCodeSection() {
90     const b = new Builder();
91     b.Code();
92     const j = JSON.parse(b.json());
93     assert.eq(j.section.length, 1);
94     assert.eq(j.section[0].name, "Code");
95     assert.eq(j.section[0].data.length, 0);
96 })();
97
98 (function CodeSectionWithEmptyFunction() {
99     const b = new Builder();
100     b.Code()
101         .Function();
102     const j = JSON.parse(b.json());
103     assert.eq(j.section.length, 1);
104     assert.eq(j.section[0].name, "Code");
105     assert.eq(j.section[0].data.length, 1);
106     assert.eq(j.section[0].data[0].parameterCount, 0);
107     assert.eq(j.section[0].data[0].locals.length, 0);
108     assert.eq(j.section[0].data[0].code.length, 0);
109 })();
110
111 (function CodeSectionWithEmptyFunctionWithParameters() {
112     const b = new Builder();
113     b.Code()
114         .Function(["i32", "i64", "f32", "f64"]);
115     const j = JSON.parse(b.json());
116     assert.eq(j.section.length, 1);
117     assert.eq(j.section[0].name, "Code");
118     assert.eq(j.section[0].data.length, 1);
119     assert.eq(j.section[0].data[0].parameterCount, 4);
120     assert.eq(j.section[0].data[0].locals[0], "i32");
121     assert.eq(j.section[0].data[0].locals[1], "i64");
122     assert.eq(j.section[0].data[0].locals[2], "f32");
123     assert.eq(j.section[0].data[0].locals[3], "f64");
124     assert.eq(j.section[0].data[0].code.length, 0);
125 })();
126
127 (function InvalidFunctionParameters() {
128     for (let invalid in ["", "void", "bool", "any", "struct"]) {
129         const c = (new Builder()).Code();
130         try {
131             c.Function([invalid]);
132         } catch (e) {
133             if (e instanceof Error) { continue; }
134             throw new Error(`Expected an Error, got ${e}`);
135         }
136         throw new Error(`Expected to throw an Error for ${invalid}`);
137     }
138 })();
139
140 (function SimpleFunction() {
141     const b = new Builder();
142     b.Code()
143         .Function()
144             .Nop()
145             .Nop()
146         .End();
147     const j = JSON.parse(b.json());
148     assert.eq(j.section[0].data.length, 1);
149     assert.eq(j.section[0].data[0].locals.length, 0);
150     assert.eq(j.section[0].data[0].code.length, 3);
151     assert.eq(j.section[0].data[0].code[0].name, "nop");
152     assert.eq(j.section[0].data[0].code[1].name, "nop");
153     assert.eq(j.section[0].data[0].code[2].name, "end");
154 })();
155
156 (function TwoSimpleFunctions() {
157     const b = new Builder();
158     b.Code()
159         .Function()
160             .Nop()
161             .Nop()
162         .End()
163         .Function()
164             .Return()
165         .End();
166     const j = JSON.parse(b.json());
167     assert.eq(j.section[0].data.length, 2);
168     assert.eq(j.section[0].data[0].locals.length, 0);
169     assert.eq(j.section[0].data[0].code.length, 3);
170     assert.eq(j.section[0].data[0].code[0].name, "nop");
171     assert.eq(j.section[0].data[0].code[1].name, "nop");
172     assert.eq(j.section[0].data[0].code[2].name, "end");
173     assert.eq(j.section[0].data[1].locals.length, 0);
174     assert.eq(j.section[0].data[1].code.length, 2);
175     assert.eq(j.section[0].data[1].code[0].name, "return");
176     assert.eq(j.section[0].data[1].code[1].name, "end");
177 })();
178
179 (function TwoBuildersAtTheSameTime() {
180     const b = [new Builder(), new Builder()];
181     const f = b.map(builder => builder.Code().Function());
182     f[0].Nop();
183     f[1].Return().End().End();
184     f[0].Nop().End().End();
185     const j = b.map(builder => JSON.parse(builder.json()));
186     assert.eq(j[0].section[0].data[0].code.length, 3);
187     assert.eq(j[0].section[0].data[0].code[0].name, "nop");
188     assert.eq(j[0].section[0].data[0].code[1].name, "nop");
189     assert.eq(j[0].section[0].data[0].code[2].name, "end");
190     assert.eq(j[1].section[0].data[0].code.length, 2);
191     assert.eq(j[1].section[0].data[0].code[0].name, "return");
192     assert.eq(j[1].section[0].data[0].code[1].name, "end");
193 })();
194
195 (function CheckedOpcodeArgumentsTooMany() {
196     assertOpThrows(f => f.Nop("uh-oh!"), `"nop" expects 0 immediates, got 1`);
197 })();
198
199 (function UncheckedOpcodeArgumentsTooMany() {
200     (new Builder()).setChecked(false).Code().Function().Nop("This is fine.", "I'm OK with the events that are unfolding currently.");
201 })();
202
203 (function CheckedOpcodeArgumentsNotEnough() {
204     assertOpThrows(f => f.I32Const(), `"i32.const" expects 1 immediates, got 0`);
205 })();
206
207 (function UncheckedOpcodeArgumentsNotEnough() {
208     (new Builder()).setChecked(false).Code().Function().I32Const();
209 })();
210
211 (function CallNoArguments() {
212     const b = (new Builder()).Code().Function().Call(0).End().End();
213     const j = JSON.parse(b.json());
214     assert.eq(j.section[0].data[0].code.length, 2);
215     assert.eq(j.section[0].data[0].code[0].name, "call");
216     assert.eq(j.section[0].data[0].code[0].arguments.length, 0);
217     assert.eq(j.section[0].data[0].code[0].immediates.length, 1);
218     assert.eq(j.section[0].data[0].code[0].immediates[0], 0);
219     assert.eq(j.section[0].data[0].code[1].name, "end");
220 })();
221
222 (function CallInvalid() {
223     for (let c of [-1, 0x100000000, "0", {}, Infinity, -Infinity, NaN, -NaN, null])
224         assertOpThrows(f => f.Call(c), `Invalid value on call: got "${c}", expected i32`);
225 })();
226
227 (function I32ConstValid() {
228     for (let c of [0, 1, 2, 42, 1337, 0xFF, 0xFFFF, 0x7FFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF]) {
229         const b = (new Builder()).Code().Function().I32Const(c).Return().End().End();
230         const j = JSON.parse(b.json());
231         assert.eq(j.section[0].data[0].code[0].name, "i32.const");
232         assert.eq(j.section[0].data[0].code[0].arguments.length, 0);
233         assert.eq(j.section[0].data[0].code[0].immediates.length, 1);
234         assert.eq(j.section[0].data[0].code[0].immediates[0], c);
235     }
236 })();
237
238 (function I32ConstInvalid() {
239     for (let c of [-1, 0x100000000, 0.1, -0.1, "0", {}, Infinity, null])
240         assertOpThrows(f => f.I32Const(c), `Invalid value on i32.const: got "${c}", expected i32`);
241 })();
242
243 // FIXME: test i64. https://bugs.webkit.org/show_bug.cgi?id=163420
244
245 (function F32ConstValid() {
246     for (let c of [0, -0., 0.2, Math.PI, 0x100000000]) {
247         const b = (new Builder()).Code().Function().F32Const(c).Return().End().End();
248         const j = JSON.parse(b.json());
249         assert.eq(j.section[0].data[0].code[0].name, "f32.const");
250         assert.eq(j.section[0].data[0].code[0].arguments.length, 0);
251         assert.eq(j.section[0].data[0].code[0].immediates.length, 1);
252         assert.eq(j.section[0].data[0].code[0].immediates[0], c);
253     }
254 })();
255
256 (function F32ConstInvalid() {
257     for (let c of ["0", {}, Infinity, -Infinity, NaN, -NaN, null])
258         assertOpThrows(f => f.F32Const(c), `Invalid value on f32.const: got "${c}", expected f32`);
259 })();
260
261 (function F64ConstValid() {
262     for (let c of [0, -0., 0.2, Math.PI, 0x100000000]) {
263         const b = (new Builder()).Code().Function().F64Const(c).Return().End().End();
264         const j = JSON.parse(b.json());
265         assert.eq(j.section[0].data[0].code[0].name, "f64.const");
266         assert.eq(j.section[0].data[0].code[0].arguments.length, 0);
267         assert.eq(j.section[0].data[0].code[0].immediates.length, 1);
268         assert.eq(j.section[0].data[0].code[0].immediates[0], c);
269     }
270 })();
271
272 (function F64ConstInvalid() {
273     for (let c of ["0", {}, Infinity, -Infinity, NaN, -NaN, null])
274         assertOpThrows(f => f.F64Const(c), `Invalid value on f64.const: got "${c}", expected f64`);
275 })();
276
277 (function CallOneFromStack() {
278     const b = (new Builder()).Code()
279         .Function(["i32"])
280             .I32Const(42)
281             .Call(0)
282         .End()
283     .End();
284     const j = JSON.parse(b.json());
285     assert.eq(j.section[0].data[0].code.length, 3);
286     assert.eq(j.section[0].data[0].code[0].name, "i32.const");
287     assert.eq(j.section[0].data[0].code[0].immediates[0], 42);
288     assert.eq(j.section[0].data[0].code[1].name, "call");
289     // FIXME: assert.eq(j.section[0].data[0].code[1].arguments.length, 1); https://bugs.webkit.org/show_bug.cgi?id=163267
290     assert.eq(j.section[0].data[0].code[1].immediates.length, 1);
291     assert.eq(j.section[0].data[0].code[1].immediates[0], 0);
292     assert.eq(j.section[0].data[0].code[2].name, "end");
293 })();
294
295 // FIXME https://bugs.webkit.org/show_bug.cgi?id=163267 all of these:
296 //  test too many pops.
297 //  test not enough pops (function has non-empty stack at the end).
298 //  test mismatched pop types.
299 //  test mismatched function signature (calling with wrong arg types).
300 //  test invalid function index.
301 //  test function names (both setting and calling them).
302
303 (function CallManyFromStack() {
304     const b = (new Builder()).Code()
305           .Function(["i32", "i32", "i32", "i32"])
306               .I32Const(42).I32Const(1337).I32Const(0xBEEF).I32Const(0xFFFF)
307               .Call(0)
308         .End()
309     .End();
310     const j = JSON.parse(b.json());
311     assert.eq(j.section[0].data[0].code.length, 6);
312     assert.eq(j.section[0].data[0].code[4].name, "call");
313     // FIXME: assert.eq(j.section[0].data[0].code[4].arguments.length, 4); https://bugs.webkit.org/show_bug.cgi?id=163267
314     assert.eq(j.section[0].data[0].code[4].immediates.length, 1);
315     assert.eq(j.section[0].data[0].code[4].immediates[0], 0);
316 })();
317
318 (function OpcodeAdd() {
319     const b = (new Builder()).Code()
320           .Function()
321               .I32Const(42).I32Const(1337)
322               .I32Add()
323               .Return()
324         .End()
325     .End();
326     const j = JSON.parse(b.json());
327     assert.eq(j.section[0].data[0].code.length, 5);
328     assert.eq(j.section[0].data[0].code[2].name, "i32.add");
329     // FIXME: assert.eq(j.section[0].data[0].code[2].arguments.length, 2); https://bugs.webkit.org/show_bug.cgi?id=163267
330     assert.eq(j.section[0].data[0].code[3].name, "return");
331     // FIXME check return. https://bugs.webkit.org/show_bug.cgi?id=163267
332 })();
333
334 (function OpcodeUnreachable() {
335     const b = (new Builder()).Code().Function().Unreachable().End().End();
336     const j = JSON.parse(b.json());
337     assert.eq(j.section[0].data[0].code.length, 2);
338     assert.eq(j.section[0].data[0].code[0].name, "unreachable");
339 })();
340
341 (function OpcodeUnreachableCombinations() {
342     (new Builder()).Code().Function().Nop().Unreachable().End().End();
343     (new Builder()).Code().Function().Unreachable().Nop().End().End();
344     (new Builder()).Code().Function().Return().Unreachable().End().End();
345     (new Builder()).Code().Function().Unreachable().Return().End().End();
346     (new Builder()).Code().Function().Call(0).Unreachable().End().End();
347     (new Builder()).Code().Function().Unreachable().Call(0).End().End();
348 })();
349
350 (function OpcodeSelect() {
351     const b = (new Builder()).Code().Function()
352         .I32Const(1).I32Const(2).I32Const(0)
353         .Select()
354         .Return()
355       .End()
356     .End();
357     const j = JSON.parse(b.json());
358     assert.eq(j.section[0].data[0].code.length, 6);
359     assert.eq(j.section[0].data[0].code[3].name, "select");
360 })();
361
362 // FIXME test type mismatch with select. https://bugs.webkit.org/show_bug.cgi?id=163267