| OLD | NEW | 
 | (Empty) | 
|    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 |  | 
|    3 // found in the LICENSE file. |  | 
|    4  |  | 
|    5 function StringRef(string) { |  | 
|    6     this.pos = -1; |  | 
|    7     this.string = string; |  | 
|    8 } |  | 
|    9  |  | 
|   10 function DataRef(data) { |  | 
|   11     this.pos = -1; |  | 
|   12     this.data = data; |  | 
|   13 } |  | 
|   14  |  | 
|   15 function WasmFunctionBuilder(name, sig_index) { |  | 
|   16     this.name = name; |  | 
|   17     this.sig_index = sig_index; |  | 
|   18     this.exports = []; |  | 
|   19 } |  | 
|   20  |  | 
|   21 WasmFunctionBuilder.prototype.exportAs = function(name) { |  | 
|   22     this.exports.push(name); |  | 
|   23     return this; |  | 
|   24 } |  | 
|   25  |  | 
|   26 WasmFunctionBuilder.prototype.addBody = function(body) { |  | 
|   27     this.body = body; |  | 
|   28     return this; |  | 
|   29 } |  | 
|   30  |  | 
|   31 WasmFunctionBuilder.prototype.addLocals = function(locals) { |  | 
|   32     this.locals = locals; |  | 
|   33     return this; |  | 
|   34 } |  | 
|   35  |  | 
|   36 function WasmModuleBuilder() { |  | 
|   37     this.signatures = []; |  | 
|   38     this.imports = []; |  | 
|   39     this.functions = []; |  | 
|   40     this.exports = []; |  | 
|   41     this.function_table = []; |  | 
|   42     this.data_segments = []; |  | 
|   43     return this; |  | 
|   44 } |  | 
|   45  |  | 
|   46 WasmModuleBuilder.prototype.addMemory = function(min, max, exp) { |  | 
|   47     this.memory = {min: min, max: max, exp: exp}; |  | 
|   48     return this; |  | 
|   49 } |  | 
|   50  |  | 
|   51 // Add a signature; format is [rettype, param0, param1, ...] |  | 
|   52 WasmModuleBuilder.prototype.addSignature = function(sig) { |  | 
|   53     // TODO: canonicalize signatures? |  | 
|   54     this.signatures.push(sig); |  | 
|   55     return this.signatures.length - 1; |  | 
|   56 } |  | 
|   57  |  | 
|   58 WasmModuleBuilder.prototype.addFunction = function(name, sig) { |  | 
|   59     var sig_index = (typeof sig) == "number" ? sig : this.addSignature(sig); |  | 
|   60     var func = new WasmFunctionBuilder(name, sig_index); |  | 
|   61     func.index = this.functions.length; |  | 
|   62     this.functions.push(func); |  | 
|   63     return func; |  | 
|   64 } |  | 
|   65  |  | 
|   66 WasmModuleBuilder.prototype.addImport = function(name, sig) { |  | 
|   67     var sig_index = (typeof sig) == "number" ? sig : this.addSignature(sig); |  | 
|   68     this.imports.push({name: name, sig_index: sig_index}); |  | 
|   69     return this.imports.length - 1; |  | 
|   70 } |  | 
|   71  |  | 
|   72 WasmModuleBuilder.prototype.addDataSegment = function(addr, data, init) { |  | 
|   73     this.data_segments.push({addr: addr, data: data, init: init}); |  | 
|   74     return this.data_segments.length - 1; |  | 
|   75 } |  | 
|   76  |  | 
|   77 WasmModuleBuilder.prototype.appendToFunctionTable = function(array) { |  | 
|   78     this.function_table = this.function_table.concat(array); |  | 
|   79     return this; |  | 
|   80 } |  | 
|   81  |  | 
|   82 function emit_u8(bytes, val) { |  | 
|   83     bytes.push(val & 0xff); |  | 
|   84 } |  | 
|   85  |  | 
|   86 function emit_u16(bytes, val) { |  | 
|   87     bytes.push(val & 0xff); |  | 
|   88     bytes.push((val >> 8) & 0xff); |  | 
|   89 } |  | 
|   90  |  | 
|   91 function emit_u32(bytes, val) { |  | 
|   92     bytes.push(val & 0xff); |  | 
|   93     bytes.push((val >> 8) & 0xff); |  | 
|   94     bytes.push((val >> 16) & 0xff); |  | 
|   95     bytes.push((val >> 24) & 0xff); |  | 
|   96 } |  | 
|   97  |  | 
|   98 function emit_string(bytes, string) { |  | 
|   99     bytes.push(new StringRef(string)); |  | 
|  100     bytes.push(0); |  | 
|  101     bytes.push(0); |  | 
|  102     bytes.push(0); |  | 
|  103 } |  | 
|  104  |  | 
|  105 function emit_data_ref(bytes, string) { |  | 
|  106     bytes.push(new DataRef(string)); |  | 
|  107     bytes.push(0); |  | 
|  108     bytes.push(0); |  | 
|  109     bytes.push(0); |  | 
|  110 } |  | 
|  111  |  | 
|  112 function emit_varint(bytes, val) { |  | 
|  113     while (true) { |  | 
|  114         var v = val & 0xff; |  | 
|  115         val = val >>> 7; |  | 
|  116         if (val == 0) { |  | 
|  117             bytes.push(v); |  | 
|  118             break; |  | 
|  119         } |  | 
|  120         bytes.push(v | 0x80); |  | 
|  121     } |  | 
|  122 } |  | 
|  123  |  | 
|  124 WasmModuleBuilder.prototype.toArray = function(debug) { |  | 
|  125     // Add header bytes |  | 
|  126     var bytes = []; |  | 
|  127     bytes = bytes.concat([kWasmH0, kWasmH1, kWasmH2, kWasmH3, |  | 
|  128                           kWasmV0, kWasmV1, kWasmV2, kWasmV3]); |  | 
|  129  |  | 
|  130     // Add memory section |  | 
|  131     if (this.memory != undefined) { |  | 
|  132         if (debug) print("emitting memory @ " + bytes.length); |  | 
|  133         emit_u8(bytes, kDeclMemory); |  | 
|  134         emit_varint(bytes, this.memory.min); |  | 
|  135         emit_varint(bytes, this.memory.max); |  | 
|  136         emit_u8(bytes, this.memory.exp ? 1 : 0); |  | 
|  137     } |  | 
|  138  |  | 
|  139     // Add signatures section |  | 
|  140     if (this.signatures.length > 0) { |  | 
|  141         if (debug) print("emitting signatures @ " + bytes.length); |  | 
|  142         emit_u8(bytes, kDeclSignatures); |  | 
|  143         emit_varint(bytes, this.signatures.length); |  | 
|  144         for (sig of this.signatures) { |  | 
|  145             var params = sig.length - 1; |  | 
|  146             emit_u8(bytes, params); |  | 
|  147             for (var j = 0; j < sig.length; j++) { |  | 
|  148                 emit_u8(bytes, sig[j]); |  | 
|  149             } |  | 
|  150         } |  | 
|  151     } |  | 
|  152  |  | 
|  153     // Add imports section |  | 
|  154     if (this.imports.length > 0) { |  | 
|  155         if (debug) print("emitting imports @ " + bytes.length); |  | 
|  156         emit_u8(bytes, kDeclImportTable); |  | 
|  157         emit_varint(bytes, this.imports.length); |  | 
|  158         for (imp of this.imports) { |  | 
|  159             emit_u16(bytes, imp.sig_index); |  | 
|  160             emit_string(bytes, ""); |  | 
|  161             emit_string(bytes, imp.name); |  | 
|  162         } |  | 
|  163     } |  | 
|  164  |  | 
|  165     // Add functions section |  | 
|  166     var names = false; |  | 
|  167     var exports = 0; |  | 
|  168     if (this.functions.length > 0) { |  | 
|  169         if (debug) print("emitting functions @ " + bytes.length); |  | 
|  170         emit_u8(bytes, kDeclFunctions); |  | 
|  171         emit_varint(bytes, this.functions.length); |  | 
|  172         var index = 0; |  | 
|  173         for (func of this.functions) { |  | 
|  174             var flags = 0; |  | 
|  175             var hasName = func.name != undefined && func.name.length > 0; |  | 
|  176             names = names || hasName; |  | 
|  177             if (hasName) flags |= kDeclFunctionName; |  | 
|  178             if (func.locals != undefined) flags |= kDeclFunctionLocals; |  | 
|  179             exports += func.exports.length; |  | 
|  180  |  | 
|  181             emit_u8(bytes, flags); |  | 
|  182             emit_u16(bytes, func.sig_index); |  | 
|  183  |  | 
|  184             if (hasName) { |  | 
|  185                 emit_string(bytes, func.name); |  | 
|  186             } |  | 
|  187             if (func.locals != undefined) { |  | 
|  188                 emit_u16(bytes, func.locals.i32_count); |  | 
|  189                 emit_u16(bytes, func.locals.i64_count); |  | 
|  190                 emit_u16(bytes, func.locals.f32_count); |  | 
|  191                 emit_u16(bytes, func.locals.f64_count); |  | 
|  192             } |  | 
|  193             emit_u16(bytes, func.body.length); |  | 
|  194             for (var i = 0; i < func.body.length; i++) { |  | 
|  195                 emit_u8(bytes, func.body[i]); |  | 
|  196             } |  | 
|  197  |  | 
|  198             index++; |  | 
|  199         } |  | 
|  200     } |  | 
|  201  |  | 
|  202     if (this.function_table.length > 0) { |  | 
|  203         if (debug) print("emitting function table @ " + bytes.length); |  | 
|  204         emit_u8(bytes, kDeclFunctionTable); |  | 
|  205         emit_varint(bytes, this.function_table.length); |  | 
|  206         for (index of this.function_table) { |  | 
|  207             emit_u16(bytes, index); |  | 
|  208         } |  | 
|  209     } |  | 
|  210  |  | 
|  211     if (exports > 0) { |  | 
|  212         if (debug) print("emitting exports @ " + bytes.length); |  | 
|  213         emit_u8(bytes, kDeclExportTable); |  | 
|  214         emit_varint(bytes, exports); |  | 
|  215         for (func of this.functions) { |  | 
|  216             for (exp of func.exports) { |  | 
|  217                 emit_u16(bytes, func.index); |  | 
|  218                 emit_string(bytes, exp); |  | 
|  219             } |  | 
|  220         } |  | 
|  221     } |  | 
|  222  |  | 
|  223     if (this.data_segments.length > 0) { |  | 
|  224         if (debug) print("emitting data segments @ " + bytes.length); |  | 
|  225         emit_u8(bytes, kDeclDataSegments); |  | 
|  226         emit_varint(bytes, this.data_segments.length); |  | 
|  227         for (seg of this.data_segments) { |  | 
|  228             emit_u32(bytes, seg.addr); |  | 
|  229             emit_data_ref(bytes, seg.data); |  | 
|  230             emit_u32(bytes, seg.data.length); |  | 
|  231             emit_u8(bytes, seg.init ? 1 : 0); |  | 
|  232         } |  | 
|  233     } |  | 
|  234  |  | 
|  235     // End the module. |  | 
|  236     if (debug) print("emitting end @ " + bytes.length); |  | 
|  237     emit_u8(bytes, kDeclEnd); |  | 
|  238  |  | 
|  239     // Collect references and canonicalize strings. |  | 
|  240     var strings = new Object(); |  | 
|  241     var data_segments = []; |  | 
|  242     var count = 0; |  | 
|  243     for (var i = 0; i < bytes.length; i++) { |  | 
|  244         var b = bytes[i]; |  | 
|  245         if (b instanceof StringRef) { |  | 
|  246             count++; |  | 
|  247             var prev = strings[b.string]; |  | 
|  248             if (prev) { |  | 
|  249                 bytes[i] = prev; |  | 
|  250             } else { |  | 
|  251                 strings[b.string] = b; |  | 
|  252             } |  | 
|  253         } |  | 
|  254         if (b instanceof DataRef) { |  | 
|  255             data_segments.push(b); |  | 
|  256             count++; |  | 
|  257         } |  | 
|  258     } |  | 
|  259  |  | 
|  260     if (count > 0) { |  | 
|  261         // Emit strings. |  | 
|  262         if (debug) print("emitting strings @ " + bytes.length); |  | 
|  263         for (str in strings) { |  | 
|  264             var ref = strings[str]; |  | 
|  265             if (!(ref instanceof StringRef)) continue; |  | 
|  266             if (debug) print("  \"" + str + "\" @ " + bytes.length); |  | 
|  267             ref.pos = bytes.length; |  | 
|  268             for (var i = 0; i < str.length; i++) { |  | 
|  269                 emit_u8(bytes, str.charCodeAt(i)); |  | 
|  270             } |  | 
|  271             emit_u8(bytes, 0);  // null terminator. |  | 
|  272         } |  | 
|  273         // Emit data. |  | 
|  274         if (debug) print("emitting data @ " + bytes.length); |  | 
|  275         for (ref of data_segments) { |  | 
|  276             ref.pos = bytes.length; |  | 
|  277             for (var i = 0; i < ref.data.length; i++) { |  | 
|  278                 emit_u8(bytes, ref.data[i]); |  | 
|  279             } |  | 
|  280         } |  | 
|  281         // Update references to strings and data. |  | 
|  282         for (var i = 0; i < bytes.length; i++) { |  | 
|  283             var b = bytes[i]; |  | 
|  284             if (b instanceof StringRef || b instanceof DataRef) { |  | 
|  285                 bytes[i] = b.pos & 0xFF; |  | 
|  286                 bytes[i + 1] = (b.pos >> 8) & 0xFF; |  | 
|  287                 bytes[i + 2] = (b.pos >> 16) & 0xFF; |  | 
|  288                 bytes[i + 3] = (b.pos >> 24) & 0xFF; |  | 
|  289             } |  | 
|  290         } |  | 
|  291     } |  | 
|  292  |  | 
|  293     return bytes; |  | 
|  294 } |  | 
|  295  |  | 
|  296 WasmModuleBuilder.prototype.toBuffer = function(debug) { |  | 
|  297     var bytes = this.toArray(debug); |  | 
|  298     var buffer = new ArrayBuffer(bytes.length); |  | 
|  299     var view = new Uint8Array(buffer); |  | 
|  300     for (var i = 0; i < bytes.length; i++) { |  | 
|  301         var val = bytes[i]; |  | 
|  302         if ((typeof val) == "string") val = val.charCodeAt(0); |  | 
|  303         view[i] = val | 0; |  | 
|  304     } |  | 
|  305     return buffer; |  | 
|  306 } |  | 
|  307  |  | 
|  308 WasmModuleBuilder.prototype.instantiate = function(ffi) { |  | 
|  309     var buffer = this.toBuffer(); |  | 
|  310     return _WASMEXP_.instantiateModule(buffer, ffi); |  | 
|  311 } |  | 
| OLD | NEW |