// test.wasm is the following: // (module // (func $div_s (param i32) (param i32) (result i32) // (get_local 0) // (get_local 1) // (i32.div_s) // ) // (func $div_u (param i32) (param i32) (result i32) // (get_local 0) // (get_local 1) // (i32.div_u) // ) // (func $echo (param i32) (result i32) // (get_local 0) // ) // (export "echo" (func $echo)) // (export "div_s" (func $div_s)) // (export "div_u" (func $div_u)) // ) fetch('test.wasm').then(response => response.arrayBuffer() ).then(bytes => WebAssembly.instantiate(bytes) ).then(module => { const {div_s, div_u, echo} = module.instance.exports; // As per the wasm spec, the ToWebAssemblyValue algoritm coerces a JS value // into a wasm value // https://webassembly.github.io/spec/js-api/index.html#exported-function-exotic-objects // for i32, this is the ToInt32 as described here: // https://tc39.github.io/ecma262/#sec-toint32 const positiveMod = (a, n) => { const remain = a % n; return remain > 0 ? remain : remain + n; }; const toWebAssemblyValue = value => { const sign = value > 0 ? 1 : -1; const ints = sign * Math.floor(Math.abs(value)); const int32bit = positiveMod(ints, Math.pow(2, 32)); return int32bit >= Math.pow(2, 31) ? int32bit - Math.pow(2, 32) : int32bit; }; // The inverse algorithm, ToJSValue, is slighty more vaguelly described // as " the Number value for i32" // my guess is that this is the following conversion const toJSValue = value => value | 0; // testing the conversion to wasm and back to JS, via a simple echo function // that simply returns the input argument const value = 335991768761; console.log("echo wasm", m.exports.echo(value)); console.log("echo js", toJSValue(toWebAssemblyValue(value))); // this works just fine! // unsigned division - here's a problem case (found through random number testing) const a = 335991768761; const b = 77022195821; console.log("div_u wasm", m.exports.div_u(a, b)); console.log("div_u js", toJSValue(div_u(toWebAssemblyValue(a), toWebAssemblyValue(b))) ); // these give a different result :-( });