From 78c968b0f9f670caf437eac24d715e885b29b275 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 4 Dec 2024 16:40:08 -0800 Subject: [PATCH] Bump minimum supported chrome version from 32 to 33 (#23077) This allows us to remove the promise polyfill: https://caniuse.com/promises --- ChangeLog.md | 1 + .../tools_reference/settings_reference.rst | 2 +- src/polyfill/promise.js | 274 ------------------ src/settings.js | 2 +- src/shell.js | 8 - test/test_other.py | 25 +- tools/feature_matrix.py | 2 +- 7 files changed, 5 insertions(+), 309 deletions(-) delete mode 100644 src/polyfill/promise.js diff --git a/ChangeLog.md b/ChangeLog.md index 13cacf0c6e90c..39938f12e5a7a 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -22,6 +22,7 @@ See docs/process.md for more on how version tagging works. ----------------------- - The file system was updated to independently track atime, mtime and ctime instead of using the same time for all three. (#22998) +- The minimum supported chrome version was bumped from 32 to 33. (#23077) 3.1.73 - 11/28/24 ----------------- diff --git a/site/source/docs/tools_reference/settings_reference.rst b/site/source/docs/tools_reference/settings_reference.rst index b8a971f917e71..902920c03c9b4 100644 --- a/site/source/docs/tools_reference/settings_reference.rst +++ b/site/source/docs/tools_reference/settings_reference.rst @@ -2939,7 +2939,7 @@ This setting also applies to modern Chromium-based Edge, which shares version numbers with Chrome. Chrome 85 was released on 2020-08-25. MAX_INT (0x7FFFFFFF, or -1) specifies that target is not supported. -Minimum supported value is 32, which was released on 2014-01-04. +Minimum supported value is 33, which was released on 2014-02-18. Default value: 85 diff --git a/src/polyfill/promise.js b/src/polyfill/promise.js deleted file mode 100644 index 461be88333461..0000000000000 --- a/src/polyfill/promise.js +++ /dev/null @@ -1,274 +0,0 @@ -// Promise polyfill from https://github.com/taylorhakes/promise-polyfill -// License: -//============================================================================== -// Copyright (c) 2014 Taylor Hakes -// Copyright (c) 2014 Forbes Lindesay -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -//============================================================================== - -#if !POLYFILL -#error "this file should never be included unless POLYFILL is set" -#endif - -/** @suppress{duplicate} This is already defined in from Closure's built-in - externs.zip//es6.js, Closure should not yell when seeing this again. */ -var Promise = (function() { - function noop() {} - - // Polyfill for Function.prototype.bind - function bind(fn, thisArg) { - return function() { - fn.apply(thisArg, arguments); - }; - } - - /** - * @constructor - * @param {Function} fn - */ - function Promise(fn) { - if (!(this instanceof Promise)) - throw new TypeError('Promises must be constructed via new'); - if (typeof fn != 'function') throw new TypeError('not a function'); - /** @type {!number} */ - this._state = 0; - /** @type {!boolean} */ - this._handled = false; - /** @type {Promise|undefined} */ - this._value = undefined; - /** @type {!Array} */ - this._deferreds = []; - - doResolve(fn, this); - } - - function handle(self, deferred) { - while (self._state === 3) { - self = self._value; - } - if (self._state === 0) { - self._deferreds.push(deferred); - return; - } - self._handled = true; - Promise._immediateFn(function() { - var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected; - if (cb === null) { - (self._state === 1 ? resolve : reject)(deferred.promise, self._value); - return; - } - var ret; - try { - ret = cb(self._value); - } catch (e) { - reject(deferred.promise, e); - return; - } - resolve(deferred.promise, ret); - }); - } - - function resolve(self, newValue) { - try { - // Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure - if (newValue === self) - throw new TypeError('A promise cannot be resolved with itself.'); - if ( - newValue && - (typeof newValue == 'object' || typeof newValue == 'function') - ) { - var then = newValue.then; - if (newValue instanceof Promise) { - self._state = 3; - self._value = newValue; - finale(self); - return; - } else if (typeof then == 'function') { - doResolve(bind(then, newValue), self); - return; - } - } - self._state = 1; - self._value = newValue; - finale(self); - } catch (e) { - reject(self, e); - } - } - - function reject(self, newValue) { - self._state = 2; - self._value = newValue; - finale(self); - } - - function finale(self) { - if (self._state === 2 && self._deferreds.length === 0) { - Promise._immediateFn(function() { - if (!self._handled) { - Promise._unhandledRejectionFn(self._value); - } - }); - } - - for (var i = 0, len = self._deferreds.length; i < len; i++) { - handle(self, self._deferreds[i]); - } - self._deferreds = null; - } - - /** - * @constructor - */ - function Handler(onFulfilled, onRejected, promise) { - this.onFulfilled = typeof onFulfilled == 'function' ? onFulfilled : null; - this.onRejected = typeof onRejected == 'function' ? onRejected : null; - this.promise = promise; - } - - /** - * Take a potentially misbehaving resolver function and make sure - * onFulfilled and onRejected are only called once. - * - * Makes no guarantees about asynchrony. - */ - function doResolve(fn, self) { - var done = false; - try { - fn( - function(value) { - if (done) return; - done = true; - resolve(self, value); - }, - function(reason) { - if (done) return; - done = true; - reject(self, reason); - } - ); - } catch (ex) { - if (done) return; - done = true; - reject(self, ex); - } - } - - Promise.prototype['catch'] = function(onRejected) { - return this.then(null, onRejected); - }; - - Promise.prototype.then = function(onFulfilled, onRejected) { - // @ts-ignore - var prom = new this.constructor(noop); - - handle(this, new Handler(onFulfilled, onRejected, prom)); - return prom; - }; - - Promise.all = function(arr) { - return new Promise(function(resolve, reject) { - if (!Array.isArray(arr)) { - return reject(new TypeError('Promise.all accepts an array')); - } - - var args = Array.prototype.slice.call(arr); - if (args.length === 0) return resolve([]); - var remaining = args.length; - - function res(i, val) { - try { - if (val && (typeof val == 'object' || typeof val == 'function')) { - var then = val.then; - if (typeof then == 'function') { - then.call( - val, - function(val) { - res(i, val); - }, - reject - ); - return; - } - } - args[i] = val; - if (--remaining === 0) { - resolve(args); - } - } catch (ex) { - reject(ex); - } - } - - for (var i = 0; i < args.length; i++) { - res(i, args[i]); - } - }); - }; - - Promise.resolve = function(value) { - if (value && typeof value == 'object' && value.constructor == Promise) { - return value; - } - - return new Promise(function(resolve) { - resolve(value); - }); - }; - - Promise.reject = function(value) { - return new Promise(function(resolve, reject) { - reject(value); - }); - }; - - Promise.race = function(arr) { - return new Promise(function(resolve, reject) { - if (!Array.isArray(arr)) { - return reject(new TypeError('Promise.race accepts an array')); - } - - for (var i = 0, len = arr.length; i < len; i++) { - Promise.resolve(arr[i]).then(resolve, reject); - } - }); - }; - - // Use polyfill for setImmediate for performance gains - Promise._immediateFn = - // @ts-ignore - (typeof setImmediate == 'function' && - function(fn) { - // @ts-ignore - setImmediate(fn); - }) || - function(fn) { - setTimeout(fn, 0); // XXX EMSCRIPTEN: just use setTimeout - }; - - Promise._unhandledRejectionFn = function _unhandledRejectionFn(err) { - if (typeof console != 'undefined' && console) { - console.warn('Possible Unhandled Promise Rejection:', err); // eslint-disable-line no-console - } - }; - - return Promise; -})(); - diff --git a/src/settings.js b/src/settings.js index e009a98c907e7..6df46f5572693 100644 --- a/src/settings.js +++ b/src/settings.js @@ -1919,7 +1919,7 @@ var MIN_SAFARI_VERSION = 140100; // numbers with Chrome. // Chrome 85 was released on 2020-08-25. // MAX_INT (0x7FFFFFFF, or -1) specifies that target is not supported. -// Minimum supported value is 32, which was released on 2014-01-04. +// Minimum supported value is 33, which was released on 2014-02-18. // [link] var MIN_CHROME_VERSION = 85; diff --git a/src/shell.js b/src/shell.js index 6d4b2431b247f..d25aeb85bcee8 100644 --- a/src/shell.js +++ b/src/shell.js @@ -34,14 +34,6 @@ var Module = typeof {{{ EXPORT_NAME }}} != 'undefined' ? {{{ EXPORT_NAME }}} : { #endif // USE_CLOSURE_COMPILER #if POLYFILL -#if ((MAYBE_WASM2JS && WASM != 2) || MODULARIZE) && (MIN_CHROME_VERSION < 33 || MIN_FIREFOX_VERSION < 29 || MIN_SAFARI_VERSION < 80000) -// Include a Promise polyfill for legacy browsers. This is needed either for -// wasm2js, where we polyfill the wasm API which needs Promises, or when using -// modularize which creates a Promise for when the module is ready. -// See https://caniuse.com/#feat=promises -#include "polyfill/promise.js" -#endif - #if MIN_CHROME_VERSION < 45 || MIN_FIREFOX_VERSION < 34 || MIN_SAFARI_VERSION < 90000 // See https://caniuse.com/mdn-javascript_builtins_object_assign #include "polyfill/objassign.js" diff --git a/test/test_other.py b/test/test_other.py index 6af58d3722262..dfdff53977072 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -12427,29 +12427,6 @@ def test_standalone_syscalls(self): for engine in config.WASM_ENGINES: self.assertContained(expected, self.run_js('test.wasm', engine)) - @parameterized({ - 'wasm2js': (['-sWASM=0'],), - 'modularize': (['-sMODULARIZE', '--extern-post-js', test_file('modularize_post_js.js')],), - }) - def test_promise_polyfill(self, constant_args): - def test(args, expect_fail): - # legacy browsers may lack Promise, which wasm2js depends on. see what - # happens when we kill the global Promise function. - self.run_process([EMCC, test_file('hello_world.c')] + constant_args + args) - js = read_file('a.out.js') - create_file('a.out.js', 'Promise = undefined;\n' + js) - return self.run_js('a.out.js', assert_returncode=NON_ZERO if expect_fail else 0) - - # we fail without legacy support - test([], expect_fail=True) - - # but work with it - output = test(['-sLEGACY_VM_SUPPORT'], expect_fail=False) - self.assertContained('hello, world!', output) - - # unless we explicitly disable polyfills - test(['-sLEGACY_VM_SUPPORT', '-sNO_POLYFILL'], expect_fail=True) - @parameterized({ '': ([],), 'assertions': (['-sASSERTIONS'],), @@ -15265,7 +15242,7 @@ def test_no_extra_output(self): def test_browser_too_old(self): err = self.expect_fail([EMCC, test_file('hello_world.c'), '-sMIN_CHROME_VERSION=10']) - self.assertContained('emcc: error: MIN_CHROME_VERSION older than 32 is not supported', err) + self.assertContained('emcc: error: MIN_CHROME_VERSION older than 33 is not supported', err) def test_js_only_settings(self): err = self.run_process([EMCC, test_file('hello_world.c'), '-o', 'foo.wasm', '-sDEFAULT_LIBRARY_FUNCS_TO_INCLUDE=emscripten_get_heap_max'], stderr=PIPE).stderr diff --git a/tools/feature_matrix.py b/tools/feature_matrix.py index 53ee6f66ce716..0757724ccf7e7 100644 --- a/tools/feature_matrix.py +++ b/tools/feature_matrix.py @@ -18,7 +18,7 @@ # Oldest support browser versions. These have been set somewhat # arbitrarily for now. # TODO(sbc): Design a of policy for managing these values. -OLDEST_SUPPORTED_CHROME = 32 +OLDEST_SUPPORTED_CHROME = 33 OLDEST_SUPPORTED_FIREFOX = 34 OLDEST_SUPPORTED_SAFARI = 90000 # 10.19.0 is the oldest version of node that we do any testing with.