Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(59)

Side by Side Diff: third_party/WebKit/LayoutTests/fast/wasm/wasm-module-builder.js

Issue 2702953002: [wasm] Block compile/instantiate of large array buffers (Closed)
Patch Set: tests Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 the V8 project authors. All rights reserved.
bradnelson 2017/02/18 22:16:22 I see this is lifted from v8. Don't imagine we hav
Mircea Trofin 2017/02/19 00:18:33 We had a similar problem with the wasm structured
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
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 {
12 emit_u8(val) {
13 this.push(val);
14 }
15
16 emit_u16(val) {
17 this.push(val & 0xff);
18 this.push((val >> 8) & 0xff);
19 }
20
21 emit_u32(val) {
22 this.push(val & 0xff);
23 this.push((val >> 8) & 0xff);
24 this.push((val >> 16) & 0xff);
25 this.push((val >> 24) & 0xff);
26 }
27
28 emit_u32v(val) {
29 while (true) {
30 let v = val & 0xff;
31 val = val >>> 7;
32 if (val == 0) {
33 this.push(v);
34 break;
35 }
36 this.push(v | 0x80);
37 }
38 }
39
40 emit_bytes(data) {
41 for (let i = 0; i < data.length; i++) {
42 this.push(data[i] & 0xff);
43 }
44 }
45
46 emit_string(string) {
47 // When testing illegal names, we pass a byte array directly.
48 if (string instanceof Array) {
49 this.emit_u32v(string.length);
50 this.emit_bytes(string);
51 return;
52 }
53
54 // This is the hacky way to convert a JavaScript string to a UTF8 encoded
55 // string only containing single-byte characters.
56 let string_utf8 = unescape(encodeURIComponent(string));
57 this.emit_u32v(string_utf8.length);
58 for (let i = 0; i < string_utf8.length; i++) {
59 this.emit_u8(string_utf8.charCodeAt(i));
60 }
61 }
62
63 emit_header() {
64 this.push(kWasmH0, kWasmH1, kWasmH2, kWasmH3,
65 kWasmV0, kWasmV1, kWasmV2, kWasmV3);
66 }
67
68 emit_section(section_code, content_generator) {
69 // Emit section name.
70 this.emit_u8(section_code);
71 // Emit the section to a temporary buffer: its full length isn't know yet.
72 let section = new Binary;
73 content_generator(section);
74 // Emit section length.
75 this.emit_u32v(section.length);
76 // Copy the temporary buffer.
77 this.push(...section);
78 }
79 }
80
81 class WasmFunctionBuilder {
82 constructor(module, name, type_index) {
83 this.module = module;
84 this.name = name;
85 this.type_index = type_index;
86 this.body = [];
87 }
88
89 exportAs(name) {
90 this.module.addExport(name, this.index);
91 return this;
92 }
93
94 exportFunc() {
95 this.exportAs(this.name);
96 return this;
97 }
98
99 addBody(body) {
100 for (let b of body) {
101 if (typeof b != 'number') throw new Error("invalid body");
102 }
103 this.body = body;
104 // Automatically add the end for the function block to the body.
105 body.push(kExprEnd);
106 return this;
107 }
108
109 addBodyWithEnd(body) {
110 this.body = body;
111 return this;
112 }
113
114 addLocals(locals) {
115 this.locals = locals;
116 return this;
117 }
118
119 end() {
120 return this.module;
121 }
122 }
123
124 class WasmGlobalBuilder {
125 constructor(module, type, mutable) {
126 this.module = module;
127 this.type = type;
128 this.mutable = mutable;
129 this.init = 0;
130 }
131
132 exportAs(name) {
133 this.module.exports.push({name: name, kind: kExternalGlobal,
134 index: this.index});
135 return this;
136 }
137 }
138
139 class WasmModuleBuilder {
140 constructor() {
141 this.types = [];
142 this.imports = [];
143 this.exports = [];
144 this.globals = [];
145 this.functions = [];
146 this.function_table = [];
147 this.function_table_length = 0;
148 this.function_table_inits = [];
149 this.segments = [];
150 this.explicit = [];
151 this.num_imported_funcs = 0;
152 this.num_imported_globals = 0;
153 return this;
154 }
155
156 addStart(start_index) {
157 this.start_index = start_index;
158 return this;
159 }
160
161 addMemory(min, max, exp) {
162 this.memory = {min: min, max: max, exp: exp};
163 return this;
164 }
165
166 addExplicitSection(bytes) {
167 this.explicit.push(bytes);
168 return this;
169 }
170
171 stringToBytes(name) {
172 var result = new Binary();
173 result.emit_u32v(name.length);
174 for (var i = 0; i < name.length; i++) {
175 result.emit_u8(name.charCodeAt(i));
176 }
177 return result;
178 }
179
180 addCustomSection(name, bytes) {
181 name = this.stringToBytes(name);
182 var length = new Binary();
183 length.emit_u32v(name.length + bytes.length);
184 this.explicit.push([0, ...length, ...name, ...bytes]);
185 }
186
187 addType(type) {
188 // TODO: canonicalize types?
189 this.types.push(type);
190 return this.types.length - 1;
191 }
192
193 addGlobal(local_type, mutable) {
194 let glob = new WasmGlobalBuilder(this, local_type, mutable);
195 glob.index = this.globals.length + this.num_imported_globals;
196 this.globals.push(glob);
197 return glob;
198 }
199
200 addFunction(name, type) {
201 let type_index = (typeof type) == "number" ? type : this.addType(type);
202 let func = new WasmFunctionBuilder(this, name, type_index);
203 func.index = this.functions.length + this.num_imported_funcs;
204 this.functions.push(func);
205 return func;
206 }
207
208 addImport(module = "", name, type) {
209 let type_index = (typeof type) == "number" ? type : this.addType(type);
210 this.imports.push({module: module, name: name, kind: kExternalFunction,
211 type: type_index});
212 return this.num_imported_funcs++;
213 }
214
215 addImportedGlobal(module = "", name, type) {
216 let o = {module: module, name: name, kind: kExternalGlobal, type: type,
217 mutable: false}
218 this.imports.push(o);
219 return this.num_imported_globals++;
220 }
221
222 addImportedMemory(module = "", name, initial = 0, maximum) {
223 let o = {module: module, name: name, kind: kExternalMemory,
224 initial: initial, maximum: maximum};
225 this.imports.push(o);
226 return this;
227 }
228
229 addImportedTable(module = "", name, initial, maximum) {
230 let o = {module: module, name: name, kind: kExternalTable, initial: initial,
231 maximum: maximum};
232 this.imports.push(o);
233 }
234
235 addExport(name, index) {
236 this.exports.push({name: name, kind: kExternalFunction, index: index});
237 return this;
238 }
239
240 addExportOfKind(name, kind, index) {
241 this.exports.push({name: name, kind: kind, index: index});
242 return this;
243 }
244
245 addDataSegment(addr, data, is_global = false) {
246 this.segments.push({addr: addr, data: data, is_global: is_global});
247 return this.segments.length - 1;
248 }
249
250 exportMemoryAs(name) {
251 this.exports.push({name: name, kind: kExternalMemory, index: 0});
252 }
253
254 addFunctionTableInit(base, is_global, array, is_import = false) {
255 this.function_table_inits.push({base: base, is_global: is_global,
256 array: array});
257 if (!is_global) {
258 var length = base + array.length;
259 if (length > this.function_table_length && !is_import) {
260 this.function_table_length = length;
261 }
262 }
263 return this;
264 }
265
266 appendToTable(array) {
267 return this.addFunctionTableInit(this.function_table.length, false, array);
268 }
269
270 setFunctionTableLength(length) {
271 this.function_table_length = length;
272 return this;
273 }
274
275 toArray(debug = false) {
276 let binary = new Binary;
277 let wasm = this;
278
279 // Add header
280 binary.emit_header();
281
282 // Add type section
283 if (wasm.types.length > 0) {
284 if (debug) print("emitting types @ " + binary.length);
285 binary.emit_section(kTypeSectionCode, section => {
286 section.emit_u32v(wasm.types.length);
287 for (let type of wasm.types) {
288 section.emit_u8(kWasmFunctionTypeForm);
289 section.emit_u32v(type.params.length);
290 for (let param of type.params) {
291 section.emit_u8(param);
292 }
293 section.emit_u32v(type.results.length);
294 for (let result of type.results) {
295 section.emit_u8(result);
296 }
297 }
298 });
299 }
300
301 // Add imports section
302 if (wasm.imports.length > 0) {
303 if (debug) print("emitting imports @ " + binary.length);
304 binary.emit_section(kImportSectionCode, section => {
305 section.emit_u32v(wasm.imports.length);
306 for (let imp of wasm.imports) {
307 section.emit_string(imp.module);
308 section.emit_string(imp.name || '');
309 section.emit_u8(imp.kind);
310 if (imp.kind == kExternalFunction) {
311 section.emit_u32v(imp.type);
312 } else if (imp.kind == kExternalGlobal) {
313 section.emit_u32v(imp.type);
314 section.emit_u8(imp.mutable);
315 } else if (imp.kind == kExternalMemory) {
316 var has_max = (typeof imp.maximum) != "undefined";
317 section.emit_u8(has_max ? 1 : 0); // flags
318 section.emit_u32v(imp.initial); // initial
319 if (has_max) section.emit_u32v(imp.maximum); // maximum
320 } else if (imp.kind == kExternalTable) {
321 section.emit_u8(kWasmAnyFunctionTypeForm);
322 var has_max = (typeof imp.maximum) != "undefined";
323 section.emit_u8(has_max ? 1 : 0); // flags
324 section.emit_u32v(imp.initial); // initial
325 if (has_max) section.emit_u32v(imp.maximum); // maximum
326 } else {
327 throw new Error("unknown/unsupported import kind " + imp.kind);
328 }
329 }
330 });
331 }
332
333 // Add functions declarations
334 let has_names = false;
335 let names = false;
336 if (wasm.functions.length > 0) {
337 if (debug) print("emitting function decls @ " + binary.length);
338 binary.emit_section(kFunctionSectionCode, section => {
339 section.emit_u32v(wasm.functions.length);
340 for (let func of wasm.functions) {
341 has_names = has_names || (func.name != undefined &&
342 func.name.length > 0);
343 section.emit_u32v(func.type_index);
344 }
345 });
346 }
347
348 // Add function_table.
349 if (wasm.function_table_length > 0) {
350 if (debug) print("emitting table @ " + binary.length);
351 binary.emit_section(kTableSectionCode, section => {
352 section.emit_u8(1); // one table entry
353 section.emit_u8(kWasmAnyFunctionTypeForm);
354 section.emit_u8(1);
355 section.emit_u32v(wasm.function_table_length);
356 section.emit_u32v(wasm.function_table_length);
357 });
358 }
359
360 // Add memory section
361 if (wasm.memory != undefined) {
362 if (debug) print("emitting memory @ " + binary.length);
363 binary.emit_section(kMemorySectionCode, section => {
364 section.emit_u8(1); // one memory entry
365 section.emit_u32v(kResizableMaximumFlag);
366 section.emit_u32v(wasm.memory.min);
367 section.emit_u32v(wasm.memory.max);
368 });
369 }
370
371 // Add global section.
372 if (wasm.globals.length > 0) {
373 if (debug) print ("emitting globals @ " + binary.length);
374 binary.emit_section(kGlobalSectionCode, section => {
375 section.emit_u32v(wasm.globals.length);
376 for (let global of wasm.globals) {
377 section.emit_u8(global.type);
378 section.emit_u8(global.mutable);
379 if ((typeof global.init_index) == "undefined") {
380 // Emit a constant initializer.
381 switch (global.type) {
382 case kWasmI32:
383 section.emit_u8(kExprI32Const);
384 section.emit_u32v(global.init);
385 break;
386 case kWasmI64:
387 section.emit_u8(kExprI64Const);
388 section.emit_u32v(global.init);
389 break;
390 case kWasmF32:
391 section.emit_u8(kExprF32Const);
392 f32_view[0] = global.init;
393 section.emit_u8(byte_view[0]);
394 section.emit_u8(byte_view[1]);
395 section.emit_u8(byte_view[2]);
396 section.emit_u8(byte_view[3]);
397 break;
398 case kWasmF64:
399 section.emit_u8(kExprF64Const);
400 f64_view[0] = global.init;
401 section.emit_u8(byte_view[0]);
402 section.emit_u8(byte_view[1]);
403 section.emit_u8(byte_view[2]);
404 section.emit_u8(byte_view[3]);
405 section.emit_u8(byte_view[4]);
406 section.emit_u8(byte_view[5]);
407 section.emit_u8(byte_view[6]);
408 section.emit_u8(byte_view[7]);
409 break;
410 }
411 } else {
412 // Emit a global-index initializer.
413 section.emit_u8(kExprGetGlobal);
414 section.emit_u32v(global.init_index);
415 }
416 section.emit_u8(kExprEnd); // end of init expression
417 }
418 });
419 }
420
421 // Add export table.
422 var mem_export = (wasm.memory != undefined && wasm.memory.exp);
423 var exports_count = wasm.exports.length + (mem_export ? 1 : 0);
424 if (exports_count > 0) {
425 if (debug) print("emitting exports @ " + binary.length);
426 binary.emit_section(kExportSectionCode, section => {
427 section.emit_u32v(exports_count);
428 for (let exp of wasm.exports) {
429 section.emit_string(exp.name);
430 section.emit_u8(exp.kind);
431 section.emit_u32v(exp.index);
432 }
433 if (mem_export) {
434 section.emit_string("memory");
435 section.emit_u8(kExternalMemory);
436 section.emit_u8(0);
437 }
438 });
439 }
440
441 // Add start function section.
442 if (wasm.start_index != undefined) {
443 if (debug) print("emitting start function @ " + binary.length);
444 binary.emit_section(kStartSectionCode, section => {
445 section.emit_u32v(wasm.start_index);
446 });
447 }
448
449 // Add table elements.
450 if (wasm.function_table_inits.length > 0) {
451 if (debug) print("emitting table @ " + binary.length);
452 binary.emit_section(kElementSectionCode, section => {
453 var inits = wasm.function_table_inits;
454 section.emit_u32v(inits.length);
455 section.emit_u8(0); // table index
456
457 for (let init of inits) {
458 if (init.is_global) {
459 section.emit_u8(kExprGetGlobal);
460 } else {
461 section.emit_u8(kExprI32Const);
462 }
463 section.emit_u32v(init.base);
464 section.emit_u8(kExprEnd);
465 section.emit_u32v(init.array.length);
466 for (let index of init.array) {
467 section.emit_u32v(index);
468 }
469 }
470 });
471 }
472
473 // Add function bodies.
474 if (wasm.functions.length > 0) {
475 // emit function bodies
476 if (debug) print("emitting code @ " + binary.length);
477 binary.emit_section(kCodeSectionCode, section => {
478 section.emit_u32v(wasm.functions.length);
479 for (let func of wasm.functions) {
480 // Function body length will be patched later.
481 let local_decls = [];
482 let l = func.locals;
483 if (l != undefined) {
484 let local_decls_count = 0;
485 if (l.i32_count > 0) {
486 local_decls.push({count: l.i32_count, type: kWasmI32});
487 }
488 if (l.i64_count > 0) {
489 local_decls.push({count: l.i64_count, type: kWasmI64});
490 }
491 if (l.f32_count > 0) {
492 local_decls.push({count: l.f32_count, type: kWasmF32});
493 }
494 if (l.f64_count > 0) {
495 local_decls.push({count: l.f64_count, type: kWasmF64});
496 }
497 }
498
499 let header = new Binary;
500 header.emit_u32v(local_decls.length);
501 for (let decl of local_decls) {
502 header.emit_u32v(decl.count);
503 header.emit_u8(decl.type);
504 }
505
506 section.emit_u32v(header.length + func.body.length);
507 section.emit_bytes(header);
508 section.emit_bytes(func.body);
509 }
510 });
511 }
512
513 // Add data segments.
514 if (wasm.segments.length > 0) {
515 if (debug) print("emitting data segments @ " + binary.length);
516 binary.emit_section(kDataSectionCode, section => {
517 section.emit_u32v(wasm.segments.length);
518 for (let seg of wasm.segments) {
519 section.emit_u8(0); // linear memory index 0
520 if (seg.is_global) {
521 // initializer is a global variable
522 section.emit_u8(kExprGetGlobal);
523 section.emit_u32v(seg.addr);
524 } else {
525 // initializer is a constant
526 section.emit_u8(kExprI32Const);
527 section.emit_u32v(seg.addr);
528 }
529 section.emit_u8(kExprEnd);
530 section.emit_u32v(seg.data.length);
531 section.emit_bytes(seg.data);
532 }
533 });
534 }
535
536 // Add any explicitly added sections
537 for (let exp of wasm.explicit) {
538 if (debug) print("emitting explicit @ " + binary.length);
539 binary.emit_bytes(exp);
540 }
541
542 // Add function names.
543 if (has_names) {
544 if (debug) print("emitting names @ " + binary.length);
545 binary.emit_section(kUnknownSectionCode, section => {
546 section.emit_string("name");
547 var count = wasm.functions.length + wasm.num_imported_funcs;
548 section.emit_u32v(count);
549 for (var i = 0; i < wasm.num_imported_funcs; i++) {
550 section.emit_u8(0); // empty string
551 section.emit_u8(0); // local names count == 0
552 }
553 for (let func of wasm.functions) {
554 var name = func.name == undefined ? "" : func.name;
555 section.emit_string(name);
556 section.emit_u8(0); // local names count == 0
557 }
558 });
559 }
560
561 return binary;
562 }
563
564 toBuffer(debug = false) {
565 let bytes = this.toArray(debug);
566 let buffer = new ArrayBuffer(bytes.length);
567 let view = new Uint8Array(buffer);
568 for (let i = 0; i < bytes.length; i++) {
569 let val = bytes[i];
570 if ((typeof val) == "string") val = val.charCodeAt(0);
571 view[i] = val | 0;
572 }
573 return buffer;
574 }
575
576 instantiate(ffi) {
577 let module = new WebAssembly.Module(this.toBuffer());
578 let instance = new WebAssembly.Instance(module, ffi);
579 return instance;
580 }
581 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698