b19b8b622bbbb7c5c6101c02e6e61e9647de3a3d
[WebKit-https.git] / JSTests / wasm / Builder_WebAssemblyBinary.js
1 /*
2  * Copyright (C) 2016 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 import * as assert from 'assert.js';
27 import LowLevelBinary from 'LowLevelBinary.js';
28 import * as WASM from 'WASM.js';
29
30 const put = (bin, type, value) => bin[type](value);
31
32 const emitters = {
33     Type: (section, bin) => {
34         put(bin, "varuint32", section.data.length);
35         for (const entry of section.data) {
36             put(bin, "varint7", WASM.typeValue["func"]);
37             put(bin, "varuint32", entry.params.length);
38             for (const param of entry.params)
39                 put(bin, "varint7", WASM.typeValue[param]);
40             if (entry.ret === "void")
41                 put(bin, "varuint1", 0);
42             else {
43                 put(bin, "varuint1", 1);
44                 put(bin, "varint7", WASM.typeValue[entry.ret]);
45             }
46         }
47     },
48     Import: (section, bin) => {
49         put(bin, "varuint32", section.data.length);
50         for (const entry of section.data) {
51             put(bin, "string", entry.module);
52             put(bin, "string", entry.field);
53             put(bin, "uint8", WASM.externalKindValue[entry.kind]);
54             switch (entry.kind) {
55             default: throw new Error(`Implementation problem: unexpected kind ${entry.kind}`);
56             case "Function": {
57                 put(bin, "varuint32", entry.type);
58                 break;
59             }
60             case "Table": throw new Error(`Not yet implemented`);
61             case "Memory": {
62                 let {initial, maximum} = entry.memoryDescription;
63                 assert.truthy(typeof initial === "number", "We expect 'initial' to be a number");
64                 initial |= 0;
65                 let hasMaximum = 0;
66                 if (typeof maximum === "number") {
67                     maximum |= 0;
68                     hasMaximum = 1;
69                 } else {
70                     assert.truthy(typeof maximum === "undefined", "We expect 'maximum' to be a number if it's defined");
71                 }
72
73                 put(bin, "varuint1", hasMaximum);
74                 put(bin, "varuint32", initial);
75                 if (hasMaximum)
76                     put(bin, "varuint32", maximum);
77                 break;
78             };
79             case "Global": throw new Error(`Not yet implemented`);
80             }
81         }
82     },
83
84     Function: (section, bin) => {
85         put(bin, "varuint32", section.data.length);
86         for (const signature of section.data)
87             put(bin, "varuint32", signature);
88     },
89
90     Table: (section, bin) => { throw new Error(`Not yet implemented`); },
91
92     Memory: (section, bin) => {
93         // Flags, currently can only be [0,1]
94         put(bin, "varuint1", section.data.length);
95         for (const memory of section.data) {
96             put(bin, "varuint32", memory.max ? 1 : 0);
97             put(bin, "varuint32", memory.initial);
98             if (memory.max)
99                 put(bin, "varuint32", memory.max);
100         }
101     },
102
103     Global: (section, bin) => { throw new Error(`Not yet implemented`); },
104     Export: (section, bin) => {
105         put(bin, "varuint32", section.data.length);
106         for (const entry of section.data) {
107             put(bin, "string", entry.field);
108             put(bin, "uint8", WASM.externalKindValue[entry.kind]);
109             switch (entry.kind) {
110             default: throw new Error(`Implementation problem: unexpected kind ${entry.kind}`);
111             case "Function": put(bin, "varuint32", entry.index); break;
112             case "Table": throw new Error(`Not yet implemented`);
113             case "Memory": throw new Error(`Not yet implemented`);
114             case "Global": throw new Error(`Not yet implemented`);
115             }
116         }
117     },
118     Start: (section, bin) => { throw new Error(`Not yet implemented`); },
119     Element: (section, bin) => { throw new Error(`Not yet implemented`); },
120
121     Code: (section, bin) => {
122         put(bin, "varuint32", section.data.length);
123         for (const func of section.data) {
124             let funcBin = bin.newPatchable("varuint32");
125             const localCount = func.locals.length - func.parameterCount;
126             put(funcBin, "varuint32", localCount);
127             for (let i = func.parameterCount; i < func.locals.length; ++i) {
128                 put(funcBin, "varuint32", 1);
129                 put(funcBin, "varint7", WASM.typeValue[func.locals[i]]);
130             }
131
132             for (const op of func.code) {
133                 put(funcBin, "uint8", op.value);
134                 if (op.arguments.length !== 0)
135                     throw new Error(`Unimplemented: arguments`); // FIXME https://bugs.webkit.org/show_bug.cgi?id=162706
136
137                 switch (op.name) {
138                 default:
139                     for (let i = 0; i < op.immediates.length; ++i) {
140                         const type = WASM.description.opcode[op.name].immediate[i].type
141                         if (!funcBin[type])
142                             throw new TypeError(`Unknown type: ${type} in op: ${op.name}`);
143                         put(funcBin, type, op.immediates[i]);
144                     }
145                     break;
146                 case "br_table":
147                     put(funcBin, "varuint32", op.immediates.length - 1);
148                     for (let imm of op.immediates)
149                         put(funcBin, "varuint32", imm);
150                     break;
151                 }
152             }
153             funcBin.apply();
154         }
155     },
156
157     Data: (section, bin) => { throw new Error(`Not yet implemented`); },
158 };
159
160 export const Binary = (preamble, sections) => {
161     let wasmBin = new LowLevelBinary();
162     for (const p of WASM.description.preamble)
163         put(wasmBin, p.type, preamble[p.name]);
164     for (const section of sections) {
165         put(wasmBin, WASM.sectionEncodingType, section.id);
166         let sectionBin = wasmBin.newPatchable("varuint32");
167         const emitter = emitters[section.name];
168         if (emitter)
169             emitter(section, sectionBin);
170         else {
171             // Unknown section.
172             put(sectionBin, "string", section.name);
173             for (const byte of section.data)
174                 put(sectionBin, "uint8", byte);
175         }
176         sectionBin.apply();
177     }
178     wasmBin.trim();
179     return wasmBin;
180 };