2 * Copyright (C) 2016 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
26 import * as assert from 'assert.js';
27 import LowLevelBinary from 'LowLevelBinary.js';
28 import * as WASM from 'WASM.js';
30 const put = (bin, type, value) => bin[type](value);
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);
43 put(bin, "varuint1", 1);
44 put(bin, "varint7", WASM.typeValue[entry.ret]);
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]);
55 default: throw new Error(`Implementation problem: unexpected kind ${entry.kind}`);
57 put(bin, "varuint32", entry.type);
60 case "Table": throw new Error(`Not yet implemented`);
62 let {initial, maximum} = entry.memoryDescription;
63 assert.truthy(typeof initial === "number", "We expect 'initial' to be a number");
66 if (typeof maximum === "number") {
70 assert.truthy(typeof maximum === "undefined", "We expect 'maximum' to be a number if it's defined");
73 put(bin, "varuint1", hasMaximum);
74 put(bin, "varuint32", initial);
76 put(bin, "varuint32", maximum);
79 case "Global": throw new Error(`Not yet implemented`);
84 Function: (section, bin) => {
85 put(bin, "varuint32", section.data.length);
86 for (const signature of section.data)
87 put(bin, "varuint32", signature);
90 Table: (section, bin) => { throw new Error(`Not yet implemented`); },
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);
99 put(bin, "varuint32", memory.max);
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`);
118 Start: (section, bin) => {
119 put(bin, "varuint32", section.data[0]);
121 Element: (section, bin) => { throw new Error(`Not yet implemented`); },
123 Code: (section, bin) => {
124 put(bin, "varuint32", section.data.length);
125 for (const func of section.data) {
126 let funcBin = bin.newPatchable("varuint32");
127 const localCount = func.locals.length - func.parameterCount;
128 put(funcBin, "varuint32", localCount);
129 for (let i = func.parameterCount; i < func.locals.length; ++i) {
130 put(funcBin, "varuint32", 1);
131 put(funcBin, "varint7", WASM.typeValue[func.locals[i]]);
134 for (const op of func.code) {
135 put(funcBin, "uint8", op.value);
136 if (op.arguments.length !== 0)
137 throw new Error(`Unimplemented: arguments`); // FIXME https://bugs.webkit.org/show_bug.cgi?id=162706
141 for (let i = 0; i < op.immediates.length; ++i) {
142 const type = WASM.description.opcode[op.name].immediate[i].type
144 throw new TypeError(`Unknown type: ${type} in op: ${op.name}`);
145 put(funcBin, type, op.immediates[i]);
149 put(funcBin, "varuint32", op.immediates.length - 1);
150 for (let imm of op.immediates)
151 put(funcBin, "varuint32", imm);
159 Data: (section, bin) => { throw new Error(`Not yet implemented`); },
162 export const Binary = (preamble, sections) => {
163 let wasmBin = new LowLevelBinary();
164 for (const p of WASM.description.preamble)
165 put(wasmBin, p.type, preamble[p.name]);
166 for (const section of sections) {
167 put(wasmBin, WASM.sectionEncodingType, section.id);
168 let sectionBin = wasmBin.newPatchable("varuint32");
169 const emitter = emitters[section.name];
171 emitter(section, sectionBin);
174 put(sectionBin, "string", section.name);
175 for (const byte of section.data)
176 put(sectionBin, "uint8", byte);