From b8c1b850cf029cbfd23a41f2695fe7e924d07348 Mon Sep 17 00:00:00 2001 From: Hood Chatham Date: Sun, 29 May 2022 18:17:29 -0700 Subject: [PATCH 1/2] Add BigInt64Array shim for Safari 14 https://github.com/emscripten-core/emscripten/pull/17103 --- ChangeLog.md | 21 +++++++++ src/polyfill/bigint64array.js | 88 +++++++++++++++++++++++++++++++++++ src/shell.js | 5 ++ 3 files changed, 114 insertions(+) create mode 100644 src/polyfill/bigint64array.js diff --git a/ChangeLog.md b/ChangeLog.md index fecdfa383..cb65c0d29 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -20,6 +20,27 @@ See docs/process.md for more on how version tagging works. 3.1.13 ------ +3.2.0 +----- +- Emscripten now knows what minimum browser versions the `WASM_BIGINT` feature + requires and will automatically set the defaults accordingly. (#17163) +- Weak undefined symbols fixed in dynamic linking. (#17164) +- Internally, the name of `main` function now gets mangled (by clang) in the + same way as with other wasm targets. This means that within the wasm module + the name of the main function can now be `__main_argc_argv`, but, since we + still export this to JS as `_main`, this should not be a user-visible change. +- Use of pkg-config from cmake not longer causes the C++ include path to be + broken. (#17137) +- `emscripten_runtime_keeplive_push()` and `emscripten_runtime_keeplive_push()` + are now exposed to native code and can be used to keep the runtime alive + without immediately unwinding the event loop (as + `emscripten_exit_with_live_runtime()` does). (#17160) +- Added a shim for `BigInt64Array` so `-sWASM_BIGINT` can be used in Safari + v14. (#17103) + +3.1.13 - 06/02/2022 +------------------- +- xlocale.h compatibility header was restored after being removed in 3.1.12. 3.1.12 - 05/25/2022 ------------------- diff --git a/src/polyfill/bigint64array.js b/src/polyfill/bigint64array.js new file mode 100644 index 000000000..3b21fe914 --- /dev/null +++ b/src/polyfill/bigint64array.js @@ -0,0 +1,88 @@ +if (typeof globalThis.BigInt64Array === "undefined") { + // BigInt64Array polyfill for Safari versions between v14.0 and v15.0. + // All browsers other than Safari added BigInt and BigInt64Array at the same + // time, but Safari introduced BigInt in v14.0 and introduced BigInt64Array in + // v15.0 + + function partsToBigIntSigned(lower, upper) { + return BigInt(lower) | (BigInt(upper + 2 * (upper & 0x80000000)) << 32n); + } + + function partsToBigIntUnsigned(lower, upper) { + return BigInt(lower) | (BigInt(upper) << 32n); + } + + function bigIntToParts(value) { + var lower = Number(BigInt(value) & BigInt(0xffffffff)) | 0; + var upper = (Number(BigInt(value) >> 32n) | 0); + return [lower, upper]; + } + + function createBigIntArrayShim(partsToBigInt) { + function createBigInt64Array(array) { + if (!ArrayBuffer.isView(array)){ + array = new Uint32Array(array); + } + var proxy = new Proxy({ + slice: function(min, max) { + var new_buf = array.slice(min * 2, max *2); + return createBigInt64Array(new_buf); + }, + subarray: function(min, max) { + var new_buf = array.subarray(min * 2, max *2); + return createBigInt64Array(new_buf); + }, + [Symbol.iterator]: function*() { + for (var i = 0; i < (array.length)/2; i++) { + yield partsToBigInt(array[2*i], array[2*i+1]); + } + }, + buffer : array.buffer, + byteLength : array.byteLength, + offset : array.byteOffset / 2, + copyWithin: function(target, start, end) { + array.copyWithin(target*2, start * 2, end*2); + return proxy; + }, + set: function(source, targetOffset) { + if (2*(source.length + targetOffset) > array.length) { + // This is the Chrome error message + // Firefox: "invalid or out-of-range index" + throw new RangeError("offset is out of bounds"); + } + for (var i = 0; i < array.length; i++) { + var value = source[i]; + var pair = bigIntToParts(BigInt(value)); + array.set(pair, 2*(targetOffset + i)); + } + } + }, { + get: function(target, idx, receiver) { + if (typeof idx !== "string" || !/^\d+$/.test(idx)) { + return Reflect.get(target, idx, receiver); + } + var lower = array[idx * 2]; + var upper = array[idx * 2 + 1]; + return partsToBigInt(lower, upper); + }, + set: function(target, idx, value, receiver) { + if (typeof idx !== "string" || !/^\d+$/.test(idx)) { + return Reflect.set(target, idx, value, receiver); + } + if (typeof value !== "bigint") { + // Chrome error message, Firefox has no "a" in front if "BigInt". + throw new TypeError(`Cannot convert ${value} to a BigInt`); + } + var pair = bigIntToParts(value); + array.set(pair, 2*idx); + return true; + } + }); + return proxy; + } + return createBigInt64Array; + } + + globalThis.BigUint64Array = createBigIntArrayShim(partsToBigIntUnsigned); + globalThis.BigInt64Array = createBigIntArrayShim(partsToBigIntSigned); +} diff --git a/src/shell.js b/src/shell.js index 22fac7f69..5a89717fe 100644 --- a/src/shell.js +++ b/src/shell.js @@ -51,6 +51,11 @@ var Module = typeof {{{ EXPORT_NAME }}} != 'undefined' ? {{{ EXPORT_NAME }}} : { #if MIN_CHROME_VERSION < 45 || MIN_EDGE_VERSION < 12 || MIN_FIREFOX_VERSION < 34 || MIN_IE_VERSION != TARGET_NOT_SUPPORTED || MIN_SAFARI_VERSION < 90000 #include "polyfill/objassign.js" #endif + +// See https://caniuse.com/mdn-javascript_builtins_bigint64array +#if WASM_BIGINT && MIN_SAFARI_VERSION < 150000 +#include "polyfill/bigint64array.js" +#endif #endif // POLYFILL #if MODULARIZE -- 2.25.1