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 function WasmFunctionBuilder(name, sig_index) { | 5 function WasmFunctionBuilder(name, sig_index) { |
6 this.name = name; | 6 this.name = name; |
7 this.sig_index = sig_index; | 7 this.sig_index = sig_index; |
8 this.exports = []; | 8 this.exports = []; |
9 } | 9 } |
10 | 10 |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
124 bytes.push(v | 0x80); | 124 bytes.push(v | 0x80); |
125 } | 125 } |
126 } | 126 } |
127 | 127 |
128 function emit_bytes(bytes, data) { | 128 function emit_bytes(bytes, data) { |
129 for (var i = 0; i < data.length; i++) { | 129 for (var i = 0; i < data.length; i++) { |
130 bytes.push(data[i] & 0xff); | 130 bytes.push(data[i] & 0xff); |
131 } | 131 } |
132 } | 132 } |
133 | 133 |
| 134 function emit_section(bytes, section_code, content_generator) { |
| 135 // Start the section in a temporary buffer: its full length isn't know yet. |
| 136 var tmp_bytes = []; |
| 137 emit_string(tmp_bytes, section_names[section_code]); |
| 138 content_generator(tmp_bytes); |
| 139 // Now that we know the section length, emit it and copy the section. |
| 140 emit_varint(bytes, tmp_bytes.length); |
| 141 Array.prototype.push.apply(bytes, tmp_bytes); |
| 142 } |
| 143 |
134 WasmModuleBuilder.prototype.toArray = function(debug) { | 144 WasmModuleBuilder.prototype.toArray = function(debug) { |
135 // Add header bytes | 145 // Add header bytes |
136 var bytes = []; | 146 var bytes = []; |
137 bytes = bytes.concat([kWasmH0, kWasmH1, kWasmH2, kWasmH3, | 147 bytes = bytes.concat([kWasmH0, kWasmH1, kWasmH2, kWasmH3, |
138 kWasmV0, kWasmV1, kWasmV2, kWasmV3]); | 148 kWasmV0, kWasmV1, kWasmV2, kWasmV3]); |
139 | 149 |
| 150 var wasm = this; |
| 151 |
140 // Add memory section | 152 // Add memory section |
141 if (this.memory != undefined) { | 153 if (wasm.memory != undefined) { |
142 if (debug) print("emitting memory @ " + bytes.length); | 154 if (debug) print("emitting memory @ " + bytes.length); |
143 emit_u8(bytes, kDeclMemory); | 155 emit_section(bytes, kDeclMemory, function(bytes) { |
144 emit_varint(bytes, this.memory.min); | 156 emit_varint(bytes, wasm.memory.min); |
145 emit_varint(bytes, this.memory.max); | 157 emit_varint(bytes, wasm.memory.max); |
146 emit_u8(bytes, this.memory.exp ? 1 : 0); | 158 emit_u8(bytes, wasm.memory.exp ? 1 : 0); |
| 159 }); |
147 } | 160 } |
148 | 161 |
149 // Add signatures section | 162 // Add signatures section |
150 if (this.signatures.length > 0) { | 163 if (wasm.signatures.length > 0) { |
151 if (debug) print("emitting signatures @ " + bytes.length); | 164 if (debug) print("emitting signatures @ " + bytes.length); |
152 emit_u8(bytes, kDeclSignatures); | 165 emit_section(bytes, kDeclSignatures, function(bytes) { |
153 emit_varint(bytes, this.signatures.length); | 166 emit_varint(bytes, wasm.signatures.length); |
154 for (sig of this.signatures) { | 167 for (sig of wasm.signatures) { |
155 var params = sig.length - 1; | 168 var params = sig.length - 1; |
156 emit_varint(bytes, params); | 169 emit_varint(bytes, params); |
157 for (var j = 0; j < sig.length; j++) { | 170 for (var j = 0; j < sig.length; j++) { |
158 emit_u8(bytes, sig[j]); | 171 emit_u8(bytes, sig[j]); |
| 172 } |
159 } | 173 } |
160 } | 174 }); |
161 } | 175 } |
162 | 176 |
163 // Add imports section | 177 // Add imports section |
164 if (this.imports.length > 0) { | 178 if (wasm.imports.length > 0) { |
165 if (debug) print("emitting imports @ " + bytes.length); | 179 if (debug) print("emitting imports @ " + bytes.length); |
166 emit_u8(bytes, kDeclImportTable); | 180 emit_section(bytes, kDeclImportTable, function(bytes) { |
167 emit_varint(bytes, this.imports.length); | 181 emit_varint(bytes, wasm.imports.length); |
168 for (imp of this.imports) { | 182 for (imp of wasm.imports) { |
169 emit_varint(bytes, imp.sig_index); | 183 emit_varint(bytes, imp.sig_index); |
170 emit_string(bytes, imp.module); | 184 emit_string(bytes, imp.module); |
171 emit_string(bytes, imp.name || ''); | 185 emit_string(bytes, imp.name || ''); |
172 } | 186 } |
| 187 }); |
173 } | 188 } |
174 | 189 |
175 // Add functions section | 190 // Add functions section |
176 var names = false; | 191 var names = false; |
177 var exports = 0; | 192 var exports = 0; |
178 if (this.functions.length > 0) { | 193 if (wasm.functions.length > 0) { |
179 var has_names = false; | 194 var has_names = false; |
180 | 195 |
181 // emit function signatures | 196 // emit function signatures |
182 if (debug) print("emitting function sigs @ " + bytes.length); | 197 if (debug) print("emitting function sigs @ " + bytes.length); |
183 emit_u8(bytes, kDeclFunctionSignatures); | 198 emit_section(bytes, kDeclFunctionSignatures, function(bytes) { |
184 emit_varint(bytes, this.functions.length); | 199 emit_varint(bytes, wasm.functions.length); |
185 for (func of this.functions) { | 200 for (func of wasm.functions) { |
186 has_names = has_names || (func.name != undefined && | 201 has_names = has_names || (func.name != undefined && |
187 func.name.length > 0); | 202 func.name.length > 0); |
188 exports += func.exports.length; | 203 exports += func.exports.length; |
189 | 204 |
190 emit_varint(bytes, func.sig_index); | 205 emit_varint(bytes, func.sig_index); |
191 } | 206 } |
| 207 }); |
192 | 208 |
193 // emit function bodies | 209 // emit function bodies |
194 if (debug) print("emitting function bodies @ " + bytes.length); | 210 if (debug) print("emitting function bodies @ " + bytes.length); |
195 emit_u8(bytes, kDeclFunctionBodies); | 211 emit_section(bytes, kDeclFunctionBodies, function(bytes) { |
196 emit_varint(bytes, this.functions.length); | 212 emit_varint(bytes, wasm.functions.length); |
197 for (func of this.functions) { | 213 for (func of wasm.functions) { |
198 // Function body length will be patched later. | 214 // Function body length will be patched later. |
199 var local_decls = []; | 215 var local_decls = []; |
200 var l = func.locals; | 216 var l = func.locals; |
201 if (l != undefined) { | 217 if (l != undefined) { |
202 var local_decls_count = 0; | 218 var local_decls_count = 0; |
203 if (l.i32_count > 0) { | 219 if (l.i32_count > 0) { |
204 local_decls.push({count: l.i32_count, type: kAstI32}); | 220 local_decls.push({count: l.i32_count, type: kAstI32}); |
205 } | 221 } |
206 if (l.i64_count > 0) { | 222 if (l.i64_count > 0) { |
207 local_decls.push({count: l.i64_count, type: kAstI64}); | 223 local_decls.push({count: l.i64_count, type: kAstI64}); |
208 } | 224 } |
209 if (l.f32_count > 0) { | 225 if (l.f32_count > 0) { |
210 local_decls.push({count: l.f32_count, type: kAstF32}); | 226 local_decls.push({count: l.f32_count, type: kAstF32}); |
211 } | 227 } |
212 if (l.f64_count > 0) { | 228 if (l.f64_count > 0) { |
213 local_decls.push({count: l.f64_count, type: kAstF64}); | 229 local_decls.push({count: l.f64_count, type: kAstF64}); |
214 } | 230 } |
| 231 } |
| 232 var header = new Array(); |
| 233 |
| 234 emit_varint(header, local_decls.length); |
| 235 for (decl of local_decls) { |
| 236 emit_varint(header, decl.count); |
| 237 emit_u8(header, decl.type); |
| 238 } |
| 239 |
| 240 emit_varint(bytes, header.length + func.body.length); |
| 241 emit_bytes(bytes, header); |
| 242 emit_bytes(bytes, func.body); |
215 } | 243 } |
216 var header = new Array(); | 244 }); |
217 | |
218 emit_varint(header, local_decls.length); | |
219 for (decl of local_decls) { | |
220 emit_varint(header, decl.count); | |
221 emit_u8(header, decl.type); | |
222 } | |
223 | |
224 emit_varint(bytes, header.length + func.body.length); | |
225 emit_bytes(bytes, header); | |
226 emit_bytes(bytes, func.body); | |
227 } | |
228 } | 245 } |
229 | 246 |
230 // emit function names | 247 // emit function names |
231 if (has_names) { | 248 if (has_names) { |
232 if (debug) print("emitting names @ " + bytes.length); | 249 if (debug) print("emitting names @ " + bytes.length); |
233 emit_u8(bytes, kDeclNames); | 250 emit_section(bytes, kDeclNames, function(bytes) { |
234 emit_varint(bytes, this.functions.length); | 251 emit_varint(bytes, wasm.functions.length); |
235 for (func of this.functions) { | 252 for (func of wasm.functions) { |
236 var name = func.name == undefined ? "" : func.name; | 253 var name = func.name == undefined ? "" : func.name; |
237 emit_string(bytes, name); | 254 emit_string(bytes, name); |
238 emit_u8(bytes, 0); // local names count == 0 | 255 emit_u8(bytes, 0); // local names count == 0 |
239 } | 256 } |
| 257 }); |
240 } | 258 } |
241 | 259 |
242 // Add start function section. | 260 // Add start function section. |
243 if (this.start_index != undefined) { | 261 if (wasm.start_index != undefined) { |
244 if (debug) print("emitting start function @ " + bytes.length); | 262 if (debug) print("emitting start function @ " + bytes.length); |
245 emit_u8(bytes, kDeclStartFunction); | 263 emit_section(bytes, kDeclStartFunction, function(bytes) { |
246 emit_varint(bytes, this.start_index); | 264 emit_varint(bytes, wasm.start_index); |
| 265 }); |
247 } | 266 } |
248 | 267 |
249 if (this.function_table.length > 0) { | 268 if (wasm.function_table.length > 0) { |
250 if (debug) print("emitting function table @ " + bytes.length); | 269 if (debug) print("emitting function table @ " + bytes.length); |
251 emit_u8(bytes, kDeclFunctionTable); | 270 emit_section(bytes, kDeclFunctionTable, function(bytes) { |
252 emit_varint(bytes, this.function_table.length); | 271 emit_varint(bytes, wasm.function_table.length); |
253 for (index of this.function_table) { | 272 for (index of wasm.function_table) { |
254 emit_varint(bytes, index); | 273 emit_varint(bytes, index); |
255 } | 274 } |
| 275 }); |
256 } | 276 } |
257 | 277 |
258 if (exports > 0) { | 278 if (exports > 0) { |
259 if (debug) print("emitting exports @ " + bytes.length); | 279 if (debug) print("emitting exports @ " + bytes.length); |
260 emit_u8(bytes, kDeclExportTable); | 280 emit_section(bytes, kDeclExportTable, function(bytes) { |
261 emit_varint(bytes, exports); | 281 emit_varint(bytes, exports); |
262 for (func of this.functions) { | 282 for (func of wasm.functions) { |
263 for (exp of func.exports) { | 283 for (exp of func.exports) { |
264 emit_varint(bytes, func.index); | 284 emit_varint(bytes, func.index); |
265 emit_string(bytes, exp); | 285 emit_string(bytes, exp); |
| 286 } |
266 } | 287 } |
267 } | 288 }); |
268 } | 289 } |
269 | 290 |
270 if (this.data_segments.length > 0) { | 291 if (wasm.data_segments.length > 0) { |
271 if (debug) print("emitting data segments @ " + bytes.length); | 292 if (debug) print("emitting data segments @ " + bytes.length); |
272 emit_u8(bytes, kDeclDataSegments); | 293 emit_section(bytes, kDeclDataSegments, function(bytes) { |
273 emit_varint(bytes, this.data_segments.length); | 294 emit_varint(bytes, wasm.data_segments.length); |
274 for (seg of this.data_segments) { | 295 for (seg of wasm.data_segments) { |
275 emit_varint(bytes, seg.addr); | 296 emit_varint(bytes, seg.addr); |
276 emit_varint(bytes, seg.data.length); | 297 emit_varint(bytes, seg.data.length); |
277 emit_bytes(bytes, seg.data); | 298 emit_bytes(bytes, seg.data); |
278 } | 299 } |
| 300 }); |
279 } | 301 } |
280 | 302 |
281 // Emit any explicitly added sections | 303 // Emit any explicitly added sections |
282 for (exp of this.explicit) { | 304 for (exp of wasm.explicit) { |
283 if (debug) print("emitting explicit @ " + bytes.length); | 305 if (debug) print("emitting explicit @ " + bytes.length); |
284 emit_bytes(bytes, exp); | 306 emit_bytes(bytes, exp); |
285 } | 307 } |
286 | 308 |
287 // End the module. | 309 // End the module. |
288 if (debug) print("emitting end @ " + bytes.length); | 310 if (debug) print("emitting end @ " + bytes.length); |
289 emit_u8(bytes, kDeclEnd); | 311 emit_section(bytes, kDeclEnd, function(bytes) {}); |
290 | 312 |
291 return bytes; | 313 return bytes; |
292 } | 314 } |
293 | 315 |
294 WasmModuleBuilder.prototype.toBuffer = function(debug) { | 316 WasmModuleBuilder.prototype.toBuffer = function(debug) { |
295 var bytes = this.toArray(debug); | 317 var bytes = this.toArray(debug); |
296 var buffer = new ArrayBuffer(bytes.length); | 318 var buffer = new ArrayBuffer(bytes.length); |
297 var view = new Uint8Array(buffer); | 319 var view = new Uint8Array(buffer); |
298 for (var i = 0; i < bytes.length; i++) { | 320 for (var i = 0; i < bytes.length; i++) { |
299 var val = bytes[i]; | 321 var val = bytes[i]; |
300 if ((typeof val) == "string") val = val.charCodeAt(0); | 322 if ((typeof val) == "string") val = val.charCodeAt(0); |
301 view[i] = val | 0; | 323 view[i] = val | 0; |
302 } | 324 } |
303 return buffer; | 325 return buffer; |
304 } | 326 } |
305 | 327 |
306 WasmModuleBuilder.prototype.instantiate = function(ffi, memory) { | 328 WasmModuleBuilder.prototype.instantiate = function(ffi, memory) { |
307 var buffer = this.toBuffer(); | 329 var buffer = this.toBuffer(); |
308 if (memory != undefined) { | 330 if (memory != undefined) { |
309 return Wasm.instantiateModule(buffer, ffi, memory); | 331 return Wasm.instantiateModule(buffer, ffi, memory); |
310 } else { | 332 } else { |
311 return Wasm.instantiateModule(buffer, ffi); | 333 return Wasm.instantiateModule(buffer, ffi); |
312 } | 334 } |
313 } | 335 } |
OLD | NEW |