OLD | NEW |
1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // Used for encoding f32 and double constants to bits. | |
6 let __buffer = new ArrayBuffer(8); | |
7 let byte_view = new Int8Array(__buffer); | |
8 let f32_view = new Float32Array(__buffer); | |
9 let f64_view = new Float64Array(__buffer); | |
10 | |
11 class Binary extends Array { | 5 class Binary extends Array { |
12 emit_u8(val) { | 6 emit_u8(val) { |
13 this.push(val); | 7 this.push(val); |
14 } | 8 } |
15 | 9 |
16 emit_u16(val) { | 10 emit_u16(val) { |
17 this.push(val & 0xff); | 11 this.push(val & 0xff); |
18 this.push((val >> 8) & 0xff); | 12 this.push((val >> 8) & 0xff); |
19 } | 13 } |
20 | 14 |
21 emit_u32(val) { | 15 emit_u32(val) { |
22 this.push(val & 0xff); | 16 this.push(val & 0xff); |
23 this.push((val >> 8) & 0xff); | 17 this.push((val >> 8) & 0xff); |
24 this.push((val >> 16) & 0xff); | 18 this.push((val >> 16) & 0xff); |
25 this.push((val >> 24) & 0xff); | 19 this.push((val >> 24) & 0xff); |
26 } | 20 } |
27 | 21 |
28 emit_u32v(val) { | 22 emit_varint(val) { |
29 while (true) { | 23 while (true) { |
30 let v = val & 0xff; | 24 let v = val & 0xff; |
31 val = val >>> 7; | 25 val = val >>> 7; |
32 if (val == 0) { | 26 if (val == 0) { |
33 this.push(v); | 27 this.push(v); |
34 break; | 28 break; |
35 } | 29 } |
36 this.push(v | 0x80); | 30 this.push(v | 0x80); |
37 } | 31 } |
38 } | 32 } |
39 | 33 |
40 emit_bytes(data) { | 34 emit_bytes(data) { |
41 for (let i = 0; i < data.length; i++) { | 35 for (let i = 0; i < data.length; i++) { |
42 this.push(data[i] & 0xff); | 36 this.push(data[i] & 0xff); |
43 } | 37 } |
44 } | 38 } |
45 | 39 |
46 emit_string(string) { | 40 emit_string(string) { |
47 // When testing illegal names, we pass a byte array directly. | 41 // When testing illegal names, we pass a byte array directly. |
48 if (string instanceof Array) { | 42 if (string instanceof Array) { |
49 this.emit_u32v(string.length); | 43 this.emit_varint(string.length); |
50 this.emit_bytes(string); | 44 this.emit_bytes(string); |
51 return; | 45 return; |
52 } | 46 } |
53 | 47 |
54 // This is the hacky way to convert a JavaScript string to a UTF8 encoded | 48 // This is the hacky way to convert a JavaScript string to a UTF8 encoded |
55 // string only containing single-byte characters. | 49 // string only containing single-byte characters. |
56 let string_utf8 = unescape(encodeURIComponent(string)); | 50 let string_utf8 = unescape(encodeURIComponent(string)); |
57 this.emit_u32v(string_utf8.length); | 51 this.emit_varint(string_utf8.length); |
58 for (let i = 0; i < string_utf8.length; i++) { | 52 for (let i = 0; i < string_utf8.length; i++) { |
59 this.emit_u8(string_utf8.charCodeAt(i)); | 53 this.emit_u8(string_utf8.charCodeAt(i)); |
60 } | 54 } |
61 } | 55 } |
62 | 56 |
63 emit_header() { | 57 emit_header() { |
64 this.push(kWasmH0, kWasmH1, kWasmH2, kWasmH3, | 58 this.push(kWasmH0, kWasmH1, kWasmH2, kWasmH3, |
65 kWasmV0, kWasmV1, kWasmV2, kWasmV3); | 59 kWasmV0, kWasmV1, kWasmV2, kWasmV3); |
66 } | 60 } |
67 | 61 |
68 emit_section(section_code, content_generator) { | 62 emit_section(section_code, content_generator) { |
69 // Emit section name. | 63 // Emit section name. |
70 this.emit_u8(section_code); | 64 this.emit_u8(section_code); |
71 // Emit the section to a temporary buffer: its full length isn't know yet. | 65 // Emit the section to a temporary buffer: its full length isn't know yet. |
72 let section = new Binary; | 66 let section = new Binary; |
73 content_generator(section); | 67 content_generator(section); |
74 // Emit section length. | 68 // Emit section length. |
75 this.emit_u32v(section.length); | 69 this.emit_varint(section.length); |
76 // Copy the temporary buffer. | 70 // Copy the temporary buffer. |
77 this.push(...section); | 71 this.push(...section); |
78 } | 72 } |
79 } | 73 } |
80 | 74 |
81 class WasmFunctionBuilder { | 75 class WasmFunctionBuilder { |
82 constructor(module, name, type_index) { | 76 constructor(name, type_index) { |
83 this.module = module; | |
84 this.name = name; | 77 this.name = name; |
85 this.type_index = type_index; | 78 this.type_index = type_index; |
| 79 this.exports = []; |
86 } | 80 } |
87 | 81 |
88 exportAs(name) { | 82 exportAs(name) { |
89 this.module.exports.push({name: name, kind: kExternalFunction, index: this.i
ndex}); | 83 this.exports.push(name); |
90 return this; | 84 return this; |
91 } | 85 } |
92 | 86 |
93 exportFunc() { | 87 exportFunc() { |
94 this.exportAs(this.name); | 88 this.exports.push(this.name); |
95 return this; | 89 return this; |
96 } | 90 } |
97 | 91 |
98 addBody(body) { | 92 addBody(body) { |
99 this.body = body; | 93 this.body = body; |
100 return this; | 94 return this; |
101 } | 95 } |
102 | 96 |
103 addLocals(locals) { | 97 addLocals(locals) { |
104 this.locals = locals; | 98 this.locals = locals; |
105 return this; | 99 return this; |
106 } | 100 } |
107 } | 101 } |
108 | |
109 class WasmGlobalBuilder { | |
110 constructor(module, type, mutable) { | |
111 this.module = module; | |
112 this.type = type; | |
113 this.mutable = mutable; | |
114 this.init = 0; | |
115 } | |
116 | |
117 exportAs(name) { | |
118 this.module.exports.push({name: name, kind: kExternalGlobal, index: this.ind
ex}); | |
119 return this; | |
120 } | |
121 } | |
122 | 102 |
123 class WasmModuleBuilder { | 103 class WasmModuleBuilder { |
124 constructor() { | 104 constructor() { |
125 this.types = []; | 105 this.types = []; |
126 this.imports = []; | 106 this.imports = []; |
127 this.exports = []; | |
128 this.globals = []; | 107 this.globals = []; |
129 this.functions = []; | 108 this.functions = []; |
| 109 this.exports = []; |
130 this.table = []; | 110 this.table = []; |
131 this.segments = []; | 111 this.segments = []; |
132 this.explicit = []; | 112 this.explicit = []; |
133 this.pad = null; | 113 this.pad = null; |
134 this.num_imported_funcs = 0; | |
135 this.num_imported_globals = 0; | |
136 return this; | 114 return this; |
137 } | 115 } |
138 | 116 |
139 addStart(start_index) { | 117 addStart(start_index) { |
140 this.start_index = start_index; | 118 this.start_index = start_index; |
141 } | 119 } |
142 | 120 |
143 addMemory(min, max, exp) { | 121 addMemory(min, max, exp) { |
144 this.memory = {min: min, max: max, exp: exp}; | 122 this.memory = {min: min, max: max, exp: exp}; |
145 return this; | 123 return this; |
146 } | 124 } |
147 | 125 |
148 addPadFunctionTable(size) { | 126 addPadFunctionTable(size) { |
149 this.pad = size; | 127 this.pad = size; |
150 return this; | 128 return this; |
151 } | 129 } |
152 | 130 |
153 addExplicitSection(bytes) { | 131 addExplicitSection(bytes) { |
154 this.explicit.push(bytes); | 132 this.explicit.push(bytes); |
155 return this; | 133 return this; |
156 } | 134 } |
157 | 135 |
158 addType(type) { | 136 addType(type) { |
159 // TODO: canonicalize types? | 137 // TODO: canonicalize types? |
160 this.types.push(type); | 138 this.types.push(type); |
161 return this.types.length - 1; | 139 return this.types.length - 1; |
162 } | 140 } |
163 | 141 |
164 addGlobal(local_type, mutable) { | 142 addGlobal(local_type) { |
165 let glob = new WasmGlobalBuilder(this, local_type, mutable); | 143 this.globals.push(local_type); |
166 glob.index = this.globals.length + this.num_imported_globals; | 144 return this.globals.length - 1; |
167 this.globals.push(glob); | |
168 return glob; | |
169 } | 145 } |
170 | 146 |
171 addFunction(name, type) { | 147 addFunction(name, type) { |
172 let type_index = (typeof type) == "number" ? type : this.addType(type); | 148 let type_index = (typeof type) == "number" ? type : this.addType(type); |
173 let func = new WasmFunctionBuilder(this, name, type_index); | 149 let func = new WasmFunctionBuilder(name, type_index); |
174 func.index = this.functions.length + this.num_imported_funcs; | 150 func.index = this.functions.length + this.imports.length; |
175 this.functions.push(func); | 151 this.functions.push(func); |
176 return func; | 152 return func; |
177 } | 153 } |
178 | 154 |
179 addImportWithModule(module, name, type) { | 155 addImportWithModule(module, name, type) { |
180 let type_index = (typeof type) == "number" ? type : this.addType(type); | 156 let type_index = (typeof type) == "number" ? type : this.addType(type); |
181 this.imports.push({module: module, name: name, kind: kExternalFunction, | 157 this.imports.push({module: module, name: name, type: type_index}); |
182 type: type_index}); | 158 return this.imports.length - 1; |
183 return this.num_imported_funcs++; | |
184 } | 159 } |
185 | 160 |
186 addImport(name, type) { | 161 addImport(name, type) { |
187 return this.addImportWithModule(name, undefined, type); | 162 return this.addImportWithModule(name, undefined, type); |
188 } | 163 } |
189 | 164 |
190 addImportedGlobal(module, name, type) { | |
191 let o = {module: module, name: name, kind: kExternalGlobal, type: type, | |
192 mutable: false} | |
193 this.imports.push(o); | |
194 return this.num_imported_globals++; | |
195 } | |
196 | |
197 addDataSegment(addr, data, init) { | 165 addDataSegment(addr, data, init) { |
198 this.segments.push({addr: addr, data: data, init: init}); | 166 this.segments.push({addr: addr, data: data, init: init}); |
199 return this.segments.length - 1; | 167 return this.segments.length - 1; |
200 } | 168 } |
201 | 169 |
202 appendToTable(array) { | 170 appendToTable(array) { |
203 this.table.push(...array); | 171 this.table.push(...array); |
204 return this; | 172 return this; |
205 } | 173 } |
206 | 174 |
207 toArray(debug) { | 175 toArray(debug) { |
208 let binary = new Binary; | 176 let binary = new Binary; |
209 let wasm = this; | 177 let wasm = this; |
210 | 178 |
211 // Add header | 179 // Add header |
212 binary.emit_header(); | 180 binary.emit_header(); |
213 | 181 |
214 // Add type section | 182 // Add type section |
215 if (wasm.types.length > 0) { | 183 if (wasm.types.length > 0) { |
216 if (debug) print("emitting types @ " + binary.length); | 184 if (debug) print("emitting types @ " + binary.length); |
217 binary.emit_section(kTypeSectionCode, section => { | 185 binary.emit_section(kTypeSectionCode, section => { |
218 section.emit_u32v(wasm.types.length); | 186 section.emit_varint(wasm.types.length); |
219 for (let type of wasm.types) { | 187 for (let type of wasm.types) { |
220 section.emit_u8(kWasmFunctionTypeForm); | 188 section.emit_u8(kWasmFunctionTypeForm); |
221 section.emit_u32v(type.params.length); | 189 section.emit_varint(type.params.length); |
222 for (let param of type.params) { | 190 for (let param of type.params) { |
223 section.emit_u8(param); | 191 section.emit_u8(param); |
224 } | 192 } |
225 section.emit_u32v(type.results.length); | 193 section.emit_varint(type.results.length); |
226 for (let result of type.results) { | 194 for (let result of type.results) { |
227 section.emit_u8(result); | 195 section.emit_u8(result); |
228 } | 196 } |
229 } | 197 } |
230 }); | 198 }); |
231 } | 199 } |
232 | 200 |
233 // Add imports section | 201 // Add imports section |
234 if (wasm.imports.length > 0) { | 202 if (wasm.imports.length > 0) { |
235 if (debug) print("emitting imports @ " + binary.length); | 203 if (debug) print("emitting imports @ " + binary.length); |
236 binary.emit_section(kImportSectionCode, section => { | 204 binary.emit_section(kImportSectionCode, section => { |
237 section.emit_u32v(wasm.imports.length); | 205 section.emit_varint(wasm.imports.length); |
238 for (let imp of wasm.imports) { | 206 for (let imp of wasm.imports) { |
239 section.emit_string(imp.module); | 207 section.emit_string(imp.module); |
240 section.emit_string(imp.name || ''); | 208 section.emit_string(imp.name || ''); |
241 section.emit_u8(imp.kind); | 209 section.emit_u8(kExternalFunction); |
242 if (imp.kind == kExternalFunction) { | 210 section.emit_varint(imp.type); |
243 section.emit_u32v(imp.type); | |
244 } else if (imp.kind == kExternalGlobal) { | |
245 section.emit_u32v(imp.type); | |
246 section.emit_u8(imp.mutable); | |
247 } else { | |
248 throw new Error("unknown/unsupported import kind " + imp.kind); | |
249 } | |
250 } | 211 } |
251 }); | 212 }); |
252 } | 213 } |
253 | 214 |
254 // Add functions declarations | 215 // Add functions declarations |
255 let has_names = false; | 216 let has_names = false; |
256 let names = false; | 217 let names = false; |
| 218 let exports = 0; |
257 if (wasm.functions.length > 0) { | 219 if (wasm.functions.length > 0) { |
258 if (debug) print("emitting function decls @ " + binary.length); | 220 if (debug) print("emitting function decls @ " + binary.length); |
259 binary.emit_section(kFunctionSectionCode, section => { | 221 binary.emit_section(kFunctionSectionCode, section => { |
260 section.emit_u32v(wasm.functions.length); | 222 section.emit_varint(wasm.functions.length); |
261 for (let func of wasm.functions) { | 223 for (let func of wasm.functions) { |
262 has_names = has_names || (func.name != undefined && | 224 has_names = has_names || (func.name != undefined && |
263 func.name.length > 0); | 225 func.name.length > 0); |
264 section.emit_u32v(func.type_index); | 226 exports += func.exports.length; |
| 227 section.emit_varint(func.type_index); |
265 } | 228 } |
266 }); | 229 }); |
267 } | 230 } |
268 | 231 |
269 // Add table. | 232 // Add table. |
270 if (wasm.table.length > 0) { | 233 if (wasm.table.length > 0) { |
271 if (debug) print("emitting table @ " + binary.length); | 234 if (debug) print("emitting table @ " + binary.length); |
272 binary.emit_section(kTableSectionCode, section => { | 235 binary.emit_section(kTableSectionCode, section => { |
273 section.emit_u8(1); // one table entry | 236 section.emit_u8(1); // one table entry |
274 section.emit_u8(kWasmAnyFunctionTypeForm); | 237 section.emit_u8(kWasmAnyFunctionTypeForm); |
275 section.emit_u8(1); | 238 section.emit_u8(1); |
276 section.emit_u32v(wasm.table.length); | 239 section.emit_varint(wasm.table.length); |
277 section.emit_u32v(wasm.table.length); | 240 section.emit_varint(wasm.table.length); |
278 }); | 241 }); |
279 } | 242 } |
280 | 243 |
281 // Add memory section | 244 // Add memory section |
282 if (wasm.memory != undefined) { | 245 if (wasm.memory != undefined) { |
283 if (debug) print("emitting memory @ " + binary.length); | 246 if (debug) print("emitting memory @ " + binary.length); |
284 binary.emit_section(kMemorySectionCode, section => { | 247 binary.emit_section(kMemorySectionCode, section => { |
285 section.emit_u8(1); // one memory entry | 248 section.emit_u8(1); // one memory entry |
286 section.emit_u32v(kResizableMaximumFlag); | 249 section.emit_varint(kResizableMaximumFlag); |
287 section.emit_u32v(wasm.memory.min); | 250 section.emit_varint(wasm.memory.min); |
288 section.emit_u32v(wasm.memory.max); | 251 section.emit_varint(wasm.memory.max); |
289 }); | 252 }); |
290 } | 253 } |
291 | 254 |
292 // Add global section. | 255 // Add global section. |
293 if (wasm.globals.length > 0) { | 256 if (wasm.globals.length > 0) { |
294 if (debug) print ("emitting globals @ " + binary.length); | 257 if (debug) print ("emitting globals @ " + binary.length); |
295 binary.emit_section(kGlobalSectionCode, section => { | 258 binary.emit_section(kGlobalSectionCode, section => { |
296 section.emit_u32v(wasm.globals.length); | 259 section.emit_varint(wasm.globals.length); |
297 for (let global of wasm.globals) { | 260 for (let global_type of wasm.globals) { |
298 section.emit_u8(global.type); | 261 section.emit_u8(global_type); |
299 section.emit_u8(global.mutable); | 262 section.emit_u8(true); // mutable |
300 if ((typeof global.init_index) == "undefined") { | 263 switch (global_type) { |
301 // Emit a constant initializer. | |
302 switch (global.type) { | |
303 case kAstI32: | 264 case kAstI32: |
304 section.emit_u8(kExprI32Const); | 265 section.emit_u8(kExprI32Const); |
305 section.emit_u32v(global.init); | 266 section.emit_u8(0); |
306 break; | 267 break; |
307 case kAstI64: | 268 case kAstI64: |
308 section.emit_u8(kExprI64Const); | 269 section.emit_u8(kExprI64Const); |
309 section.emit_u8(global.init); | 270 section.emit_u8(0); |
310 break; | 271 break; |
311 case kAstF32: | 272 case kAstF32: |
312 section.emit_u8(kExprF32Const); | 273 section.emit_u8(kExprF32Const); |
313 f32_view[0] = global.init; | 274 section.emit_u32(0); |
314 section.emit_u8(byte_view[0]); | |
315 section.emit_u8(byte_view[1]); | |
316 section.emit_u8(byte_view[2]); | |
317 section.emit_u8(byte_view[3]); | |
318 break; | 275 break; |
319 case kAstF64: | 276 case kAstF64: |
320 section.emit_u8(kExprF64Const); | 277 section.emit_u8(kExprI32Const); |
321 f64_view[0] = global.init; | 278 section.emit_u32(0); |
322 section.emit_u8(byte_view[0]); | 279 section.emit_u32(0); |
323 section.emit_u8(byte_view[1]); | |
324 section.emit_u8(byte_view[2]); | |
325 section.emit_u8(byte_view[3]); | |
326 section.emit_u8(byte_view[4]); | |
327 section.emit_u8(byte_view[5]); | |
328 section.emit_u8(byte_view[6]); | |
329 section.emit_u8(byte_view[7]); | |
330 break; | 280 break; |
331 } | |
332 } else { | |
333 // Emit a global-index initializer. | |
334 section.emit_u8(kExprGetGlobal); | |
335 section.emit_u32v(global.init_index); | |
336 } | 281 } |
337 section.emit_u8(kExprEnd); // end of init expression | 282 section.emit_u8(kExprEnd); // end of init expression |
338 } | 283 } |
339 }); | 284 }); |
340 } | 285 } |
341 | 286 |
342 // Add export table. | 287 // Add export table. |
343 var mem_export = (wasm.memory != undefined && wasm.memory.exp); | 288 var mem_export = (wasm.memory != undefined && wasm.memory.exp); |
344 var exports_count = wasm.exports.length + (mem_export ? 1 : 0); | 289 if (exports > 0 || mem_export) { |
345 if (exports_count > 0) { | |
346 if (debug) print("emitting exports @ " + binary.length); | 290 if (debug) print("emitting exports @ " + binary.length); |
347 binary.emit_section(kExportSectionCode, section => { | 291 binary.emit_section(kExportSectionCode, section => { |
348 section.emit_u32v(exports_count); | 292 section.emit_varint(exports + (mem_export ? 1 : 0)); |
349 for (let exp of wasm.exports) { | 293 for (let func of wasm.functions) { |
350 section.emit_string(exp.name); | 294 for (let exp of func.exports) { |
351 section.emit_u8(exp.kind); | 295 section.emit_string(exp); |
352 section.emit_u32v(exp.index); | 296 section.emit_u8(kExternalFunction); |
| 297 section.emit_varint(func.index); |
| 298 } |
353 } | 299 } |
354 if (mem_export) { | 300 if (mem_export) { |
355 section.emit_string("memory"); | 301 section.emit_string("memory"); |
356 section.emit_u8(kExternalMemory); | 302 section.emit_u8(kExternalMemory); |
357 section.emit_u8(0); | 303 section.emit_u8(0); |
358 } | 304 } |
359 }); | 305 }); |
360 } | 306 } |
361 | 307 |
362 // Add start function section. | 308 // Add start function section. |
363 if (wasm.start_index != undefined) { | 309 if (wasm.start_index != undefined) { |
364 if (debug) print("emitting start function @ " + binary.length); | 310 if (debug) print("emitting start function @ " + binary.length); |
365 binary.emit_section(kStartSectionCode, section => { | 311 binary.emit_section(kStartSectionCode, section => { |
366 section.emit_u32v(wasm.start_index); | 312 section.emit_varint(wasm.start_index); |
367 }); | 313 }); |
368 } | 314 } |
369 | 315 |
370 // Add table elements. | 316 // Add table elements. |
371 if (wasm.table.length > 0) { | 317 if (wasm.table.length > 0) { |
372 if (debug) print("emitting table @ " + binary.length); | 318 if (debug) print("emitting table @ " + binary.length); |
373 binary.emit_section(kElementSectionCode, section => { | 319 binary.emit_section(kElementSectionCode, section => { |
374 section.emit_u8(1); | 320 section.emit_u8(1); |
375 section.emit_u8(0); // table index | 321 section.emit_u8(0); // table index |
376 section.emit_u8(kExprI32Const); | 322 section.emit_u8(kExprI32Const); |
377 section.emit_u8(0); | 323 section.emit_u8(0); |
378 section.emit_u8(kExprEnd); | 324 section.emit_u8(kExprEnd); |
379 section.emit_u32v(wasm.table.length); | 325 section.emit_varint(wasm.table.length); |
380 for (let index of wasm.table) { | 326 for (let index of wasm.table) { |
381 section.emit_u32v(index); | 327 section.emit_varint(index); |
382 } | 328 } |
383 }); | 329 }); |
384 } | 330 } |
385 | 331 |
386 // Add function bodies. | 332 // Add function bodies. |
387 if (wasm.functions.length > 0) { | 333 if (wasm.functions.length > 0) { |
388 // emit function bodies | 334 // emit function bodies |
389 if (debug) print("emitting code @ " + binary.length); | 335 if (debug) print("emitting code @ " + binary.length); |
390 binary.emit_section(kCodeSectionCode, section => { | 336 binary.emit_section(kCodeSectionCode, section => { |
391 section.emit_u32v(wasm.functions.length); | 337 section.emit_varint(wasm.functions.length); |
392 for (let func of wasm.functions) { | 338 for (let func of wasm.functions) { |
393 // Function body length will be patched later. | 339 // Function body length will be patched later. |
394 let local_decls = []; | 340 let local_decls = []; |
395 let l = func.locals; | 341 let l = func.locals; |
396 if (l != undefined) { | 342 if (l != undefined) { |
397 let local_decls_count = 0; | 343 let local_decls_count = 0; |
398 if (l.i32_count > 0) { | 344 if (l.i32_count > 0) { |
399 local_decls.push({count: l.i32_count, type: kAstI32}); | 345 local_decls.push({count: l.i32_count, type: kAstI32}); |
400 } | 346 } |
401 if (l.i64_count > 0) { | 347 if (l.i64_count > 0) { |
402 local_decls.push({count: l.i64_count, type: kAstI64}); | 348 local_decls.push({count: l.i64_count, type: kAstI64}); |
403 } | 349 } |
404 if (l.f32_count > 0) { | 350 if (l.f32_count > 0) { |
405 local_decls.push({count: l.f32_count, type: kAstF32}); | 351 local_decls.push({count: l.f32_count, type: kAstF32}); |
406 } | 352 } |
407 if (l.f64_count > 0) { | 353 if (l.f64_count > 0) { |
408 local_decls.push({count: l.f64_count, type: kAstF64}); | 354 local_decls.push({count: l.f64_count, type: kAstF64}); |
409 } | 355 } |
410 } | 356 } |
411 | 357 |
412 let header = new Binary; | 358 let header = new Binary; |
413 header.emit_u32v(local_decls.length); | 359 header.emit_varint(local_decls.length); |
414 for (let decl of local_decls) { | 360 for (let decl of local_decls) { |
415 header.emit_u32v(decl.count); | 361 header.emit_varint(decl.count); |
416 header.emit_u8(decl.type); | 362 header.emit_u8(decl.type); |
417 } | 363 } |
418 | 364 |
419 section.emit_u32v(header.length + func.body.length); | 365 section.emit_varint(header.length + func.body.length); |
420 section.emit_bytes(header); | 366 section.emit_bytes(header); |
421 section.emit_bytes(func.body); | 367 section.emit_bytes(func.body); |
422 } | 368 } |
423 }); | 369 }); |
424 } | 370 } |
425 | 371 |
426 // Add data segments. | 372 // Add data segments. |
427 if (wasm.segments.length > 0) { | 373 if (wasm.segments.length > 0) { |
428 if (debug) print("emitting data segments @ " + binary.length); | 374 if (debug) print("emitting data segments @ " + binary.length); |
429 binary.emit_section(kDataSectionCode, section => { | 375 binary.emit_section(kDataSectionCode, section => { |
430 section.emit_u32v(wasm.segments.length); | 376 section.emit_varint(wasm.segments.length); |
431 for (let seg of wasm.segments) { | 377 for (let seg of wasm.segments) { |
432 section.emit_u8(0); // linear memory index 0 | 378 section.emit_u8(0); // linear memory index 0 |
433 section.emit_u8(kExprI32Const); | 379 section.emit_u8(kExprI32Const); |
434 section.emit_u32v(seg.addr); | 380 section.emit_varint(seg.addr); |
435 section.emit_u8(kExprEnd); | 381 section.emit_u8(kExprEnd); |
436 section.emit_u32v(seg.data.length); | 382 section.emit_varint(seg.data.length); |
437 section.emit_bytes(seg.data); | 383 section.emit_bytes(seg.data); |
438 } | 384 } |
439 }); | 385 }); |
440 } | 386 } |
441 | 387 |
442 // Add any explicitly added sections | 388 // Add any explicitly added sections |
443 for (let exp of wasm.explicit) { | 389 for (let exp of wasm.explicit) { |
444 if (debug) print("emitting explicit @ " + binary.length); | 390 if (debug) print("emitting explicit @ " + binary.length); |
445 binary.emit_bytes(exp); | 391 binary.emit_bytes(exp); |
446 } | 392 } |
447 | 393 |
448 // Add function names. | 394 // Add function names. |
449 if (has_names) { | 395 if (has_names) { |
450 if (debug) print("emitting names @ " + binary.length); | 396 if (debug) print("emitting names @ " + binary.length); |
451 binary.emit_section(kUnknownSectionCode, section => { | 397 binary.emit_section(kUnknownSectionCode, section => { |
452 section.emit_string("name"); | 398 section.emit_string("name"); |
453 section.emit_u32v(wasm.functions.length); | 399 section.emit_varint(wasm.functions.length); |
454 for (let func of wasm.functions) { | 400 for (let func of wasm.functions) { |
455 var name = func.name == undefined ? "" : func.name; | 401 var name = func.name == undefined ? "" : func.name; |
456 section.emit_string(name); | 402 section.emit_string(name); |
457 section.emit_u8(0); // local names count == 0 | 403 section.emit_u8(0); // local names count == 0 |
458 } | 404 } |
459 }); | 405 }); |
460 } | 406 } |
461 | 407 |
462 return binary; | 408 return binary; |
463 } | 409 } |
464 | 410 |
465 toBuffer(debug) { | 411 toBuffer(debug) { |
466 let bytes = this.toArray(debug); | 412 let bytes = this.toArray(debug); |
467 let buffer = new ArrayBuffer(bytes.length); | 413 let buffer = new ArrayBuffer(bytes.length); |
468 let view = new Uint8Array(buffer); | 414 let view = new Uint8Array(buffer); |
469 for (let i = 0; i < bytes.length; i++) { | 415 for (let i = 0; i < bytes.length; i++) { |
470 let val = bytes[i]; | 416 let val = bytes[i]; |
471 if ((typeof val) == "string") val = val.charCodeAt(0); | 417 if ((typeof val) == "string") val = val.charCodeAt(0); |
472 view[i] = val | 0; | 418 view[i] = val | 0; |
473 } | 419 } |
474 return buffer; | 420 return buffer; |
475 } | 421 } |
476 | 422 |
477 instantiate(...args) { | 423 instantiate(...args) { |
478 let module = new WebAssembly.Module(this.toBuffer()); | 424 let module = new WebAssembly.Module(this.toBuffer()); |
479 let instance = new WebAssembly.Instance(module, ...args); | 425 let instance = new WebAssembly.Instance(module, ...args); |
480 return instance; | 426 return instance; |
481 } | 427 } |
482 } | 428 } |
OLD | NEW |