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