| /* |
| * Copyright 2016 WebAssembly Community Group participants |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| var WABT_OK = 0; |
| var WABT_ERROR = 1; |
| var FEATURES = [ |
| 'exceptions', |
| 'mutable_globals', |
| 'sat_float_to_int', |
| 'sign_extension', |
| 'simd', |
| 'threads', |
| 'multi_value', |
| 'tail_call', |
| 'bulk_memory', |
| 'reference_types', |
| ]; |
| |
| /// If value is not undefined, return it. Otherwise return default_. |
| function maybeDefault(value, default_) { |
| if (value === undefined) { |
| return default_; |
| } |
| return value; |
| } |
| |
| /// Coerce value to boolean if not undefined. Otherwise return default_. |
| function booleanOrDefault(value, default_) { |
| return !!maybeDefault(value, default_); |
| } |
| |
| /// Allocate memory in the Module. |
| function malloc(size) { |
| var addr = Module._malloc(size); |
| if (addr == 0) { |
| throw new Error('out of memory'); |
| } |
| return addr; |
| } |
| |
| /// Convert an ArrayBuffer/TypedArray/string into a buffer that can be |
| /// used by the Module. |
| function allocateBuffer(buf) { |
| var addr; |
| var size; |
| if (buf instanceof ArrayBuffer) { |
| size = buf.byteLength; |
| addr = malloc(size); |
| (new Uint8Array(HEAP8.buffer, addr, size)).set(new Uint8Array(buf)) |
| } else if (ArrayBuffer.isView(buf)) { |
| size = buf.buffer.byteLength; |
| addr = malloc(size); |
| (new Uint8Array(HEAP8.buffer, addr, size)).set(buf); |
| } else if (typeof buf == 'string') { |
| size = buf.length; |
| addr = malloc(size); |
| writeAsciiToMemory(buf, addr, true); // don't null-terminate |
| } else { |
| throw new Error('unknown buffer type: ' + buf); |
| } |
| return {addr: addr, size: size}; |
| } |
| |
| function allocateCString(s) { |
| var size = s.length; |
| var addr = malloc(size); |
| writeAsciiToMemory(s, addr); |
| return {addr: addr, size: size}; |
| } |
| |
| |
| /// Features |
| function Features(obj) { |
| this.addr = Module._wabt_new_features(); |
| for (var i = 0; i < FEATURES.length; ++i) { |
| var feature = FEATURES[i]; |
| this[feature] = obj[feature] | 0; |
| } |
| } |
| Features.prototype = Object.create(Object.prototype); |
| |
| Features.prototype.destroy = function() { |
| Module._wabt_destroy_features(this.addr); |
| }; |
| |
| FEATURES.forEach(function(feature) { |
| Object.defineProperty(Features.prototype, feature, { |
| enumerable: true, |
| get: function() { |
| return Module['_wabt_' + feature + '_enabled'](this.addr); |
| }, |
| set: function(newValue) { |
| Module['_wabt_set_' + feature + '_enabled'](this.addr, newValue | 0); |
| } |
| }); |
| }); |
| |
| |
| /// Lexer |
| function Lexer(filename, buffer) { |
| this.filenameObj = allocateCString(filename); |
| this.bufferObj = allocateBuffer(buffer); |
| this.addr = Module._wabt_new_wast_buffer_lexer( |
| this.filenameObj.addr, this.bufferObj.addr, this.bufferObj.size); |
| } |
| Lexer.prototype = Object.create(Object.prototype); |
| |
| Lexer.prototype.destroy = function() { |
| Module._wabt_destroy_wast_lexer(this.addr); |
| Module._free(this.bufferObj.addr); |
| Module._free(this.filenameObj.addr); |
| }; |
| |
| |
| /// OutputBuffer |
| function OutputBuffer(addr) { |
| this.addr = addr; |
| } |
| OutputBuffer.prototype = Object.create(Object.prototype); |
| |
| OutputBuffer.prototype.toTypedArray = function() { |
| if (!this.addr) { |
| return null; |
| } |
| |
| var addr = Module._wabt_output_buffer_get_data(this.addr); |
| var size = Module._wabt_output_buffer_get_size(this.addr); |
| var buffer = new Uint8Array(size); |
| buffer.set(new Uint8Array(HEAPU8.buffer, addr, size)); |
| return buffer; |
| }; |
| |
| OutputBuffer.prototype.toString = function() { |
| if (!this.addr) { |
| return ''; |
| } |
| |
| var addr = Module._wabt_output_buffer_get_data(this.addr); |
| var size = Module._wabt_output_buffer_get_size(this.addr); |
| return UTF8ToString(addr, size); |
| }; |
| |
| OutputBuffer.prototype.destroy = function() { |
| Module._wabt_destroy_output_buffer(this.addr); |
| }; |
| |
| |
| /// Errors |
| function Errors(kind, lexer) { |
| this.kind = kind; |
| this.addr = Module._wabt_new_errors(); |
| this.lexer = lexer; |
| } |
| Errors.prototype = Object.create(Object.prototype); |
| |
| Errors.prototype.format = function() { |
| var buffer; |
| switch (this.kind) { |
| case 'text': |
| buffer = new OutputBuffer( |
| Module._wabt_format_text_errors(this.addr, this.lexer.addr)); |
| break; |
| case 'binary': |
| buffer = new OutputBuffer(Module._wabt_format_binary_errors(this.addr)); |
| break; |
| default: |
| throw new Error('Invalid Errors kind: ' + this.kind); |
| } |
| var message = buffer.toString(); |
| buffer.destroy(); |
| return message; |
| }; |
| |
| Errors.prototype.destroy = function() { |
| Module._wabt_destroy_errors(this.addr); |
| if (this.lexer) { |
| this.lexer.destroy(); |
| } |
| }; |
| |
| |
| /// parseWat |
| function parseWat(filename, buffer, options) { |
| var lexer = new Lexer(filename, buffer); |
| var errors = new Errors('text', lexer); |
| var features = new Features(options || {}); |
| |
| try { |
| var parseResult_addr = |
| Module._wabt_parse_wat(lexer.addr, features.addr, errors.addr); |
| |
| var result = Module._wabt_parse_wat_result_get_result(parseResult_addr); |
| if (result !== WABT_OK) { |
| throw new Error('parseWat failed:\n' + errors.format()); |
| } |
| |
| var module_addr = |
| Module._wabt_parse_wat_result_release_module(parseResult_addr); |
| var result = new WasmModule(module_addr, errors); |
| // Clear errors so it isn't destroyed below. |
| errors = null; |
| return result; |
| } finally { |
| Module._wabt_destroy_parse_wat_result(parseResult_addr); |
| features.destroy(); |
| if (errors) { |
| errors.destroy(); |
| } |
| } |
| } |
| |
| |
| // readWasm |
| function readWasm(buffer, options) { |
| var bufferObj = allocateBuffer(buffer); |
| var errors = new Errors('binary'); |
| var readDebugNames = booleanOrDefault(options.readDebugNames, false); |
| var features = new Features(options); |
| |
| try { |
| var readBinaryResult_addr = Module._wabt_read_binary( |
| bufferObj.addr, bufferObj.size, readDebugNames, features.addr, |
| errors.addr); |
| |
| var result = |
| Module._wabt_read_binary_result_get_result(readBinaryResult_addr); |
| if (result !== WABT_OK) { |
| throw new Error('readWasm failed:\n' + errors.format()); |
| } |
| |
| var module_addr = |
| Module._wabt_read_binary_result_release_module(readBinaryResult_addr); |
| var result = new WasmModule(module_addr, errors); |
| // Clear errors so it isn't destroyed below. |
| errors = null; |
| return result; |
| } finally { |
| Module._wabt_destroy_read_binary_result(readBinaryResult_addr); |
| features.destroy(); |
| if (errors) { |
| errors.destroy(); |
| } |
| Module._free(bufferObj.addr); |
| } |
| } |
| |
| |
| // WasmModule (can't call it Module because emscripten has claimed it.) |
| function WasmModule(module_addr, errors) { |
| this.module_addr = module_addr; |
| this.errors = errors; |
| } |
| WasmModule.prototype = Object.create(Object.prototype); |
| |
| WasmModule.prototype.validate = function(options) { |
| var features = new Features(options || {}); |
| try { |
| var result = Module._wabt_validate_module( |
| this.module_addr, features.addr, this.errors.addr); |
| if (result !== WABT_OK) { |
| throw new Error('validate failed:\n' + this.errors.format()); |
| } |
| } finally { |
| features.destroy(); |
| } |
| }; |
| |
| WasmModule.prototype.resolveNames = function() { |
| // No-op, this is now part of text parsing. |
| }; |
| |
| WasmModule.prototype.generateNames = function() { |
| var result = Module._wabt_generate_names_module(this.module_addr); |
| if (result !== WABT_OK) { |
| throw new Error('generateNames failed.'); |
| } |
| }; |
| |
| WasmModule.prototype.applyNames = function() { |
| var result = Module._wabt_apply_names_module(this.module_addr); |
| if (result !== WABT_OK) { |
| throw new Error('applyNames failed.'); |
| } |
| }; |
| |
| WasmModule.prototype.toText = function(options) { |
| var foldExprs = booleanOrDefault(options.foldExprs, false); |
| var inlineExport = booleanOrDefault(options.inlineExport, false); |
| |
| var writeModuleResult_addr = |
| Module._wabt_write_text_module(this.module_addr, foldExprs, inlineExport); |
| |
| var result = Module._wabt_write_module_result_get_result( |
| writeModuleResult_addr); |
| |
| try { |
| if (result !== WABT_OK) { |
| throw new Error('toText failed.'); |
| } |
| |
| var outputBuffer = new OutputBuffer( |
| Module._wabt_write_module_result_release_output_buffer( |
| writeModuleResult_addr)); |
| |
| return outputBuffer.toString(); |
| |
| } finally { |
| if (outputBuffer) { |
| outputBuffer.destroy(); |
| } |
| Module._wabt_destroy_write_module_result(writeModuleResult_addr); |
| } |
| }; |
| |
| WasmModule.prototype.toBinary = function(options) { |
| var log = booleanOrDefault(options.log, false); |
| var canonicalize_lebs = booleanOrDefault(options.canonicalize_lebs, true); |
| var relocatable = booleanOrDefault(options.relocatable, false); |
| var write_debug_names = booleanOrDefault(options.write_debug_names, false); |
| |
| var writeModuleResult_addr = Module._wabt_write_binary_module( |
| this.module_addr, log, canonicalize_lebs, relocatable, write_debug_names); |
| |
| var result = |
| Module._wabt_write_module_result_get_result(writeModuleResult_addr); |
| |
| try { |
| if (result !== WABT_OK) { |
| throw new Error('toBinary failed.'); |
| } |
| |
| var binaryOutputBuffer = |
| new OutputBuffer(Module._wabt_write_module_result_release_output_buffer( |
| writeModuleResult_addr)); |
| var logOutputBuffer = new OutputBuffer( |
| Module._wabt_write_module_result_release_log_output_buffer( |
| writeModuleResult_addr)); |
| |
| return { |
| buffer: binaryOutputBuffer.toTypedArray(), |
| log: logOutputBuffer.toString() |
| }; |
| |
| } finally { |
| if (binaryOutputBuffer) { |
| binaryOutputBuffer.destroy(); |
| } |
| if (logOutputBuffer) { |
| logOutputBuffer.destroy(); |
| } |
| Module._wabt_destroy_write_module_result(writeModuleResult_addr); |
| } |
| }; |
| |
| WasmModule.prototype.destroy = function() { |
| Module._wabt_destroy_module(this.module_addr); |
| if (this.errors) { |
| this.errors.destroy(); |
| } |
| }; |
| |
| Module['parseWat'] = parseWat; |
| Module['readWasm'] = readWasm; |