From 53c81324624f8cc3d09bc32151831d5d7830ac22 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 12 Dec 2024 16:57:17 -0800 Subject: [PATCH] Remove polyfills for Fetch and Object.assign (#23118) This change required the minimum supported browser versions to be bumped just a little. --- ChangeLog.md | 6 ++- src/polyfill/fetch.js | 80 -------------------------------------- src/polyfill/objassign.js | 34 ---------------- src/shell.js | 10 ----- src/shell_minimal.js | 7 ---- test/browser_reporting.js | 3 +- test/test_browser.py | 82 --------------------------------------- test/test_other.py | 2 +- tools/feature_matrix.py | 6 +-- 9 files changed, 10 insertions(+), 220 deletions(-) delete mode 100644 src/polyfill/fetch.js delete mode 100644 src/polyfill/objassign.js diff --git a/ChangeLog.md b/ChangeLog.md index 649ed9e0b344e..fde29fc55de81 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -22,7 +22,6 @@ 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) - Emscripten-generated code will now use async/await internally when loading the Wasm module. This will be lowered away by babel when targeting older browsers. (#23068) @@ -30,6 +29,11 @@ See docs/process.md for more on how version tagging works. - `std::basic_string` (https://github.com/llvm/llvm-project/pull/72694), the support for `std::basic_string` was removed from embind. (#23070) +- The minimum supported versions of browser engines that we support were updated + to versions that support Promise, Fetch and Object.asign APIs, allowing the + polyfills for these to be removed. Chrome 32 -> 45, Firefox 34 -> 40, Safari + 9.0 -> 10.1. These browser engines version are all over 8 years old now. + (#23077, #23118) 3.1.73 - 11/28/24 ----------------- diff --git a/src/polyfill/fetch.js b/src/polyfill/fetch.js deleted file mode 100644 index 979335699a84e..0000000000000 --- a/src/polyfill/fetch.js +++ /dev/null @@ -1,80 +0,0 @@ -// Fetch polyfill from https://github.com/developit/unfetch -// License: -//============================================================================== -// Copyright (c) 2017 Jason Miller -// -// 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 - -if (typeof globalThis.fetch == 'undefined') { - globalThis.fetch = function (url, options) { - options = options || {}; - return new Promise((resolve, reject) => { - const request = new XMLHttpRequest(); - const keys = []; - const headers = {}; - - request.responseType = 'arraybuffer'; - - const response = () => ({ - ok: ((request.status / 100) | 0) == 2, // 200-299 - statusText: request.statusText, - status: request.status, - url: request.responseURL, - text: () => Promise.resolve(request.responseText), - json: () => Promise.resolve(request.responseText).then(JSON.parse), - blob: () => Promise.resolve(new Blob([request.response])), - arrayBuffer: () => Promise.resolve(request.response), - clone: response, - headers: { - keys: () => keys, - entries: () => keys.map((n) => [n, request.getResponseHeader(n)]), - get: (n) => request.getResponseHeader(n), - has: (n) => request.getResponseHeader(n) != null, - }, - }); - - request.open(options.method || "get", url, true); - - request.onload = () => { - request - .getAllResponseHeaders() - .toLowerCase() - .replace(/^(.+?):/gm, (m, key) => { - headers[key] || keys.push((headers[key] = key)); - }); - resolve(response()); - }; - - request.onerror = reject; - - request.withCredentials = options.credentials == "include"; - - for (const i in options.headers) { - request.setRequestHeader(i, options.headers[i]); - } - - request.send(options.body || null); - }); - } -} diff --git a/src/polyfill/objassign.js b/src/polyfill/objassign.js deleted file mode 100644 index e9aafe02d3274..0000000000000 --- a/src/polyfill/objassign.js +++ /dev/null @@ -1,34 +0,0 @@ -// Object.assign polyfill from: -// https://github.com/google/closure-compiler/blob/master/src/com/google/javascript/jscomp/js/es6/util/assign.js - -#if !POLYFILL -#error "this file should never be included unless POLYFILL is set" -#endif - -if (typeof Object.assign == 'undefined') { - /** - * Equivalent to the Object.assign() method, but guaranteed to be available for use in code - * generated by the compiler. - * - * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign - * - * Copies values of all enumerable own properties from one or more - * sources to the given target object, and returns the target. - * - * @final - * @param {!Object} target The target object onto which to copy. - * @param {...?Object} source The source objects. - * @return {!Object} The target object is returned. - * @suppress {visibility, duplicate, checkTypes} - */ - Object.assign = function(target, source) { - for (var i = 1; i < arguments.length; i++) { - var source = arguments[i]; - if (!source) continue; - for (var key in source) { - if (source.hasOwnProperty(key)) target[key] = source[key]; - } - } - return target; - }; -} diff --git a/src/shell.js b/src/shell.js index d25aeb85bcee8..79c4e2b5bb732 100644 --- a/src/shell.js +++ b/src/shell.js @@ -34,20 +34,10 @@ var Module = typeof {{{ EXPORT_NAME }}} != 'undefined' ? {{{ EXPORT_NAME }}} : { #endif // USE_CLOSURE_COMPILER #if POLYFILL -#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" -#endif - #if WASM_BIGINT && MIN_SAFARI_VERSION < 150000 // See https://caniuse.com/mdn-javascript_builtins_bigint64array #include "polyfill/bigint64array.js" #endif - -#if MIN_CHROME_VERSION < 40 || MIN_FIREFOX_VERSION < 39 || MIN_SAFARI_VERSION < 103000 -// See https://caniuse.com/fetch -#include "polyfill/fetch.js" -#endif #endif // POLYFILL #if MODULARIZE diff --git a/src/shell_minimal.js b/src/shell_minimal.js index 3c879ffb9383e..9e8b3039208f0 100644 --- a/src/shell_minimal.js +++ b/src/shell_minimal.js @@ -128,13 +128,6 @@ function ready() { #endif } -#if POLYFILL -// See https://caniuse.com/mdn-javascript_builtins_object_assign -#if MIN_CHROME_VERSION < 45 || MIN_FIREFOX_VERSION < 34 || MIN_SAFARI_VERSION < 90000 -#include "polyfill/objassign.js" -#endif -#endif - #if PTHREADS // MINIMAL_RUNTIME does not support --proxy-to-worker option, so Worker and Pthread environments // coincide. diff --git a/test/browser_reporting.js b/test/browser_reporting.js index 603c29f9b0907..0ba4b90482de6 100644 --- a/test/browser_reporting.js +++ b/test/browser_reporting.js @@ -11,8 +11,7 @@ function reportResultToServer(result) { if ((typeof ENVIRONMENT_IS_NODE !== 'undefined' && ENVIRONMENT_IS_NODE) || (typeof ENVIRONMENT_IS_AUDIO_WORKLET !== 'undefined' && ENVIRONMENT_IS_AUDIO_WORKLET)) { out(`RESULT: ${result}`); } else { - let doFetch = typeof origFetch != 'undefined' ? origFetch : fetch; - doFetch(`${reportingURL}/report_result?${encodeURIComponent(result)}`).then(() => { + fetch(`${reportingURL}/report_result?${encodeURIComponent(result)}`).then(() => { if (typeof window === 'object' && window && hasModule && !Module['pageThrewException']) { /* for easy debugging, don't close window on failure */ window.close(); diff --git a/test/test_browser.py b/test/test_browser.py index 0e8d7edee8a93..135e69d0203b8 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -5445,88 +5445,6 @@ def test_webpack(self, es6): shutil.copy('webpack/src/hello.wasm', 'webpack/dist/') self.run_browser('webpack/dist/index.html', '/report_result?exit:0') - def test_fetch_polyfill_preload(self): - create_file('hello.txt', 'hello, world!') - create_file('main.c', r''' - #include - #include - #include - int main() { - FILE *f = fopen("hello.txt", "r"); - char buf[100]; - fread(buf, 1, 20, f); - buf[20] = 0; - fclose(f); - printf("%s\n", buf); - return 0; - }''') - - create_file('on_window_error_shell.html', r''' - -
-

- - {{{ SCRIPT }}} - - ''') - - def test(args, expect_fail): - self.compile_btest('main.c', ['-sEXIT_RUNTIME', '--preload-file', 'hello.txt', '--shell-file', 'on_window_error_shell.html', '-o', 'a.out.html'] + args) - if expect_fail: - js = read_file('a.out.js') - create_file('a.out.js', 'let origFetch = fetch; fetch = undefined;\n' + js) - return self.run_browser('a.out.html', '/report_result?exception:fetch is not a function') - else: - return self.run_browser('a.out.html', '/report_result?exit:0') - - test([], expect_fail=False) - test([], expect_fail=True) - test(['-sLEGACY_VM_SUPPORT'], expect_fail=False) - test(['-sLEGACY_VM_SUPPORT', '-sNO_POLYFILL'], expect_fail=True) - - @no_wasm64('https://github.com/llvm/llvm-project/issues/98778') - def test_fetch_polyfill_shared_lib(self): - create_file('library.c', r''' - int library_func() { - return 42; - } - ''') - create_file('main.c', r''' - #include - #include - int main() { - void *lib_handle = dlopen("/library.so", RTLD_NOW); - typedef int (*voidfunc)(); - voidfunc x = (voidfunc)dlsym(lib_handle, "library_func"); - return x(); - } - ''') - - self.emcc('library.c', ['-sSIDE_MODULE', '-O2', '-o', 'library.so']) - - def test(args, expect_fail): - self.compile_btest('main.c', ['-fPIC', 'library.so', '-sMAIN_MODULE=2', '-sEXIT_RUNTIME', '-o', 'a.out.html'] + args) - if expect_fail: - js = read_file('a.out.js') - create_file('a.out.js', 'let origFetch = fetch; fetch = undefined;\n' + js) - return self.run_browser('a.out.html', '/report_result?abort:both async and sync fetching of the wasm failed') - else: - return self.run_browser('a.out.html', '/report_result?exit:42') - - test([], expect_fail=True) - test(['-sLEGACY_VM_SUPPORT'], expect_fail=False) - test(['-sLEGACY_VM_SUPPORT', '-sNO_POLYFILL'], expect_fail=True) - class emrun(RunnerCore): def test_emrun_info(self): diff --git a/test/test_other.py b/test/test_other.py index b034bbea1f75b..c1ec01d9177e3 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -15260,7 +15260,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 33 is not supported', err) + self.assertContained('emcc: error: MIN_CHROME_VERSION older than 45 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 0757724ccf7e7..61c9399dd1aad 100644 --- a/tools/feature_matrix.py +++ b/tools/feature_matrix.py @@ -18,9 +18,9 @@ # 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 = 33 -OLDEST_SUPPORTED_FIREFOX = 34 -OLDEST_SUPPORTED_SAFARI = 90000 +OLDEST_SUPPORTED_CHROME = 45 # September 1, 2015 +OLDEST_SUPPORTED_FIREFOX = 40 # August 11, 2015 +OLDEST_SUPPORTED_SAFARI = 101000 # September 20, 2016 # 10.19.0 is the oldest version of node that we do any testing with. # Keep this in sync with the test-node-compat in .circleci/config.yml. OLDEST_SUPPORTED_NODE = 101900