diff --git a/emcc.py b/emcc.py index e8c437fa19e56..b63155db0d295 100755 --- a/emcc.py +++ b/emcc.py @@ -2019,6 +2019,9 @@ def check_human_readable_list(items): # requires JS legalization shared.Settings.LEGALIZE_JS_FFI = 0 + if shared.Settings.WASM_BIGINT: + shared.Settings.LEGALIZE_JS_FFI = 0 + if shared.Settings.WASM_BACKEND: if shared.Settings.SIMD: newargs.append('-msimd128') diff --git a/emscripten.py b/emscripten.py index 02d152213f3dc..9b4e472f4d7f7 100644 --- a/emscripten.py +++ b/emscripten.py @@ -2327,6 +2327,8 @@ def finalize_wasm(temp_files, infile, outfile, memfile, DEBUG): # (which matches what llvm+lld has given us) if shared.Settings.DEBUG_LEVEL >= 2 or shared.Settings.PROFILING_FUNCS or shared.Settings.EMIT_SYMBOL_MAP or shared.Settings.ASYNCIFY_WHITELIST or shared.Settings.ASYNCIFY_BLACKLIST: args.append('-g') + if shared.Settings.WASM_BIGINT: + args.append('--bigint') if shared.Settings.LEGALIZE_JS_FFI != 1: args.append('--no-legalize-javascript-ffi') if not shared.Settings.MEM_INIT_IN_WASM: diff --git a/src/closure-externs/closure-externs.js b/src/closure-externs/closure-externs.js index aa452438948be..9456722f9112a 100644 --- a/src/closure-externs/closure-externs.js +++ b/src/closure-externs/closure-externs.js @@ -994,3 +994,7 @@ var threadInfoStruct; var selfThreadId; /** @suppress {duplicate} */ var noExitRuntime; + +// No BigInt in closure yet +// https://github.com/google/closure-compiler/issues/3167 +var BigInt; diff --git a/src/library_syscall.js b/src/library_syscall.js index aa78173df7bcb..5e988bf31a828 100644 --- a/src/library_syscall.js +++ b/src/library_syscall.js @@ -1390,7 +1390,9 @@ var SyscallsLibrary = { FS.utime(path, atime, mtime); return 0; }, - __sys_fallocate: function(fd, mode, off_low, off_high, len_low, len_high) { + __sys_fallocate: function(fd, mode, {{{ defineI64Param('off') }}}, {{{ defineI64Param('len') }}}) { + {{{ receiveI64ParamAsI32s('off') }}} + {{{ receiveI64ParamAsI32s('len') }}} var stream = SYSCALLS.getStreamFromFD(fd) var offset = SYSCALLS.get64(off_low, off_high); var len = SYSCALLS.get64(len_low, len_high); @@ -1522,7 +1524,8 @@ var SyscallsLibrary = { return 0; }, fd_seek__sig: 'iiiiii', - fd_seek: function(fd, offset_low, offset_high, whence, newOffset) { + fd_seek: function(fd, {{{ defineI64Param('offset') }}}, whence, newOffset) { + {{{ receiveI64ParamAsI32s('offset') }}} var stream = SYSCALLS.getStreamFromFD(fd); var HIGH_OFFSET = 0x100000000; // 2^32 // use an unsigned operator on low and shift high by 32-bits diff --git a/src/library_wasi.js b/src/library_wasi.js index ca0519f4edbf4..7faae63f19341 100644 --- a/src/library_wasi.js +++ b/src/library_wasi.js @@ -103,7 +103,8 @@ var WasiLibrary = { // either wait for BigInt support or to legalize on the client. clock_time_get__sig: 'iiiii', clock_time_get__deps: ['emscripten_get_now', 'emscripten_get_now_is_monotonic', '__setErrNo'], - clock_time_get: function(clk_id, precision_l, precision_h, ptime) { + clock_time_get: function(clk_id, {{{ defineI64Param('precision') }}}, ptime) { + {{{ receiveI64ParamAsI32s('precision') }}} var now; if (clk_id === {{{ cDefine('__WASI_CLOCKID_REALTIME') }}}) { now = Date.now(); diff --git a/src/library_webgpu.js b/src/library_webgpu.js index 99eee7ad45816..135eff8b06088 100644 --- a/src/library_webgpu.js +++ b/src/library_webgpu.js @@ -958,7 +958,8 @@ var LibraryWebGPU = { // wgpuFence - wgpuFenceOnCompletion: function(fenceId, completionValue_l, completionValue_h, callback, userdata) { + wgpuFenceOnCompletion: function(fenceId, {{{ defineI64Param('completionValue') }}}, callback, userdata) { + {{{ receiveI64ParamAsI32s('completionValue') }}} var fence = WebGPU.mgrFence.get(fenceId); var completionValue = {{{ gpu.makeU64ToNumber('completionValue_l', 'completionValue_h') }}}; @@ -990,7 +991,8 @@ var LibraryWebGPU = { return WebGPU.mgrFence.create(queue.createFence(desc)); }, - wgpuQueueSignal: function(queueId, fenceId, signalValue_l, signalValue_h) { + wgpuQueueSignal: function(queueId, fenceId, {{{ defineI64Param('signalValue') }}}) { + {{{ receiveI64ParamAsI32s('signalValue') }}} var queue = WebGPU.mgrQueue.get(queueId); var fence = WebGPU.mgrFence.get(fenceId); var signalValue = {{{ gpu.makeU64ToNumber('signalValue_l', 'signalValue_h') }}}; @@ -1135,7 +1137,10 @@ var LibraryWebGPU = { return WebGPU.mgrRenderPassEncoder.create(commandEncoder["beginRenderPass"](desc)); }, - wgpuCommandEncoderCopyBufferToBuffer: function(encoderId, srcId, srcOffset_l, srcOffset_h, dstId, dstOffset_l, dstOffset_h, size_l, size_h) { + wgpuCommandEncoderCopyBufferToBuffer: function(encoderId, srcId, {{{ defineI64Param('srcOffset') }}}, dstId, {{{ defineI64Param('dstOffset') }}}, {{{ defineI64Param('size') }}}) { + {{{ receiveI64ParamAsI32s('srcOffset') }}} + {{{ receiveI64ParamAsI32s('dstOffset') }}} + {{{ receiveI64ParamAsI32s('size') }}} var commandEncoder = WebGPU.mgrCommandEncoder.get(encoderId); var src = WebGPU.mgrBuffer.get(srcId); var dst = WebGPU.mgrBuffer.get(dstId); @@ -1168,7 +1173,9 @@ var LibraryWebGPU = { // wgpuBuffer - wgpuBufferSetSubData: function(bufferId, start_l, start_h, count_l, count_h, data) { + wgpuBufferSetSubData: function(bufferId, {{{ defineI64Param('start') }}}, {{{ defineI64Param('count') }}}, data) { + {{{ receiveI64ParamAsI32s('start') }}} + {{{ receiveI64ParamAsI32s('count') }}} var buffer = WebGPU.mgrBuffer.get(bufferId); var start = {{{ gpu.makeU64ToNumber('start_l', 'start_h') }}}; var count = {{{ gpu.makeU64ToNumber('count_l', 'count_h') }}}; @@ -1187,7 +1194,7 @@ var LibraryWebGPU = { var dataLength_h = (mapped.byteLength / 0x100000000) | 0; var dataLength_l = mapped.byteLength | 0; // WGPUBufferMapAsyncStatus status, const void* data, uint64_t dataLength, void* userdata - dynCall('viiji', callback, [WEBGPU_BUFFER_MAP_ASYNC_STATUS_SUCCESS, data, dataLength_l, dataLength_h, userdata]); + dynCall('viiji', callback, [WEBGPU_BUFFER_MAP_ASYNC_STATUS_SUCCESS, data, {{{ sendI64Argument('dataLength_l', 'dataLength_h') }}}, userdata]); }, function() { // TODO(kainino0x): Figure out how to pick other error status values. var WEBGPU_BUFFER_MAP_ASYNC_STATUS_ERROR = 1; @@ -1208,7 +1215,7 @@ var LibraryWebGPU = { var dataLength_h = (mapped.byteLength / 0x100000000) | 0; var dataLength_l = mapped.byteLength | 0; // WGPUBufferMapAsyncStatus status, void* data, uint64_t dataLength, void* userdata - dynCall('viiji', callback, [WEBGPU_BUFFER_MAP_ASYNC_STATUS_SUCCESS, data, dataLength_l, dataLength_h, userdata]); + dynCall('viiji', callback, [WEBGPU_BUFFER_MAP_ASYNC_STATUS_SUCCESS, data, {{{ sendI64Argument('dataLength_l', 'dataLength_h') }}}, userdata]); }, function() { // TODO(kainino0x): Figure out how to pick other error status values. dynCall('viiji', callback, [WEBGPU_BUFFER_MAP_ASYNC_STATUS_ERROR, 0, 0, 0, userdata]); @@ -1271,7 +1278,8 @@ var LibraryWebGPU = { var pass = WebGPU.mgrComputePassEncoder.get(passId); pass["dispatch"](x, y, z); }, - wgpuComputePassEncoderDispatchIndirect: function(passId, indirectBufferId, indirectOffset_l, indirectOffset_h) { + wgpuComputePassEncoderDispatchIndirect: function(passId, indirectBufferId, {{{ defineI64Param('indirectOffset') }}}) { + {{{ receiveI64ParamAsI32s('indirectOffset') }}} var indirectBuffer = WebGPU.mgrBuffer.get(indirectBufferId); var indirectOffset = {{{ gpu.makeU64ToNumber('indirectOffset_l', 'indirectOffset_h') }}}; var pass = WebGPU.mgrComputePassEncoder.get(passId); @@ -1336,13 +1344,15 @@ var LibraryWebGPU = { var pass = WebGPU.mgrRenderPassEncoder.get(passId); pass["drawIndexed"](indexCount, instanceCount, firstIndex, baseVertex, firstInstance); }, - wgpuRenderPassEncoderDrawIndirect: function(passId, indirectBufferId, indirectOffset_l, indirectOffset_h) { + wgpuRenderPassEncoderDrawIndirect: function(passId, indirectBufferId, {{{ defineI64Param('indirectOffset') }}}) { + {{{ receiveI64ParamAsI32s('indirectOffset') }}} var indirectBuffer = WebGPU.mgrBuffer.get(indirectBufferId); var indirectOffset = {{{ gpu.makeU64ToNumber('indirectOffset_l', 'indirectOffset_h') }}}; var pass = WebGPU.mgrRenderPassEncoder.get(passId); pass["drawIndirect"](indirectBuffer, indirectOffset); }, - wgpuRenderPassEncoderDrawIndexedIndirect: function(passId, indirectBufferId, indirectOffset_l, indirectOffset_h) { + wgpuRenderPassEncoderDrawIndexedIndirect: function(passId, indirectBufferId, {{{ defineI64Param('indirectOffset') }}}) { + {{{ receiveI64ParamAsI32s('indirectOffset') }}} var indirectBuffer = WebGPU.mgrBuffer.get(indirectBufferId); var indirectOffset = {{{ gpu.makeU64ToNumber('indirectOffset_l', 'indirectOffset_h') }}}; var pass = WebGPU.mgrRenderPassEncoder.get(passId); @@ -1379,7 +1389,8 @@ var LibraryWebGPU = { pass["setBindGroup"](groupIndex, group, offsets); } }, - wgpuRenderBundleEncoderSetIndexBuffer: function(bundleId, bufferId, offset_l, offset_h) { + wgpuRenderBundleEncoderSetIndexBuffer: function(bundleId, bufferId, {{{ defineI64Param('offset') }}}) { + {{{ receiveI64ParamAsI32s('offset') }}} var offset = {{{ gpu.makeU64ToNumber('offset_l', 'offset_h') }}}; var pass = WebGPU.mgrRenderBundleEncoder.get(bundleId); var buffer = WebGPU.mgrBuffer.get(bufferId); @@ -1390,7 +1401,8 @@ var LibraryWebGPU = { var pipeline = WebGPU.mgrRenderPipeline.get(pipelineId); pass["setPipeline"](pipeline); }, - wgpuRenderBundleEncoderSetVertexBuffer: function(bundleId, slot, bufferId, offset_l, offset_h) { + wgpuRenderBundleEncoderSetVertexBuffer: function(bundleId, slot, bufferId, {{{ defineI64Param('offset') }}}) { + {{{ receiveI64ParamAsI32s('offset') }}} var offset = {{{ gpu.makeU64ToNumber('offset_l', 'offset_h') }}}; var pass = WebGPU.mgrRenderBundleEncoder.get(bundleId); pass["setVertexBuffer"](slot, WebGPU.mgrBuffer.get(bufferId), offset); diff --git a/src/parseTools.js b/src/parseTools.js index f01fc23efa5e2..b493280b2e5ef 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -1677,3 +1677,34 @@ function makeAsmImportsAccessInPthread(variable) { function hasExportedFunction(func) { return Object.keys(EXPORTED_FUNCTIONS).indexOf(func) != -1; } + +// JS API I64 param handling: if we have BigInt support, the ABI is simple, +// it is a BigInt. Otherwise, we legalize into pairs of i32s. +function defineI64Param(name) { + if (WASM_BIGINT) { + return name + '_bigint'; + } else { + return name + '_low, ' + name + '_high'; + } +} + +function receiveI64ParamAsI32s(name) { + if (WASM_BIGINT) { + // TODO: use Xn notation when JS parsers support it (as of April 6 2020, + // * closure compiler is missing support + // https://github.com/google/closure-compiler/issues/3167 + // * acorn needs to be upgraded, and to set ecmascript version >= 11 + // * terser needs to be upgraded + return 'var ' + name + '_low = Number(' + name + '_bigint & BigInt(0xffffffff)) | 0, ' + name + '_high = Number(' + name + '_bigint >> BigInt(32)) | 0;'; + } else { + return ''; + } +} + +function sendI64Argument(low, high) { + if (WASM_BIGINT) { + return 'BigInt(low) | (BigInt(high) << BigInt(32))'; + } else { + return low + ', ' + high; + } +} diff --git a/src/settings.js b/src/settings.js index 36e8ad29d09c5..e1394ee11b48e 100644 --- a/src/settings.js +++ b/src/settings.js @@ -1317,6 +1317,11 @@ var BINARYEN_EXTRA_PASSES = ""; // (This option was formerly called BINARYEN_ASYNC_COMPILATION) var WASM_ASYNC_COMPILATION = 1; +// WebAssembly integration with JavaScript BigInt. When enabled we don't need +// to legalize i64s into pairs of i32s, as the wasm VM will use a BigInt where +// an i64 is used. +var WASM_BIGINT = 0; + // WebAssembly defines a "producers section" which compilers and tools can // annotate themselves in. Emscripten does not emit this by default, as it // increases code size, and some users may not want information about their tools diff --git a/src/support.js b/src/support.js index d8566ad950bd2..ecd5a671151b6 100644 --- a/src/support.js +++ b/src/support.js @@ -444,9 +444,13 @@ function loadWebAssemblyModule(binary, flags) { var moduleLocal = {}; var resolveSymbol = function(sym, type, legalized) { +#if WASM_BIGINT + assert(!legalized); +#else if (legalized) { sym = 'orig$' + sym; } +#endif var resolved = Module["asm"][sym]; if (!resolved) { @@ -460,7 +464,7 @@ function loadWebAssemblyModule(binary, flags) { #if ASSERTIONS assert(resolved, 'missing linked ' + type + ' `' + sym + '`. perhaps a side module was not linked in? if this global was expected to arrive from a system library, try to build the MAIN_MODULE with EMCC_FORCE_STDLIBS=1 in the environment'); #endif - } + } return resolved; } @@ -510,7 +514,11 @@ function loadWebAssemblyModule(binary, flags) { assert(parts.length == 3) var name = parts[1]; var sig = parts[2]; +#if WASM_BIGINT + var legalized = false; +#else var legalized = sig.indexOf('j') >= 0; // check for i64s +#endif var fp = 0; return obj[prop] = function() { if (!fp) { diff --git a/tests/core/test_i64_invoke_bigint.cpp b/tests/core/test_i64_invoke_bigint.cpp new file mode 100644 index 0000000000000..0db35fa0a2334 --- /dev/null +++ b/tests/core/test_i64_invoke_bigint.cpp @@ -0,0 +1,29 @@ + +#include +#include +#include + +int64_t big = 0x12345678aabbccddL; + +__attribute__((noinline)) +int64_t foobar(int64_t x, int y) { + x += EM_ASM_INT({ + return 0; // prevents llvm from seeing the final value + }); + if (x == 1337) { + throw 1; // looks like we might throw + } + return x + y; // use the int parameter too, to show they are all handled +} + +int main() { + int64_t x; + try { + puts("try"); + x = foobar(big, 1); + } catch(int) { + puts("caught"); + } + printf("ok: 0x%llx.\n", x); +} + diff --git a/tests/core/test_i64_invoke_bigint.txt b/tests/core/test_i64_invoke_bigint.txt new file mode 100644 index 0000000000000..70f9aac54985f --- /dev/null +++ b/tests/core/test_i64_invoke_bigint.txt @@ -0,0 +1,2 @@ +try +ok: 0x12345678aabbccde. diff --git a/tests/return64bit/test.c b/tests/return64bit/test.c index 6250bcf287d31..8942ab368b346 100644 --- a/tests/return64bit/test.c +++ b/tests/return64bit/test.c @@ -5,8 +5,17 @@ * found in the LICENSE file. */ -// This is just a trivial test function, the key bit of interest is that it returns a 64 bit long. -long long test_return64() { - long long x = ((long long)1234 << 32) + 5678; - return x; +#include +#include +#include + +int64_t test_return64(int64_t input) { + int64_t x = ((int64_t)1234 << 32) + 5678; + printf("input = 0x%llx\n", input); + return x; +} + +EMSCRIPTEN_KEEPALIVE +void* get_func_ptr() { + return &test_return64; } diff --git a/tests/return64bit/testbind.js b/tests/return64bit/testbind.js index 7a795c1ae4649..8b595772cbe34 100644 --- a/tests/return64bit/testbind.js +++ b/tests/return64bit/testbind.js @@ -8,11 +8,14 @@ var Module = { }; Module['runtest'] = function() { - var low = _test_return64(); - var high = getTempRet0(); + var low = _test_return64(0x11223344, 0xaabbccdd); + var high = getTempRet0(); + console.log("low = " + low); + console.log("high = " + high); - console.log("low = " + low); - console.log("high = " + high); + var ptr = _get_func_ptr(); + low = dynCall_jj(ptr, 0x12345678, 0xabcdef19); + high = getTempRet0(); + console.log("low = " + low); + console.log("high = " + high); }; - - diff --git a/tests/return64bit/testbind_bigint.js b/tests/return64bit/testbind_bigint.js new file mode 100644 index 0000000000000..6fe717397cb40 --- /dev/null +++ b/tests/return64bit/testbind_bigint.js @@ -0,0 +1,25 @@ +// This code represents a simple native JavaScript binding to a test C function +// that returns a 64 bit long. Notice that the least significant 32 bits are +// returned in the normal return value, but the most significant 32 bits are +// returned via the accessor method Runtime.getTempRet0() + +var Module = { + 'noExitRuntime' : true +}; + +Module['runtest'] = function() { + // Use eval to create BigInt, as no support for Xn notation yet in JS + // optimizer. + var bigint = _test_return64(eval('0xaabbccdd11223344n')); + var low = Number(bigint & BigInt(0xffffffff)); + var high = Number(bigint >> BigInt(32)); + console.log("low = " + low); + console.log("high = " + high); + + var ptr = _get_func_ptr(); + bigint = dynCall_jj(ptr, eval('0xabcdef1912345678n')); + low = Number(bigint & BigInt(0xffffffff)); + high = Number(bigint >> BigInt(32)); + console.log("low = " + low); + console.log("high = " + high); +}; diff --git a/tests/test_core.py b/tests/test_core.py index 71a44461d6761..80b998b5931a6 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -74,6 +74,16 @@ def decorated(self): return decorated +def also_with_wasm_bigint(f): + def decorated(self): + self.set_setting('WASM_BIGINT', 0) + f(self, None) + if self.is_wasm_backend() and self.get_setting('WASM'): + self.set_setting('WASM_BIGINT', 1) + f(self, [NODE_JS + ['--experimental-wasm-bigint']]) + return decorated + + # without EMTEST_ALL_ENGINES set we only run tests in a single VM by # default. in some tests we know that cross-VM differences may happen and # so are worth testing, and they should be marked with this decorator @@ -439,6 +449,14 @@ def test_i64_varargs(self): args='waka fleefl asdfasdfasdfasdf' .split(' ')) + @no_fastcomp('wasm bigint') + @no_wasm2js('wasm_bigint') + def test_i64_invoke_bigint(self): + self.set_setting('WASM_BIGINT', 1) + self.emcc_args += ['-fexceptions'] + self.do_run_in_out_file_test('tests', 'core', 'test_i64_invoke_bigint', + js_engines=[NODE_JS + ['--experimental-wasm-bigint']]) + def test_vararg_copy(self): self.do_run_in_out_file_test('tests', 'va_arg', 'test_va_copy') @@ -4101,7 +4119,8 @@ def test_dylink_i64_b(self): ''', 'other says -1311768467750121224.\nmy fp says: 43.\nmy second fp says: 43.') @needs_dlfcn - def test_dylink_i64_c(self): + @also_with_wasm_bigint + def test_dylink_i64_c(self, js_engines): self.dylink_test(r''' #include #include @@ -4149,7 +4168,7 @@ def test_dylink_i64_c(self): #include EMSCRIPTEN_KEEPALIVE int32_t function_ret_32(int32_t i, int32_t j, int32_t k); EMSCRIPTEN_KEEPALIVE int64_t function_ret_64(int32_t i, int32_t j, int32_t k); - ''') + ''', js_engines=js_engines) @needs_dlfcn def test_dylink_class(self): @@ -5243,10 +5262,11 @@ def test_utf8(self): ['UTF8ToString', 'stringToUTF8', 'AsciiToString', 'stringToAscii']) self.do_run(open(path_from_root('tests', 'utf8.cpp')).read(), 'OK.') - def test_utf8_textdecoder(self): + @also_with_wasm_bigint + def test_utf8_textdecoder(self, js_engines): self.set_setting('EXTRA_EXPORTED_RUNTIME_METHODS', ['UTF8ToString', 'stringToUTF8']) self.emcc_args += ['--embed-file', path_from_root('tests/utf8_corpus.txt') + '@/utf8_corpus.txt'] - self.do_run(open(path_from_root('tests', 'benchmark_utf8.cpp')).read(), 'OK.') + self.do_run(open(path_from_root('tests', 'benchmark_utf8.cpp')).read(), 'OK.', js_engines=js_engines) # Test that invalid character in UTF8 does not cause decoding to crash. def test_utf8_invalid(self): @@ -5558,18 +5578,19 @@ def test_unistd_sleep(self): expected = open(path_from_root('tests', 'unistd', 'sleep.out')).read() self.do_run(src, expected) - def test_unistd_io(self): + @also_with_wasm_bigint + def test_unistd_io(self, js_engines): self.set_setting('INCLUDE_FULL_LIBRARY', 1) # uses constants from ERRNO_CODES self.set_setting('ERROR_ON_UNDEFINED_SYMBOLS', 0) # avoid errors when linking in full library - self.clear() orig_compiler_opts = self.emcc_args[:] src = open(path_from_root('tests', 'unistd', 'io.c')).read() expected = open(path_from_root('tests', 'unistd', 'io.out')).read() for fs in ['MEMFS', 'NODEFS']: + self.clear() self.emcc_args = orig_compiler_opts + ['-D' + fs] if fs == 'NODEFS': self.emcc_args += ['-lnodefs.js'] - self.do_run(src, expected, js_engines=[NODE_JS]) + self.do_run(src, expected, js_engines=js_engines) @no_windows('https://github.com/emscripten-core/emscripten/issues/8882') def test_unistd_misc(self): diff --git a/tests/test_other.py b/tests/test_other.py index 947a532a09c31..3bcceff4772d5 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -7207,7 +7207,12 @@ def test(page_diff): # default maximum memory is 2GB. self.assertEqual(less, none) - def test_sixtyfour_bit_return_value(self): + @no_fastcomp('depends on wasm-emscripten-finalize') + @parameterized({ + 'normal': (['-s', 'WASM_BIGINT=0'], 'testbind.js'), + 'bigint': (['-s', 'WASM_BIGINT=1'], 'testbind_bigint.js'), + }) + def test_sixtyfour_bit_return_value(self, args, bind_js): # This test checks that the most significant 32 bits of a 64 bit long are correctly made available # to native JavaScript applications that wish to interact with compiled code returning 64 bit longs. # The MS 32 bits should be available in Runtime.getTempRet0() even when compiled with -O2 --closure 1 @@ -7215,10 +7220,10 @@ def test_sixtyfour_bit_return_value(self): # Compile test.c and wrap it in a native JavaScript binding so we can call our compiled function from JS. run_process([PYTHON, EMCC, path_from_root('tests', 'return64bit', 'test.c'), '--pre-js', path_from_root('tests', 'return64bit', 'testbindstart.js'), - '--pre-js', path_from_root('tests', 'return64bit', 'testbind.js'), + '--pre-js', path_from_root('tests', 'return64bit', bind_js), '--post-js', path_from_root('tests', 'return64bit', 'testbindend.js'), '-s', 'EXPORTED_FUNCTIONS=["_test_return64"]', '-o', 'test.js', '-O2', - '--closure', '1', '-g1', '-s', 'WASM_ASYNC_COMPILATION=0']) + '--closure', '1', '-g1', '-s', 'WASM_ASYNC_COMPILATION=0'] + args) # Simple test program to load the test.js binding library and call the binding to the # C function returning the 64 bit long. @@ -7228,9 +7233,15 @@ def test_sixtyfour_bit_return_value(self): ''') # Run the test and confirm the output is as expected. - out = run_js('testrun.js', full_output=True) - self.assertContained('low = 5678', out) - self.assertContained('high = 1234', out) + out = run_js('testrun.js', engine=NODE_JS + ['--experimental-wasm-bigint']) + self.assertContained('''\ +input = 0xaabbccdd11223344 +low = 5678 +high = 1234 +input = 0xabcdef1912345678 +low = 5678 +high = 1234 +''', out) def test_lib_include_flags(self): run_process([PYTHON, EMCC] + '-l m -l c -I'.split() + [path_from_root('tests', 'include_test'), path_from_root('tests', 'lib_include_flags.c')]) diff --git a/tools/shared.py b/tools/shared.py index e12b91554eebb..cb069b2d9b73e 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -3112,6 +3112,9 @@ def make_coercion(value, sig, settings=None, ffi_arg=False, ffi_result=False, co @staticmethod def legalize_sig(sig): + # with BigInt support all sigs are legal since we can use i64s. + if Settings.WASM_BIGINT: + return sig legal = [sig[0]] # a return of i64 is legalized into an i32 (and the high bits are # accessible on the side through getTempRet0). @@ -3128,6 +3131,9 @@ def legalize_sig(sig): @staticmethod def is_legal_sig(sig): + # with BigInt support all sigs are legal since we can use i64s. + if Settings.WASM_BIGINT: + return True return sig == JS.legalize_sig(sig) @staticmethod