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

Side by Side Diff: test/mjsunit/wasm/wasm-module-builder.js

Issue 2081973003: Refactor module builder (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 years, 6 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
« no previous file with comments | « test/mjsunit/wasm/wasm-constants.js ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 function WasmFunctionBuilder(name, sig_index) { 5 class Binary extends Array {
bradnelson 2016/06/21 19:05:00 Nice pithy name :-)
6 emit_u8(val) {
7 this.push(val);
8 }
9
10 emit_u16(val) {
11 this.push(val & 0xff);
12 this.push((val >> 8) & 0xff);
13 }
14
15 emit_u32(val) {
16 this.push(val & 0xff);
17 this.push((val >> 8) & 0xff);
18 this.push((val >> 16) & 0xff);
19 this.push((val >> 24) & 0xff);
20 }
21
22 emit_varint(val) {
23 while (true) {
24 let v = val & 0xff;
25 val = val >>> 7;
26 if (val == 0) {
27 this.push(v);
28 break;
29 }
30 this.push(v | 0x80);
31 }
32 }
33
34 emit_bytes(data) {
35 for (let i = 0; i < data.length; i++) {
36 this.push(data[i] & 0xff);
37 }
38 }
39
40 emit_string(string) {
41 // When testing illegal names, we pass a byte array directly.
42 if (string instanceof Array) {
43 this.emit_varint(string.length);
44 this.emit_bytes(string);
45 return;
46 }
47
48 // This is the hacky way to convert a JavaScript string to a UTF8 encoded
49 // string only containing single-byte characters.
50 let string_utf8 = unescape(encodeURIComponent(string));
51 this.emit_varint(string_utf8.length);
52 for (let i = 0; i < string_utf8.length; i++) {
53 this.emit_u8(string_utf8.charCodeAt(i));
54 }
55 }
56
57 emit_header() {
58 this.push(kWasmH0, kWasmH1, kWasmH2, kWasmH3,
59 kWasmV0, kWasmV1, kWasmV2, kWasmV3);
60 }
61
62 emit_section(section_code, content_generator) {
63 // Emit section name.
64 this.emit_string(section_names[section_code]);
65 // Emit the section to a temporary buffer: its full length isn't know yet.
66 let section = new Binary;
67 content_generator(section);
68 // Emit section length.
69 this.emit_varint(section.length);
70 // Copy the temporary buffer.
71 this.push(...section);
72 }
73 }
74
75 class WasmFunctionBuilder {
76 constructor(name, type_index) {
6 this.name = name; 77 this.name = name;
7 this.sig_index = sig_index; 78 this.type_index = type_index;
8 this.exports = []; 79 this.exports = [];
80 }
81
82 exportAs(name) {
83 this.exports.push(name);
84 return this;
85 }
86
87 exportFunc() {
88 this.exports.push(this.name);
89 return this;
90 }
91
92 addBody(body) {
93 this.body = body;
94 return this;
95 }
96
97 addLocals(locals) {
98 this.locals = locals;
99 return this;
100 }
9 } 101 }
10 102
11 WasmFunctionBuilder.prototype.exportAs = function(name) { 103 class WasmModuleBuilder {
12 this.exports.push(name); 104 constructor() {
13 return this; 105 this.types = [];
14 }
15
16 WasmFunctionBuilder.prototype.exportFunc = function() {
17 this.exports.push(this.name);
18 return this;
19 }
20
21 WasmFunctionBuilder.prototype.addBody = function(body) {
22 this.body = body;
23 return this;
24 }
25
26 WasmFunctionBuilder.prototype.addLocals = function(locals) {
27 this.locals = locals;
28 return this;
29 }
30
31 function WasmModuleBuilder() {
32 this.signatures = [];
33 this.imports = []; 106 this.imports = [];
34 this.functions = []; 107 this.functions = [];
35 this.exports = []; 108 this.exports = [];
36 this.function_table = []; 109 this.table = [];
37 this.data_segments = []; 110 this.segments = [];
38 this.explicit = []; 111 this.explicit = [];
39 return this; 112 }
40 } 113
41 114 addStart(start_index) {
42 WasmModuleBuilder.prototype.addStart = function(start_index) {
43 this.start_index = start_index; 115 this.start_index = start_index;
44 } 116 }
45 117
46 WasmModuleBuilder.prototype.addMemory = function(min, max, exp) { 118 addMemory(min, max, exp) {
47 this.memory = {min: min, max: max, exp: exp}; 119 this.memory = {min: min, max: max, exp: exp};
48 return this; 120 return this;
49 } 121 }
50 122
51 WasmModuleBuilder.prototype.addExplicitSection = function(bytes) { 123 addExplicitSection(bytes) {
52 this.explicit.push(bytes); 124 this.explicit.push(bytes);
53 return this; 125 return this;
54 } 126 }
55 127
56 // Add a signature; format is [param_count, param0, param1, ..., retcount, ret0] 128 addType(type) {
57 WasmModuleBuilder.prototype.addSignature = function(sig) { 129 // TODO: canonicalize types?
58 // TODO: canonicalize signatures? 130 this.types.push(type);
59 this.signatures.push(sig); 131 return this.types.length - 1;
60 return this.signatures.length - 1; 132 }
61 } 133
62 134 addFunction(name, type) {
63 WasmModuleBuilder.prototype.addFunction = function(name, sig) { 135 let type_index = (typeof type) == "number" ? type : this.addType(type);
64 var sig_index = (typeof sig) == "number" ? sig : this.addSignature(sig); 136 let func = new WasmFunctionBuilder(name, type_index);
65 var func = new WasmFunctionBuilder(name, sig_index);
66 func.index = this.functions.length; 137 func.index = this.functions.length;
67 this.functions.push(func); 138 this.functions.push(func);
68 return func; 139 return func;
69 } 140 }
70 141
71 WasmModuleBuilder.prototype.addImportWithModule = function(module, name, sig) { 142 addImportWithModule(module, name, type) {
72 var sig_index = (typeof sig) == "number" ? sig : this.addSignature(sig); 143 let type_index = (typeof type) == "number" ? type : this.addType(type);
73 this.imports.push({module: module, name: name, sig_index: sig_index}); 144 this.imports.push({module: module, name: name, type: type_index});
74 return this.imports.length - 1; 145 return this.imports.length - 1;
75 } 146 }
76 147
77 WasmModuleBuilder.prototype.addImport = function(name, sig) { 148 addImport(name, type) {
78 this.addImportWithModule(name, undefined, sig); 149 return this.addImportWithModule(name, undefined, type);
79 } 150 }
80 151
81 WasmModuleBuilder.prototype.addDataSegment = function(addr, data, init) { 152 addDataSegment(addr, data, init) {
82 this.data_segments.push({addr: addr, data: data, init: init}); 153 this.segments.push({addr: addr, data: data, init: init});
83 return this.data_segments.length - 1; 154 return this.segments.length - 1;
84 } 155 }
85 156
86 WasmModuleBuilder.prototype.appendToFunctionTable = function(array) { 157 appendToTable(array) {
87 this.function_table = this.function_table.concat(array); 158 this.table.push(...array);
88 return this; 159 return this;
89 } 160 }
90 161
91 function emit_u8(bytes, val) { 162 toArray(debug) {
92 bytes.push(val & 0xff); 163 let binary = new Binary;
93 } 164 let wasm = this;
94 165
95 function emit_u16(bytes, val) { 166 // Add header
96 bytes.push(val & 0xff); 167 binary.emit_header();
97 bytes.push((val >> 8) & 0xff); 168
98 } 169 // Add type section
99 170 if (wasm.types.length > 0) {
100 function emit_u32(bytes, val) { 171 if (debug) print("emitting types @ " + binary.length);
101 bytes.push(val & 0xff); 172 binary.emit_section(kDeclTypes, section => {
102 bytes.push((val >> 8) & 0xff); 173 section.emit_varint(wasm.types.length);
103 bytes.push((val >> 16) & 0xff); 174 for (let type of wasm.types) {
104 bytes.push((val >> 24) & 0xff); 175 section.emit_u8(kWasmFunctionTypeForm);
105 } 176 section.emit_varint(type.params.length);
106 177 for (let param of type.params) {
107 function emit_string(bytes, string) { 178 section.emit_u8(param);
108 // When testing illegal names, we pass a byte array directly. 179 }
109 if (string instanceof Array) { 180 section.emit_varint(type.results.length);
110 emit_varint(bytes, string.length); 181 for (let result of type.results) {
111 emit_bytes(bytes, string); 182 section.emit_u8(result);
112 return; 183 }
113 } 184 }
114 185 });
115 // This is the hacky way to convert a JavaScript scring to a UTF8 encoded
116 // string only containing single-byte characters.
117 var string_utf8 = unescape(encodeURIComponent(string));
118 emit_varint(bytes, string_utf8.length);
119 for (var i = 0; i < string_utf8.length; i++) {
120 emit_u8(bytes, string_utf8.charCodeAt(i));
121 }
122 }
123
124 function emit_varint(bytes, val) {
125 while (true) {
126 var v = val & 0xff;
127 val = val >>> 7;
128 if (val == 0) {
129 bytes.push(v);
130 break;
131 }
132 bytes.push(v | 0x80);
133 }
134 }
135
136 function emit_bytes(bytes, data) {
137 for (var i = 0; i < data.length; i++) {
138 bytes.push(data[i] & 0xff);
139 }
140 }
141
142 function emit_section(bytes, section_code, content_generator) {
143 // Emit section name.
144 emit_string(bytes, section_names[section_code]);
145 // Emit the section to a temporary buffer: its full length isn't know yet.
146 var tmp_bytes = [];
147 content_generator(tmp_bytes);
148 // Emit section length.
149 emit_varint(bytes, tmp_bytes.length);
150 // Copy the temporary buffer.
151 Array.prototype.push.apply(bytes, tmp_bytes);
152 }
153
154 WasmModuleBuilder.prototype.toArray = function(debug) {
155 // Add header bytes
156 var bytes = [];
157 bytes = bytes.concat([kWasmH0, kWasmH1, kWasmH2, kWasmH3,
158 kWasmV0, kWasmV1, kWasmV2, kWasmV3]);
159
160 var wasm = this;
161
162 // Add signatures section
163 if (wasm.signatures.length > 0) {
164 if (debug) print("emitting signatures @ " + bytes.length);
165 emit_section(bytes, kDeclSignatures, function(bytes) {
166 emit_varint(bytes, wasm.signatures.length);
167 for (sig of wasm.signatures) {
168 emit_u8(bytes, kWasmFunctionTypeForm);
169 for (var j = 0; j < sig.length; j++) {
170 emit_u8(bytes, sig[j]);
171 }
172 }
173 });
174 } 186 }
175 187
176 // Add imports section 188 // Add imports section
177 if (wasm.imports.length > 0) { 189 if (wasm.imports.length > 0) {
178 if (debug) print("emitting imports @ " + bytes.length); 190 if (debug) print("emitting imports @ " + binary.length);
179 emit_section(bytes, kDeclImportTable, function(bytes) { 191 binary.emit_section(kDeclImports, section => {
180 emit_varint(bytes, wasm.imports.length); 192 section.emit_varint(wasm.imports.length);
181 for (imp of wasm.imports) { 193 for (let imp of wasm.imports) {
182 emit_varint(bytes, imp.sig_index); 194 section.emit_varint(imp.type);
183 emit_string(bytes, imp.module); 195 section.emit_string(imp.module);
184 emit_string(bytes, imp.name || ''); 196 section.emit_string(imp.name || '');
185 } 197 }
186 }); 198 });
187 } 199 }
188 200
189 // Add functions declarations 201 // Add functions declarations
190 var names = false; 202 let has_names = false;
191 var exports = 0; 203 let names = false;
204 let exports = 0;
192 if (wasm.functions.length > 0) { 205 if (wasm.functions.length > 0) {
193 var has_names = false; 206 if (debug) print("emitting function decls @ " + binary.length);
194 207 binary.emit_section(kDeclFunctions, section => {
195 // emit function signatures 208 section.emit_varint(wasm.functions.length);
196 if (debug) print("emitting function sigs @ " + bytes.length); 209 for (let func of wasm.functions) {
197 emit_section(bytes, kDeclFunctionSignatures, function(bytes) { 210 has_names = has_names || (func.name != undefined &&
198 emit_varint(bytes, wasm.functions.length); 211 func.name.length > 0);
199 for (func of wasm.functions) { 212 exports += func.exports.length;
200 has_names = has_names || (func.name != undefined && 213 section.emit_varint(func.type_index);
201 func.name.length > 0); 214 }
202 exports += func.exports.length; 215 });
203 216 }
204 emit_varint(bytes, func.sig_index); 217
205 } 218 // Add table.
206 }); 219 if (wasm.table.length > 0) {
207 220 if (debug) print("emitting table @ " + binary.length);
208 } 221 binary.emit_section(kDeclTable, section => {
209 222 section.emit_varint(wasm.table.length);
210 // Add function table. 223 for (let index of wasm.table) {
211 if (wasm.function_table.length > 0) { 224 section.emit_varint(index);
212 if (debug) print("emitting function table @ " + bytes.length); 225 }
213 emit_section(bytes, kDeclFunctionTable, function(bytes) { 226 });
214 emit_varint(bytes, wasm.function_table.length);
215 for (index of wasm.function_table) {
216 emit_varint(bytes, index);
217 }
218 });
219 } 227 }
220 228
221 // Add memory section 229 // Add memory section
222 if (wasm.memory != undefined) { 230 if (wasm.memory != undefined) {
223 if (debug) print("emitting memory @ " + bytes.length); 231 if (debug) print("emitting memory @ " + binary.length);
224 emit_section(bytes, kDeclMemory, function(bytes) { 232 binary.emit_section(kDeclMemory, section => {
225 emit_varint(bytes, wasm.memory.min); 233 section.emit_varint(wasm.memory.min);
226 emit_varint(bytes, wasm.memory.max); 234 section.emit_varint(wasm.memory.max);
227 emit_u8(bytes, wasm.memory.exp ? 1 : 0); 235 section.emit_u8(wasm.memory.exp ? 1 : 0);
228 }); 236 });
229 } 237 }
230 238
231 239
232 // Add export table. 240 // Add export table.
233 if (exports > 0) { 241 if (exports > 0) {
234 if (debug) print("emitting exports @ " + bytes.length); 242 if (debug) print("emitting exports @ " + binary.length);
235 emit_section(bytes, kDeclExportTable, function(bytes) { 243 binary.emit_section(kDeclExports, section => {
236 emit_varint(bytes, exports); 244 section.emit_varint(exports);
237 for (func of wasm.functions) { 245 for (let func of wasm.functions) {
238 for (exp of func.exports) { 246 for (let exp of func.exports) {
239 emit_varint(bytes, func.index); 247 section.emit_varint(func.index);
240 emit_string(bytes, exp); 248 section.emit_string(exp);
241 } 249 }
242 } 250 }
243 }); 251 });
244 } 252 }
245 253
246 // Add start function section. 254 // Add start function section.
247 if (wasm.start_index != undefined) { 255 if (wasm.start_index != undefined) {
248 if (debug) print("emitting start function @ " + bytes.length); 256 if (debug) print("emitting start function @ " + binary.length);
249 emit_section(bytes, kDeclStartFunction, function(bytes) { 257 binary.emit_section(kDeclStart, section => {
250 emit_varint(bytes, wasm.start_index); 258 section.emit_varint(wasm.start_index);
251 }); 259 });
252 } 260 }
253 261
254 // Add function bodies. 262 // Add function bodies.
255 if (wasm.functions.length > 0) { 263 if (wasm.functions.length > 0) {
256 // emit function bodies 264 // emit function bodies
257 if (debug) print("emitting function bodies @ " + bytes.length); 265 if (debug) print("emitting code @ " + binary.length);
258 emit_section(bytes, kDeclFunctionBodies, function(bytes) { 266 binary.emit_section(kDeclCode, section => {
259 emit_varint(bytes, wasm.functions.length); 267 section.emit_varint(wasm.functions.length);
260 for (func of wasm.functions) { 268 for (let func of wasm.functions) {
261 // Function body length will be patched later. 269 // Function body length will be patched later.
262 var local_decls = []; 270 let local_decls = [];
263 var l = func.locals; 271 let l = func.locals;
264 if (l != undefined) { 272 if (l != undefined) {
265 var local_decls_count = 0; 273 let local_decls_count = 0;
266 if (l.i32_count > 0) { 274 if (l.i32_count > 0) {
267 local_decls.push({count: l.i32_count, type: kAstI32}); 275 local_decls.push({count: l.i32_count, type: kAstI32});
268 }
269 if (l.i64_count > 0) {
270 local_decls.push({count: l.i64_count, type: kAstI64});
271 }
272 if (l.f32_count > 0) {
273 local_decls.push({count: l.f32_count, type: kAstF32});
274 }
275 if (l.f64_count > 0) {
276 local_decls.push({count: l.f64_count, type: kAstF64});
277 }
278 }
279 var header = new Array();
280
281 emit_varint(header, local_decls.length);
282 for (decl of local_decls) {
283 emit_varint(header, decl.count);
284 emit_u8(header, decl.type);
285 }
286
287 emit_varint(bytes, header.length + func.body.length);
288 emit_bytes(bytes, header);
289 emit_bytes(bytes, func.body);
290 } 276 }
291 }); 277 if (l.i64_count > 0) {
278 local_decls.push({count: l.i64_count, type: kAstI64});
279 }
280 if (l.f32_count > 0) {
281 local_decls.push({count: l.f32_count, type: kAstF32});
282 }
283 if (l.f64_count > 0) {
284 local_decls.push({count: l.f64_count, type: kAstF64});
285 }
286 }
287
288 let header = new Binary;
289 header.emit_varint(local_decls.length);
290 for (let decl of local_decls) {
291 header.emit_varint(decl.count);
292 header.emit_u8(decl.type);
293 }
294
295 section.emit_varint(header.length + func.body.length);
296 section.emit_bytes(header);
297 section.emit_bytes(func.body);
298 }
299 });
292 } 300 }
293 301
294 // Add data segments. 302 // Add data segments.
295 if (wasm.data_segments.length > 0) { 303 if (wasm.segments.length > 0) {
296 if (debug) print("emitting data segments @ " + bytes.length); 304 if (debug) print("emitting data segments @ " + binary.length);
297 emit_section(bytes, kDeclDataSegments, function(bytes) { 305 binary.emit_section(kDeclData, section => {
298 emit_varint(bytes, wasm.data_segments.length); 306 section.emit_varint(wasm.segments.length);
299 for (seg of wasm.data_segments) { 307 for (let seg of wasm.segments) {
300 emit_varint(bytes, seg.addr); 308 section.emit_varint(seg.addr);
301 emit_varint(bytes, seg.data.length); 309 section.emit_varint(seg.data.length);
302 emit_bytes(bytes, seg.data); 310 section.emit_bytes(seg.data);
303 } 311 }
304 }); 312 });
305 } 313 }
306 314
307 // Add any explicitly added sections 315 // Add any explicitly added sections
308 for (exp of wasm.explicit) { 316 for (let exp of wasm.explicit) {
309 if (debug) print("emitting explicit @ " + bytes.length); 317 if (debug) print("emitting explicit @ " + binary.length);
310 emit_bytes(bytes, exp); 318 binary.emit_bytes(exp);
311 } 319 }
312 320
313 // Add function names. 321 // Add function names.
314 if (has_names) { 322 if (has_names) {
315 if (debug) print("emitting names @ " + bytes.length); 323 if (debug) print("emitting names @ " + binary.length);
316 emit_section(bytes, kDeclNames, function(bytes) { 324 binary.emit_section(kDeclNames, section => {
317 emit_varint(bytes, wasm.functions.length); 325 section.emit_varint(wasm.functions.length);
318 for (func of wasm.functions) { 326 for (let func of wasm.functions) {
319 var name = func.name == undefined ? "" : func.name; 327 var name = func.name == undefined ? "" : func.name;
320 emit_string(bytes, name); 328 section.emit_string(name);
321 emit_u8(bytes, 0); // local names count == 0 329 section.emit_u8(0); // local names count == 0
322 } 330 }
323 }); 331 });
324 } 332 }
325 333
326 // End the module. 334 return binary;
327 if (debug) print("emitting end @ " + bytes.length); 335 }
328 emit_section(bytes, kDeclEnd, function(bytes) {}); 336
329 337 toBuffer(debug) {
330 return bytes; 338 let bytes = this.toArray(debug);
339 let buffer = new ArrayBuffer(bytes.length);
340 let view = new Uint8Array(buffer);
341 for (let i = 0; i < bytes.length; i++) {
342 let val = bytes[i];
343 if ((typeof val) == "string") val = val.charCodeAt(0);
344 view[i] = val | 0;
345 }
346 return buffer;
347 }
348
349 instantiate(...args) {
350 let module = new WebAssembly.Module(this.toBuffer());
351 let instance = new WebAssembly.Instance(module, ...args);
352 return instance;
353 }
331 } 354 }
332
333 WasmModuleBuilder.prototype.toBuffer = function(debug) {
334 var bytes = this.toArray(debug);
335 var buffer = new ArrayBuffer(bytes.length);
336 var view = new Uint8Array(buffer);
337 for (var i = 0; i < bytes.length; i++) {
338 var val = bytes[i];
339 if ((typeof val) == "string") val = val.charCodeAt(0);
340 view[i] = val | 0;
341 }
342 return buffer;
343 }
344
345 WasmModuleBuilder.prototype.instantiate = function(...args) {
346 var module = new WebAssembly.Module(this.toBuffer());
347 var instance = new WebAssembly.Instance(module, ...args);
348 return instance;
349 }
OLDNEW
« no previous file with comments | « test/mjsunit/wasm/wasm-constants.js ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698