diff --git a/README.md b/README.md index fb0226aee60..3e77e611de8 100644 --- a/README.md +++ b/README.md @@ -280,13 +280,33 @@ as a translation of ) ``` -You can also tell wasm2js to optimize, using the normal optimization flags -wasm-opt and other tools receive (such as `-Os`). For optimal code size, -you should both optimize and run a JavaScript minifier afterwards. +wasm2js's output is in ES6 module format - basically, it converts a wasm +module into an ES6 module (to run on older browsers and Node.js versions +you can use Babel etc. to convert it to ES5). Let's look at a full example +of calling that hello world wast; first, create the main JS file: -Things to keep in mind with wasm2js's output: +```javascript +// main.mjs +import { add } from "./hello_world.mjs"; +console.log('the sum of 1 and 2 is:', add(1, 2)); +``` + +The run this (note that you need a new enough Node.js with ES6 module +support): + +```shell +$ bin/wasm2js test/hello_world.wast -o hello_world.mjs +$ node --experimental-modules main.mjs +the sum of 1 and 2 is: 3 +``` + +Things keep to in mind with wasm2js's output: - * It is not possible to match WebAssemblty semantics 100% precisely with fast + * You should run wasm2js with optimizations for release builds, using `-O` + or another optimization level. That will optimize along the entire pipeline + (wasm and JS). It won't do everything a JS minifer would, though, like + minify whitespace, so you should still run a normal JS minifer afterwards. + * It is not possible to match WebAssembly semantics 100% precisely with fast JavaScript code. For example, every load and store may trap, and to make JavaScript do the same we'd need to add checks everywhere, which would be large and slow. Instead, wasm2js assumes loads and stores do not trap, that diff --git a/scripts/test/mod.ule.js b/scripts/test/mod.ule.js new file mode 100644 index 00000000000..785cce78af6 --- /dev/null +++ b/scripts/test/mod.ule.js @@ -0,0 +1,4 @@ + +export function ba_se() { + console.log('"mod.ule"."ba.se"'); +} diff --git a/scripts/test/node-esm-loader.mjs b/scripts/test/node-esm-loader.mjs index 8cd72282299..5d41033fb80 100644 --- a/scripts/test/node-esm-loader.mjs +++ b/scripts/test/node-esm-loader.mjs @@ -16,9 +16,8 @@ export function resolve(specifier, parentModuleURL = baseURL, defaultResolve) { format: 'builtin' }; } - // Resolve the 'spectest' and 'env' modules to our custom implementations of - // various builtins. - if (specifier == 'spectest' || specifier == 'env') { + // Resolve special modules used in our test suite. + if (specifier == 'spectest' || specifier == 'env' || specifier == 'mod.ule') { const resolved = new URL('./scripts/test/' + specifier + '.js', parentModuleURL); return { url: resolved.href, diff --git a/src/wasm2js.h b/src/wasm2js.h index b1548c0cae1..e032ac26dab 100644 --- a/src/wasm2js.h +++ b/src/wasm2js.h @@ -2087,7 +2087,8 @@ void Wasm2JSGlue::emitPreES6() { } baseModuleMap[base] = module; - out << "import { " << base.str << " } from '" << module.str << "';\n"; + out << "import { " << asmangle(base.str) << " } from '" << module.str + << "';\n"; }; ImportInfo imports(wasm); @@ -2185,7 +2186,7 @@ void Wasm2JSGlue::emitPostES6() { if (ABI::wasm2js::isScratchMemoryHelper(import->base)) { return; } - out << "," << import->base.str; + out << "," << asmangle(import->base.str); }); out << "},mem" << moduleName.str << ");\n"; diff --git a/test/wasm2js/dot_import.2asm.js b/test/wasm2js/dot_import.2asm.js new file mode 100644 index 00000000000..87b9971ea27 --- /dev/null +++ b/test/wasm2js/dot_import.2asm.js @@ -0,0 +1,37 @@ +import { ba_se } from 'mod.ule'; + +function asmFunc(global, env, buffer) { + var HEAP8 = new global.Int8Array(buffer); + var HEAP16 = new global.Int16Array(buffer); + var HEAP32 = new global.Int32Array(buffer); + var HEAPU8 = new global.Uint8Array(buffer); + var HEAPU16 = new global.Uint16Array(buffer); + var HEAPU32 = new global.Uint32Array(buffer); + var HEAPF32 = new global.Float32Array(buffer); + var HEAPF64 = new global.Float64Array(buffer); + var Math_imul = global.Math.imul; + var Math_fround = global.Math.fround; + var Math_abs = global.Math.abs; + var Math_clz32 = global.Math.clz32; + var Math_min = global.Math.min; + var Math_max = global.Math.max; + var Math_floor = global.Math.floor; + var Math_ceil = global.Math.ceil; + var Math_sqrt = global.Math.sqrt; + var abort = env.abort; + var nan = global.NaN; + var infinity = global.Infinity; + var base = env.ba_se; + function $0() { + base(); + } + + var FUNCTION_TABLE = []; + return { + "exported": $0 + }; +} + +var memasmFunc = new ArrayBuffer(65536); +var retasmFunc = asmFunc({Math,Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array,NaN,Infinity}, {abort:function() { throw new Error('abort'); },ba_se},memasmFunc); +export var exported = retasmFunc.exported; diff --git a/test/wasm2js/dot_import.2asm.js.opt b/test/wasm2js/dot_import.2asm.js.opt new file mode 100644 index 00000000000..87b9971ea27 --- /dev/null +++ b/test/wasm2js/dot_import.2asm.js.opt @@ -0,0 +1,37 @@ +import { ba_se } from 'mod.ule'; + +function asmFunc(global, env, buffer) { + var HEAP8 = new global.Int8Array(buffer); + var HEAP16 = new global.Int16Array(buffer); + var HEAP32 = new global.Int32Array(buffer); + var HEAPU8 = new global.Uint8Array(buffer); + var HEAPU16 = new global.Uint16Array(buffer); + var HEAPU32 = new global.Uint32Array(buffer); + var HEAPF32 = new global.Float32Array(buffer); + var HEAPF64 = new global.Float64Array(buffer); + var Math_imul = global.Math.imul; + var Math_fround = global.Math.fround; + var Math_abs = global.Math.abs; + var Math_clz32 = global.Math.clz32; + var Math_min = global.Math.min; + var Math_max = global.Math.max; + var Math_floor = global.Math.floor; + var Math_ceil = global.Math.ceil; + var Math_sqrt = global.Math.sqrt; + var abort = env.abort; + var nan = global.NaN; + var infinity = global.Infinity; + var base = env.ba_se; + function $0() { + base(); + } + + var FUNCTION_TABLE = []; + return { + "exported": $0 + }; +} + +var memasmFunc = new ArrayBuffer(65536); +var retasmFunc = asmFunc({Math,Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array,NaN,Infinity}, {abort:function() { throw new Error('abort'); },ba_se},memasmFunc); +export var exported = retasmFunc.exported; diff --git a/test/wasm2js/dot_import.wast b/test/wasm2js/dot_import.wast new file mode 100644 index 00000000000..46c843fdedb --- /dev/null +++ b/test/wasm2js/dot_import.wast @@ -0,0 +1,6 @@ +(module + (import "mod.ule" "ba.se" (func $base)) + (func "exported" + (call $base) + ) +)