Source code

Revision control

Copy as Markdown

Other Tools

/*
* 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
*
*
* 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;
/// features and default enabled state
const FEATURES = Object.freeze({
'exceptions': false,
'mutable_globals': true,
'sat_float_to_int': true,
'sign_extension': true,
'simd': true,
'threads': false,
'function_references': false,
'multi_value': true,
'tail_call': false,
'bulk_memory': true,
'reference_types': true,
'annotations': false,
'code_metadata': false,
'gc': false,
'memory64': false,
'multi_memory': false,
'extended_const': false,
'relaxed_simd': false,
});
/// 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 ([f, v] of Object.entries(FEATURES)) {
this[f] = booleanOrDefault(obj[f], v);
}
}
Features.prototype = Object.create(Object.prototype);
Features.prototype.destroy = function() {
Module._wabt_destroy_features(this.addr);
};
Object.keys(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, errors) {
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,
errors.addr);
}
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) {
this.kind = kind;
this.addr = Module._wabt_new_errors();
}
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 errors = new Errors('text');
var lexer = new Lexer(filename, buffer, errors);
errors.lexer = 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;
Module['FEATURES'] = FEATURES;