From 7e46b7fb2349d553a2ad70347dae4004f5e3a338 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 14 Mar 2023 08:59:42 -0700 Subject: [PATCH 0001/1523] Pass `-z` flags directly through the linker (#18956) This is what the gcc and clang drivers both do. Fixes: #18948 --- ChangeLog.md | 2 ++ emcc.py | 10 +++++++++- test/test_other.py | 10 ++++++++-- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 4ad279a87a730..e474d33e5266b 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -20,6 +20,8 @@ See docs/process.md for more on how version tagging works. 3.1.34 (in development) ----------------------- +- `-z` arguments are now passed directly to wasm-ld without the need for the + `-Wl,` prefix. This matches the behaviour of both clang and gcc. (#18956) - The prefered way to enable pthread is now to just the the standard `-pthread` flag. The `-sUSE_PTHREADS` setting still works but is marked as legacy and will generate a warning in `-sSTRICT` mode. diff --git a/emcc.py b/emcc.py index 1f0353b6be2c4..564f0bd11eea3 100755 --- a/emcc.py +++ b/emcc.py @@ -1482,7 +1482,7 @@ def phase_setup(options, state, newargs): '-isysroot', '-imultilib', '-A', '-isystem', '-iquote', '-install_name', '-compatibility_version', '-current_version', '-I', '-L', '-include-pch', - '-Xlinker', '-Xclang'): + '-Xlinker', '-Xclang', '-z'): skip = True if not arg.startswith('-'): @@ -1518,6 +1518,14 @@ def phase_setup(options, state, newargs): elif arg.startswith('-l'): add_link_flag(state, i, arg) newargs[i] = '' + elif arg == '-z': + add_link_flag(state, i, newargs[i]) + add_link_flag(state, i + 1, newargs[i + 1]) + newargs[i] = '' + newargs[i + 1] = '' + elif arg.startswith('-z'): + add_link_flag(state, i, newargs[i]) + newargs[i] = '' elif arg.startswith('-Wl,'): # Multiple comma separated link flags can be specified. Create fake # fractional indices for these: -Wl,a,b,c,d at index 4 becomes: diff --git a/test/test_other.py b/test/test_other.py index 9e45a8d7ab450..9e5d5b2be6ace 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -10841,12 +10841,18 @@ def test_supported_linker_flag_skip_next(self): self.assertContained('error: unable to find library -lbar', err) def test_linker_flags_pass_through(self): - err = self.expect_fail([EMXX, test_file('hello_world.cpp'), '-Wl,--waka']) + err = self.expect_fail([EMCC, test_file('hello_world.c'), '-Wl,--waka']) self.assertContained('wasm-ld: error: unknown argument: --waka', err) - err = self.expect_fail([EMXX, test_file('hello_world.cpp'), '-Xlinker', '--waka']) + err = self.expect_fail([EMCC, test_file('hello_world.c'), '-Xlinker', '--waka']) self.assertContained('wasm-ld: error: unknown argument: --waka', err) + err = self.run_process([EMCC, test_file('hello_world.c'), '-z', 'foo'], stderr=PIPE).stderr + self.assertContained('wasm-ld: warning: unknown -z value: foo', err) + + err = self.run_process([EMCC, test_file('hello_world.c'), '-zfoo'], stderr=PIPE).stderr + self.assertContained('wasm-ld: warning: unknown -z value: foo', err) + def test_linker_flags_unused(self): err = self.run_process([EMXX, test_file('hello_world.cpp'), '-c', '-lbar'], stderr=PIPE).stderr self.assertContained("warning: argument unused during compilation: '-lbar' [-Wunused-command-line-argument]", err) From a89f3ce817527f602a36205751f8cd779ff38ceb Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 14 Mar 2023 10:22:29 -0700 Subject: [PATCH 0002/1523] Require explict opt-out of scons tests (#18947) This prevents us from accidentally not running this tests when scons is not installed on the host system. --- .circleci/config.yml | 4 +++- test/test_other.py | 20 +++++++++++++++++--- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index c1bfaf61a1c88..7559743c6f0de 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -596,7 +596,7 @@ jobs: test-other: executor: bionic steps: - - run: apt-get install ninja-build + - run: apt-get install ninja-build scons - run-tests-linux: # some native-dependent tests fail because of the lack of native # headers on emsdk-bundled clang @@ -629,6 +629,7 @@ jobs: EMTEST_SKIP_EH: "1" EMTEST_SKIP_WASM64: "1" EMTEST_SKIP_SIMD: "1" + EMTEST_SKIP_SCONS: "1" steps: - checkout - run: @@ -702,6 +703,7 @@ jobs: EMTEST_SKIP_EH: "1" EMTEST_SKIP_WASM64: "1" EMTEST_SKIP_SIMD: "1" + EMTEST_SKIP_SCONS: "1" EMCC_SKIP_SANITY_CHECK: "1" steps: - run: diff --git a/test/test_other.py b/test/test_other.py index 9e5d5b2be6ace..027927f6277cf 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -20,7 +20,6 @@ import sys import tarfile import time -import unittest from pathlib import Path from subprocess import PIPE, STDOUT @@ -133,6 +132,21 @@ def decorated(self, *args, **kwargs): return decorated +def requires_scons(func): + assert callable(func) + + @wraps(func) + def decorated(self, *args, **kwargs): + if not utils.which('scons'): + if 'EMTEST_SKIP_SCONS' in os.environ: + self.skipTest('test requires scons and EMTEST_SKIP_SCONS is set') + else: + self.fail('scons required to run this test. Use EMTEST_SKIP_SKIP to skip') + return func(self, *args, **kwargs) + + return decorated + + def requires_pkg_config(func): assert callable(func) @@ -2662,7 +2676,7 @@ def test_dwarf_with_source_map(self): self.verify_dwarf_exists(wasm_file) self.verify_source_map_exists(map_file) - @unittest.skipIf(not scons_path, 'scons not found in PATH') + @requires_scons @with_env_modify({'EMSCRIPTEN_ROOT': path_from_root()}) def test_scons(self): # this test copies the site_scons directory alongside the test @@ -2673,7 +2687,7 @@ def test_scons(self): output = self.run_js('scons_integration.js', assert_returncode=5) self.assertContained('If you see this - the world is all right!', output) - @unittest.skipIf(not scons_path, 'scons not found in PATH') + @requires_scons @with_env_modify({'EMSCRIPTEN_TOOLPATH': path_from_root('tools/scons/site_scons'), 'EMSCRIPTEN_ROOT': path_from_root()}) def test_emscons(self): From 92a8464cb8bb9ea989b56cc433e0309cd79eb491 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 14 Mar 2023 13:48:52 -0700 Subject: [PATCH 0003/1523] Add cmake test `find_package(Threads)`. NFC (#18955) Verifies that cmake can detect our pthread support. See #18948 --- test/cmake/threads/CMakeLists.txt | 13 +++++++++++++ test/cmake/threads/hello.c | 6 ++++++ test/test_other.py | 4 ++++ 3 files changed, 23 insertions(+) create mode 100644 test/cmake/threads/CMakeLists.txt create mode 100644 test/cmake/threads/hello.c diff --git a/test/cmake/threads/CMakeLists.txt b/test/cmake/threads/CMakeLists.txt new file mode 100644 index 0000000000000..d55448777561c --- /dev/null +++ b/test/cmake/threads/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 3.0) + +project(threads VERSION 0.42) + +find_package(Threads REQUIRED) + +if (!CMAKE_USE_PTHREADS_INIT) + message(FATAL_ERROR "pthreads not found") +endif() + +add_executable(hello hello.c) + +target_link_libraries(hello ${CMAKE_THREAD_LIBS_INIT}) diff --git a/test/cmake/threads/hello.c b/test/cmake/threads/hello.c new file mode 100644 index 0000000000000..ce0cca4630ed8 --- /dev/null +++ b/test/cmake/threads/hello.c @@ -0,0 +1,6 @@ +#include + +int main() { + printf("hello, world!\n"); + return 0; +} diff --git a/test/test_other.py b/test/test_other.py index 027927f6277cf..6d13645dc8d08 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -908,6 +908,10 @@ def test_cmake_find_modules(self): self.assertContained('AL_VERSION: 1.1', output) self.assertContained('SDL version: 2.', output) + def test_cmake_threads(self): + self.run_process([EMCMAKE, 'cmake', test_file('cmake/threads')]) + self.run_process(['cmake', '--build', '.']) + @requires_pkg_config def test_cmake_find_pkg_config(self): out = self.run_process([EMCMAKE, 'cmake', test_file('cmake/find_pkg_config')], stdout=PIPE).stdout From 66392f4cc583e3f80e54893930494f53b1aff29b Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 14 Mar 2023 15:52:12 -0700 Subject: [PATCH 0004/1523] Remove `Fetch.setu64` which essentially duplicates writeI53ToI64. NFC (#18959) --- src/Fetch.js | 29 ++++++++++++----------------- src/library_fetch.js | 1 + 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/src/Fetch.js b/src/Fetch.js index 9110b6beaab1b..1913b5fe24568 100644 --- a/src/Fetch.js +++ b/src/Fetch.js @@ -15,11 +15,6 @@ var Fetch = { // as a preload step before the Emscripten application starts. (this field is populated on demand, start as undefined to save code size) // dbInstance: undefined, - setu64: function(addr, val) { - HEAPU32[addr >> 2] = val; - HEAPU32[addr + 4 >> 2] = (val / 4294967296)|0; - }, - #if FETCH_SUPPORT_INDEXEDDB // Be cautious that `onerror` may be run synchronously openDatabase: function(dbname, dbversion, onsuccess, onerror) { @@ -94,9 +89,9 @@ function fetchDeleteCachedData(db, fetch, onsuccess, onerror) { dbg('fetch: Deleted file ' + pathStr + ' from IndexedDB'); #endif HEAPU32[fetch + {{{ C_STRUCTS.emscripten_fetch_t.data }}} >> 2] = 0; - Fetch.setu64(fetch + {{{ C_STRUCTS.emscripten_fetch_t.numBytes }}}, 0); - Fetch.setu64(fetch + {{{ C_STRUCTS.emscripten_fetch_t.dataOffset }}}, 0); - Fetch.setu64(fetch + {{{ C_STRUCTS.emscripten_fetch_t.totalBytes }}}, 0); + writeI53ToI64(fetch + {{{ C_STRUCTS.emscripten_fetch_t.numBytes }}}, 0); + writeI53ToI64(fetch + {{{ C_STRUCTS.emscripten_fetch_t.dataOffset }}}, 0); + writeI53ToI64(fetch + {{{ C_STRUCTS.emscripten_fetch_t.totalBytes }}}, 0); HEAPU16[fetch + {{{ C_STRUCTS.emscripten_fetch_t.readyState }}} >> 1] = 4; // Mimic XHR readyState 4 === 'DONE: The operation is complete' HEAPU16[fetch + {{{ C_STRUCTS.emscripten_fetch_t.status }}} >> 1] = 200; // Mimic XHR HTTP status code 200 "OK" stringToUTF8("OK", fetch + {{{ C_STRUCTS.emscripten_fetch_t.statusText }}}, 64); @@ -149,9 +144,9 @@ function fetchLoadCachedData(db, fetch, onsuccess, onerror) { var ptr = _malloc(len); HEAPU8.set(new Uint8Array(value), ptr); HEAPU32[fetch + {{{ C_STRUCTS.emscripten_fetch_t.data }}} >> 2] = ptr; - Fetch.setu64(fetch + {{{ C_STRUCTS.emscripten_fetch_t.numBytes }}}, len); - Fetch.setu64(fetch + {{{ C_STRUCTS.emscripten_fetch_t.dataOffset }}}, 0); - Fetch.setu64(fetch + {{{ C_STRUCTS.emscripten_fetch_t.totalBytes }}}, len); + writeI53ToI64(fetch + {{{ C_STRUCTS.emscripten_fetch_t.numBytes }}}, len); + writeI53ToI64(fetch + {{{ C_STRUCTS.emscripten_fetch_t.dataOffset }}}, 0); + writeI53ToI64(fetch + {{{ C_STRUCTS.emscripten_fetch_t.totalBytes }}}, len); HEAPU16[fetch + {{{ C_STRUCTS.emscripten_fetch_t.readyState }}} >> 1] = 4; // Mimic XHR readyState 4 === 'DONE: The operation is complete' HEAPU16[fetch + {{{ C_STRUCTS.emscripten_fetch_t.status }}} >> 1] = 200; // Mimic XHR HTTP status code 200 "OK" stringToUTF8("OK", fetch + {{{ C_STRUCTS.emscripten_fetch_t.statusText }}}, 64); @@ -332,14 +327,14 @@ function fetchXHR(fetch, onsuccess, onerror, onprogress, onreadystatechange) { HEAPU8.set(new Uint8Array(/** @type{Array} */(xhr.response)), ptr); } HEAPU32[fetch + {{{ C_STRUCTS.emscripten_fetch_t.data }}} >> 2] = ptr; - Fetch.setu64(fetch + {{{ C_STRUCTS.emscripten_fetch_t.numBytes }}}, ptrLen); - Fetch.setu64(fetch + {{{ C_STRUCTS.emscripten_fetch_t.dataOffset }}}, 0); + writeI53ToI64(fetch + {{{ C_STRUCTS.emscripten_fetch_t.numBytes }}}, ptrLen); + writeI53ToI64(fetch + {{{ C_STRUCTS.emscripten_fetch_t.dataOffset }}}, 0); var len = xhr.response ? xhr.response.byteLength : 0; if (len) { // If the final XHR.onload handler receives the bytedata to compute total length, report that, // otherwise don't write anything out here, which will retain the latest byte size reported in // the most recent XHR.onprogress handler. - Fetch.setu64(fetch + {{{ C_STRUCTS.emscripten_fetch_t.totalBytes }}}, len); + writeI53ToI64(fetch + {{{ C_STRUCTS.emscripten_fetch_t.totalBytes }}}, len); } HEAPU16[fetch + {{{ C_STRUCTS.emscripten_fetch_t.readyState }}} >> 1] = xhr.readyState; HEAPU16[fetch + {{{ C_STRUCTS.emscripten_fetch_t.status }}} >> 1] = xhr.status; @@ -404,9 +399,9 @@ function fetchXHR(fetch, onsuccess, onerror, onprogress, onreadystatechange) { HEAPU8.set(new Uint8Array(/** @type{Array} */(xhr.response)), ptr); } HEAPU32[fetch + {{{ C_STRUCTS.emscripten_fetch_t.data }}} >> 2] = ptr; - Fetch.setu64(fetch + {{{ C_STRUCTS.emscripten_fetch_t.numBytes }}}, ptrLen); - Fetch.setu64(fetch + {{{ C_STRUCTS.emscripten_fetch_t.dataOffset }}}, e.loaded - ptrLen); - Fetch.setu64(fetch + {{{ C_STRUCTS.emscripten_fetch_t.totalBytes }}}, e.total); + writeI53ToI64(fetch + {{{ C_STRUCTS.emscripten_fetch_t.numBytes }}}, ptrLen); + writeI53ToI64(fetch + {{{ C_STRUCTS.emscripten_fetch_t.dataOffset }}}, e.loaded - ptrLen); + writeI53ToI64(fetch + {{{ C_STRUCTS.emscripten_fetch_t.totalBytes }}}, e.total); HEAPU16[fetch + {{{ C_STRUCTS.emscripten_fetch_t.readyState }}} >> 1] = xhr.readyState; // If loading files from a source that does not give HTTP status code, assume success if we get data bytes if (xhr.readyState >= 3 && xhr.status === 0 && e.loaded > 0) xhr.status = 200; diff --git a/src/library_fetch.js b/src/library_fetch.js index 44492af5a814e..1467a90c5a279 100644 --- a/src/library_fetch.js +++ b/src/library_fetch.js @@ -32,6 +32,7 @@ var LibraryFetch = { '$Fetch', '$fetchXHR', '$callUserCallback', + '$writeI53ToI64', #if FETCH_SUPPORT_INDEXEDDB '$fetchCacheData', '$fetchLoadCachedData', From 335120a1cd5d411bb588555461a34d0cdfb15580 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 14 Mar 2023 18:47:58 -0700 Subject: [PATCH 0005/1523] Mark 3.1.34 as released (#18964) --- ChangeLog.md | 8 +++++++- emscripten-version.txt | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index e474d33e5266b..104d5f017105e 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -18,10 +18,16 @@ to browse the changes between the tags. See docs/process.md for more on how version tagging works. -3.1.34 (in development) +3.1.35 (in development) ----------------------- - `-z` arguments are now passed directly to wasm-ld without the need for the `-Wl,` prefix. This matches the behaviour of both clang and gcc. (#18956) + +3.1.34 - 03/14/23 +----------------- +- Fix for using `EM_JS` functions defined in other object files. This was a bug + that was introduced when `LLD_REPORT_UNDEFINED` was enabled by default back in + 3.1.28. (#18928) - The prefered way to enable pthread is now to just the the standard `-pthread` flag. The `-sUSE_PTHREADS` setting still works but is marked as legacy and will generate a warning in `-sSTRICT` mode. diff --git a/emscripten-version.txt b/emscripten-version.txt index e5813add0fefe..95bd3806a33f8 100644 --- a/emscripten-version.txt +++ b/emscripten-version.txt @@ -1 +1 @@ -3.1.34-git +3.1.35-git From 54d8e4575694f8f322c71f975fd6dff9d0d64470 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 14 Mar 2023 19:09:05 -0700 Subject: [PATCH 0006/1523] Minor cleanup to some `test_other.py` tests. NFC (#18953) --- test/test_other.py | 99 ++++++++++++++++++++++++---------------------- 1 file changed, 51 insertions(+), 48 deletions(-) diff --git a/test/test_other.py b/test/test_other.py index 6d13645dc8d08..e4c9d07ab53ab 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -833,7 +833,7 @@ def test_cmake_with_embind_cpp11_mode(self): print(str(build)) self.run_process(build) - out = self.run_process(config.NODE_JS + ['cmake_with_emval.js'], stdout=PIPE).stdout + out = self.run_js('cmake_with_emval.js') if '-DNO_GNU_EXTENSIONS=1' in args: self.assertContained('Hello! __STRICT_ANSI__: 1, __cplusplus: 201103', out) else: @@ -1735,6 +1735,7 @@ def test_export_from_archive(self): 'preload': (['--preload-file', 'somefile.txt'],), 'preload_and_embed': (['--preload-file', 'somefile.txt', '--embed-file', 'hello.txt'],) }) + @requires_node def test_include_file(self, args): create_file('somefile.txt', 'hello from a file with lots of data and stuff in it thank you very much') create_file('hello.txt', 'hello world') @@ -1756,7 +1757,7 @@ def test_include_file(self, args): self.run_process([EMCC, 'main.c'] + args) # run in node.js to ensure we verify that file preloading works there - result = self.run_js('a.out.js', engine=config.NODE_JS) + result = self.run_js('a.out.js') self.assertContained('|hello from a file wi|', result) @parameterized({ @@ -2839,6 +2840,7 @@ def test_embind(self, extra_args): output = self.run_js('a.out.js') self.assertNotContained('FAIL', output) + @requires_node def test_embind_finalization(self): self.run_process( [EMXX, @@ -2847,7 +2849,7 @@ def test_embind_finalization(self): '-lembind'] ) self.node_args += ['--expose-gc'] - output = self.run_js('a.out.js', engine=config.NODE_JS) + output = self.run_js('a.out.js') self.assertContained('Constructed from C++ destructed', output) self.assertContained('Constructed from JS destructed', output) self.assertNotContained('Foo* destructed', output) @@ -5138,7 +5140,7 @@ def test_only_force_stdlibs(self, env, fail): if 'EMCC_ONLY_FORCED_STDLIBS' in env: self.assertContained('EMCC_ONLY_FORCED_STDLIBS is deprecated', err) if fail: - output = self.expect_fail(config.NODE_JS + ['a.out.js'], stdout=PIPE) + output = self.run_js('a.out.js', assert_returncode=NON_ZERO) self.assertContained('missing function', output) else: self.assertContained('hello, world!', self.run_js('a.out.js')) @@ -5823,33 +5825,33 @@ def test_link_with_bad_o_in_a(self): def test_require(self): inname = test_file('hello_world.c') self.emcc(inname, args=['-sASSERTIONS=0'], output_filename='a.out.js') - output = self.run_process(config.NODE_JS + ['-e', 'require("./a.out.js")'], stdout=PIPE, stderr=PIPE) - assert output.stdout == 'hello, world!\n' and output.stderr == '', 'expected no output, got\n===\nSTDOUT\n%s\n===\nSTDERR\n%s\n===\n' % (output.stdout, output.stderr) + create_file('run.js', 'require("./a.out.js")') + output = self.run_js('run.js') + self.assertEqual('hello, world!\n', output) @requires_node def test_require_modularize(self): self.run_process([EMCC, test_file('hello_world.c'), '-sMODULARIZE', '-sASSERTIONS=0']) src = read_file('a.out.js') self.assertContained('module.exports = Module;', src) - output = self.run_process(config.NODE_JS + ['-e', 'var m = require("./a.out.js"); m();'], stdout=PIPE, stderr=PIPE) - self.assertFalse(output.stderr) - self.assertEqual(output.stdout, 'hello, world!\n') + create_file('run.js', 'var m = require("./a.out.js"); m();') + output = self.run_js('run.js') + self.assertEqual(output, 'hello, world!\n') self.run_process([EMCC, test_file('hello_world.c'), '-sMODULARIZE', '-sEXPORT_NAME="NotModule"', '-sASSERTIONS=0']) - src = read_file('a.out.js') - self.assertContained('module.exports = NotModule;', src) - output = self.run_process(config.NODE_JS + ['-e', 'var m = require("./a.out.js"); m();'], stdout=PIPE, stderr=PIPE) - self.assertFalse(output.stderr) - self.assertEqual(output.stdout, 'hello, world!\n') + self.assertContained('module.exports = NotModule;', read_file('a.out.js')) + output = self.run_js('run.js') + self.assertEqual(output, 'hello, world!\n') self.run_process([EMCC, test_file('hello_world.c'), '-sMODULARIZE']) # We call require() twice to ensure it returns wrapper function each time - output = self.run_process(config.NODE_JS + ['-e', 'require("./a.out.js")();var m = require("./a.out.js"); m();'], stdout=PIPE, stderr=PIPE) - self.assertFalse(output.stderr) - self.assertEqual(output.stdout, 'hello, world!\nhello, world!\n') + create_file('require_twice.js', 'require("./a.out.js")();var m = require("./a.out.js"); m();') + output = self.run_js('require_twice.js') + self.assertEqual(output, 'hello, world!\nhello, world!\n') def test_modularize_strict(self): self.run_process([EMCC, test_file('hello_world.c'), '-sMODULARIZE', '-sSTRICT']) - stdout = self.run_process(config.NODE_JS + ['-e', 'var m = require("./a.out.js"); m();'], stdout=PIPE, stderr=PIPE).stdout - self.assertEqual(stdout, 'hello, world!\n') + create_file('run.js', 'var m = require("./a.out.js"); m();') + output = self.run_js('run.js') + self.assertEqual(output, 'hello, world!\n') @node_pthreads def test_pthread_print_override_modularize(self): @@ -5886,15 +5888,19 @@ def test_define_modularize(self): self.run_process([EMCC, test_file('hello_world.c'), '-sMODULARIZE', '-sASSERTIONS=0']) src = 'var module = 0; ' + read_file('a.out.js') create_file('a.out.js', src) - assert "define([], function() { return Module; });" in src - output = self.run_process(config.NODE_JS + ['-e', 'var m; (global.define = function(deps, factory) { m = factory(); }).amd = true; require("./a.out.js"); m();'], stdout=PIPE, stderr=PIPE) - assert output.stdout == 'hello, world!\n' and output.stderr == '', 'expected output, got\n===\nSTDOUT\n%s\n===\nSTDERR\n%s\n===\n' % (output.stdout, output.stderr) + self.assertContained("define([], function() { return Module; });", src) + + create_file('run_module.js', 'var m; (global.define = function(deps, factory) { m = factory(); }).amd = true; require("./a.out.js"); m();') + output = self.run_js('run_module.js') + self.assertContained('hello, world!\n', output) + self.run_process([EMCC, test_file('hello_world.c'), '-sMODULARIZE', '-sEXPORT_NAME="NotModule"', '-sASSERTIONS=0']) src = 'var module = 0; ' + read_file('a.out.js') create_file('a.out.js', src) - assert "define([], function() { return NotModule; });" in src - output = self.run_process(config.NODE_JS + ['-e', 'var m; (global.define = function(deps, factory) { m = factory(); }).amd = true; require("./a.out.js"); m();'], stdout=PIPE, stderr=PIPE) - assert output.stdout == 'hello, world!\n' and output.stderr == '', 'expected output, got\n===\nSTDOUT\n%s\n===\nSTDERR\n%s\n===\n' % (output.stdout, output.stderr) + self.assertContained("define([], function() { return NotModule; });", src) + + output = self.run_js('run_module.js') + self.assertContained('hello, world!\n', output) def test_EXPORT_NAME_with_html(self): err = self.expect_fail([EMCC, test_file('hello_world.c'), '-o', 'a.html', '-sEXPORT_NAME=Other']) @@ -7092,6 +7098,7 @@ def test(page_diff): 'normal': (['-sWASM_BIGINT=0'], 'testbind.js'), 'bigint': (['-sWASM_BIGINT'], 'testbind_bigint.js'), }) + @requires_node def test_i64_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. @@ -7115,7 +7122,8 @@ def test_i64_return_value(self, args, bind_js): ''') # Run the test and confirm the output is as expected. - out = self.run_js('testrun.js', engine=config.NODE_JS + shared.node_bigint_flags()) + self.node_args += shared.node_bigint_flags() + out = self.run_js('testrun.js') self.assertContained('''\ input = 0xaabbccdd11223344 low = 5678 @@ -7369,9 +7377,7 @@ def test_override_js_execution_environment(self): def test_override_c_environ(self): create_file('pre.js', r''' - var Module = { - preRun: [function() { ENV.hello = 'world'; ENV.LANG = undefined; }] - }; + Module.preRun = () => { ENV.hello = 'world'; ENV.LANG = undefined; } ''') create_file('src.cpp', r''' #include @@ -7387,16 +7393,15 @@ def test_override_c_environ(self): self.assertContained('LANG is not set', output) create_file('pre.js', r''' - var Module = { - preRun: [function(module) { module.ENV.hello = 'world' }] - }; + Module.preRun = (module) => { module.ENV.hello = 'world' } ''') self.run_process([EMXX, 'src.cpp', '--pre-js', 'pre.js', '-sEXPORTED_RUNTIME_METHODS=ENV']) self.assertContained('|world|', self.run_js('a.out.js')) self.run_process([EMXX, 'src.cpp', '--pre-js', 'pre.js', '-sEXPORTED_RUNTIME_METHODS=ENV', '-sMODULARIZE']) - output = self.run_process(config.NODE_JS + ['-e', 'require("./a.out.js")();'], stdout=PIPE, stderr=PIPE) - self.assertContained('|world|', output.stdout) + create_file('run.js', 'require("./a.out.js")();') + output = self.run_js('run.js') + self.assertContained('|world|', output) def test_warn_no_filesystem(self): error = 'Filesystem support (FS) was not included. The problem is that you are using files from JS, but files were not used from C/C++, so filesystem support was not auto-included. You can force-include filesystem support with -sFORCE_FILESYSTEM' @@ -9340,28 +9345,26 @@ def test_html_preprocess(self): def test_node_js_run_from_different_directory(self): ensure_dir('subdir') self.run_process([EMCC, test_file('hello_world.c'), '-o', Path('subdir/a.js'), '-O3']) - ret = self.run_process(config.NODE_JS + [Path('subdir/a.js')], stdout=PIPE).stdout + ret = self.run_js('subdir/a.js') self.assertContained('hello, world!', ret) # Tests that a pthreads + modularize build can be run in node js - @requires_node + @node_pthreads def test_node_js_pthread_module(self): # create module loader script - moduleLoader = 'moduleLoader.js' - moduleLoaderContents = ''' + ensure_dir('subdir') + create_file('subdir/moduleLoader.js', ''' const test_module = require("./module"); test_module().then((test_module_instance) => { test_module_instance._main(); }); -''' - ensure_dir('subdir') - create_file(os.path.join('subdir', moduleLoader), moduleLoaderContents) +''') # build hello_world.c self.run_process([EMCC, test_file('hello_world.c'), '-o', Path('subdir/module.js'), '-pthread', '-sPTHREAD_POOL_SIZE=2', '-sMODULARIZE', '-sEXPORT_NAME=test_module', '-sENVIRONMENT=worker,node']) # run the module - ret = self.run_process(config.NODE_JS + shared.node_pthread_flags() + [os.path.join('subdir', moduleLoader)], stdout=PIPE).stdout + ret = self.run_js('subdir/moduleLoader.js') self.assertContained('hello, world!', ret) @no_windows('node system() does not seem to work, see https://github.com/emscripten-core/emscripten/pull/10547') @@ -9371,7 +9374,7 @@ def test_system_node_js(self): def test_node_eval(self): self.run_process([EMCC, '-sENVIRONMENT=node', test_file('hello_world.c'), '-o', 'a.js', '-O3']) - js = open('a.js').read() + js = read_file('a.js') ret = self.run_process(config.NODE_JS + ['-e', js], stdout=PIPE).stdout self.assertContained('hello, world!', ret) @@ -9811,7 +9814,7 @@ def check_size(f, expected_size): print(' '.join(args)) self.run_process(args) - ret = self.run_process(config.NODE_JS + ['a.js'], stdout=PIPE).stdout + ret = self.run_js('a.js') self.assertTextDataIdentical('Sum of numbers from 1 to 1000: 500500 (expected 500500)', ret.strip()) check_size('a.js', 150000) @@ -11323,8 +11326,8 @@ def test_native_call_before_init(self): self.add_pre_run('console.log("calling foo"); Module["_foo"]();') create_file('foo.c', '#include \nint foo() { puts("foo called"); return 3; }') self.build('foo.c') - err = self.expect_fail(config.NODE_JS + ['foo.js'], stdout=PIPE) - self.assertContained('native function `foo` called before runtime initialization', err) + out = self.run_js('foo.js', assert_returncode=NON_ZERO) + self.assertContained('native function `foo` called before runtime initialization', out) def test_native_call_after_exit(self): self.set_setting('ASSERTIONS') @@ -11332,8 +11335,8 @@ def test_native_call_after_exit(self): self.add_on_exit('console.log("calling main again"); Module["_main"]();') create_file('foo.c', '#include \nint main() { puts("foo called"); return 0; }') self.build('foo.c') - err = self.expect_fail(config.NODE_JS + ['foo.js'], stdout=PIPE) - self.assertContained('native function `main` called after runtime exit', err) + out = self.run_js('foo.js', assert_returncode=NON_ZERO) + self.assertContained('native function `main` called after runtime exit', out) def test_metadce_wasm2js_i64(self): # handling i64 unsigned remainder brings in some i64 support code. metadce From 2fcbc820e6e37d3267cfe95350688a519a2fac2e Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 15 Mar 2023 11:52:35 -0700 Subject: [PATCH 0007/1523] Fix for-of in acorn optimizer (#18968) The JS AST has a separate node type for for-of, like for-in. Fixes #18967 --- test/optimizer/JSDCE-fors-output.js | 2 ++ test/optimizer/JSDCE-fors.js | 1 + tools/acorn-optimizer.js | 3 +++ 3 files changed, 6 insertions(+) diff --git a/test/optimizer/JSDCE-fors-output.js b/test/optimizer/JSDCE-fors-output.js index ec992dd36ebbd..45e46242c3fbb 100644 --- a/test/optimizer/JSDCE-fors-output.js +++ b/test/optimizer/JSDCE-fors-output.js @@ -1,3 +1,5 @@ for (var i in x) {} +for (var i of [ 1, 2, 3 ]) {} + for (var j = 0; ;) {} diff --git a/test/optimizer/JSDCE-fors.js b/test/optimizer/JSDCE-fors.js index 71e8010252285..642fc9358cf8c 100644 --- a/test/optimizer/JSDCE-fors.js +++ b/test/optimizer/JSDCE-fors.js @@ -1,4 +1,5 @@ for (var i in x) {} +for (var i of [1, 2, 3]) {} for (var j = 0;;) {} diff --git a/tools/acorn-optimizer.js b/tools/acorn-optimizer.js index a44cfc06d383e..a6874c04c9329 100755 --- a/tools/acorn-optimizer.js +++ b/tools/acorn-optimizer.js @@ -209,6 +209,9 @@ function restoreForVars(node) { ForInStatement(node) { fix(node.left); }, + ForOfStatement(node) { + fix(node.left); + }, }); return restored; } From 324e5dac2858a686aba8df91532f1dec4f208de7 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 15 Mar 2023 13:31:40 -0700 Subject: [PATCH 0008/1523] Add tests that use emscripten output in a bundler (webpack). NFC (#18969) If we want to iterate and improve on or support for MODULARIZE I think its good it we start testing it in the environments where it will likely be used. This change and an initial test for the use of MODULARIZE with the webpack bundler and verifies that the resulting bundle works. --- package-lock.json | 4386 +++++++++++++++++++++++++++++++++- package.json | 2 + test/test_browser.py | 9 + test/webpack/dist/index.html | 6 + test/webpack/src/index.js | 17 + 5 files changed, 4395 insertions(+), 25 deletions(-) create mode 100644 test/webpack/dist/index.html create mode 100644 test/webpack/src/index.js diff --git a/package-lock.json b/package-lock.json index 90bd69a5cd69f..16026dd816996 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,3547 @@ { + "name": "emscripten", + "lockfileVersion": 2, "requires": true, - "lockfileVersion": 1, + "packages": { + "": { + "dependencies": { + "acorn": "^8.7.1", + "google-closure-compiler": "20220502.0.0", + "html-minifier-terser": "6.1.0", + "wasm2c": "1.0.0" + }, + "devDependencies": { + "es-check": "^6.2.1", + "eslint": "^8.16.0", + "eslint-config-prettier": "^8.5.0", + "prettier": "^2.7.1", + "source-map": "0.7.4", + "webpack": "^5.76.1", + "webpack-cli": "^5.0.1", + "ws": "^8.6.0" + } + }, + "node_modules/@caporal/core": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@caporal/core/-/core-2.0.2.tgz", + "integrity": "sha512-o3J5aZINFWkkL+sL0DUs1dPHJjaetAAdwMRLbJ4U8aJW3K81E323IFMkFNYcOwTiPVhNzllC3USxZbU6xWFjFg==", + "dev": true, + "dependencies": { + "@types/glob": "^7.1.1", + "@types/lodash": "4.14.149", + "@types/node": "13.9.3", + "@types/table": "5.0.0", + "@types/tabtab": "^3.0.1", + "@types/wrap-ansi": "^3.0.0", + "chalk": "3.0.0", + "glob": "^7.1.6", + "lodash": "4.17.15", + "table": "5.4.6", + "tabtab": "^3.0.2", + "winston": "3.2.1", + "wrap-ansi": "^6.2.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@caporal/core/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@caporal/core/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@caporal/core/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@caporal/core/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@caporal/core/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@caporal/core/node_modules/lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "node_modules/@caporal/core/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", + "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.3.2", + "globals": "^13.15.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", + "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "dependencies": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@types/eslint": { + "version": "8.21.2", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.21.2.tgz", + "integrity": "sha512-EMpxUyystd3uZVByZap1DACsMXvb82ypQnGn89e1Y0a+LYu3JJscUd/gqhRsVFDkaD2MIiWo0MT8EfXr3DGRKw==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", + "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", + "dev": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "dev": true + }, + "node_modules/@types/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", + "dev": true, + "dependencies": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "node_modules/@types/lodash": { + "version": "4.14.149", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.149.tgz", + "integrity": "sha512-ijGqzZt/b7BfzcK9vTrS6MFljQRPn5BFWOx8oE0GYxribu6uV+aA9zZuXI1zc/etK9E8nrgdoF2+LgUw7+9tJQ==", + "dev": true + }, + "node_modules/@types/minimatch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", + "dev": true + }, + "node_modules/@types/node": { + "version": "13.9.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.9.3.tgz", + "integrity": "sha512-01s+ac4qerwd6RHD+mVbOEsraDHSgUaefQlEdBbUolnQFjKwCr7luvAlEwW1RFojh67u0z4OUTjPn9LEl4zIkA==", + "dev": true + }, + "node_modules/@types/table": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/table/-/table-5.0.0.tgz", + "integrity": "sha512-fQLtGLZXor264zUPWI95WNDsZ3QV43/c0lJpR/h1hhLJumXRmHNsrvBfEzW2YMhb0EWCsn4U6h82IgwsajAuTA==", + "dev": true + }, + "node_modules/@types/tabtab": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/tabtab/-/tabtab-3.0.2.tgz", + "integrity": "sha512-d8aOSJPS3SEGZevyr7vbAVUNPWGFmdFlk13vbPPK87vz+gYGM57L8T11k4wK2mOgQYZjEVYQEqmCTvupPoQBWw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/wrap-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/wrap-ansi/-/wrap-ansi-3.0.0.tgz", + "integrity": "sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g==", + "dev": true + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", + "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", + "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", + "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", + "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", + "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", + "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", + "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", + "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", + "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", + "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", + "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/helper-wasm-section": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-opt": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "@webassemblyjs/wast-printer": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", + "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", + "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", + "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", + "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webpack-cli/configtest": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.0.1.tgz", + "integrity": "sha512-njsdJXJSiS2iNbQVS0eT8A/KPnmyH4pv1APj2K0d1wrZcBLw+yppxOy4CGqa0OxDJkzfL/XELDhD8rocnIwB5A==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/info": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.1.tgz", + "integrity": "sha512-fE1UEWTwsAxRhrJNikE7v4EotYflkEhBL7EbajfkPlf6E37/2QshOy/D48Mw8G5XMFlQtS6YV42vtbG9zBpIQA==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/serve": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.1.tgz", + "integrity": "sha512-0G7tNyS+yW8TdgHwZKlDWYXFA6OJQnoLCQvYKkQP0Q2X205PSQ6RNUj0M+1OB/9gRQaUZ/ccYfaxd0nhaWKfjw==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-assertions": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", + "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "dev": true, + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "dev": true, + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.21.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", + "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001449", + "electron-to-chromium": "^1.4.284", + "node-releases": "^2.0.8", + "update-browserslist-db": "^1.0.10" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001465", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001465.tgz", + "integrity": "sha512-HvjgL3MYAJjceTDCcjRnQGjwUz/5qec9n7JPOzUursUoOTIsYCSDOb1l7RsnZE8mjbxG78zVRCKfrBXyvChBag==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ] + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/clean-css": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.2.2.tgz", + "integrity": "sha512-/eR8ru5zyxKzpBLv9YZvMXgTSSQn7AdkMItMYynsFgGwTveCRVam9IUPFloE85B4vAIj05IuKmmEoV7/AQjT0w==", + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 10.0" + } + }, + "node_modules/clean-css/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==", + "dev": true, + "dependencies": { + "restore-cursor": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cli-width": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", + "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", + "dev": true + }, + "node_modules/clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", + "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/clone-stats": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", + "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=" + }, + "node_modules/cloneable-readable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.3.tgz", + "integrity": "sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==", + "dependencies": { + "inherits": "^2.0.1", + "process-nextick-args": "^2.0.0", + "readable-stream": "^2.3.5" + } + }, + "node_modules/color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dev": true, + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/colorette": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", + "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", + "dev": true + }, + "node_modules/colornames": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/colornames/-/colornames-1.1.1.tgz", + "integrity": "sha1-+IiQMGhcfE/54qVZ9Qd+t2qBb5Y=", + "dev": true + }, + "node_modules/colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "dev": true, + "dependencies": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } + }, + "node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/diagnostics": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/diagnostics/-/diagnostics-1.1.1.tgz", + "integrity": "sha512-8wn1PmdunLJ9Tqbx+Fx/ZEuHfJf4NKSN2ZBj7SJC/OWRWha843+WsTjqMe1B5E3p28jqBlp+mJ2fPVxPyNgYKQ==", + "dev": true, + "dependencies": { + "colorspace": "1.1.x", + "enabled": "1.0.x", + "kuler": "1.0.x" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.328", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.328.tgz", + "integrity": "sha512-DE9tTy2PNmy1v55AZAO542ui+MLC2cvINMK4P2LXGsJdput/ThVG9t+QGecPuAZZSgC8XoI+Jh9M1OG9IoNSCw==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "node_modules/enabled": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-1.0.2.tgz", + "integrity": "sha1-ll9lE9LC0cX0ZStkouM5ZGf8L5M=", + "dev": true, + "dependencies": { + "env-variable": "0.0.x" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.12.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", + "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/env-variable": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/env-variable/-/env-variable-0.0.6.tgz", + "integrity": "sha512-bHz59NlBbtS0NhftmR8+ExBEekE7br0e01jw+kk0NDro7TtZzBYZ5ScGPs3OmwnpyfHTHOtr1Y6uedCdrIldtg==", + "dev": true + }, + "node_modules/envinfo": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", + "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", + "dev": true, + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/es-check": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/es-check/-/es-check-6.2.1.tgz", + "integrity": "sha512-IPiRXUlwSTd2yMklIf9yEGe6GK5wCS8Sz1aTNHm1QSiYzI4aiq19giYbLi95tb+e0JJVKmcU0iQXQWW60a8V9A==", + "dev": true, + "dependencies": { + "@caporal/core": "^2.0.2", + "acorn": "^8.7.0", + "fast-glob": "^3.2.11" + }, + "bin": { + "es-check": "index.js" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/es-module-lexer": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", + "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", + "dev": true + }, + "node_modules/es6-promisify": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-6.1.1.tgz", + "integrity": "sha512-HBL8I3mIki5C1Cc9QjKUenHtnG0A5/xA8Q/AllRcfiwl2CZFXGK7ddBiCoRwAix4i2KxcQfjtIVcrVbB3vbmwg==", + "dev": true + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.16.0.tgz", + "integrity": "sha512-MBndsoXY/PeVTDJeWsYj7kLZ5hQpJOfMYLsF6LicLHQWbRDG19lK5jOix4DPl8yY4SUFcE3txy86OzFLWT+yoA==", + "dev": true, + "dependencies": { + "@eslint/eslintrc": "^1.3.0", + "@humanwhocodes/config-array": "^0.9.2", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.2", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^6.0.1", + "globals": "^13.15.0", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz", + "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/espree": { + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.2.tgz", + "integrity": "sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==", + "dev": true, + "dependencies": { + "acorn": "^8.7.1", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==", + "dev": true + }, + "node_modules/figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", + "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", + "dev": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "node_modules/globals": { + "version": "13.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.15.0.tgz", + "integrity": "sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/google-closure-compiler": { + "version": "20220502.0.0", + "resolved": "https://registry.npmjs.org/google-closure-compiler/-/google-closure-compiler-20220502.0.0.tgz", + "integrity": "sha512-i9Qdve2v3jlerkHzlm00bpYds+kfAlIdeaOQ+acK/pHPHeLjhiXS+EyIpegVnH8+TY3I1QAMZFuVEXkMVJqpBQ==", + "dependencies": { + "chalk": "2.x", + "google-closure-compiler-java": "^20220502.0.0", + "minimist": "1.x", + "vinyl": "2.x", + "vinyl-sourcemaps-apply": "^0.2.0" + }, + "bin": { + "google-closure-compiler": "cli.js" + }, + "engines": { + "node": ">=10" + }, + "optionalDependencies": { + "google-closure-compiler-linux": "^20220502.0.0", + "google-closure-compiler-osx": "^20220502.0.0", + "google-closure-compiler-windows": "^20220502.0.0" + } + }, + "node_modules/google-closure-compiler-java": { + "version": "20220502.0.0", + "resolved": "https://registry.npmjs.org/google-closure-compiler-java/-/google-closure-compiler-java-20220502.0.0.tgz", + "integrity": "sha512-XDXw1v+1zcNHuEUXQg24eD9MUF2XTHnEDKCwF0P0zQe+8TWQajKvjsekdJnO6JH/Lqcu8XKc7dxO5+SMijr0sw==" + }, + "node_modules/google-closure-compiler-linux": { + "version": "20220502.0.0", + "resolved": "https://registry.npmjs.org/google-closure-compiler-linux/-/google-closure-compiler-linux-20220502.0.0.tgz", + "integrity": "sha512-T+2p/Qj02yGZHxymhj1oZsiHudNvI9sQKfCLoIH0wi0ikDiVIOh/dsH+57lsaGDJ+XTP/ur5Ozl8GIOjv1Efrw==", + "cpu": [ + "x64", + "x86" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/google-closure-compiler-osx": { + "version": "20220502.0.0", + "resolved": "https://registry.npmjs.org/google-closure-compiler-osx/-/google-closure-compiler-osx-20220502.0.0.tgz", + "integrity": "sha512-VwEncD4I1gfkF3zyHlRcUsx2o/poC0qzHjBv+g3Z09wHy9tuqjQ4EP8LmN/GMuV2Hai6gQvkKC0XjYnZTFx2mQ==", + "cpu": [ + "x64", + "x86", + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/google-closure-compiler-windows": { + "version": "20220502.0.0", + "resolved": "https://registry.npmjs.org/google-closure-compiler-windows/-/google-closure-compiler-windows-20220502.0.0.tgz", + "integrity": "sha512-ssdAUS2VZxJAyciVrbhpnYymvm//V4CHyg8aLvMisUfWRDeUSsOCC5mNXy6D8f9i9bYHs3cFV3itIRUfnYCEWg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "engines": { + "node": ">=4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "bin": { + "he": "bin/he" + } + }, + "node_modules/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "dependencies": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/html-minifier-terser/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "engines": { + "node": ">= 12" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/inquirer": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", + "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", + "dev": true, + "dependencies": { + "ansi-escapes": "^3.2.0", + "chalk": "^2.4.2", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^2.0.0", + "lodash": "^4.17.12", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rxjs": "^6.4.0", + "string-width": "^2.1.0", + "strip-ansi": "^5.1.0", + "through": "^2.3.6" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/inquirer/node_modules/ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/inquirer/node_modules/string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/inquirer/node_modules/string-width/node_modules/strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "dev": true + }, + "node_modules/is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/kuler": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-1.0.1.tgz", + "integrity": "sha512-J9nVUucG1p/skKul6DU3PUZrhs0LPulNaeUOox0IyXDi8S4CztTHs1gQphhuZmzXG7VOQSf6NJfKuzteQLv9gQ==", + "dev": true, + "dependencies": { + "colornames": "^1.1.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/logform": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.4.0.tgz", + "integrity": "sha512-CPSJw4ftjf517EhXZGGvTHHkYobo7ZCc0kvwUoOYcjfR2UVrI66RHj8MCrfAdEitdmFqbu2BYdYs8FHHZSb6iw==", + "dev": true, + "dependencies": { + "@colors/colors": "1.5.0", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + } + }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "dev": true + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/node-releases": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", + "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", + "dev": true + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/one-time": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-0.0.4.tgz", + "integrity": "sha1-+M33eISCb+Tf+T46nMN7HkSAdC4=", + "dev": true + }, + "node_modules/onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "dependencies": { + "mimic-fn": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", + "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "dev": true, + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" + }, + "node_modules/replace-ext": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.1.tgz", + "integrity": "sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "dependencies": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/rxjs/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/safe-stable-stringify": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.3.1.tgz", + "integrity": "sha512-kYBSfT+troD9cDA85VDnHZ1rpHC50O0g1e6WlGHVCz/g+JS+9WKLj+XwFYyR8UbrZN8ll9HUpDAAddY58MGisg==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "dev": true, + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "dependencies": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/tabtab": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/tabtab/-/tabtab-3.0.2.tgz", + "integrity": "sha512-jANKmUe0sIQc/zTALTBy186PoM/k6aPrh3A7p6AaAfF6WPSbTx1JYeGIGH162btpH+mmVEXln+UxwViZHO2Jhg==", + "dev": true, + "dependencies": { + "debug": "^4.0.1", + "es6-promisify": "^6.0.0", + "inquirer": "^6.0.0", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "untildify": "^3.0.3" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser": { + "version": "5.16.6", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.6.tgz", + "integrity": "sha512-IBZ+ZQIA9sMaXmRZCUMDjNH0D5AQQfdn4WUjHL0+1lF4TP1IHRJbrhb6fNaXWikrYQTSkb7SLxkeXAiy1p7mbg==", + "dependencies": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.7", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.7.tgz", + "integrity": "sha512-AfKwIktyP7Cu50xNjXF/6Qb5lBNzYaWpU6YfoX3uZicTx0zTy0stDDCsvjDapKsSDvOeWo5MEq4TmdBy2cNoHw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.17", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.16.5" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "node_modules/text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", + "dev": true + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/triple-beam": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", + "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==", + "dev": true + }, + "node_modules/tslib": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/untildify": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-3.0.3.tgz", + "integrity": "sha512-iSk/J8efr8uPT/Z4eSUywnqyrQU7DSdMfdqK4iWEaUVVmcP5JcnpRqmVMwcwcnmI1ATFNgC5V90u09tBynNFKA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist-lint": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "node_modules/v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "node_modules/vinyl": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.1.tgz", + "integrity": "sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw==", + "dependencies": { + "clone": "^2.1.1", + "clone-buffer": "^1.0.0", + "clone-stats": "^1.0.0", + "cloneable-readable": "^1.0.0", + "remove-trailing-separator": "^1.0.1", + "replace-ext": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vinyl-sourcemaps-apply": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz", + "integrity": "sha1-q2VJ1h0XLCsbh75cUI0jnI74dwU=", + "dependencies": { + "source-map": "^0.5.1" + } + }, + "node_modules/vinyl-sourcemaps-apply/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wasm2c": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wasm2c/-/wasm2c-1.0.0.tgz", + "integrity": "sha512-4SIESF2JNxrry6XFa/UQcsQibn+bxPkQ/oqixiXz2o8fsMl8J4vtvhH/evgbi8vZajAlaukuihEcQTWb9tVLUA==" + }, + "node_modules/watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dev": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack": { + "version": "5.76.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.1.tgz", + "integrity": "sha512-4+YIK4Abzv8172/SGqObnUjaIHjLEuUasz9EwQj/9xmPPkYJy2Mh03Q/lJfSD3YLzbxy5FeTq5Uw0323Oh6SJQ==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.10.0", + "es-module-lexer": "^0.9.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-cli": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.0.1.tgz", + "integrity": "sha512-S3KVAyfwUqr0Mo/ur3NzIp6jnerNpo7GUO6so51mxLi1spqsA17YcMXy0WOIJtBSnj748lthxC6XLbNKh/ZC+A==", + "dev": true, + "dependencies": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^2.0.1", + "@webpack-cli/info": "^2.0.1", + "@webpack-cli/serve": "^2.0.1", + "colorette": "^2.0.14", + "commander": "^9.4.1", + "cross-spawn": "^7.0.3", + "envinfo": "^7.7.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", + "webpack-merge": "^5.7.3" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true + }, + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-merge": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", + "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/webpack/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wildcard": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", + "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", + "dev": true + }, + "node_modules/winston": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.2.1.tgz", + "integrity": "sha512-zU6vgnS9dAWCEKg/QYigd6cgMVVNwyTzKs81XZtTFuRwJOcDdBg7AU0mXVyNbs7O5RH2zdv+BdNZUlx7mXPuOw==", + "dev": true, + "dependencies": { + "async": "^2.6.1", + "diagnostics": "^1.1.1", + "is-stream": "^1.1.0", + "logform": "^2.1.1", + "one-time": "0.0.4", + "readable-stream": "^3.1.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.3.0" + }, + "engines": { + "node": ">= 6.4.0" + } + }, + "node_modules/winston-transport": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.5.0.tgz", + "integrity": "sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q==", + "dev": true, + "dependencies": { + "logform": "^2.3.2", + "readable-stream": "^3.6.0", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 6.4.0" + } + }, + "node_modules/winston-transport/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/winston/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "node_modules/ws": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.6.0.tgz", + "integrity": "sha512-AzmM3aH3gk0aX7/rZLYvjdvZooofDu3fFOzGqcSnQ1tOcTWwhM/o+q++E8mAyVVIyUdajrkzWUGftaVSDLn1bw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + } + }, "dependencies": { "@caporal/core": { "version": "2.0.2", @@ -86,6 +3627,12 @@ "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", "dev": true }, + "@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true + }, "@eslint/eslintrc": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", @@ -120,6 +3667,49 @@ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "dev": true }, + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==" + }, + "@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" + }, + "@jridgewell/trace-mapping": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "requires": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -146,6 +3736,32 @@ "fastq": "^1.6.0" } }, + "@types/eslint": { + "version": "8.21.2", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.21.2.tgz", + "integrity": "sha512-EMpxUyystd3uZVByZap1DACsMXvb82ypQnGn89e1Y0a+LYu3JJscUd/gqhRsVFDkaD2MIiWo0MT8EfXr3DGRKw==", + "dev": true, + "requires": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "@types/eslint-scope": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", + "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", + "dev": true, + "requires": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "@types/estree": { + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "dev": true + }, "@types/glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", @@ -156,6 +3772,12 @@ "@types/node": "*" } }, + "@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, "@types/lodash": { "version": "4.14.149", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.149.tgz", @@ -189,10 +3811,189 @@ "@types/node": "*" } }, - "@types/wrap-ansi": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/wrap-ansi/-/wrap-ansi-3.0.0.tgz", - "integrity": "sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g==", + "@types/wrap-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/wrap-ansi/-/wrap-ansi-3.0.0.tgz", + "integrity": "sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g==", + "dev": true + }, + "@webassemblyjs/ast": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", + "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "dev": true, + "requires": { + "@webassemblyjs/helper-numbers": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", + "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", + "dev": true + }, + "@webassemblyjs/helper-api-error": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", + "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", + "dev": true + }, + "@webassemblyjs/helper-buffer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", + "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", + "dev": true + }, + "@webassemblyjs/helper-numbers": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", + "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", + "dev": true, + "requires": { + "@webassemblyjs/floating-point-hex-parser": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", + "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", + "dev": true + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", + "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", + "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "dev": true, + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", + "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "dev": true, + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", + "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", + "dev": true + }, + "@webassemblyjs/wasm-edit": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", + "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/helper-wasm-section": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-opt": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "@webassemblyjs/wast-printer": "1.11.1" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", + "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", + "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", + "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", + "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "@webpack-cli/configtest": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.0.1.tgz", + "integrity": "sha512-njsdJXJSiS2iNbQVS0eT8A/KPnmyH4pv1APj2K0d1wrZcBLw+yppxOy4CGqa0OxDJkzfL/XELDhD8rocnIwB5A==", + "dev": true, + "requires": {} + }, + "@webpack-cli/info": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.1.tgz", + "integrity": "sha512-fE1UEWTwsAxRhrJNikE7v4EotYflkEhBL7EbajfkPlf6E37/2QshOy/D48Mw8G5XMFlQtS6YV42vtbG9zBpIQA==", + "dev": true, + "requires": {} + }, + "@webpack-cli/serve": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.1.tgz", + "integrity": "sha512-0G7tNyS+yW8TdgHwZKlDWYXFA6OJQnoLCQvYKkQP0Q2X205PSQ6RNUj0M+1OB/9gRQaUZ/ccYfaxd0nhaWKfjw==", + "dev": true, + "requires": {} + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", "dev": true }, "acorn": { @@ -200,11 +4001,19 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==" }, + "acorn-import-assertions": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", + "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "dev": true, + "requires": {} + }, "acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true + "dev": true, + "requires": {} }, "ajv": { "version": "6.12.6", @@ -218,6 +4027,13 @@ "uri-js": "^4.2.2" } }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "requires": {} + }, "ansi-escapes": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", @@ -284,6 +4100,18 @@ "fill-range": "^7.0.1" } }, + "browserslist": { + "version": "4.21.5", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", + "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001449", + "electron-to-chromium": "^1.4.284", + "node-releases": "^2.0.8", + "update-browserslist-db": "^1.0.10" + } + }, "buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -304,6 +4132,12 @@ "tslib": "^2.0.3" } }, + "caniuse-lite": { + "version": "1.0.30001465", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001465.tgz", + "integrity": "sha512-HvjgL3MYAJjceTDCcjRnQGjwUz/5qec9n7JPOzUursUoOTIsYCSDOb1l7RsnZE8mjbxG78zVRCKfrBXyvChBag==", + "dev": true + }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -320,6 +4154,12 @@ "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", "dev": true }, + "chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true + }, "clean-css": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.2.2.tgz", @@ -360,6 +4200,17 @@ "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=" }, + "clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + } + }, "clone-stats": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", @@ -408,6 +4259,12 @@ "simple-swizzle": "^0.2.2" } }, + "colorette": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", + "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", + "dev": true + }, "colornames": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/colornames/-/colornames-1.1.1.tgz", @@ -424,6 +4281,12 @@ "text-hex": "1.0.x" } }, + "commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "dev": true + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -490,6 +4353,12 @@ "tslib": "^2.0.3" } }, + "electron-to-chromium": { + "version": "1.4.328", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.328.tgz", + "integrity": "sha512-DE9tTy2PNmy1v55AZAO542ui+MLC2cvINMK4P2LXGsJdput/ThVG9t+QGecPuAZZSgC8XoI+Jh9M1OG9IoNSCw==", + "dev": true + }, "emoji-regex": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", @@ -505,12 +4374,28 @@ "env-variable": "0.0.x" } }, + "enhanced-resolve": { + "version": "5.12.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", + "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + } + }, "env-variable": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/env-variable/-/env-variable-0.0.6.tgz", "integrity": "sha512-bHz59NlBbtS0NhftmR8+ExBEekE7br0e01jw+kk0NDro7TtZzBYZ5ScGPs3OmwnpyfHTHOtr1Y6uedCdrIldtg==", "dev": true }, + "envinfo": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", + "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", + "dev": true + }, "es-check": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/es-check/-/es-check-6.2.1.tgz", @@ -522,12 +4407,24 @@ "fast-glob": "^3.2.11" } }, + "es-module-lexer": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", + "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", + "dev": true + }, "es6-promisify": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-6.1.1.tgz", "integrity": "sha512-HBL8I3mIki5C1Cc9QjKUenHtnG0A5/xA8Q/AllRcfiwl2CZFXGK7ddBiCoRwAix4i2KxcQfjtIVcrVbB3vbmwg==", "dev": true }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -661,7 +4558,8 @@ "version": "8.5.0", "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz", "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==", - "dev": true + "dev": true, + "requires": {} }, "eslint-scope": { "version": "7.1.1", @@ -737,6 +4635,12 @@ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true + }, "external-editor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", @@ -779,6 +4683,12 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, + "fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true + }, "fastq": { "version": "1.13.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", @@ -821,6 +4731,16 @@ "to-regex-range": "^5.0.1" } }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, "flat-cache": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", @@ -843,6 +4763,12 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, "functional-red-black-tree": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", @@ -872,6 +4798,12 @@ "is-glob": "^4.0.1" } }, + "glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, "globals": { "version": "13.15.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.15.0.tgz", @@ -919,6 +4851,21 @@ "integrity": "sha512-ssdAUS2VZxJAyciVrbhpnYymvm//V4CHyg8aLvMisUfWRDeUSsOCC5mNXy6D8f9i9bYHs3cFV3itIRUfnYCEWg==", "optional": true }, + "graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -975,6 +4922,16 @@ "resolve-from": "^4.0.0" } }, + "import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "requires": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + } + }, "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -1046,12 +5003,27 @@ } } }, + "interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "dev": true + }, "is-arrayish": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", "dev": true }, + "is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -1079,6 +5051,15 @@ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", @@ -1096,6 +5077,40 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true + }, + "jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -1105,6 +5120,12 @@ "argparse": "^2.0.1" } }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -1117,6 +5138,12 @@ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, "kuler": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/kuler/-/kuler-1.0.1.tgz", @@ -1136,6 +5163,21 @@ "type-check": "~0.4.0" } }, + "loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -1169,6 +5211,12 @@ "tslib": "^2.0.3" } }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, "merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -1185,6 +5233,21 @@ "picomatch": "^2.3.1" } }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "requires": { + "mime-db": "1.52.0" + } + }, "mimic-fn": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", @@ -1232,6 +5295,12 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, "no-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", @@ -1241,6 +5310,12 @@ "tslib": "^2.0.3" } }, + "node-releases": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", + "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", + "dev": true + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -1285,6 +5360,30 @@ "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, "param-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", @@ -1312,6 +5411,12 @@ "tslib": "^2.0.3" } }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -1324,12 +5429,33 @@ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, "picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, "prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -1359,6 +5485,15 @@ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, "readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", @@ -1373,6 +5508,15 @@ "util-deprecate": "~1.0.1" } }, + "rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "dev": true, + "requires": { + "resolve": "^1.20.0" + } + }, "regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", @@ -1394,6 +5538,34 @@ "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.1.tgz", "integrity": "sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==" }, + "resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "requires": { + "resolve-from": "^5.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + } + } + }, "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -1474,6 +5646,35 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, + "schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + }, + "serialize-javascript": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "requires": { + "kind-of": "^6.0.2" + } + }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -1543,6 +5744,14 @@ "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", "dev": true }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", @@ -1554,14 +5763,6 @@ "strip-ansi": "^5.1.0" } }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - }, "strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", @@ -1585,6 +5786,12 @@ "has-flag": "^3.0.0" } }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, "table": { "version": "5.4.6", "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", @@ -1611,13 +5818,20 @@ "untildify": "^3.0.3" } }, + "tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true + }, "terser": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.10.0.tgz", - "integrity": "sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA==", + "version": "5.16.6", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.6.tgz", + "integrity": "sha512-IBZ+ZQIA9sMaXmRZCUMDjNH0D5AQQfdn4WUjHL0+1lF4TP1IHRJbrhb6fNaXWikrYQTSkb7SLxkeXAiy1p7mbg==", "requires": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", "commander": "^2.20.0", - "source-map": "~0.7.2", "source-map-support": "~0.5.20" }, "dependencies": { @@ -1625,14 +5839,22 @@ "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" } } }, + "terser-webpack-plugin": { + "version": "5.3.7", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.7.tgz", + "integrity": "sha512-AfKwIktyP7Cu50xNjXF/6Qb5lBNzYaWpU6YfoX3uZicTx0zTy0stDDCsvjDapKsSDvOeWo5MEq4TmdBy2cNoHw==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.17", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.16.5" + } + }, "text-hex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", @@ -1701,6 +5923,16 @@ "integrity": "sha512-iSk/J8efr8uPT/Z4eSUywnqyrQU7DSdMfdqK4iWEaUVVmcP5JcnpRqmVMwcwcnmI1ATFNgC5V90u09tBynNFKA==", "dev": true }, + "update-browserslist-db": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "dev": true, + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, "uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -1754,6 +5986,103 @@ "resolved": "https://registry.npmjs.org/wasm2c/-/wasm2c-1.0.0.tgz", "integrity": "sha512-4SIESF2JNxrry6XFa/UQcsQibn+bxPkQ/oqixiXz2o8fsMl8J4vtvhH/evgbi8vZajAlaukuihEcQTWb9tVLUA==" }, + "watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dev": true, + "requires": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + } + }, + "webpack": { + "version": "5.76.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.1.tgz", + "integrity": "sha512-4+YIK4Abzv8172/SGqObnUjaIHjLEuUasz9EwQj/9xmPPkYJy2Mh03Q/lJfSD3YLzbxy5FeTq5Uw0323Oh6SJQ==", + "dev": true, + "requires": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.10.0", + "es-module-lexer": "^0.9.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "dependencies": { + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + } + } + }, + "webpack-cli": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.0.1.tgz", + "integrity": "sha512-S3KVAyfwUqr0Mo/ur3NzIp6jnerNpo7GUO6so51mxLi1spqsA17YcMXy0WOIJtBSnj748lthxC6XLbNKh/ZC+A==", + "dev": true, + "requires": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^2.0.1", + "@webpack-cli/info": "^2.0.1", + "@webpack-cli/serve": "^2.0.1", + "colorette": "^2.0.14", + "commander": "^9.4.1", + "cross-spawn": "^7.0.3", + "envinfo": "^7.7.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", + "webpack-merge": "^5.7.3" + } + }, + "webpack-merge": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", + "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", + "dev": true, + "requires": { + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" + } + }, + "webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true + }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -1763,6 +6092,12 @@ "isexe": "^2.0.0" } }, + "wildcard": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", + "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", + "dev": true + }, "winston": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/winston/-/winston-3.2.1.tgz", @@ -1908,7 +6243,8 @@ "version": "8.6.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.6.0.tgz", "integrity": "sha512-AzmM3aH3gk0aX7/rZLYvjdvZooofDu3fFOzGqcSnQ1tOcTWwhM/o+q++E8mAyVVIyUdajrkzWUGftaVSDLn1bw==", - "dev": true + "dev": true, + "requires": {} } } } diff --git a/package.json b/package.json index 85671429bbacc..e04114fbd9e75 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,8 @@ "eslint-config-prettier": "^8.5.0", "prettier": "^2.7.1", "source-map": "0.7.4", + "webpack": "^5.76.1", + "webpack-cli": "^5.0.1", "ws": "^8.6.0" }, "dependencies": { diff --git a/test/test_browser.py b/test/test_browser.py index 24bc919e7c8f0..e12995c04762a 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -26,6 +26,7 @@ from common import read_file, requires_v8, also_with_minimal_runtime, EMRUN from tools import shared from tools import ports +from tools import utils from tools.shared import EMCC, WINDOWS, FILE_PACKAGER, PIPE from tools.utils import delete_file, delete_dir @@ -5524,6 +5525,14 @@ def test_error_reporting(self): create_file('post.js', 'throw "foo";') self.btest(test_file('hello_world.c'), args=['--post-js=post.js'], expected='exception:foo') + def test_webpack(self): + shutil.copytree(test_file('webpack'), 'webpack') + with utils.chdir('webpack'): + self.compile_btest([test_file('hello_world.c'), '-sEXIT_RUNTIME', '-sMODULARIZE', '-sENVIRONMENT=web', '-o', 'src/hello.js']) + self.run_process(shared.get_npm_cmd('webpack') + ['--mode=development', '--no-devtool']) + shutil.copyfile('webpack/src/hello.wasm', 'webpack/dist/hello.wasm') + self.run_browser('webpack/dist/index.html', '/report_result?exit:0') + class emrun(RunnerCore): def test_emrun_info(self): diff --git a/test/webpack/dist/index.html b/test/webpack/dist/index.html new file mode 100644 index 0000000000000..a5e8b18cf27c6 --- /dev/null +++ b/test/webpack/dist/index.html @@ -0,0 +1,6 @@ + + +

+ + + diff --git a/test/webpack/src/index.js b/test/webpack/src/index.js new file mode 100644 index 0000000000000..cb7b9db7de533 --- /dev/null +++ b/test/webpack/src/index.js @@ -0,0 +1,17 @@ +var params = { + print: (function() { + var element = document.getElementById('output'); + return function(text) { + console.log(text); + element.innerHTML += text.replace('\n', '
', 'g') + '
'; + }; + })(), + canvas: document.getElementById('canvas'), +}; + +params.print("testing.."); + +var mod = require('./hello'); +mod(params).then((instance) => { + console.log('loaded'); +}); From 0db304e684947a04f7ee6c99431653f70785ad43 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 15 Mar 2023 13:32:03 -0700 Subject: [PATCH 0009/1523] Enable simd tests under wasm64. NFC (#18832) --- test/runner.py | 2 ++ test/test_core.py | 3 --- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/test/runner.py b/test/runner.py index afb3fea9c46eb..7f6af2532f7e0 100755 --- a/test/runner.py +++ b/test/runner.py @@ -65,6 +65,8 @@ 'asan', 'lsan', 'ubsan', + 'wasm64', + 'wasm64_v8', ] # The default core test mode, used when none is specified diff --git a/test/test_core.py b/test/test_core.py index 86ced5adb068d..cfb640c962f13 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -6737,7 +6737,6 @@ def test_neon_wasm_simd(self): # Tests invoking the SIMD API via x86 SSE1 xmmintrin.h header (_mm_x() functions) @wasm_simd @requires_native_clang - @no_wasm64('https://github.com/llvm/llvm-project/issues/57577') @no_safe_heap('has unaligned 64-bit operations in wasm') @no_ubsan('test contains UB') def test_sse1(self): @@ -6766,7 +6765,6 @@ def test_sse2(self): self.do_runf(src, native_result) # Tests invoking the SIMD API via x86 SSE3 pmmintrin.h header (_mm_x() functions) - @no_wasm64('https://github.com/llvm/llvm-project/issues/57577') @wasm_simd @requires_native_clang def test_sse3(self): @@ -6852,7 +6850,6 @@ def test_sse_diagnostics(self): @requires_native_clang @wasm_relaxed_simd - @no_wasm64('https://github.com/llvm/llvm-project/issues/57577') def test_relaxed_simd_implies_simd128(self): src = test_file('sse/test_sse1.cpp') self.build(src, emcc_args=['-msse']) From b9131b0ea4a99b6964caf7d9edf5d46f7007e3e9 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 15 Mar 2023 13:43:07 -0700 Subject: [PATCH 0010/1523] Using -sMEMORY64 rather than -sMEMORY64=2 in browser tests (#18960) --- .circleci/config.yml | 7 ++++--- test/test_browser.py | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 7559743c6f0de..4402430f4f23c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -266,7 +266,7 @@ commands: - run: name: download firefox command: | - wget -O ~/ff.tar.bz2 "https://download.mozilla.org/?product=firefox-devedition-latest-ssl&os=linux64&lang=en-US" + wget -O ~/ff.tar.bz2 "https://download.mozilla.org/?product=firefox-nightly-latest-ssl&os=linux64&lang=en-US" tar -C ~ -xf ~/ff.tar.bz2 - run: name: configure firefox @@ -275,6 +275,7 @@ commands: cat > ~/tmp-firefox-profile/user.js \< Date: Wed, 15 Mar 2023 17:05:38 -0700 Subject: [PATCH 0011/1523] Ninja library build: allow deferred/combined builds using a parent ninja (#17871) This creates separate build/generate steps for library builds, and uses them in embuilder when building multiple libraries at once (non-embuilder builds are still separated). It creates a "parent" build.ninja and adds a subninja for each library as it is built (either by embuilder or emcc). Embuilder gets a "rebuild" command in embuilder that invokes ninja on that file, thus rebuilding all libraries that have been built in the current cache. This is expected to be most useful for developing emscripten (since the dependencies will ensure only necessary files are rebuilt when editing emscripten library sources), but using it on CircleCI also cuts 7 minutes (~25%) off build-linux step due to parallelism across libraries. --- .circleci/config.yml | 2 ++ embuilder.py | 22 ++++++++++++++++------ tools/cache.py | 5 +++-- tools/system_libs.py | 42 ++++++++++++++++++++++++++++++++++++------ 4 files changed, 57 insertions(+), 14 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 4402430f4f23c..54b258fd55c79 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -158,6 +158,7 @@ commands: command: | ./emcc --clear-cache - pip-install + - run: apt-get install ninja-build - run: name: embuilder build ALL command: | @@ -404,6 +405,7 @@ jobs: resource_class: xlarge environment: EMCC_CORES: 16 + EMCC_USE_NINJA: 1 steps: - checkout - run: diff --git a/embuilder.py b/embuilder.py index 7e2178ffad55d..993a30f272fca 100755 --- a/embuilder.py +++ b/embuilder.py @@ -23,6 +23,7 @@ from tools import system_libs from tools import ports from tools.settings import settings +from tools.system_libs import USE_NINJA import emscripten @@ -173,12 +174,15 @@ def main(): help='show build commands') parser.add_argument('--wasm64', action='store_true', help='use wasm64 architecture') - parser.add_argument('operation', help='currently only "build" and "clear" are supported') - parser.add_argument('targets', nargs='+', help='see below') + parser.add_argument('operation', choices=['build', 'clear', 'rebuild']) + parser.add_argument('targets', nargs='*', help='see below') args = parser.parse_args() - if args.operation not in ('build', 'clear'): - shared.exit_with_error('unfamiliar operation: ' + args.operation) + if args.operation != 'rebuild' and len(args.targets) == 0: + shared.exit_with_error('no build targets specified') + + if args.operation == 'rebuild' and not USE_NINJA: + shared.exit_with_error('"rebuild" operation is only valid when using Ninja') # process flags @@ -244,7 +248,10 @@ def main(): if do_clear: library.erase() if do_build: - library.build(deterministic_paths=True) + if USE_NINJA: + library.generate() + else: + library.build(deterministic_paths=True) elif what == 'sysroot': if do_clear: cache.erase_file('sysroot_install.stamp') @@ -267,7 +274,10 @@ def main(): time_taken = time.time() - start_time logger.info('...success. Took %s(%.2fs)' % (('%02d:%02d mins ' % (time_taken // 60, time_taken % 60) if time_taken >= 60 else ''), time_taken)) - if len(tasks) > 1: + if USE_NINJA and not do_clear: + system_libs.build_deferred() + + if len(tasks) > 1 or USE_NINJA: all_build_time_taken = time.time() - all_build_start_time logger.info('Built %d targets in %s(%.2fs)' % (len(tasks), ('%02d:%02d mins ' % (all_build_time_taken // 60, all_build_time_taken % 60) if all_build_time_taken >= 60 else ''), all_build_time_taken)) diff --git a/tools/cache.py b/tools/cache.py index f6f60057a5ab2..b9ccb93c4a262 100644 --- a/tools/cache.py +++ b/tools/cache.py @@ -138,7 +138,7 @@ def get_lib(libname, *args, **kwargs): # Request a cached file. If it isn't in the cache, it will be created with # the given creator function -def get(shortname, creator, what=None, force=False, quiet=False): +def get(shortname, creator, what=None, force=False, quiet=False, deferred=False): cachename = Path(cachedir, shortname) # Check for existence before taking the lock in case we can avoid the # lock completely. @@ -162,7 +162,8 @@ def get(shortname, creator, what=None, force=False, quiet=False): logger.info(message) utils.safe_ensure_dirs(cachename.parent) creator(str(cachename)) - assert cachename.exists() + if not deferred: + assert cachename.exists() if not quiet: logger.info(' - ok') diff --git a/tools/system_libs.py b/tools/system_libs.py index 34bf8b330b724..cfb5b1bbe770e 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -20,6 +20,7 @@ from . import cache from tools.shared import demangle_c_symbol_name from tools.settings import settings +from tools.utils import read_file logger = logging.getLogger('system_libs') @@ -103,14 +104,25 @@ def create_lib(libname, inputs): building.emar('cr', libname, inputs) +def get_top_level_ninja_file(): + return os.path.join(cache.get_path('build'), 'build.ninja') + + def run_ninja(build_dir): diagnostics.warning('experimental', 'ninja support is experimental') - cmd = ['ninja', '-C', build_dir] + cmd = ['ninja', '-C', build_dir, f'-j{shared.get_num_cores()}'] if shared.PRINT_STAGES: cmd.append('-v') shared.check_call(cmd, env=clean_env()) +def ensure_target_in_ninja_file(ninja_file, target): + if os.path.isfile(ninja_file) and target in read_file(ninja_file): + return + with open(ninja_file, 'a') as f: + f.write(target + '\n') + + def create_ninja_file(input_files, filename, libname, cflags, asflags=None, customize_build_flags=None): if asflags is None: asflags = [] @@ -164,6 +176,7 @@ def join(flags): ''' suffix = shared.suffix(libname) + build_dir = os.path.dirname(filename) case_insensitive = is_case_insensitive(os.path.dirname(filename)) if suffix == '.o': @@ -177,7 +190,7 @@ def join(flags): # Resolve duplicates by appending unique. # This is needed on case insensitve filesystem to handle, # for example, _exit.o and _Exit.o. - o = shared.unsuffixed_basename(src) + '.o' + o = os.path.join(build_dir, shared.unsuffixed_basename(src) + '.o') object_uuid = 0 if case_insensitive: o = o.lower() @@ -210,6 +223,7 @@ def join(flags): out += f'build {libname}: archive {objects}\n' utils.write_file(filename, out) + ensure_target_in_ninja_file(get_top_level_ninja_file(), f'subninja {filename}') def is_case_insensitive(path): @@ -373,6 +387,11 @@ def build(self, deterministic_paths=False): self.deterministic_paths = deterministic_paths return cache.get(self.get_path(), self.do_build, force=USE_NINJA == 2, quiet=USE_NINJA) + def generate(self): + self.deterministic_paths = False + return cache.get(self.get_path(), self.do_generate, force=USE_NINJA == 2, quiet=USE_NINJA, + deferred=True) + def get_link_flag(self): """ Gets the link flags needed to use the library. @@ -405,7 +424,7 @@ def get_files(self): raise NotImplementedError() - def build_with_ninja(self, build_dir, libname): + def generate_ninja(self, build_dir, libname): ensure_sysroot() utils.safe_ensure_dirs(build_dir) @@ -418,7 +437,6 @@ def build_with_ninja(self, build_dir, libname): input_files = self.get_files() ninja_file = os.path.join(build_dir, 'build.ninja') create_ninja_file(input_files, ninja_file, libname, cflags, asflags=asflags, customize_build_flags=self.customize_build_cmd) - run_ninja(build_dir) def build_objects(self, build_dir): """ @@ -477,12 +495,14 @@ def customize_build_cmd(self, cmd, _filename): For example, libc uses this to replace -Oz with -O2 for some subset of files.""" return cmd - def do_build(self, out_filename): + def do_build(self, out_filename, generate_only=False): """Builds the library and returns the path to the file.""" assert out_filename == self.get_path(absolute=True) build_dir = os.path.join(cache.get_path('build'), self.get_base_name()) if USE_NINJA: - self.build_with_ninja(build_dir, out_filename) + self.generate_ninja(build_dir, out_filename) + if not generate_only: + run_ninja(build_dir) else: # Use a seperate build directory to the ninja flavor so that building without # EMCC_USE_NINJA doesn't clobber the ninja build tree @@ -492,6 +512,9 @@ def do_build(self, out_filename): if not shared.DEBUG: utils.delete_dir(build_dir) + def do_generate(self, out_filename): + self.do_build(out_filename, generate_only=True) + @classmethod def _inherit_list(cls, attr): # Some properties, like cflags and includes, makes more sense to inherit @@ -2266,3 +2289,10 @@ def install_system_headers(stamp): @ToolchainProfiler.profile() def ensure_sysroot(): cache.get('sysroot_install.stamp', install_system_headers, what='system headers') + + +def build_deferred(): + assert USE_NINJA + top_level_ninja = get_top_level_ninja_file() + if os.path.isfile(top_level_ninja): + run_ninja(os.path.dirname(top_level_ninja)) From cebc40879bd4825587679d53203310f271042238 Mon Sep 17 00:00:00 2001 From: arsnyder16 Date: Thu, 16 Mar 2023 13:02:50 -0400 Subject: [PATCH 0012/1523] emrun establish browser url after starting web server (#18932) --- emrun.py | 11 +++++++---- test/test_browser.py | 1 + 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/emrun.py b/emrun.py index 5a936ea041cf0..59a95b40317b8 100644 --- a/emrun.py +++ b/emrun.py @@ -1643,10 +1643,6 @@ def run(): url = file_to_serve else: url = os.path.relpath(os.path.abspath(file_to_serve), serve_dir) - if len(options.cmdlineparams): - url += '?' + '&'.join(options.cmdlineparams) - hostname = socket.gethostbyname(socket.gethostname()) if options.android else options.hostname - url = 'http://' + hostname + ':' + str(options.port) + '/' + url os.chdir(serve_dir) if options.run_server: @@ -1659,6 +1655,13 @@ def run(): # to support binding to port zero we must allow the server to open to socket then retrieve the final port number options.port = httpd.socket.getsockname()[1] + if not file_to_serve_is_url: + if len(options.cmdlineparams): + url += '?' + '&'.join(options.cmdlineparams) + hostname = socket.gethostbyname(socket.gethostname()) if options.android else options.hostname + # create url for browser after opening the server so we have the final port number in case we are binding to port 0 + url = 'http://' + hostname + ':' + str(options.port) + '/' + url + if options.android: if options.run_browser or options.browser_info: if not options.browser: diff --git a/test/test_browser.py b/test/test_browser.py index 68e7d62678aba..f3dc06fad07e5 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -5615,6 +5615,7 @@ def test_emrun(self): for args in [ args_base, + args_base + ['--port', '0'], args_base + ['--private_browsing', '--port', '6941'], args_base + ['--dump_out_directory', 'other dir/multiple', '--port', '6942'] ]: From 5ab6f6ea24fead0f5e9ef75bf5045612b9874c8a Mon Sep 17 00:00:00 2001 From: Daksh Makhija <91017744+Daksh2356@users.noreply.github.com> Date: Fri, 17 Mar 2023 00:02:58 +0530 Subject: [PATCH 0013/1523] docs: html5.h.rst: id[128] changed to id[64] (#18966) --- site/source/docs/api_reference/html5.h.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/site/source/docs/api_reference/html5.h.rst b/site/source/docs/api_reference/html5.h.rst index dcf35bc377457..778a2dcf46bd1 100644 --- a/site/source/docs/api_reference/html5.h.rst +++ b/site/source/docs/api_reference/html5.h.rst @@ -1662,13 +1662,13 @@ Struct An ID for the brand or style of the connected gamepad device. Typically, this will include the USB vendor and a product ID. - Maximum size 64 ``char`` (i.e. ``EM_UTF8 id[128]``). + Maximum size 64 ``char`` (i.e. ``EM_UTF8 id[64]``). .. c:member:: EM_UTF8 mapping A string that identifies the layout or control mapping of this device. - Maximum size 128 ``char`` (i.e. ``EM_UTF8 mapping[128]``). + Maximum size 64 ``char`` (i.e. ``EM_UTF8 mapping[64]``). From 64c274a7585b1b22d0117000a2487f643543d165 Mon Sep 17 00:00:00 2001 From: Ryo Ota Date: Fri, 17 Mar 2023 04:12:27 +0900 Subject: [PATCH 0014/1523] Fix typo in preamble.js [NFC] (#18978) --- src/preamble.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/preamble.js b/src/preamble.js index 69b09341662ec..527df8e762826 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -666,7 +666,7 @@ function getBinary(file) { } function getBinaryPromise(binaryFile) { - // If we don't have the binary yet, try to to load it asynchronously. + // If we don't have the binary yet, try to load it asynchronously. // Fetch has some additional restrictions over XHR, like it can't be used on a file:// url. // See https://github.com/github/fetch/pull/92#issuecomment-140665932 // Cordova or Electron apps are typically loaded from a file:// url. From edc036b7096f7ce5a284b569fb65b198cbc5b83d Mon Sep 17 00:00:00 2001 From: Derek Schuff Date: Thu, 16 Mar 2023 17:58:38 -0700 Subject: [PATCH 0015/1523] Update mac builder to medium gen2 resource class (#18987) see https://circleci.com/product/features/resource-classes/ The 'medium' class will go away later this year. The gen2 class is more expensive per build minute but according to my test https://app.circleci.com/pipelines/github/emscripten-core/emscripten/26604/workflows/c2acf4d1-1d2d-4556-b148-32278b852d42/jobs/614937 vs https://app.circleci.com/pipelines/github/emscripten-core/emscripten/26608/workflows/8ecccca3-44b6-493e-a3e8-62e74f931fda/jobs/615017 it's enough faster that it's slightly cheaper overall. --- .circleci/config.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 54b258fd55c79..833271c9198f1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -25,6 +25,7 @@ executors: EMSDK_NOTTY: "1" macos: xcode: "13.4.1" + resource_class: macos.x86.medium.gen2 commands: download-chrome: From d86faec6c60432507df3305b9bd5239d9bd72f26 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 16 Mar 2023 18:27:59 -0700 Subject: [PATCH 0016/1523] Remove old/unused autodebug functions. NFC (#18983) These days that autodebug functions are found in library_autodebug.js and have names like `set_i64` and `get_i64`. --- src/library.js | 21 --------------------- tools/system_libs.py | 1 + 2 files changed, 1 insertion(+), 21 deletions(-) diff --git a/src/library.js b/src/library.js index 91098b9d1de6a..084f6e1119186 100644 --- a/src/library.js +++ b/src/library.js @@ -3150,27 +3150,6 @@ mergeInto(LibraryManager.library, { }, #endif - // autodebugging - - emscripten_autodebug_i64: function(line, valuel, valueh) { - out('AD:' + [line, valuel, valueh]); - }, - emscripten_autodebug_i32: function(line, value) { - out('AD:' + [line, value]); - }, - emscripten_autodebug_i16: function(line, value) { - out('AD:' + [line, value]); - }, - emscripten_autodebug_i8: function(line, value) { - out('AD:' + [line, value]); - }, - emscripten_autodebug_float: function(line, value) { - out('AD:' + [line, value]); - }, - emscripten_autodebug_double: function(line, value) { - out('AD:' + [line, value]); - }, - // special runtime support #if STACK_OVERFLOW_CHECK diff --git a/tools/system_libs.py b/tools/system_libs.py index cfb5b1bbe770e..877364cb1dd45 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -72,6 +72,7 @@ def clean_env(): safe_env = os.environ.copy() for opt in ['CFLAGS', 'CXXFLAGS', 'LDFLAGS', 'EMCC_CFLAGS', + 'EMCC_AUTODEBUG', 'EMCC_FORCE_STDLIBS', 'EMCC_ONLY_FORCED_STDLIBS', 'EMMAKEN_JUST_CONFIGURE']: From 31702daffbd5df2759267771897f7274bccf27aa Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 16 Mar 2023 18:44:05 -0700 Subject: [PATCH 0017/1523] Rebaseline codesize expectations. NFC --- test/code_size/hello_webgl2_wasm.json | 8 ++++---- test/code_size/hello_webgl2_wasm2js.json | 8 ++++---- test/code_size/hello_webgl_wasm.json | 8 ++++---- test/code_size/hello_webgl_wasm2js.json | 8 ++++---- test/other/test_unoptimized_code_size.js.size | 2 +- test/other/test_unoptimized_code_size_no_asserts.js.size | 2 +- test/other/test_unoptimized_code_size_strict.js.size | 2 +- 7 files changed, 19 insertions(+), 19 deletions(-) diff --git a/test/code_size/hello_webgl2_wasm.json b/test/code_size/hello_webgl2_wasm.json index c505b625b67bf..8f2a7cbe7bf44 100644 --- a/test/code_size/hello_webgl2_wasm.json +++ b/test/code_size/hello_webgl2_wasm.json @@ -3,8 +3,8 @@ "a.html.gz": 379, "a.js": 4971, "a.js.gz": 2430, - "a.wasm": 10470, - "a.wasm.gz": 6690, - "total": 16010, - "total_gz": 9499 + "a.wasm": 10451, + "a.wasm.gz": 6680, + "total": 15991, + "total_gz": 9489 } diff --git a/test/code_size/hello_webgl2_wasm2js.json b/test/code_size/hello_webgl2_wasm2js.json index ea4b9e2ab4187..b57f45586eb05 100644 --- a/test/code_size/hello_webgl2_wasm2js.json +++ b/test/code_size/hello_webgl2_wasm2js.json @@ -1,10 +1,10 @@ { "a.html": 567, "a.html.gz": 379, - "a.js": 18220, - "a.js.gz": 8084, + "a.js": 18210, + "a.js.gz": 8068, "a.mem": 3171, "a.mem.gz": 2714, - "total": 21958, - "total_gz": 11177 + "total": 21948, + "total_gz": 11161 } diff --git a/test/code_size/hello_webgl_wasm.json b/test/code_size/hello_webgl_wasm.json index f6d8584b41894..2e5c5d3487a3e 100644 --- a/test/code_size/hello_webgl_wasm.json +++ b/test/code_size/hello_webgl_wasm.json @@ -3,8 +3,8 @@ "a.html.gz": 379, "a.js": 4450, "a.js.gz": 2250, - "a.wasm": 10470, - "a.wasm.gz": 6690, - "total": 15489, - "total_gz": 9319 + "a.wasm": 10451, + "a.wasm.gz": 6680, + "total": 15470, + "total_gz": 9309 } diff --git a/test/code_size/hello_webgl_wasm2js.json b/test/code_size/hello_webgl_wasm2js.json index b8a2c9de91a5a..4f88747f65ba3 100644 --- a/test/code_size/hello_webgl_wasm2js.json +++ b/test/code_size/hello_webgl_wasm2js.json @@ -1,10 +1,10 @@ { "a.html": 567, "a.html.gz": 379, - "a.js": 17691, - "a.js.gz": 7903, + "a.js": 17681, + "a.js.gz": 7887, "a.mem": 3171, "a.mem.gz": 2714, - "total": 21429, - "total_gz": 10996 + "total": 21419, + "total_gz": 10980 } diff --git a/test/other/test_unoptimized_code_size.js.size b/test/other/test_unoptimized_code_size.js.size index 3516f8567219f..af31831ce1ef8 100644 --- a/test/other/test_unoptimized_code_size.js.size +++ b/test/other/test_unoptimized_code_size.js.size @@ -1 +1 @@ -63871 +63868 diff --git a/test/other/test_unoptimized_code_size_no_asserts.js.size b/test/other/test_unoptimized_code_size_no_asserts.js.size index 7c9c36008eb92..7054030185832 100644 --- a/test/other/test_unoptimized_code_size_no_asserts.js.size +++ b/test/other/test_unoptimized_code_size_no_asserts.js.size @@ -1 +1 @@ -37783 +37780 diff --git a/test/other/test_unoptimized_code_size_strict.js.size b/test/other/test_unoptimized_code_size_strict.js.size index 87443f3685b85..9bc3ebe0ee2c4 100644 --- a/test/other/test_unoptimized_code_size_strict.js.size +++ b/test/other/test_unoptimized_code_size_strict.js.size @@ -1 +1 @@ -63223 +63220 From ffa2a5137419fd2cf581f4cd8c9ad1f75df23b9e Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 16 Mar 2023 18:47:01 -0700 Subject: [PATCH 0018/1523] Remove unused code from library_sdl.js. NFC (#18986) This came out of the work I'm doing on #18979 - SDL_malloc/SDL_free are not declared in the SDL header but instead defined to malloc/free (because we define HAVE_MALLOC). - Mix_PlayChannel is defined to Mix_PlayChannelTimes in the header. - SDL_BlitScaled/SDL_BlitSurface are defined to SDL_UpperBlitScaled and SDL_UpperBlit respectively. - SDL_UnlockMutex and SDL_LockMutex are defined to SDL_mutexV and SDL_mutexP. - SDL_LoadBMP is defined as SDL_LoadBMP_RW --- src/library_sdl.js | 34 +++------------------------------- 1 file changed, 3 insertions(+), 31 deletions(-) diff --git a/src/library_sdl.js b/src/library_sdl.js index d3f9796a40ffe..cda11e0a5b2d2 100644 --- a/src/library_sdl.js +++ b/src/library_sdl.js @@ -1845,18 +1845,6 @@ var LibrarySDL = { SDL_SetError: function() {}, - SDL_malloc__sig: 'ii', - SDL_malloc__deps: ['malloc'], - SDL_malloc: function(size) { - return _malloc(size); - }, - - SDL_free__sig: 'vi', - SDL_free__deps: ['free'], - SDL_free: function(ptr) { - _free(ptr); - }, - SDL_CreateRGBSurface__deps: ['malloc', 'free'], SDL_CreateRGBSurface__proxy: 'sync', SDL_CreateRGBSurface__sig: 'iiiiiiiii', @@ -1990,18 +1978,6 @@ var LibrarySDL = { return 0; }, - SDL_BlitSurface__proxy: 'sync', - SDL_BlitSurface__sig: 'iiiii', - SDL_BlitSurface: function(src, srcrect, dst, dstrect) { - return SDL.blitSurface(src, srcrect, dst, dstrect, false); - }, - - SDL_BlitScaled__proxy: 'sync', - SDL_BlitScaled__sig: 'iiiii', - SDL_BlitScaled: function(src, srcrect, dst, dstrect) { - return SDL.blitSurface(src, srcrect, dst, dstrect, true); - }, - zoomSurface: function(src, x, y, smooth) { var srcData = SDL.surfaces[src]; var w = srcData.width * x; @@ -2400,7 +2376,6 @@ var LibrarySDL = { cleanup(); } }, - SDL_LoadBMP: 'IMG_Load', SDL_LoadBMP_RW: 'IMG_Load_RW', IMG_Load__deps: ['IMG_Load_RW', 'SDL_RWFromFile'], @@ -2682,8 +2657,6 @@ var LibrarySDL = { SDL_UnlockAudio: function() {}, SDL_CreateMutex: function() { return 0 }, - SDL_LockMutex: function() {}, - SDL_UnlockMutex: function() {}, SDL_mutexP: function() { return 0 }, SDL_mutexV: function() { return 0 }, SDL_DestroyMutex: function() {}, @@ -2931,9 +2904,9 @@ var LibrarySDL = { Mix_ReserveChannels: function(num) { SDL.channelMinimumNumber = num; }, - Mix_PlayChannel__proxy: 'sync', - Mix_PlayChannel__sig: 'iiii', - Mix_PlayChannel: function(channel, id, loops) { + Mix_PlayChannelTimed__proxy: 'sync', + Mix_PlayChannelTimed__sig: 'iiii', + Mix_PlayChannelTimed: function(channel, id, loops) { // TODO: handle fixed amount of N loops. Currently loops either 0 or infinite times. // Get the audio element associated with the ID @@ -2984,7 +2957,6 @@ var LibrarySDL = { audio.play(); return channel; }, - Mix_PlayChannelTimed: 'Mix_PlayChannel', // XXX ignore Timing Mix_FadingChannel: function(channel) { return 0; // MIX_NO_FADING, TODO From fab93a2bff6273c882b0c7fb7b54eccc37276e03 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 16 Mar 2023 19:05:20 -0700 Subject: [PATCH 0019/1523] Remove unused __syscall_rename implementations. NFC (#18984) This syscall was removed in #15411 --- src/library_syscall.js | 7 ------- system/lib/wasmfs/syscalls.cpp | 4 ---- 2 files changed, 11 deletions(-) diff --git a/src/library_syscall.js b/src/library_syscall.js index 9899e9e34dd81..ac78c024ea0ce 100644 --- a/src/library_syscall.js +++ b/src/library_syscall.js @@ -175,13 +175,6 @@ var SyscallsLibrary = { FS.chmod(path, mode); return 0; }, - __syscall_rename__sig: 'ipp', - __syscall_rename: function(old_path, new_path) { - old_path = SYSCALLS.getStr(old_path); - new_path = SYSCALLS.getStr(new_path); - FS.rename(old_path, new_path); - return 0; - }, __syscall_rmdir__sig: 'ip', __syscall_rmdir: function(path) { path = SYSCALLS.getStr(path); diff --git a/system/lib/wasmfs/syscalls.cpp b/system/lib/wasmfs/syscalls.cpp index 14a8d69b65eed..a9146922ee6c4 100644 --- a/system/lib/wasmfs/syscalls.cpp +++ b/system/lib/wasmfs/syscalls.cpp @@ -1038,10 +1038,6 @@ int __syscall_renameat(int olddirfd, return 0; } -int __syscall_rename(intptr_t oldpath, intptr_t newpath) { - return __syscall_renameat(AT_FDCWD, oldpath, AT_FDCWD, newpath); -} - // TODO: Test this with non-AT_FDCWD values. int __syscall_symlinkat(intptr_t target, int newdirfd, intptr_t linkpath) { auto parsed = path::parseParent((char*)linkpath, newdirfd); From da29b3f9b06a0c0e5202bf37e359e61d45006188 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 17 Mar 2023 09:41:44 -0700 Subject: [PATCH 0020/1523] Revert workaround in harfbuzz port (#18822) The issue that required this change has been fixed. See https://github.com/emscripten-core/emsdk/issues/982 --- tools/ports/harfbuzz.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tools/ports/harfbuzz.py b/tools/ports/harfbuzz.py index 9c162db29bb7f..ed0537db18c08 100644 --- a/tools/ports/harfbuzz.py +++ b/tools/ports/harfbuzz.py @@ -7,7 +7,7 @@ import logging VERSION = '3.2.0' -HASH = '2e5ab5ad83a0d8801abd3f82a276f776a0ad330edc0ab843f879dd7ad3fd2e0dc0e9a3efbb6c5f2e67d14c0e37f0d9abdb40c5e25d8231a357c0025669f219c3' +HASH = 'c9d88068d8017046842f444f02f31dbae109026ede943aaf265db5508de8b4b2be84203950f274a237f515bf7cbd361629d2032c6e8ee8f50354b430bba3a8ca' deps = ['freetype'] variants = {'harfbuzz-mt': {'PTHREADS': 1}} @@ -80,10 +80,7 @@ def get_lib_name(settings): def get(ports, settings, shared): - # Harfbuzz only published `.xz` packages, but not all python builds support - # unpacking lzma archives, so we mirror a `.gz` version: - # See https://github.com/emscripten-core/emsdk/issues/982 - ports.fetch_project('harfbuzz', f'https://storage.googleapis.com/webassembly/emscripten-ports/harfbuzz-{VERSION}.tar.gz', sha512hash=HASH) + ports.fetch_project('harfbuzz', f'https://github.com/harfbuzz/harfbuzz/releases/download/{VERSION}/harfbuzz-{VERSION}.tar.xz', sha512hash=HASH) def create(final): logging.info('building port: harfbuzz') From 36eb862fff6446a33cb4197a26f7366b30c1d6d3 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 17 Mar 2023 10:33:16 -0700 Subject: [PATCH 0021/1523] Fix __sig attributes that had the wrong length (#18990) This is the first set of __sig fixes that comes out of a larger fix for #18979, which will eventually remove all of these sigs from the JS code. --- src/library.js | 4 ++-- src/library_browser.js | 4 ++-- src/library_dylink.js | 2 +- src/library_glut.js | 2 +- src/library_html5.js | 6 +++--- src/library_sdl.js | 21 ++++++++++----------- src/library_syscall.js | 8 ++++---- src/library_webgl.js | 4 ++-- system/include/emscripten/emscripten.h | 2 +- 9 files changed, 26 insertions(+), 27 deletions(-) diff --git a/src/library.js b/src/library.js index 084f6e1119186..bdef2d5198277 100644 --- a/src/library.js +++ b/src/library.js @@ -1225,9 +1225,9 @@ mergeInto(LibraryManager.library, { return 0; }, - strptime_l__sig: 'pppp', + strptime_l__sig: 'ppppp', strptime_l__deps: ['strptime'], - strptime_l: function(buf, format, tm) { + strptime_l: function(buf, format, tm, locale) { return _strptime(buf, format, tm); // no locale support yet }, diff --git a/src/library_browser.js b/src/library_browser.js index d0f394efdd77d..88def7c945e7f 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -1174,7 +1174,7 @@ var LibraryBrowser = { }, emscripten_get_window_title__proxy: 'sync', - emscripten_get_window_title__sig: 'iv', + emscripten_get_window_title__sig: 'p', emscripten_get_window_title: function() { var buflen = 256; @@ -1349,7 +1349,7 @@ var LibraryBrowser = { #endif emscripten_get_worker_queue_size__proxy: 'sync', - emscripten_get_worker_queue_size__sig: 'i', + emscripten_get_worker_queue_size__sig: 'ii', emscripten_get_worker_queue_size: function(id) { var info = Browser.workers[id]; if (!info) return -1; diff --git a/src/library_dylink.js b/src/library_dylink.js index cdbc16844bad6..7dbdc042fc0da 100644 --- a/src/library_dylink.js +++ b/src/library_dylink.js @@ -1109,7 +1109,7 @@ var LibraryDylink = { // Async version of dlopen. _emscripten_dlopen_js__deps: ['$dlopenInternal', '$callUserCallback', '$dlSetError'], - _emscripten_dlopen_js__sig: 'vppp', + _emscripten_dlopen_js__sig: 'vpppp', _emscripten_dlopen_js: function(handle, onsuccess, onerror, user_data) { /** @param {Object=} e */ function errorCallback(e) { diff --git a/src/library_glut.js b/src/library_glut.js index fd3aef401adf2..9ea0eed4636ac 100644 --- a/src/library_glut.js +++ b/src/library_glut.js @@ -599,7 +599,7 @@ var LibraryGLUT = { glutReshapeWindow__proxy: 'sync', glutReshapeWindow__deps: ['$GLUT', 'glutPostRedisplay'], - glutReshapeWindow__sig: 'vi', + glutReshapeWindow__sig: 'vii', glutReshapeWindow: function(width, height) { Browser.exitFullscreen(); Browser.setCanvasSize(width, height, true); // N.B. GLUT.reshapeFunc is also registered as a canvas resize callback. diff --git a/src/library_html5.js b/src/library_html5.js index 68138ef5d8271..62e0c1fa8c065 100644 --- a/src/library_html5.js +++ b/src/library_html5.js @@ -2305,7 +2305,7 @@ var LibraryHTML5 = { }, emscripten_set_beforeunload_callback_on_thread__proxy: 'sync', - emscripten_set_beforeunload_callback_on_thread__sig: 'iii', + emscripten_set_beforeunload_callback_on_thread__sig: 'ippp', emscripten_set_beforeunload_callback_on_thread__deps: ['$registerBeforeUnloadEventCallback'], emscripten_set_beforeunload_callback_on_thread: function(userData, callbackfunc, targetThread) { if (typeof onbeforeunload == 'undefined') return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; @@ -2358,7 +2358,7 @@ var LibraryHTML5 = { }, emscripten_set_batterychargingchange_callback_on_thread__proxy: 'sync', - emscripten_set_batterychargingchange_callback_on_thread__sig: 'iii', + emscripten_set_batterychargingchange_callback_on_thread__sig: 'ippp', emscripten_set_batterychargingchange_callback_on_thread__deps: ['$registerBatteryEventCallback', '$battery', 'malloc'], emscripten_set_batterychargingchange_callback_on_thread: function(userData, callbackfunc, targetThread) { if (!battery()) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; @@ -2367,7 +2367,7 @@ var LibraryHTML5 = { }, emscripten_set_batterylevelchange_callback_on_thread__proxy: 'sync', - emscripten_set_batterylevelchange_callback_on_thread__sig: 'iii', + emscripten_set_batterylevelchange_callback_on_thread__sig: 'ippp', emscripten_set_batterylevelchange_callback_on_thread__deps: ['$registerBatteryEventCallback', '$battery', 'malloc'], emscripten_set_batterylevelchange_callback_on_thread: function(userData, callbackfunc, targetThread) { if (!battery()) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; diff --git a/src/library_sdl.js b/src/library_sdl.js index cda11e0a5b2d2..c51dbdaa4ba76 100644 --- a/src/library_sdl.js +++ b/src/library_sdl.js @@ -1398,8 +1398,8 @@ var LibrarySDL = { SDL_WasInit__deps: ['SDL_Init'], SDL_WasInit__proxy: 'sync', - SDL_WasInit__sig: 'i', - SDL_WasInit: function() { + SDL_WasInit__sig: 'ii', + SDL_WasInit: function(flags) { if (SDL.startTime === null) { _SDL_Init(); } @@ -1937,7 +1937,7 @@ var LibrarySDL = { }, SDL_SetClipRect__proxy: 'sync', - SDL_SetClipRect__sig: 'vii', + SDL_SetClipRect__sig: 'iii', SDL_SetClipRect: function(surf, rect) { var surfData = SDL.surfaces[surf]; @@ -2905,9 +2905,10 @@ var LibrarySDL = { SDL.channelMinimumNumber = num; }, Mix_PlayChannelTimed__proxy: 'sync', - Mix_PlayChannelTimed__sig: 'iiii', - Mix_PlayChannelTimed: function(channel, id, loops) { + Mix_PlayChannelTimed__sig: 'iiiii', + Mix_PlayChannelTimed: function(channel, id, loops, ticks) { // TODO: handle fixed amount of N loops. Currently loops either 0 or infinite times. + assert(ticks == -1); // Get the audio element associated with the ID var info = SDL.audios[id]; @@ -3459,8 +3460,8 @@ var LibrarySDL = { SDL_DestroyRenderer: function(renderer) {}, SDL_GetWindowFlags__proxy: 'sync', - SDL_GetWindowFlags__sig: 'iii', - SDL_GetWindowFlags: function(x, y) { + SDL_GetWindowFlags__sig: 'ip', + SDL_GetWindowFlags: function(window) { if (Browser.isFullscreen) { return 1; } @@ -3475,8 +3476,8 @@ var LibrarySDL = { SDL_GL_DeleteContext: function(context) {}, SDL_GL_GetSwapInterval__proxy: 'sync', - SDL_GL_GetSwapInterval__sig: 'ii', - SDL_GL_GetSwapInterval: function(state) { + SDL_GL_GetSwapInterval__sig: 'i', + SDL_GL_GetSwapInterval: function() { if (Browser.mainLoop.timingMode == 1/*EM_TIMING_RAF*/) return Browser.mainLoop.timingValue; else return 0; }, @@ -3513,8 +3514,6 @@ var LibrarySDL = { return 0; }, - SDL_GetWindowFlags: function() {}, - SDL_ClearError: function() {}, // TODO diff --git a/src/library_syscall.js b/src/library_syscall.js index ac78c024ea0ce..1b26f517d0381 100644 --- a/src/library_syscall.js +++ b/src/library_syscall.js @@ -328,8 +328,8 @@ var SyscallsLibrary = { return 0; }, __syscall_connect__deps: ['$getSocketFromFD', '$getSocketAddress'], - __syscall_connect__sig: 'iipi', - __syscall_connect: function(fd, addr, addrlen) { + __syscall_connect__sig: 'iipiiii', + __syscall_connect: function(fd, addr, addrlen, d1, d2, d3) { var sock = getSocketFromFD(fd); var info = getSocketAddress(addr, addrlen); sock.sock_ops.connect(sock, info.addr, info.port); @@ -353,8 +353,8 @@ var SyscallsLibrary = { return newsock.stream.fd; }, __syscall_bind__deps: ['$getSocketFromFD', '$getSocketAddress'], - __syscall_bind__sig: 'iipi', - __syscall_bind: function(fd, addr, addrlen) { + __syscall_bind__sig: 'iipiiii', + __syscall_bind: function(fd, addr, addrlen, d1, d2, d3) { var sock = getSocketFromFD(fd); var info = getSocketAddress(addr, addrlen); sock.sock_ops.bind(sock, info.addr, info.port); diff --git a/src/library_webgl.js b/src/library_webgl.js index 5caa0b9ba819e..5fedc92347fa3 100644 --- a/src/library_webgl.js +++ b/src/library_webgl.js @@ -3824,8 +3824,8 @@ var LibraryGL = { }, #endif // ~#if !LEGACY_GL_EMULATION - glShaderBinary__sig: 'v', - glShaderBinary: function() { + glShaderBinary__sig: 'vipipi', + glShaderBinary: function(count, shaders, binaryformat, binary, length) { GL.recordError(0x500/*GL_INVALID_ENUM*/); #if GL_ASSERTIONS err("GL_INVALID_ENUM in glShaderBinary: WebGL does not support binary shader formats! Calls to glShaderBinary always fail."); diff --git a/system/include/emscripten/emscripten.h b/system/include/emscripten/emscripten.h index 2651d60092a80..f0331df8a479b 100644 --- a/system/include/emscripten/emscripten.h +++ b/system/include/emscripten/emscripten.h @@ -77,7 +77,7 @@ void emscripten_force_exit(int status) __attribute__((__noreturn__)); double emscripten_get_device_pixel_ratio(void); -char *emscripten_get_window_title(); +char *emscripten_get_window_title(void); void emscripten_set_window_title(const char *); void emscripten_get_screen_size(int *width __attribute__((nonnull)), int *height __attribute__((nonnull))); void emscripten_hide_mouse(void); From a049bee65e30da473bd2f8525cace2d325464d3a Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 17 Mar 2023 14:16:42 -0700 Subject: [PATCH 0022/1523] Internalize JS functions. NFC (#18988) This came out of my work on #18979. Without the $ prefix on these symbols they are effectively exposed to native code and my code tried to figure out their native signatures, which can't exist because these functions are not called from native code and mostly take JS object as arguments. --- src/library.js | 88 +++++++-------- src/library_html5_webgl.js | 46 ++++---- src/library_webgl.js | 102 +++++++++--------- src/library_webgl2.js | 18 ++-- .../metadce/test_metadce_hello_O0.jssize | 2 +- .../metadce/test_metadce_minimal_O0.jssize | 2 +- test/other/test_unoptimized_code_size.js.size | 2 +- .../test_unoptimized_code_size_strict.js.size | 2 +- 8 files changed, 131 insertions(+), 131 deletions(-) diff --git a/src/library.js b/src/library.js index bdef2d5198277..ab3ec9554838b 100644 --- a/src/library.js +++ b/src/library.js @@ -445,7 +445,7 @@ mergeInto(LibraryManager.library, { // time.h // ========================================================================== - _mktime_js__deps: ['_yday_from_date'], + _mktime_js__deps: ['$ydayFromDate'], _mktime_js__sig: 'ip', _mktime_js: function(tmPtr) { var date = new Date({{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_year, 'i32') }}} + 1900, @@ -476,7 +476,7 @@ mergeInto(LibraryManager.library, { } {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_wday, 'date.getDay()', 'i32') }}}; - var yday = __yday_from_date(date)|0; + var yday = ydayFromDate(date)|0; {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_yday, 'yday', 'i32') }}}; // To match expected behavior, update fields from date {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_sec, 'date.getSeconds()', 'i32') }}}; @@ -524,7 +524,7 @@ mergeInto(LibraryManager.library, { return (date.getTime() / 1000)|0; }, - _localtime_js__deps: ['$readI53FromI64', '_yday_from_date'], + _localtime_js__deps: ['$readI53FromI64', '$ydayFromDate'], _localtime_js__sig: 'ipp', _localtime_js: function(time, tmPtr) { var date = new Date({{{ makeGetValue('time', 0, 'i53') }}}*1000); @@ -536,7 +536,7 @@ mergeInto(LibraryManager.library, { {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_year, 'date.getFullYear()-1900', 'i32') }}}; {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_wday, 'date.getDay()', 'i32') }}}; - var yday = __yday_from_date(date)|0; + var yday = ydayFromDate(date)|0; {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_yday, 'yday', 'i32') }}}; {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_gmtoff, '-(date.getTimezoneOffset() * 60)', 'i32') }}}; @@ -631,25 +631,25 @@ mergeInto(LibraryManager.library, { } }, - _MONTH_DAYS_REGULAR: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], - _MONTH_DAYS_LEAP: [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], - _MONTH_DAYS_REGULAR_CUMULATIVE: [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334], - _MONTH_DAYS_LEAP_CUMULATIVE: [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335], + $MONTH_DAYS_REGULAR: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], + $MONTH_DAYS_LEAP: [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31], + $MONTH_DAYS_REGULAR_CUMULATIVE: [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334], + $MONTH_DAYS_LEAP_CUMULATIVE: [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335], - _isLeapYear: function(year) { + $isLeapYear: function(year) { return year%4 === 0 && (year%100 !== 0 || year%400 === 0); }, - _yday_from_date__deps: ['_isLeapYear', '_MONTH_DAYS_LEAP_CUMULATIVE', '_MONTH_DAYS_REGULAR_CUMULATIVE'], - _yday_from_date: function(date) { - var isLeapYear = __isLeapYear(date.getFullYear()); - var monthDaysCumulative = (isLeapYear ? __MONTH_DAYS_LEAP_CUMULATIVE : __MONTH_DAYS_REGULAR_CUMULATIVE); + $ydayFromDate__deps: ['$isLeapYear', '$MONTH_DAYS_LEAP_CUMULATIVE', '$MONTH_DAYS_REGULAR_CUMULATIVE'], + $ydayFromDate: function(date) { + var leap = isLeapYear(date.getFullYear()); + var monthDaysCumulative = (leap ? MONTH_DAYS_LEAP_CUMULATIVE : MONTH_DAYS_REGULAR_CUMULATIVE); var yday = monthDaysCumulative[date.getMonth()] + date.getDate() - 1; // -1 since it's days since Jan 1 return yday; }, - _arraySum: function(array, index) { + $arraySum: function(array, index) { var sum = 0; for (var i = 0; i <= index; sum += array[i++]) { // no-op @@ -657,13 +657,13 @@ mergeInto(LibraryManager.library, { return sum; }, - _addDays__deps: ['_isLeapYear', '_MONTH_DAYS_LEAP', '_MONTH_DAYS_REGULAR'], - _addDays: function(date, days) { + $addDays__deps: ['$isLeapYear', '$MONTH_DAYS_LEAP', '$MONTH_DAYS_REGULAR'], + $addDays: function(date, days) { var newDate = new Date(date.getTime()); while (days > 0) { - var leap = __isLeapYear(newDate.getFullYear()); + var leap = isLeapYear(newDate.getFullYear()); var currentMonth = newDate.getMonth(); - var daysInCurrentMonth = (leap ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR)[currentMonth]; + var daysInCurrentMonth = (leap ? MONTH_DAYS_LEAP : MONTH_DAYS_REGULAR)[currentMonth]; if (days > daysInCurrentMonth-newDate.getDate()) { // we spill over to next month @@ -687,7 +687,7 @@ mergeInto(LibraryManager.library, { // Note: this is not used in STANDALONE_WASM mode, because it is more // compact to do it in JS. - strftime__deps: ['_isLeapYear', '_arraySum', '_addDays', '_MONTH_DAYS_REGULAR', '_MONTH_DAYS_LEAP', + strftime__deps: ['$isLeapYear', '$arraySum', '$addDays', '$MONTH_DAYS_REGULAR', '$MONTH_DAYS_LEAP', '$intArrayFromString', '$writeArrayToMemory' ], strftime__sig: 'ppppp', @@ -798,7 +798,7 @@ mergeInto(LibraryManager.library, { } function getWeekBasedYear(date) { - var thisDate = __addDays(new Date(date.tm_year+1900, 0, 1), date.tm_yday); + var thisDate = addDays(new Date(date.tm_year+1900, 0, 1), date.tm_yday); var janFourthThisYear = new Date(thisDate.getFullYear(), 0, 4); var janFourthNextYear = new Date(thisDate.getFullYear()+1, 0, 4); @@ -866,7 +866,7 @@ mergeInto(LibraryManager.library, { }, '%j': function(date) { // Day of the year (001-366) - return leadingNulls(date.tm_mday+__arraySum(__isLeapYear(date.tm_year+1900) ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR, date.tm_mon-1), 3); + return leadingNulls(date.tm_mday + arraySum(isLeapYear(date.tm_year+1900) ? MONTH_DAYS_LEAP : MONTH_DAYS_REGULAR, date.tm_mon-1), 3); }, '%m': function(date) { return leadingNulls(date.tm_mon+1, 2); @@ -913,14 +913,14 @@ mergeInto(LibraryManager.library, { // If 31 December of prev year a Thursday, or Friday of a // leap year, then the prev year has 53 weeks. var dec31 = (date.tm_wday + 7 - date.tm_yday - 1) % 7; - if (dec31 == 4 || (dec31 == 5 && __isLeapYear(date.tm_year%400-1))) { + if (dec31 == 4 || (dec31 == 5 && isLeapYear(date.tm_year%400-1))) { val++; } } else if (val == 53) { // If 1 January is not a Thursday, and not a Wednesday of a // leap year, then this year has only 52 weeks. var jan1 = (date.tm_wday + 371 - date.tm_yday) % 7; - if (jan1 != 4 && (jan1 != 3 || !__isLeapYear(date.tm_year))) + if (jan1 != 4 && (jan1 != 3 || !isLeapYear(date.tm_year))) val = 1; } return leadingNulls(val, 2); @@ -982,7 +982,7 @@ mergeInto(LibraryManager.library, { return _strftime(s, maxsize, format, tm); // no locale support yet }, - strptime__deps: ['_isLeapYear', '_arraySum', '_addDays', '_MONTH_DAYS_REGULAR', '_MONTH_DAYS_LEAP', + strptime__deps: ['$isLeapYear', '$arraySum', '$addDays', '$MONTH_DAYS_REGULAR', '$MONTH_DAYS_LEAP', '$jstoi_q', '$intArrayFromString' ], strptime__sig: 'pppp', strptime: function(buf, format, tm) { @@ -1143,10 +1143,10 @@ mergeInto(LibraryManager.library, { } else if ((value=getMatch('j'))) { // get day of month from day of year ... var day = jstoi_q(value); - var leapYear = __isLeapYear(date.year); + var leapYear = isLeapYear(date.year); for (var month=0; month<12; ++month) { - var daysUntilMonth = __arraySum(leapYear ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR, month-1); - if (day<=daysUntilMonth+(leapYear ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR)[month]) { + var daysUntilMonth = arraySum(leapYear ? MONTH_DAYS_LEAP : MONTH_DAYS_REGULAR, month-1); + if (day<=daysUntilMonth+(leapYear ? MONTH_DAYS_LEAP : MONTH_DAYS_REGULAR)[month]) { date.day = day-daysUntilMonth; } } @@ -1165,10 +1165,10 @@ mergeInto(LibraryManager.library, { var endDate; if (janFirst.getDay() === 0) { // Jan 1st is a Sunday, and, hence in the 1st CW - endDate = __addDays(janFirst, weekDayNumber+7*(weekNumber-1)); + endDate = addDays(janFirst, weekDayNumber+7*(weekNumber-1)); } else { // Jan 1st is not a Sunday, and, hence still in the 0th CW - endDate = __addDays(janFirst, 7-janFirst.getDay()+weekDayNumber+7*(weekNumber-1)); + endDate = addDays(janFirst, 7-janFirst.getDay()+weekDayNumber+7*(weekNumber-1)); } date.day = endDate.getDate(); date.month = endDate.getMonth(); @@ -1184,10 +1184,10 @@ mergeInto(LibraryManager.library, { var endDate; if (janFirst.getDay()===1) { // Jan 1st is a Monday, and, hence in the 1st CW - endDate = __addDays(janFirst, weekDayNumber+7*(weekNumber-1)); + endDate = addDays(janFirst, weekDayNumber+7*(weekNumber-1)); } else { // Jan 1st is not a Monday, and, hence still in the 0th CW - endDate = __addDays(janFirst, 7-janFirst.getDay()+1+weekDayNumber+7*(weekNumber-1)); + endDate = addDays(janFirst, 7-janFirst.getDay()+1+weekDayNumber+7*(weekNumber-1)); } date.day = endDate.getDate(); @@ -1215,7 +1215,7 @@ mergeInto(LibraryManager.library, { {{{ makeSetValue('tm', C_STRUCTS.tm.tm_mon, 'fullDate.getMonth()', 'i32') }}}; {{{ makeSetValue('tm', C_STRUCTS.tm.tm_year, 'fullDate.getFullYear()-1900', 'i32') }}}; {{{ makeSetValue('tm', C_STRUCTS.tm.tm_wday, 'fullDate.getDay()', 'i32') }}}; - {{{ makeSetValue('tm', C_STRUCTS.tm.tm_yday, '__arraySum(__isLeapYear(fullDate.getFullYear()) ? __MONTH_DAYS_LEAP : __MONTH_DAYS_REGULAR, fullDate.getMonth()-1)+fullDate.getDate()-1', 'i32') }}}; + {{{ makeSetValue('tm', C_STRUCTS.tm.tm_yday, 'arraySum(isLeapYear(fullDate.getFullYear()) ? MONTH_DAYS_LEAP : MONTH_DAYS_REGULAR, fullDate.getMonth()-1)+fullDate.getDate()-1', 'i32') }}}; {{{ makeSetValue('tm', C_STRUCTS.tm.tm_isdst, '0', 'i32') }}}; // we need to convert the matched sequence into an integer array to take care of UTF-8 characters > 0x7F @@ -2475,9 +2475,9 @@ mergeInto(LibraryManager.library, { return [args, funcname, str]; }, - emscripten_get_callstack_js__deps: ['$traverseStack', '$jsStackTrace', '$warnOnce'], - emscripten_get_callstack_js__docs: '/** @param {number=} flags */', - emscripten_get_callstack_js: function(flags) { + $getCallstack__deps: ['$traverseStack', '$jsStackTrace', '$warnOnce'], + $getCallstack__docs: '/** @param {number=} flags */', + $getCallstack: function(flags) { var callstack = jsStackTrace(); // Find the symbols in the callstack that corresponds to the functions that @@ -2588,13 +2588,13 @@ mergeInto(LibraryManager.library, { return callstack; }, - emscripten_get_callstack__deps: ['emscripten_get_callstack_js'], + emscripten_get_callstack__deps: ['$getCallstack'], emscripten_get_callstack: function(flags, str, maxbytes) { // Use explicit calls to from64 rather then using the __sig // magic here. This is because the __sig wrapper uses arrow function // notation which causes the inner call to traverseStack to fail. {{{ from64('str') }}}; - var callstack = _emscripten_get_callstack_js(flags); + var callstack = getCallstack(flags); // User can query the required amount of bytes to hold the callstack. if (!str || maxbytes <= 0) { return lengthBytesUTF8(callstack)+1; @@ -2606,11 +2606,11 @@ mergeInto(LibraryManager.library, { return bytesWrittenExcludingNull+1; }, - emscripten_log_js__deps: ['emscripten_get_callstack_js'], - emscripten_log_js: function(flags, str) { + $emscriptenLog__deps: ['$getCallstack'], + $emscriptenLog: function(flags, str) { if (flags & {{{ cDefine('EM_LOG_C_STACK') | cDefine('EM_LOG_JS_STACK') }}}) { str = str.replace(/\s+$/, ''); // Ensure the message and the callstack are joined cleanly with exactly one newline. - str += (str.length > 0 ? '\n' : '') + _emscripten_get_callstack_js(flags); + str += (str.length > 0 ? '\n' : '') + getCallstack(flags); } if (flags & {{{ cDefine('EM_LOG_CONSOLE') }}}) { @@ -2633,11 +2633,11 @@ mergeInto(LibraryManager.library, { }, emscripten_log__sig: 'vipp', - emscripten_log__deps: ['$formatString', 'emscripten_log_js'], + emscripten_log__deps: ['$formatString', '$emscriptenLog'], emscripten_log: function(flags, format, varargs) { var result = formatString(format, varargs); var str = UTF8ArrayToString(result, 0); - _emscripten_log_js(flags, str); + emscriptenLog(flags, str); }, // We never free the return values of this function so we need to allocate @@ -3121,9 +3121,9 @@ mergeInto(LibraryManager.library, { #if LINK_AS_CXX // libunwind - _Unwind_Backtrace__deps: ['emscripten_get_callstack_js'], + _Unwind_Backtrace__deps: ['$getCallstack'], _Unwind_Backtrace: function(func, arg) { - var trace = _emscripten_get_callstack_js(); + var trace = getCallstack(); var parts = trace.split('\n'); for (var i = 0; i < parts.length; i++) { var ret = {{{ makeDynCall('iii', 'func') }}}(0, arg); diff --git a/src/library_html5_webgl.js b/src/library_html5_webgl.js index d2bce7fdcd2a0..3e37197b25c23 100644 --- a/src/library_html5_webgl.js +++ b/src/library_html5_webgl.js @@ -45,7 +45,7 @@ var LibraryHtml5WebGL = { #endif }, - _emscripten_webgl_power_preferences: "['default', 'low-power', 'high-performance']", + $emscripten_webgl_power_preferences: "['default', 'low-power', 'high-performance']", #if PTHREADS && OFFSCREEN_FRAMEBUFFER // In offscreen framebuffer mode, we implement a proxied version of the @@ -82,7 +82,7 @@ var LibraryHtml5WebGL = { #if PTHREADS && OFFSCREEN_FRAMEBUFFER 'emscripten_webgl_create_context_proxied', #endif - '$JSEvents', '_emscripten_webgl_power_preferences', '$findEventTarget', '$findCanvasEventTarget'], + '$JSEvents', '$emscripten_webgl_power_preferences', '$findEventTarget', '$findCanvasEventTarget'], // This function performs proxying manually, depending on the style of context that is to be created. emscripten_webgl_do_create_context__sig: 'iii', emscripten_webgl_do_create_context: function(target, attributes) { @@ -98,7 +98,7 @@ var LibraryHtml5WebGL = { 'antialias': !!HEAP32[a + ({{{ C_STRUCTS.EmscriptenWebGLContextAttributes.antialias }}}>>2)], 'premultipliedAlpha': !!HEAP32[a + ({{{ C_STRUCTS.EmscriptenWebGLContextAttributes.premultipliedAlpha }}}>>2)], 'preserveDrawingBuffer': !!HEAP32[a + ({{{ C_STRUCTS.EmscriptenWebGLContextAttributes.preserveDrawingBuffer }}}>>2)], - 'powerPreference': __emscripten_webgl_power_preferences[powerPreference], + 'powerPreference': emscripten_webgl_power_preferences[powerPreference], 'failIfMajorPerformanceCaveat': !!HEAP32[a + ({{{ C_STRUCTS.EmscriptenWebGLContextAttributes.failIfMajorPerformanceCaveat }}}>>2)], // The following are not predefined WebGL context attributes in the WebGL specification, so the property names can be minified by Closure. majorVersion: HEAP32[a + ({{{ C_STRUCTS.EmscriptenWebGLContextAttributes.majorVersion }}}>>2)], @@ -291,7 +291,7 @@ var LibraryHtml5WebGL = { emscripten_webgl_get_context_attributes__proxy: 'sync_on_webgl_context_handle_thread', emscripten_webgl_get_context_attributes__sig: 'iii', - emscripten_webgl_get_context_attributes__deps: ['_emscripten_webgl_power_preferences'], + emscripten_webgl_get_context_attributes__deps: ['$emscripten_webgl_power_preferences'], emscripten_webgl_get_context_attributes: function(c, a) { if (!a) return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_PARAM') }}}; c = GL.contexts[c]; @@ -306,7 +306,7 @@ var LibraryHtml5WebGL = { {{{ makeSetValue('a', C_STRUCTS.EmscriptenWebGLContextAttributes.antialias, 't.antialias', 'i32') }}}; {{{ makeSetValue('a', C_STRUCTS.EmscriptenWebGLContextAttributes.premultipliedAlpha, 't.premultipliedAlpha', 'i32') }}}; {{{ makeSetValue('a', C_STRUCTS.EmscriptenWebGLContextAttributes.preserveDrawingBuffer, 't.preserveDrawingBuffer', 'i32') }}}; - var power = t['powerPreference'] && __emscripten_webgl_power_preferences.indexOf(t['powerPreference']); + var power = t['powerPreference'] && emscripten_webgl_power_preferences.indexOf(t['powerPreference']); {{{ makeSetValue('a', C_STRUCTS.EmscriptenWebGLContextAttributes.powerPreference, 'power', 'i32') }}}; {{{ makeSetValue('a', C_STRUCTS.EmscriptenWebGLContextAttributes.failIfMajorPerformanceCaveat, 't.failIfMajorPerformanceCaveat', 'i32') }}}; {{{ makeSetValue('a', C_STRUCTS.EmscriptenWebGLContextAttributes.majorVersion, 'c.version', 'i32') }}}; @@ -339,15 +339,15 @@ var LibraryHtml5WebGL = { emscripten_webgl_enable_extension__deps: [ #if GL_SUPPORT_SIMPLE_ENABLE_EXTENSIONS #if MIN_WEBGL_VERSION == 1 - '_webgl_enable_ANGLE_instanced_arrays', - '_webgl_enable_OES_vertex_array_object', - '_webgl_enable_WEBGL_draw_buffers', + '$webgl_enable_ANGLE_instanced_arrays', + '$webgl_enable_OES_vertex_array_object', + '$webgl_enable_WEBGL_draw_buffers', #endif #if MAX_WEBGL_VERSION >= 2 - '_webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance', - '_webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance', + '$webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance', + '$webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance', #endif - '_webgl_enable_WEBGL_multi_draw', + '$webgl_enable_WEBGL_multi_draw', #endif ], emscripten_webgl_enable_extension__proxy: 'sync_on_webgl_context_handle_thread', @@ -365,17 +365,17 @@ var LibraryHtml5WebGL = { #if MIN_WEBGL_VERSION == 1 // Obtain function entry points to WebGL 1 extension related functions. - if (extString == 'ANGLE_instanced_arrays') __webgl_enable_ANGLE_instanced_arrays(GLctx); - if (extString == 'OES_vertex_array_object') __webgl_enable_OES_vertex_array_object(GLctx); - if (extString == 'WEBGL_draw_buffers') __webgl_enable_WEBGL_draw_buffers(GLctx); + if (extString == 'ANGLE_instanced_arrays') webgl_enable_ANGLE_instanced_arrays(GLctx); + if (extString == 'OES_vertex_array_object') webgl_enable_OES_vertex_array_object(GLctx); + if (extString == 'WEBGL_draw_buffers') webgl_enable_WEBGL_draw_buffers(GLctx); #endif #if MAX_WEBGL_VERSION >= 2 - if (extString == 'WEBGL_draw_instanced_base_vertex_base_instance') __webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance(GLctx); - if (extString == 'WEBGL_multi_draw_instanced_base_vertex_base_instance') __webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance(GLctx); + if (extString == 'WEBGL_draw_instanced_base_vertex_base_instance') webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance(GLctx); + if (extString == 'WEBGL_multi_draw_instanced_base_vertex_base_instance') webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance(GLctx); #endif - if (extString == 'WEBGL_multi_draw') __webgl_enable_WEBGL_multi_draw(GLctx); + if (extString == 'WEBGL_multi_draw') webgl_enable_WEBGL_multi_draw(GLctx); #else @@ -407,8 +407,8 @@ var LibraryHtml5WebGL = { #endif }, - _registerWebGlEventCallback__deps: ['$JSEvents', '$findEventTarget'], - _registerWebGlEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) { + $registerWebGlEventCallback__deps: ['$JSEvents', '$findEventTarget'], + $registerWebGlEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) { #if PTHREADS targetThread = JSEvents.getTargetThreadForEventCallback(targetThread); #endif @@ -437,17 +437,17 @@ var LibraryHtml5WebGL = { emscripten_set_webglcontextlost_callback_on_thread__proxy: 'sync', emscripten_set_webglcontextlost_callback_on_thread__sig: 'iiiiii', - emscripten_set_webglcontextlost_callback_on_thread__deps: ['_registerWebGlEventCallback'], + emscripten_set_webglcontextlost_callback_on_thread__deps: ['$registerWebGlEventCallback'], emscripten_set_webglcontextlost_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - __registerWebGlEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_WEBGLCONTEXTLOST') }}}, "webglcontextlost", targetThread); + registerWebGlEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_WEBGLCONTEXTLOST') }}}, "webglcontextlost", targetThread); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, emscripten_set_webglcontextrestored_callback_on_thread__proxy: 'sync', emscripten_set_webglcontextrestored_callback_on_thread__sig: 'iiiiii', - emscripten_set_webglcontextrestored_callback_on_thread__deps: ['_registerWebGlEventCallback'], + emscripten_set_webglcontextrestored_callback_on_thread__deps: ['$registerWebGlEventCallback'], emscripten_set_webglcontextrestored_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - __registerWebGlEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_WEBGLCONTEXTRESTORED') }}}, "webglcontextrestored", targetThread); + registerWebGlEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_WEBGLCONTEXTRESTORED') }}}, "webglcontextrestored", targetThread); return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, diff --git a/src/library_webgl.js b/src/library_webgl.js index 5fedc92347fa3..0a096b9add922 100644 --- a/src/library_webgl.js +++ b/src/library_webgl.js @@ -31,11 +31,11 @@ var LibraryGL = { + 'miniTempWebGLFloatBuffers[i] = miniTempWebGLFloatBuffersStorage.subarray(0, i+1);\n' + '}\n', - _miniTempWebGLIntBuffers: [], - _miniTempWebGLIntBuffers__postset: - 'var __miniTempWebGLIntBuffersStorage = new Int32Array(' + {{{ GL_POOL_TEMP_BUFFERS_SIZE }}} + ');\n' + $miniTempWebGLIntBuffers: [], + $miniTempWebGLIntBuffers__postset: + 'var miniTempWebGLIntBuffersStorage = new Int32Array(' + {{{ GL_POOL_TEMP_BUFFERS_SIZE }}} + ');\n' + 'for (/**@suppress{duplicate}*/var i = 0; i < ' + {{{ GL_POOL_TEMP_BUFFERS_SIZE }}} + '; ++i) {\n' - + '__miniTempWebGLIntBuffers[i] = __miniTempWebGLIntBuffersStorage.subarray(0, i+1);\n' + + 'miniTempWebGLIntBuffers[i] = miniTempWebGLIntBuffersStorage.subarray(0, i+1);\n' + '}\n', $heapObjectForWebGLType: function(type) { @@ -88,7 +88,7 @@ var LibraryGL = { }, #if MIN_WEBGL_VERSION == 1 - _webgl_enable_ANGLE_instanced_arrays: function(ctx) { + $webgl_enable_ANGLE_instanced_arrays: function(ctx) { // Extension available in WebGL 1 from Firefox 26 and Google Chrome 30 onwards. Core feature in WebGL 2. var ext = ctx.getExtension('ANGLE_instanced_arrays'); if (ext) { @@ -99,12 +99,12 @@ var LibraryGL = { } }, - emscripten_webgl_enable_ANGLE_instanced_arrays__deps: ['_webgl_enable_ANGLE_instanced_arrays'], + emscripten_webgl_enable_ANGLE_instanced_arrays__deps: ['$webgl_enable_ANGLE_instanced_arrays'], emscripten_webgl_enable_ANGLE_instanced_arrays: function(ctx) { - return __webgl_enable_ANGLE_instanced_arrays(GL.contexts[ctx].GLctx); + return webgl_enable_ANGLE_instanced_arrays(GL.contexts[ctx].GLctx); }, - _webgl_enable_OES_vertex_array_object: function(ctx) { + $webgl_enable_OES_vertex_array_object: function(ctx) { // Extension available in WebGL 1 from Firefox 25 and WebKit 536.28/desktop Safari 6.0.3 onwards. Core feature in WebGL 2. var ext = ctx.getExtension('OES_vertex_array_object'); if (ext) { @@ -116,12 +116,12 @@ var LibraryGL = { } }, - emscripten_webgl_enable_OES_vertex_array_object__deps: ['_webgl_enable_OES_vertex_array_object'], + emscripten_webgl_enable_OES_vertex_array_object__deps: ['$webgl_enable_OES_vertex_array_object'], emscripten_webgl_enable_OES_vertex_array_object: function(ctx) { - return __webgl_enable_OES_vertex_array_object(GL.contexts[ctx].GLctx); + return webgl_enable_OES_vertex_array_object(GL.contexts[ctx].GLctx); }, - _webgl_enable_WEBGL_draw_buffers: function(ctx) { + $webgl_enable_WEBGL_draw_buffers: function(ctx) { // Extension available in WebGL 1 from Firefox 28 onwards. Core feature in WebGL 2. var ext = ctx.getExtension('WEBGL_draw_buffers'); if (ext) { @@ -130,20 +130,20 @@ var LibraryGL = { } }, - emscripten_webgl_enable_WEBGL_draw_buffers__deps: ['_webgl_enable_WEBGL_draw_buffers'], + emscripten_webgl_enable_WEBGL_draw_buffers__deps: ['$webgl_enable_WEBGL_draw_buffers'], emscripten_webgl_enable_WEBGL_draw_buffers: function(ctx) { - return __webgl_enable_WEBGL_draw_buffers(GL.contexts[ctx].GLctx); + return webgl_enable_WEBGL_draw_buffers(GL.contexts[ctx].GLctx); }, #endif - _webgl_enable_WEBGL_multi_draw: function(ctx) { + $webgl_enable_WEBGL_multi_draw: function(ctx) { // Closure is expected to be allowed to minify the '.multiDrawWebgl' property, so not accessing it quoted. return !!(ctx.multiDrawWebgl = ctx.getExtension('WEBGL_multi_draw')); }, - emscripten_webgl_enable_WEBGL_multi_draw__deps: ['_webgl_enable_WEBGL_multi_draw'], + emscripten_webgl_enable_WEBGL_multi_draw__deps: ['$webgl_enable_WEBGL_multi_draw'], emscripten_webgl_enable_WEBGL_multi_draw: function(ctx) { - return __webgl_enable_WEBGL_multi_draw(GL.contexts[ctx].GLctx); + return webgl_enable_WEBGL_multi_draw(GL.contexts[ctx].GLctx); }, $GL__postset: 'var GLctx;', @@ -154,16 +154,16 @@ var LibraryGL = { 'malloc', // Needed by registerContext #endif #if MIN_WEBGL_VERSION == 1 - '_webgl_enable_ANGLE_instanced_arrays', - '_webgl_enable_OES_vertex_array_object', - '_webgl_enable_WEBGL_draw_buffers', + '$webgl_enable_ANGLE_instanced_arrays', + '$webgl_enable_OES_vertex_array_object', + '$webgl_enable_WEBGL_draw_buffers', #endif #if MAX_WEBGL_VERSION >= 2 - '_webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance', - '_webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance', + '$webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance', + '$webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance', #endif - '_webgl_enable_WEBGL_multi_draw', - ], + '$webgl_enable_WEBGL_multi_draw', + ], #endif $GL: { #if GL_DEBUG @@ -1099,14 +1099,14 @@ var LibraryGL = { #if MIN_WEBGL_VERSION == 1 // Extensions that are only available in WebGL 1 (the calls will be no-ops if called on a WebGL 2 context active) - __webgl_enable_ANGLE_instanced_arrays(GLctx); - __webgl_enable_OES_vertex_array_object(GLctx); - __webgl_enable_WEBGL_draw_buffers(GLctx); + webgl_enable_ANGLE_instanced_arrays(GLctx); + webgl_enable_OES_vertex_array_object(GLctx); + webgl_enable_WEBGL_draw_buffers(GLctx); #endif #if MAX_WEBGL_VERSION >= 2 // Extensions that are available from WebGL >= 2 (no-op if called on a WebGL 1 context active) - __webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance(GLctx); - __webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance(GLctx); + webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance(GLctx); + webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance(GLctx); #endif #if MAX_WEBGL_VERSION >= 2 @@ -1126,7 +1126,7 @@ var LibraryGL = { GLctx.disjointTimerQueryExt = GLctx.getExtension("EXT_disjoint_timer_query"); } - __webgl_enable_WEBGL_multi_draw(GLctx); + webgl_enable_WEBGL_multi_draw(GLctx); // .getSupportedExtensions() can return null if context is lost, so coerce to empty array. var exts = GLctx.getSupportedExtensions() || []; @@ -1473,7 +1473,7 @@ var LibraryGL = { return height * alignedRowSize; }, - _colorChannelsInGlTextureFormat: function(format) { + $colorChannelsInGlTextureFormat: function(format) { // Micro-optimizations for size: map format to size by subtracting smallest enum value (0x1902) from all values first. // Also omit the most common size value (1) from the list, which is assumed by formats not on the list. var colorChannels = { @@ -1501,18 +1501,18 @@ var LibraryGL = { && format != 0x1909 /* GL_LUMINANCE */ && format != 0x1903 /* GL_RED */ && format != 0x8D94 /* GL_RED_INTEGER */) { - err('Invalid format=' + ptrToString(format) + ' passed to function _colorChannelsInGlTextureFormat()!'); + err('Invalid format=' + ptrToString(format) + ' passed to function colorChannelsInGlTextureFormat()!'); } #endif return colorChannels[format - 0x1902]||1; }, - $emscriptenWebGLGetTexPixelData__deps: ['$computeUnpackAlignedImageSize', '_colorChannelsInGlTextureFormat', '$heapObjectForWebGLType', '$heapAccessShiftForWebGLHeap'], + $emscriptenWebGLGetTexPixelData__deps: ['$computeUnpackAlignedImageSize', '$colorChannelsInGlTextureFormat', '$heapObjectForWebGLType', '$heapAccessShiftForWebGLHeap'], $emscriptenWebGLGetTexPixelData: function(type, format, width, height, pixels, internalFormat) { var heap = heapObjectForWebGLType(type); var shift = heapAccessShiftForWebGLHeap(heap); var byteSize = 1<> shift) << shift == pixels, 'Pointer to texture data passed to texture get function must be aligned to the byte size of the pixel type!'); @@ -1684,8 +1684,8 @@ var LibraryGL = { // merge the functions together to only have one generated copy of this. 'createFunction' refers to the WebGL context function name to do // the actual creation, 'objectTable' points to the GL object table where to populate the created objects, and 'functionName' carries // the name of the caller for debug information. - _glGenObject__sig: 'vii', - _glGenObject: function(n, buffers, createFunction, objectTable + $__glGenObject__sig: 'vii', + $__glGenObject: function(n, buffers, createFunction, objectTable #if GL_ASSERTIONS , functionName #endif @@ -1706,7 +1706,7 @@ var LibraryGL = { } }, - glGenBuffers__deps: ['_glGenObject'], + glGenBuffers__deps: ['$__glGenObject'], glGenBuffers__sig: 'vii', glGenBuffers: function(n, buffers) { __glGenObject(n, buffers, 'createBuffer', GL.buffers @@ -1716,7 +1716,7 @@ var LibraryGL = { ); }, - glGenTextures__deps: ['_glGenObject'], + glGenTextures__deps: ['$__glGenObject'], glGenTextures__sig: 'vii', glGenTextures: function(n, textures) { __glGenObject(n, textures, 'createTexture', GL.textures @@ -1963,7 +1963,7 @@ var LibraryGL = { }, glGenRenderbuffers__sig: 'vii', - glGenRenderbuffers__deps: ['_glGenObject'], + glGenRenderbuffers__deps: ['$__glGenObject'], glGenRenderbuffers: function(n, renderbuffers) { __glGenObject(n, renderbuffers, 'createRenderbuffer', GL.renderbuffers #if GL_ASSERTIONS @@ -2360,7 +2360,7 @@ var LibraryGL = { glUniform1iv__sig: 'viii', glUniform1iv__deps: ['$webglGetUniformLocation' #if GL_POOL_TEMP_BUFFERS && MIN_WEBGL_VERSION == 1 - , '_miniTempWebGLIntBuffers' + , '$miniTempWebGLIntBuffers' #endif ], glUniform1iv: function(location, count, value) { @@ -2386,7 +2386,7 @@ var LibraryGL = { #if GL_POOL_TEMP_BUFFERS if (count <= {{{ GL_POOL_TEMP_BUFFERS_SIZE }}}) { // avoid allocation when uploading few enough uniforms - var view = __miniTempWebGLIntBuffers[count-1]; + var view = miniTempWebGLIntBuffers[count-1]; for (var i = 0; i < count; ++i) { view[i] = {{{ makeGetValue('value', '4*i', 'i32') }}}; } @@ -2405,7 +2405,7 @@ var LibraryGL = { glUniform2iv__sig: 'viii', glUniform2iv__deps: ['$webglGetUniformLocation' #if GL_POOL_TEMP_BUFFERS && MIN_WEBGL_VERSION == 1 - , '_miniTempWebGLIntBuffers' + , '$miniTempWebGLIntBuffers' #endif ], glUniform2iv: function(location, count, value) { @@ -2431,7 +2431,7 @@ var LibraryGL = { #if GL_POOL_TEMP_BUFFERS if (count <= {{{ GL_POOL_TEMP_BUFFERS_SIZE / 2 }}}) { // avoid allocation when uploading few enough uniforms - var view = __miniTempWebGLIntBuffers[2*count-1]; + var view = miniTempWebGLIntBuffers[2*count-1]; for (var i = 0; i < 2*count; i += 2) { view[i] = {{{ makeGetValue('value', '4*i', 'i32') }}}; view[i+1] = {{{ makeGetValue('value', '4*i+4', 'i32') }}}; @@ -2451,7 +2451,7 @@ var LibraryGL = { glUniform3iv__sig: 'viii', glUniform3iv__deps: ['$webglGetUniformLocation' #if GL_POOL_TEMP_BUFFERS && MIN_WEBGL_VERSION == 1 - , '_miniTempWebGLIntBuffers' + , '$miniTempWebGLIntBuffers' #endif ], glUniform3iv: function(location, count, value) { @@ -2477,7 +2477,7 @@ var LibraryGL = { #if GL_POOL_TEMP_BUFFERS if (count <= {{{ GL_POOL_TEMP_BUFFERS_SIZE / 3 }}}) { // avoid allocation when uploading few enough uniforms - var view = __miniTempWebGLIntBuffers[3*count-1]; + var view = miniTempWebGLIntBuffers[3*count-1]; for (var i = 0; i < 3*count; i += 3) { view[i] = {{{ makeGetValue('value', '4*i', 'i32') }}}; view[i+1] = {{{ makeGetValue('value', '4*i+4', 'i32') }}}; @@ -2498,7 +2498,7 @@ var LibraryGL = { glUniform4iv__sig: 'viii', glUniform4iv__deps: ['$webglGetUniformLocation' #if GL_POOL_TEMP_BUFFERS && MIN_WEBGL_VERSION == 1 - , '_miniTempWebGLIntBuffers' + , '$miniTempWebGLIntBuffers' #endif ], glUniform4iv: function(location, count, value) { @@ -2524,7 +2524,7 @@ var LibraryGL = { #if GL_POOL_TEMP_BUFFERS if (count <= {{{ GL_POOL_TEMP_BUFFERS_SIZE / 4 }}}) { // avoid allocation when uploading few enough uniforms - var view = __miniTempWebGLIntBuffers[4*count-1]; + var view = miniTempWebGLIntBuffers[4*count-1]; for (var i = 0; i < 4*count; i += 4) { view[i] = {{{ makeGetValue('value', '4*i', 'i32') }}}; view[i+1] = {{{ makeGetValue('value', '4*i+4', 'i32') }}}; @@ -2977,7 +2977,7 @@ var LibraryGL = { return GLctx.getAttribLocation(GL.programs[program], UTF8ToString(name)); }, - _glGetActiveAttribOrUniform: function(funcName, program, index, bufSize, length, size, type, name) { + $__glGetActiveAttribOrUniform: function(funcName, program, index, bufSize, length, size, type, name) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.programs, program, funcName, 'program'); #endif @@ -2992,13 +2992,13 @@ var LibraryGL = { }, glGetActiveAttrib__sig: 'viiiiiii', - glGetActiveAttrib__deps: ['_glGetActiveAttribOrUniform'], + glGetActiveAttrib__deps: ['$__glGetActiveAttribOrUniform'], glGetActiveAttrib: function(program, index, bufSize, length, size, type, name) { __glGetActiveAttribOrUniform('getActiveAttrib', program, index, bufSize, length, size, type, name); }, glGetActiveUniform__sig: 'viiiiiii', - glGetActiveUniform__deps: ['_glGetActiveAttribOrUniform'], + glGetActiveUniform__deps: ['$__glGetActiveAttribOrUniform'], glGetActiveUniform: function(program, index, bufSize, length, size, type, name) { __glGetActiveAttribOrUniform('getActiveUniform', program, index, bufSize, length, size, type, name); }, @@ -3576,7 +3576,7 @@ var LibraryGL = { }, glGenFramebuffers__sig: 'vii', - glGenFramebuffers__deps: ['_glGenObject'], + glGenFramebuffers__deps: ['$__glGenObject'], glGenFramebuffers: function(n, ids) { __glGenObject(n, ids, 'createFramebuffer', GL.framebuffers #if GL_ASSERTIONS @@ -3632,7 +3632,7 @@ var LibraryGL = { return GLctx.isFramebuffer(fb); }, - glGenVertexArrays__deps: ['_glGenObject' + glGenVertexArrays__deps: ['$__glGenObject' #if LEGACY_GL_EMULATION , 'emulGlGenVertexArrays' #endif diff --git a/src/library_webgl2.js b/src/library_webgl2.js index 8ee79961e91f8..1b9ef5388e5c6 100644 --- a/src/library_webgl2.js +++ b/src/library_webgl2.js @@ -188,7 +188,7 @@ var LibraryWebGL2 = { // Queries glGenQueries__sig: 'vii', - glGenQueries__deps: ['_glGenObject'], + glGenQueries__deps: ['$__glGenObject'], glGenQueries: function(n, ids) { __glGenObject(n, ids, 'createQuery', GL.queries #if GL_ASSERTIONS @@ -268,7 +268,7 @@ var LibraryWebGL2 = { // Sampler objects glGenSamplers__sig: 'vii', - glGenSamplers__deps: ['_glGenObject'], + glGenSamplers__deps: ['$__glGenObject'], glGenSamplers: function(n, samplers) { __glGenObject(n, samplers, 'createSampler', GL.samplers #if GL_ASSERTIONS @@ -372,7 +372,7 @@ var LibraryWebGL2 = { // Transform Feedback glGenTransformFeedbacks__sig: 'vii', - glGenTransformFeedbacks__deps: ['_glGenObject'], + glGenTransformFeedbacks__deps: ['$__glGenObject'], glGenTransformFeedbacks: function(n, ids) { __glGenObject(n, ids, 'createTransformFeedback', GL.transformFeedbacks #if GL_ASSERTIONS @@ -1044,14 +1044,14 @@ var LibraryWebGL2 = { }, glDrawElementsInstancedBaseVertexBaseInstanceANGLE: 'glDrawElementsInstancedBaseVertexBaseInstanceWEBGL', - _webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance: function(ctx) { + $webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance: function(ctx) { // Closure is expected to be allowed to minify the '.dibvbi' property, so not accessing it quoted. return !!(ctx.dibvbi = ctx.getExtension('WEBGL_draw_instanced_base_vertex_base_instance')); }, - emscripten_webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance__deps: ['_webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance'], + emscripten_webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance__deps: ['$webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance'], emscripten_webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance: function(ctx) { - return __webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance(GL.contexts[ctx].GLctx); + return webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance(GL.contexts[ctx].GLctx); }, glMultiDrawArraysInstancedBaseInstanceWEBGL__sig: 'viiiiii', @@ -1089,14 +1089,14 @@ var LibraryWebGL2 = { }, glMultiDrawElementsInstancedBaseVertexBaseInstanceANGLE: 'glMultiDrawElementsInstancedBaseVertexBaseInstanceWEBGL', - _webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance: function(ctx) { + $webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance: function(ctx) { // Closure is expected to be allowed to minify the '.mdibvbi' property, so not accessing it quoted. return !!(ctx.mdibvbi = ctx.getExtension('WEBGL_multi_draw_instanced_base_vertex_base_instance')); }, - emscripten_webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance__deps: ['_webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance'], + emscripten_webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance__deps: ['$webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance'], emscripten_webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance: function(ctx) { - return __webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance(GL.contexts[ctx].GLctx); + return webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance(GL.contexts[ctx].GLctx); }, glVertexAttribI4i__sig: 'viiiii', diff --git a/test/other/metadce/test_metadce_hello_O0.jssize b/test/other/metadce/test_metadce_hello_O0.jssize index 235384b4b2d38..7451e1e04eef3 100644 --- a/test/other/metadce/test_metadce_hello_O0.jssize +++ b/test/other/metadce/test_metadce_hello_O0.jssize @@ -1 +1 @@ -23491 +23946 diff --git a/test/other/metadce/test_metadce_minimal_O0.jssize b/test/other/metadce/test_metadce_minimal_O0.jssize index 15a17080a76ef..570a495f908e8 100644 --- a/test/other/metadce/test_metadce_minimal_O0.jssize +++ b/test/other/metadce/test_metadce_minimal_O0.jssize @@ -1 +1 @@ -19799 +20254 diff --git a/test/other/test_unoptimized_code_size.js.size b/test/other/test_unoptimized_code_size.js.size index af31831ce1ef8..7734a8d01e994 100644 --- a/test/other/test_unoptimized_code_size.js.size +++ b/test/other/test_unoptimized_code_size.js.size @@ -1 +1 @@ -63868 +64423 diff --git a/test/other/test_unoptimized_code_size_strict.js.size b/test/other/test_unoptimized_code_size_strict.js.size index 9bc3ebe0ee2c4..e834ee820806e 100644 --- a/test/other/test_unoptimized_code_size_strict.js.size +++ b/test/other/test_unoptimized_code_size_strict.js.size @@ -1 +1 @@ -63220 +63430 From f51beb1a86d57838c04c8f44691ec17ce938a220 Mon Sep 17 00:00:00 2001 From: Derek Schuff Date: Fri, 17 Mar 2023 16:20:04 -0700 Subject: [PATCH 0023/1523] Create @crossplatform_test decorator (#18997) Currently the CircleCI windows builder uses a hardcoded list of tests. Switch to using a decorator to discover these tests, to make it easier to share the list. --- .circleci/config.yml | 44 ++------------------------------------------ test/common.py | 5 +++++ test/runner.py | 25 ++++++++++++++++++++++--- test/test_core.py | 9 ++++++++- test/test_other.py | 38 +++++++++++++++++++++++++++++++++++++- 5 files changed, 74 insertions(+), 47 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 833271c9198f1..49fa95823a607 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -649,48 +649,8 @@ jobs: - pip-install: python: "$EMSDK_PYTHON" - run-tests: - title: "other subset" - test_targets: " - core0.test_dylink_basics - core2.test_sse1 - core2.test_ccall - core2.test_utf16 - core2.test_em_asm_unicode - core2.test_em_js - core2.test_em_js_pthreads - core2.test_unicode_js_library - other.test_reproduce - other.test_stack_overflow - other.test_dlmalloc_modes - other.test_c_preprocessor - other.test_prejs_unicode - other.test_em_js_side_module - other.test_es5_transpile - other.test_emcc_cflags - other.test_stdin - other.test_bad_triple - other.test_closure_externs - other.test_binaryen_debug - other.test_js_optimizer* - other.test_output_to_nowhere - other.test_emcc_dev_null - other.test_cmake* - other.test_system_include_paths - other.test_emar_response_file - other.test_special_chars_in_arguments - other.test_toolchain_profiler - other.test_realpath_nodefs - other.test_response_file_encoding - other.test_libc_progname - other.test_realpath - other.test_embed_file_dup - other.test_dot_a_all_contents_invalid - other.test_emcc_print_search_dirs - other.test_emcc_print_file_name - other.test_minimal_runtime_export_all_modularize - other.test_pkg_config* - other.test_pthreads_flag - other.test_sdl2_config" + title: "crossplatform tests" + test_targets: "--crossplatform-only" - upload-test-results # Run a single websockify-based test to ensure it works on windows. - run-tests: diff --git a/test/common.py b/test/common.py index 1c8e1d798eb83..c5b258e0298f9 100644 --- a/test/common.py +++ b/test/common.py @@ -221,6 +221,11 @@ def decorated(self, *args, **kwargs): return decorated +def crossplatform(f): + f.is_crossplatform_test = True + return f + + @contextlib.contextmanager def env_modify(updates): """A context manager that updates os.environ.""" diff --git a/test/runner.py b/test/runner.py index 7f6af2532f7e0..3baf775eb970c 100755 --- a/test/runner.py +++ b/test/runner.py @@ -127,6 +127,21 @@ def get_all_tests(modules): return all_tests +def get_crossplatform_tests(modules): + suites = ['core2', 'other'] # We don't need all versions of every test + crossplatform_tests = [] + # Walk over the test suites and find the test functions with the + # is_crossplatform_test attribute applied by @crossplatform decorator + for m in modules: + for s in suites: + if hasattr(m, s): + testclass = getattr(m, s) + for funcname in dir(testclass): + if hasattr(getattr(testclass, funcname), 'is_crossplatform_test'): + crossplatform_tests.append(s + '.' + funcname) + return crossplatform_tests + + def tests_with_expanded_wildcards(args, all_tests): # Process wildcards, e.g. "browser.test_pthread_*" should expand to list all pthread tests new_args = [] @@ -353,6 +368,7 @@ def parse_args(args): const=True, default=False) parser.add_argument('--force64', dest='force64', action='store_const', const=True, default=None) + parser.add_argument('--crossplatform-only', action='store_true') return parser.parse_args() @@ -426,9 +442,12 @@ def prepend_default(arg): modules = get_and_import_modules() all_tests = get_all_tests(modules) - tests = tests_with_expanded_wildcards(tests, all_tests) - tests = skip_requested_tests(tests, modules) - tests = args_for_random_tests(tests, modules) + if options.crossplatform_only: + tests = get_crossplatform_tests(modules) + else: + tests = tests_with_expanded_wildcards(tests, all_tests) + tests = skip_requested_tests(tests, modules) + tests = args_for_random_tests(tests, modules) suites, unmatched_tests = load_test_suites(tests, modules) if unmatched_tests: print('ERROR: could not find the following tests: ' + ' '.join(unmatched_tests)) diff --git a/test/test_core.py b/test/test_core.py index cfb640c962f13..664e95b3b080e 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -27,7 +27,7 @@ from common import RunnerCore, path_from_root, requires_native_clang, test_file, create_file from common import skip_if, needs_dylink, no_windows, no_mac, is_slow_test, parameterized from common import env_modify, with_env_modify, disabled, node_pthreads, also_with_wasm_bigint -from common import read_file, read_binary, requires_v8, requires_node, compiler_for +from common import read_file, read_binary, requires_v8, requires_node, compiler_for, crossplatform from common import NON_ZERO, WEBIDL_BINDER, EMBUILDER, PYTHON import clang_native @@ -2294,6 +2294,7 @@ def test_main_thread_async_em_asm(self, args, force_c=False): def test_main_thread_em_asm_signatures(self): self.do_core_test('test_em_asm_signatures.cpp', assert_returncode=NON_ZERO) + @crossplatform def test_em_asm_unicode(self): self.do_core_test('test_em_asm_unicode.cpp') self.do_core_test('test_em_asm_unicode.cpp', force_c=True) @@ -2334,6 +2335,7 @@ def test_em_asm_side_module(self): 'dylink': (['-sMAIN_MODULE=2'], False), 'dylink_c': (['-sMAIN_MODULE=2'], True), }) + @crossplatform def test_em_js(self, args, force_c): if '-sMAIN_MODULE=2' in args: self.check_dylink() @@ -4273,6 +4275,7 @@ def do_basic_dylink_test(self, **kwargs): ''', 'other says 11.', 'int sidey();', force_c=True, **kwargs) @needs_dylink + @crossplatform def test_dylink_basics(self): self.do_basic_dylink_test(need_reverse=False) self.verify_in_strict_mode('main.js') @@ -5905,6 +5908,7 @@ def test_utf32(self): self.do_runf(test_file('utf32.cpp'), 'OK.') self.do_runf(test_file('utf32.cpp'), 'OK.', args=['-fshort-wchar']) + @crossplatform def test_utf16(self): self.set_setting('EXPORTED_RUNTIME_METHODS', ['writeAsciiToMemory', 'UTF16ToString', 'stringToUTF16']) self.do_runf(test_file('core/test_utf16.cpp'), 'OK.') @@ -6457,6 +6461,7 @@ def test_js_libraries(self): self.do_runf('main.cpp', 'hello from lib!\n*32*\n') @with_env_modify({'LC_ALL': 'latin-1', 'PYTHONUTF8': '0', 'PYTHONCOERCECLOCALE': '0'}) + @crossplatform def test_unicode_js_library(self): create_file('main.c', ''' #include @@ -6736,6 +6741,7 @@ def test_neon_wasm_simd(self): # Tests invoking the SIMD API via x86 SSE1 xmmintrin.h header (_mm_x() functions) @wasm_simd + @crossplatform @requires_native_clang @no_safe_heap('has unaligned 64-bit operations in wasm') @no_ubsan('test contains UB') @@ -7169,6 +7175,7 @@ def test_wasm2c_sandboxing(self, mode): ### Integration tests + @crossplatform def test_ccall(self): self.emcc_args.append('-Wno-return-stack-address') self.set_setting('EXPORTED_RUNTIME_METHODS', ['ccall', 'cwrap', 'STACK_SIZE']) diff --git a/test/test_other.py b/test/test_other.py index e4c9d07ab53ab..9b5376b8485c5 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -33,7 +33,7 @@ from common import env_modify, no_mac, no_windows, requires_native_clang, with_env_modify from common import create_file, parameterized, NON_ZERO, node_pthreads, TEST_ROOT, test_file from common import compiler_for, EMBUILDER, requires_v8, requires_node, requires_wasm64 -from common import requires_wasm_eh +from common import requires_wasm_eh, crossplatform from common import also_with_minimal_runtime, also_with_wasm_bigint, EMTEST_BUILD_VERBOSE, PYTHON from tools import shared, building, utils, deps_info, response_file, cache from tools.utils import read_file, write_file, delete_file, read_binary @@ -241,6 +241,7 @@ def parse_wasm(self, filename): # This needs to work because many tools run `emcc -v` internally and it should # always work even if the user has `EMCC_CFLAGS` set. @with_env_modify({'EMCC_CFLAGS': '-should -be -ignored'}) + @crossplatform def test_emcc_v(self): for compiler in [EMCC, EMXX]: # -v, without input files @@ -566,6 +567,7 @@ def test_multiple_sources(self): def test_tsearch(self): self.do_other_test('test_tsearch.c') + @crossplatform def test_libc_progname(self): self.do_other_test('test_libc_progname.c') @@ -676,6 +678,7 @@ def test_emcc_cflags(self): self.run_process([EMCC, 'out.o']) self.assertContained('hello, world!', self.run_js('a.out.js')) + @crossplatform def test_emcc_print_search_dirs(self): output = self.run_process([EMCC, '-print-search-dirs'], stdout=PIPE).stdout self.assertContained('programs: =', output) @@ -686,6 +689,7 @@ def test_emcc_print_search_dirs(self): print(libpath) self.assertIn(cache.get_lib_dir(absolute=True), libpath) + @crossplatform def test_emcc_print_file_name(self): self.run_process([EMBUILDER, 'build', 'libc']) output = self.run_process([EMCC, '-print-file-name=libc.a'], stdout=PIPE).stdout @@ -722,6 +726,7 @@ def test_emstrip(self): self.assertNotContained('.debug_info', output) @is_slow_test + @crossplatform @parameterized({ # ('directory to the test', 'output filename', ['extra args to pass to # CMake']) Testing all combinations would be too much work and the test @@ -920,6 +925,7 @@ def test_cmake_find_pkg_config(self): self.assertContained('PKG_CONFIG_LIBDIR: ' + libdir, out) @requires_pkg_config + @crossplatform def test_pkg_config_packages(self): packages = [ ('egl', '10.2.2'), @@ -943,6 +949,7 @@ def test_cmake_check_type_size(self, flags): # execution. self.run_process(cmd + ['-DCMAKE_CROSSCOMPILING_EMULATOR=/missing_binary']) + @crossplatform def test_system_include_paths(self): # Verify that all default include paths are within `emscripten/system` @@ -1325,6 +1332,7 @@ def test_redundant_link(self): self.assertContained('result: 1', self.run_js('a.out.js')) @no_mac('https://github.com/emscripten-core/emscripten/issues/16649') + @crossplatform def test_dot_a_all_contents_invalid(self): # check that we error if an object file in a .a is not valid bitcode. # do not silently ignore native object files, which may have been @@ -1406,6 +1414,7 @@ def write_js_main(): write_js_main() self.assertContained('42\n', self.run_js('main.js')) + @crossplatform def test_minimal_runtime_export_all_modularize(self): """This test ensures that MODULARIZE and EXPORT_ALL work simultaneously. @@ -1470,6 +1479,7 @@ def test_export_all_and_exported_functions(self): self.emcc('lib.c', ['-sEXPORTED_FUNCTIONS=_libfunc2', '-sEXPORT_ALL', '--pre-js', 'main.js'], output_filename='a.out.js') self.assertContained('libfunc\n', self.run_js('a.out.js')) + @crossplatform def test_stdin(self): def run_test(): for engine in config.JS_ENGINES: @@ -1764,6 +1774,7 @@ def test_include_file(self, args): '': ([],), 'wasmfs': (['-sWASMFS'],), }) + @crossplatform def test_embed_file_dup(self, args): ensure_dir(self.in_dir('tst', 'test1')) ensure_dir(self.in_dir('tst', 'test2')) @@ -2510,6 +2521,7 @@ def test_extern_prepost(self): 'safeHeap': ('optimizer/test-safeHeap.js', ['safeHeap']), 'LittleEndianHeap': ('optimizer/test-LittleEndianHeap.js', ['littleEndianHeap']), }) + @crossplatform def test_js_optimizer(self, input, passes): input = test_file(input) expected_file = os.path.splitext(input)[0] + '-output.js' @@ -2524,6 +2536,7 @@ def test_js_optimizer(self, input, passes): 'wasm2js': ('wasm2js', ['minifyNames', 'last']), 'constructor': ('constructor', ['minifyNames']) }) + @crossplatform def test_js_optimizer_py(self, name, passes): # run the js optimizer python script. this differs from test_js_optimizer # which runs the internal js optimizer JS script directly (which the python @@ -4267,6 +4280,7 @@ def test_implicit_func(self): self.assertContained(INCOMPATIBLE, stderr) @requires_native_clang + @crossplatform def test_bad_triple(self): # compile a minimal program, with as few dependencies as possible, as # native building on CI may not always work well @@ -5996,6 +6010,7 @@ def test_emmake_python(self): # the existence of an executable. self.run_process([emmake, PYTHON, test_file('emmake/make.py')]) + @crossplatform def test_sdl2_config(self): for args, expected in [ [['--version'], '2.0.10'], @@ -6825,6 +6840,7 @@ def test_musl_syscalls(self): # there should be no musl syscalls in hello world output self.assertNotContained('__syscall', src) + @crossplatform def test_emcc_dev_null(self): out = self.run_process([EMCC, '-dM', '-E', '-x', 'c', os.devnull], stdout=PIPE).stdout self.assertContained('#define __EMSCRIPTEN__ 1', out) # all our defines should show up @@ -6909,6 +6925,7 @@ def test_js_lib_native_deps(self): self.do_runf('test.c', 'dddddddddd\n', emcc_args=['--js-library', 'lib.js']) + @crossplatform def test_realpath(self): create_file('src.c', r''' #include @@ -6932,6 +6949,7 @@ def test_realpath(self): self.run_process([EMCC, 'src.c', '-sSAFE_HEAP', '--embed-file', 'boot']) self.assertContained('Resolved: /boot/README.txt', self.run_js('a.out.js')) + @crossplatform def test_realpath_nodefs(self): create_file('src.c', r''' #include @@ -7017,6 +7035,7 @@ def test_no_warnings(self): err = self.run_process([EMXX, test_file('hello_libcxx.cpp')], stderr=PIPE).stderr self.assertEqual(err, '') + @crossplatform def test_dlmalloc_modes(self): create_file('src.cpp', r''' #include @@ -7664,6 +7683,7 @@ def test_binaryen_ctors(self): assert correct == seen, correct + '\n vs \n' + seen # test debug info and debuggability of JS output + @crossplatform def test_binaryen_debug(self): for args, expect_dash_g, expect_emit_text, expect_clean_js, expect_whitespace_js, expect_closured in [ (['-O0'], False, False, False, True, False), @@ -8499,6 +8519,7 @@ def test_emar_duplicate_inputs(self): create_file('file1', ' ') self.run_process([EMAR, 'cr', 'file1.a', 'file1', 'file1']) + @crossplatform def test_emar_response_file(self): # Test that special character such as single quotes in filenames survive being # sent via response file @@ -8646,6 +8667,7 @@ def test_closure_webgpu(self): ]) # Tests --closure-args command line flag + @crossplatform def test_closure_externs(self): # Test with relocate path to the externs file to ensure that incoming relative paths # are translated correctly (Since closure runs with a different CWD) @@ -8728,6 +8750,7 @@ def test_closure_type_annotations(self): if 'my ' + attribute in code: self.assertFalse('Attribute `%s` could not be DCEd' % attribute) + @crossplatform @with_env_modify({'EMPROFILE': '1'}) def test_toolchain_profiler(self): # Verify some basic functionality of EMPROFILE @@ -8858,6 +8881,7 @@ def test_main_module_without_main(self): ''') self.do_runf('src.c', 'bar', emcc_args=['--pre-js', 'pre.js', '-sMAIN_MODULE=2']) + @crossplatform def test_js_optimizer_parse_error(self): # check we show a proper understandable error for JS parse problems create_file('src.cpp', r''' @@ -8875,6 +8899,7 @@ def test_js_optimizer_parse_error(self): ^ '''), stderr) + @crossplatform def test_js_optimizer_chunk_size_determinism(self): def build(): self.run_process([EMCC, test_file('hello_world.c'), '-O3', '-sWASM=0']) @@ -8898,6 +8923,7 @@ def build(): self.assertIdentical(normal, tiny) self.assertIdentical(normal, huge) + @crossplatform def test_js_optimizer_verbose(self): # build at -O3 with wasm2js to use as much as possible of the JS # optimization code, and verify it works ok in verbose mode @@ -10075,6 +10101,7 @@ def get_file_gzipped_size(f): self.assertEqual(total_output_size, total_expected_size) # Tests the library_c_preprocessor.js functionality. + @crossplatform def test_c_preprocessor(self): self.do_runf(test_file('test_c_preprocessor.c'), emcc_args=['--js-library', path_from_root('src/library_c_preprocessor.js')]) @@ -11054,6 +11081,7 @@ def fail(args, details): fail(required_flags + ['-O2'], optimization_message) fail(required_flags + ['-O3'], optimization_message) + @crossplatform def test_output_to_nowhere(self): self.run_process([EMXX, test_file('hello_world.cpp'), '-o', os.devnull, '-c']) @@ -11923,6 +11951,7 @@ def test_runtime_keepalive(self): self.set_setting('EXIT_RUNTIME') self.do_other_test('test_runtime_keepalive.cpp') + @crossplatform def test_em_js_side_module(self): err = self.expect_fail([EMXX, '-sSIDE_MODULE', test_file('core/test_em_js.cpp')]) self.assertContained('EM_JS is not supported in side modules', err) @@ -11996,6 +12025,7 @@ def create_o(name, i): self.assertContained(str(count * (count - 1) // 2), self.run_js('a.out.js')) # Tests that the filename suffix of the response files can be used to detect which encoding the file is. + @crossplatform def test_response_file_encoding(self): open('äö.c', 'w').write('int main(){}') @@ -12074,6 +12104,7 @@ def test_auto_ptr_cxx17(self): '-D_LIBCPP_ENABLE_CXX17_REMOVED_AUTO_PTR', '-Wno-deprecated-declarations']) + @crossplatform def test_special_chars_in_arguments(self): # We had some regressions where the windows `.bat` files that run the compiler # driver were failing to accept certain special characters such as `(`, `)` and `!`. @@ -12565,6 +12596,7 @@ def test_hello_function(self): '': ([],), 'O2': (['-O2'],), }) + @crossplatform def test_es5_transpile(self, args): self.emcc_args += args @@ -12897,6 +12929,7 @@ def test_lto_atexit(self): self.set_setting('EXIT_RUNTIME') self.do_runf(test_file('other/test_lto_atexit.c'), 'main done\nmy_dtor\n') + @crossplatform def test_prejs_unicode(self): create_file('script.js', r''' console.log('↓'); @@ -13055,6 +13088,7 @@ def test_em_js_deps(self): self.do_runf('f2.c', emcc_args=['f1.c']) @no_mac('https://github.com/emscripten-core/emscripten/issues/18175') + @crossplatform def test_stack_overflow(self): self.set_setting('STACK_OVERFLOW_CHECK', 1) self.emcc_args += ['-O1', '--profiling-funcs'] @@ -13062,6 +13096,7 @@ def test_stack_overflow(self): 'Stack overflow detected. You can try increasing -sSTACK_SIZE', assert_returncode=NON_ZERO) + @crossplatform def test_reproduce(self): self.run_process([EMCC, '-sASSERTIONS=1', '--reproduce=foo.tar', test_file('hello_world.c')]) self.assertExists('foo.tar') @@ -13225,6 +13260,7 @@ def test_cpp_module(self): self.run_process([EMXX, '-std=c++20', test_file('other/hello_world.cppm'), '--precompile', '-o', 'hello_world.pcm']) self.do_other_test('test_cpp_module.cpp', emcc_args=['-std=c++20', '-fprebuilt-module-path=.', 'hello_world.pcm']) + @crossplatform def test_pthreads_flag(self): # We support just the singular form of `-pthread`, like gcc # Clang supports the plural form too but I think just due to historical accident: From 999cca3067f6c8f32758d2a69ea0c4d4110c0309 Mon Sep 17 00:00:00 2001 From: Derek Schuff Date: Mon, 20 Mar 2023 08:27:59 -0700 Subject: [PATCH 0024/1523] Only test crossplatform tests on mac (#18999) This makes the mac builder run only the tests that are marked with the @crossplatform decorator, having been explicitly added for Windows or mac. It will be a large reduction in test coverage for mac, but of course run much faster. --- .circleci/config.yml | 13 ++----------- test/test_core.py | 2 ++ test/test_sockets.py | 3 ++- 3 files changed, 6 insertions(+), 12 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 49fa95823a607..1b6723cb42759 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -695,17 +695,8 @@ jobs: - pip-install: python: "$EMSDK_PYTHON" - run-tests: - # skip other.test_stack_switching_size as we do not currently install - # d8 on mac - title: "other+extras" - test_targets: " - other - sockets.test_nodejs_sockets_echo* - core0.test_lua - core0.test_longjmp_standalone - core2.test_sse1 - skip:other.test_native_link_error_message - skip:other.test_stack_switching_size" + title: "crossplatform tests" + test_targets: "--crossplatform-only" - upload-test-results workflows: diff --git a/test/test_core.py b/test/test_core.py index 664e95b3b080e..b355a404e0785 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -1108,6 +1108,7 @@ def test_wcslen(self): def test_regex(self): self.do_core_test('test_regex.c') + @crossplatform @also_with_standalone_wasm(wasm2c=True, impure=True) def test_longjmp_standalone(self): self.do_core_test('test_longjmp.c') @@ -6867,6 +6868,7 @@ def test_gcc_unmangler(self): self.do_runf(test_file('third_party/libiberty/cp-demangle.c'), '*d_demangle(char const*, int, unsigned int*)*', args=['_ZL10d_demanglePKciPj']) @needs_make('make') + @crossplatform def test_lua(self): self.emcc_args.remove('-Werror') env_init = { diff --git a/test/test_sockets.py b/test/test_sockets.py index b7518ab868916..12abd2c3cd28d 100644 --- a/test/test_sockets.py +++ b/test/test_sockets.py @@ -18,7 +18,7 @@ import clang_native import common from common import BrowserCore, no_windows, create_file, test_file, read_file -from common import parameterized, requires_native_clang, PYTHON +from common import parameterized, requires_native_clang, crossplatform, PYTHON from tools import config, utils from tools.shared import EMCC, path_from_root, run_process, CLANG_CC @@ -277,6 +277,7 @@ def test_enet(self): with CompiledServerHarness(test_file('sockets/test_enet_server.c'), enet, 49210) as harness: self.btest_exit(test_file('sockets/test_enet_client.c'), args=enet + ['-DSOCKK=%d' % harness.listen_port]) + @crossplatform @parameterized({ 'native': [WebsockifyServerHarness, 59160, ['-DTEST_DGRAM=0']], 'tcp': [CompiledServerHarness, 59162, ['-DTEST_DGRAM=0']], From 5db9a87e11393207ba1360b26d30a4e910627650 Mon Sep 17 00:00:00 2001 From: jameshu15869 <55058507+jameshu15869@users.noreply.github.com> Date: Mon, 20 Mar 2023 12:15:05 -0400 Subject: [PATCH 0025/1523] Implement open() in library_wasmfs.js (#18919) Implemented FS.open() in library_wasmfs.js Added tests to test FS.open() with different flags. --- emcc.py | 1 + src/library_wasmfs.js | 27 +++++++++++++++++++++++++ system/lib/wasmfs/js_api.cpp | 4 ++++ test/fs/test_open_wasmfs.c | 38 ++++++++++++++++++++++++++++++++++++ test/test_core.py | 5 +++-- 5 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 test/fs/test_open_wasmfs.c diff --git a/emcc.py b/emcc.py index 564f0bd11eea3..d72412d4a05dd 100755 --- a/emcc.py +++ b/emcc.py @@ -2329,6 +2329,7 @@ def phase_linker_setup(options, state, newargs): # JS API directly. settings.REQUIRED_EXPORTS += [ '_wasmfs_write_file', + '_wasmfs_open', '_wasmfs_mkdir', '_wasmfs_unlink', '_wasmfs_chdir', diff --git a/src/library_wasmfs.js b/src/library_wasmfs.js index 68bf1405d9eb2..42f50d08f4d99 100644 --- a/src/library_wasmfs.js +++ b/src/library_wasmfs.js @@ -61,6 +61,25 @@ mergeInto(LibraryManager.library, { if (canWrite) mode |= {{{ cDefine('S_IWUGO') }}}; return mode; }, + modeStringToFlags: (str) => { + var flags = FS.flagModes[str]; + if (typeof flags == 'undefined') { + throw new Error('Unknown file open mode: ' + str); + } + return flags; + }, + flagModes: { + // copied directly from library_fs.js + // Extra quotes used here on the keys to this object otherwise jsifier will + // erase them in the process of reading and then writing the JS library + // code. + '"r"': {{{ cDefine('O_RDONLY') }}}, + '"r+"': {{{ cDefine('O_RDWR') }}}, + '"w"': {{{ cDefine('O_TRUNC') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_WRONLY') }}}, + '"w+"': {{{ cDefine('O_TRUNC') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_RDWR') }}}, + '"a"': {{{ cDefine('O_APPEND') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_WRONLY') }}}, + '"a+"': {{{ cDefine('O_APPEND') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_RDWR') }}}, + }, createDataFile: (parent, name, data, canRead, canWrite, canOwn) => { // Data files must be cached until the file system itself has been initialized. var mode = FS.getMode(canRead, canWrite); @@ -122,6 +141,14 @@ mergeInto(LibraryManager.library, { // TODO: mkdirTree // TDOO: rmdir // TODO: open + open: (path, flags, mode) => { + flags = typeof flags == 'string' ? FS.modeStringToFlags(flags) : flags; + mode = typeof mode == 'undefined' ? 438 /* 0666 */ : mode; + return withStackSave(() => { + var buffer = allocateUTF8OnStack(path); + return __wasmfs_open({{{ to64('buffer') }}}, flags, mode); + }) + }, // TODO: create // TODO: close unlink: (path) => { diff --git a/system/lib/wasmfs/js_api.cpp b/system/lib/wasmfs/js_api.cpp index ec9139153eccf..7f85d1ed80fa5 100644 --- a/system/lib/wasmfs/js_api.cpp +++ b/system/lib/wasmfs/js_api.cpp @@ -100,6 +100,10 @@ int _wasmfs_mkdir(char* path, int mode) { return __syscall_mkdirat(AT_FDCWD, (intptr_t)path, mode); } +int _wasmfs_open(char* path, int flags, mode_t mode) { + return __syscall_openat(AT_FDCWD, (intptr_t)path, flags, mode); +} + int _wasmfs_unlink(char* path) { return __syscall_unlinkat(AT_FDCWD, (intptr_t)path, 0); } diff --git a/test/fs/test_open_wasmfs.c b/test/fs/test_open_wasmfs.c new file mode 100644 index 0000000000000..91ad3fc936e64 --- /dev/null +++ b/test/fs/test_open_wasmfs.c @@ -0,0 +1,38 @@ +/* + * Copyright 2023 The Emscripten Authors. All rights reserved. + * Emscripten is available under two separate licenses, the MIT license and the + * University of Illinois/NCSA Open Source License. Both these licenses can be + * found in the LICENSE file. + */ + +#include +#include +#include + + +int main() { + EM_ASM( + FS.writeFile('testfile', 'a=1\nb=2\n'); + var readStream = FS.open('testfile', 'r'); + assert(readStream >= 0); + + var writeStream = FS.open('testfile', 'w'); + assert(writeStream >= 0); + + var writePlusStream = FS.open('testfile', 'w+'); + assert(writePlusStream >= 0); + + var appendStream = FS.open('testfile', 'a'); + assert(appendStream >= 0); + + var notFound = FS.open('filenothere', 'r'); + assert(notFound < 0); + + var createFileNotHere = FS.open('filenothere', 'w+'); + assert(createFileNotHere >= 0); + ); + puts("success"); + + + return 0; +} diff --git a/test/test_core.py b/test/test_core.py index b355a404e0785..35d2019740868 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -6037,13 +6037,14 @@ def test_fs_trackingdelegate(self): self.do_run_in_out_file_test('fs/test_trackingdelegate.c') @also_with_noderawfs + @also_with_wasmfs_js def test_fs_writeFile(self): self.do_run_in_out_file_test('fs/test_writeFile.cpp') - def test_fs_writeFile_wasmfs(self): + def test_fs_open_wasmfs(self): self.emcc_args += ['-sWASMFS'] self.emcc_args += ['-sFORCE_FILESYSTEM'] - self.do_run_in_out_file_test('fs/test_writeFile.cpp') + self.do_runf(test_file('fs/test_open_wasmfs.c'), 'success') def test_fs_write(self): self.do_run_in_out_file_test('fs/test_write.cpp') From b2dbf78c947490d5cf46da664796c504961d57fc Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 20 Mar 2023 09:51:25 -0700 Subject: [PATCH 0026/1523] Revert preprocesing of pre/post JS files (#19006) Reverts #18525 Fixes: #19002, #18609 --- ChangeLog.md | 5 +++++ src/jsifier.js | 8 +++++++- src/parseTools.js | 2 +- test/test_other.py | 15 --------------- 4 files changed, 13 insertions(+), 17 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 104d5f017105e..ead54a346cbae 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -22,6 +22,11 @@ See docs/process.md for more on how version tagging works. ----------------------- - `-z` arguments are now passed directly to wasm-ld without the need for the `-Wl,` prefix. This matches the behaviour of both clang and gcc. (#18956) +- Reverted #18525 which runs the JS pre-processor over files passed via + --pre-js and --post-js. It turned out this change caused issue for several + folks who had JS files with lines that start with `#` so can't be run through + the pre-processor. If folks want to re-enable this we can looks into ways to + make it conditional/optional. 3.1.34 - 03/14/23 ----------------- diff --git a/src/jsifier.js b/src/jsifier.js index 01faabd03da42..804355b3e8ec3 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -457,6 +457,12 @@ function ${name}(${args}) { print(`// end include: ${fileName}`); } + function includeFileRaw(fileName) { + print(`// include: ${fileName}`); + print(read(fileName)); + print(`// end include: ${fileName}`); + } + function finalCombiner() { const splitPostSets = splitter(postSets, (x) => x.symbol && x.dependencies); postSets = splitPostSets.leftIn; @@ -525,7 +531,7 @@ function ${name}(${args}) { includeFile(postFile); for (const fileName of POST_JS_FILES) { - includeFile(fileName); + includeFileRaw(fileName); } print('//FORWARDED_DATA:' + JSON.stringify({ diff --git a/src/parseTools.js b/src/parseTools.js index 49d569ad55290..be894884d048f 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -991,7 +991,7 @@ function getEntryFunction() { function preJS() { let result = ''; for (const fileName of PRE_JS_FILES) { - result += preprocess(fileName); + result += read(fileName); } return result; } diff --git a/test/test_other.py b/test/test_other.py index 9b5376b8485c5..a41b1cfa83e71 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -9295,21 +9295,6 @@ def test_js_preprocess(self): self.assertContained('JSLIB: EXIT_RUNTIME', err) self.assertNotContained('JSLIB: MAIN_MODULE', err) - def test_js_preprocess_pre_post(self): - create_file('pre.js', ''' - #if ASSERTIONS - console.log('assertions enabled') - #else - console.log('assertions disabled') - #endif - ''') - create_file('post.js', ''' - console.log({{{ POINTER_SIZE }}}); - ''') - self.emcc_args += ['--pre-js', 'pre.js', '--post-js', 'post.js'] - self.do_runf(test_file('hello_world.c'), 'assertions enabled\n4') - self.do_runf(test_file('hello_world.c'), 'assertions disabled\n4', emcc_args=['-sASSERTIONS=0']) - def test_html_preprocess(self): src_file = test_file('module/test_stdin.c') output_file = 'test_stdin.html' From e5ee191173fe6f16c4d7771a0c4727e58cbd17ff Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 20 Mar 2023 10:01:52 -0700 Subject: [PATCH 0027/1523] Update JS library signatures (#18995) This change was 100% automatically generated by the tool I'm working on as part of #18979. Once this change lands, I plan to completely remove these signatures and instead auto-generate them, but in order to make that change into no-op I'd like to first update them all in-place. See #18985 --- src/embind/embind.js | 8 +-- src/embind/emval.js | 10 +-- src/library.js | 14 ++-- src/library_async.js | 2 +- src/library_browser.js | 24 +++---- src/library_dylink.js | 2 +- src/library_eventloop.js | 2 +- src/library_glew.js | 2 +- src/library_glut.js | 28 ++++---- src/library_html5.js | 102 +++++++++++++------------- src/library_html5_webgl.js | 44 ++++++------ src/library_math.js | 2 +- src/library_openal.js | 128 ++++++++++++++++----------------- src/library_sdl.js | 136 +++++++++++++++++------------------ src/library_syscall.js | 10 +-- src/library_webaudio.js | 48 +++++++++---- src/library_webgl.js | 142 ++++++++++++++++++------------------- src/library_websocket.js | 32 ++++----- src/library_wget.js | 8 +-- 19 files changed, 384 insertions(+), 360 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index f82fced89b5e5..22e863ae7b2c9 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -1318,7 +1318,7 @@ var LibraryEmbind = { $structRegistrations: {}, - _embind_register_value_object__sig: 'viiiiii', + _embind_register_value_object__sig: 'vpppppp', _embind_register_value_object__deps: [ '$structRegistrations', '$readLatin1String', '$embind__requireFunction'], _embind_register_value_object: function( @@ -1337,7 +1337,7 @@ var LibraryEmbind = { }; }, - _embind_register_value_object_field__sig: 'viiiiiiiiii', + _embind_register_value_object_field__sig: 'vpppppppppp', _embind_register_value_object_field__deps: [ '$structRegistrations', '$readLatin1String', '$embind__requireFunction'], _embind_register_value_object_field: function( @@ -1363,7 +1363,7 @@ var LibraryEmbind = { }); }, - _embind_finalize_value_object__sig: 'ii', + _embind_finalize_value_object__sig: 'vp', _embind_finalize_value_object__deps: [ '$structRegistrations', '$runDestructors', '$simpleReadValueFromPointer', '$whenDependentTypesAreResolved'], @@ -2598,7 +2598,7 @@ var LibraryEmbind = { exposePublicSymbol(name, ctor); }, - _embind_register_enum_value__sig: 'vppi', + _embind_register_enum_value__sig: 'vppp', _embind_register_enum_value__deps: ['$createNamedFunction', '$readLatin1String', '$requireRegisteredType'], _embind_register_enum_value: function(rawEnumType, name, enumValue) { var enumType = requireRegisteredType(rawEnumType, 'enum'); diff --git a/src/embind/emval.js b/src/embind/emval.js index 83b0df9fb4fdf..c540fc64e2a2e 100644 --- a/src/embind/emval.js +++ b/src/embind/emval.js @@ -327,7 +327,7 @@ var LibraryEmVal = { }, _emval_as_int64__deps: ['$Emval', '$requireRegisteredType'], - _emval_as_int64__sig: 'dppp', + _emval_as_int64__sig: 'jpp', _emval_as_int64: function(handle, returnType, destructorsRef) { handle = Emval.toValue(handle); returnType = requireRegisteredType(returnType, 'emval::as'); @@ -335,7 +335,7 @@ var LibraryEmVal = { }, _emval_as_uint64__deps: ['$Emval', '$requireRegisteredType'], - _emval_as_uint64__sig: 'dppp', + _emval_as_uint64__sig: 'jpp', _emval_as_uint64: function(handle, returnType, destructorsRef) { handle = Emval.toValue(handle); returnType = requireRegisteredType(returnType, 'emval::as'); @@ -381,7 +381,7 @@ var LibraryEmVal = { return !object; }, - _emval_call__sig: 'ppppp', + _emval_call__sig: 'ppipp', _emval_call__deps: ['$emval_lookupTypes', '$Emval'], _emval_call: function(handle, argCount, argTypes, argv) { handle = Emval.toValue(handle); @@ -427,7 +427,7 @@ var LibraryEmVal = { }, $emval_registeredMethods: [], - _emval_get_method_caller__sig: 'ppp', + _emval_get_method_caller__sig: 'pip', _emval_get_method_caller__deps: ['$emval_addMethodCaller', '$emval_lookupTypes', '$new_', '$makeLegalFunctionName', '$emval_registeredMethods'], _emval_get_method_caller: function(argCount, argTypes) { var types = emval_lookupTypes(argCount, argTypes); @@ -564,7 +564,7 @@ var LibraryEmVal = { }, _emval_throw__deps: ['$Emval'], - _emval_throw__sig: 'vp', + _emval_throw__sig: 'ip', _emval_throw: function(object) { object = Emval.toValue(object); throw object; diff --git a/src/library.js b/src/library.js index ab3ec9554838b..4e80f15ca8aa4 100644 --- a/src/library.js +++ b/src/library.js @@ -490,7 +490,7 @@ mergeInto(LibraryManager.library, { }, _gmtime_js__deps: ['$readI53FromI64'], - _gmtime_js__sig: 'ipp', + _gmtime_js__sig: 'vpp', _gmtime_js: function(time, tmPtr) { var date = new Date({{{ makeGetValue('time', 0, 'i53') }}}*1000); {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_sec, 'date.getUTCSeconds()', 'i32') }}}; @@ -525,7 +525,7 @@ mergeInto(LibraryManager.library, { }, _localtime_js__deps: ['$readI53FromI64', '$ydayFromDate'], - _localtime_js__sig: 'ipp', + _localtime_js__sig: 'vpp', _localtime_js: function(time, tmPtr) { var date = new Date({{{ makeGetValue('time', 0, 'i53') }}}*1000); {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_sec, 'date.getSeconds()', 'i32') }}}; @@ -1831,7 +1831,7 @@ mergeInto(LibraryManager.library, { // note: lots of leaking here! gethostbyaddr__deps: ['$DNS', '$getHostByName', '$inetNtop4', '$setErrNo'], gethostbyaddr__proxy: 'sync', - gethostbyaddr__sig: 'ipii', + gethostbyaddr__sig: 'ppii', gethostbyaddr: function (addr, addrlen, type) { if (type !== {{{ cDefine('AF_INET') }}}) { setErrNo({{{ cDefine('EAFNOSUPPORT') }}}); @@ -1877,7 +1877,7 @@ mergeInto(LibraryManager.library, { gethostbyname_r__deps: ['gethostbyname', 'memcpy', 'free'], gethostbyname_r__proxy: 'sync', - gethostbyname_r__sig: 'ipppipp', + gethostbyname_r__sig: 'ipppppp', gethostbyname_r: function(name, ret, buf, buflen, out, err) { var data = _gethostbyname(name); _memcpy(ret, data, {{{ C_STRUCTS.hostent.__size__ }}}); @@ -2671,7 +2671,7 @@ mergeInto(LibraryManager.library, { debugger; }, - emscripten_print_double__sig: 'iipi', + emscripten_print_double__sig: 'idpi', emscripten_print_double: function(x, to, max) { var str = x + ''; if (to) return stringToUTF8(str, to, max); @@ -3066,7 +3066,7 @@ mergeInto(LibraryManager.library, { return ASM_CONSTS[code].apply(null, args); }, emscripten_asm_const_int_sync_on_main_thread__deps: ['$runMainThreadEmAsm'], - emscripten_asm_const_int_sync_on_main_thread__sig: 'iiii', + emscripten_asm_const_int_sync_on_main_thread__sig: 'ippp', emscripten_asm_const_int_sync_on_main_thread: function(code, sigPtr, argbuf) { return runMainThreadEmAsm(code, sigPtr, argbuf, 1); }, @@ -3413,7 +3413,7 @@ mergeInto(LibraryManager.library, { // Use program_invocation_short_name and program_invocation_name in compiled // programs. This function is for implementing them. - _emscripten_get_progname__sig: 'vpp', + _emscripten_get_progname__sig: 'vpi', _emscripten_get_progname: function(str, len) { #if !MINIMAL_RUNTIME #if ASSERTIONS diff --git a/src/library_async.js b/src/library_async.js index b8c7c9753c7f3..bb713e4222636 100644 --- a/src/library_async.js +++ b/src/library_async.js @@ -608,7 +608,7 @@ mergeInto(LibraryManager.library, { }, }, - emscripten_fiber_swap__sig: 'vii', + emscripten_fiber_swap__sig: 'vpp', emscripten_fiber_swap__deps: ["$Asyncify", "$Fibers"], emscripten_fiber_swap: function(oldFiber, newFiber) { if (ABORT) return; diff --git a/src/library_browser.js b/src/library_browser.js index 88def7c945e7f..7062da465f461 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -779,7 +779,7 @@ var LibraryBrowser = { emscripten_run_preload_plugins__deps: ['$PATH'], emscripten_run_preload_plugins__proxy: 'sync', - emscripten_run_preload_plugins__sig: 'iiii', + emscripten_run_preload_plugins__sig: 'ippp', emscripten_run_preload_plugins: function(file, onload, onerror) { {{{ runtimeKeepalivePush() }}} @@ -805,7 +805,7 @@ var LibraryBrowser = { emscripten_run_preload_plugins_data__proxy: 'sync', emscripten_run_preload_plugins_data__deps: ['malloc'], - emscripten_run_preload_plugins_data__sig: 'viiiiii', + emscripten_run_preload_plugins_data__sig: 'vpipppp', emscripten_run_preload_plugins_data: function(data, size, suffix, arg, onload, onerror) { {{{ runtimeKeepalivePush() }}} @@ -875,7 +875,7 @@ var LibraryBrowser = { }, // Runs natively in pthread, no __proxy needed. - emscripten_get_main_loop_timing__sig: 'vii', + emscripten_get_main_loop_timing__sig: 'vpp', emscripten_get_main_loop_timing: function(mode, value) { if (mode) {{{ makeSetValue('mode', 0, 'Browser.mainLoop.timingMode', 'i32') }}}; if (value) {{{ makeSetValue('value', 0, 'Browser.mainLoop.timingValue', 'i32') }}}; @@ -942,7 +942,7 @@ var LibraryBrowser = { }, emscripten_set_main_loop__deps: ['$setMainLoop'], - emscripten_set_main_loop__sig: 'viii', + emscripten_set_main_loop__sig: 'vpii', emscripten_set_main_loop: function(func, fps, simulateInfiniteLoop) { var browserIterationFunc = {{{ makeDynCall('v', 'func') }}}; setMainLoop(browserIterationFunc, fps, simulateInfiniteLoop); @@ -1104,7 +1104,7 @@ var LibraryBrowser = { // Runs natively in pthread, no __proxy needed. emscripten_set_main_loop_arg__deps: ['$setMainLoop'], - emscripten_set_main_loop_arg__sig: 'viiii', + emscripten_set_main_loop_arg__sig: 'vppii', emscripten_set_main_loop_arg: function(func, arg, fps, simulateInfiniteLoop) { var browserIterationFunc = () => {{{ makeDynCall('vi', 'func') }}}(arg); setMainLoop(browserIterationFunc, fps, simulateInfiniteLoop, arg); @@ -1188,13 +1188,13 @@ var LibraryBrowser = { }, emscripten_set_window_title__proxy: 'sync', - emscripten_set_window_title__sig: 'vi', + emscripten_set_window_title__sig: 'vp', emscripten_set_window_title: function(title) { setWindowTitle(UTF8ToString(title)); }, emscripten_get_screen_size__proxy: 'sync', - emscripten_get_screen_size__sig: 'vii', + emscripten_get_screen_size__sig: 'vpp', emscripten_get_screen_size: function(width, height) { {{{ makeSetValue('width', '0', 'screen.width', 'i32') }}}; {{{ makeSetValue('height', '0', 'screen.height', 'i32') }}}; @@ -1221,7 +1221,7 @@ var LibraryBrowser = { }, emscripten_get_canvas_size__proxy: 'sync', - emscripten_get_canvas_size__sig: 'viii', + emscripten_get_canvas_size__sig: 'vppp', emscripten_get_canvas_size: function(width, height, isFullscreen) { var canvas = Module['canvas']; {{{ makeSetValue('width', '0', 'canvas.width', 'i32') }}}; @@ -1231,7 +1231,7 @@ var LibraryBrowser = { // To avoid creating worker parent->child chains, always proxies to execute on the main thread. emscripten_create_worker__proxy: 'sync', - emscripten_create_worker__sig: 'ii', + emscripten_create_worker__sig: 'ip', emscripten_create_worker: function(url) { url = UTF8ToString(url); var id = Browser.workers.length; @@ -1283,7 +1283,7 @@ var LibraryBrowser = { }, emscripten_call_worker__proxy: 'sync', - emscripten_call_worker__sig: 'viiiiii', + emscripten_call_worker__sig: 'vippipp', emscripten_call_worker: function(id, funcName, data, size, callback, arg) { funcName = UTF8ToString(funcName); var info = Browser.workers[id]; @@ -1358,7 +1358,7 @@ var LibraryBrowser = { emscripten_get_preloaded_image_data__deps: ['$PATH_FS', 'malloc'], emscripten_get_preloaded_image_data__proxy: 'sync', - emscripten_get_preloaded_image_data__sig: 'iiii', + emscripten_get_preloaded_image_data__sig: 'pppp', emscripten_get_preloaded_image_data: function(path, w, h) { if ((path | 0) === path) path = UTF8ToString(path); @@ -1382,7 +1382,7 @@ var LibraryBrowser = { emscripten_get_preloaded_image_data_from_FILE__deps: ['emscripten_get_preloaded_image_data', 'fileno'], emscripten_get_preloaded_image_data_from_FILE__proxy: 'sync', - emscripten_get_preloaded_image_data_from_FILE__sig: 'iiii', + emscripten_get_preloaded_image_data_from_FILE__sig: 'pppp', emscripten_get_preloaded_image_data_from_FILE: function(file, w, h) { var fd = _fileno(file); var stream = FS.getStream(fd); diff --git a/src/library_dylink.js b/src/library_dylink.js index 7dbdc042fc0da..a35bb52ed5b12 100644 --- a/src/library_dylink.js +++ b/src/library_dylink.js @@ -1132,7 +1132,7 @@ var LibraryDylink = { } }, - _dlsym_catchup_js__sig: 'ppp', + _dlsym_catchup_js__sig: 'ppi', _dlsym_catchup_js: function(handle, symbolIndex) { #if DYLINK_DEBUG dbg("_dlsym_catchup: handle=" + ptrToString(handle) + " symbolIndex=" + symbolIndex); diff --git a/src/library_eventloop.js b/src/library_eventloop.js index e51a88638fdb6..394507fd93a3a 100644 --- a/src/library_eventloop.js +++ b/src/library_eventloop.js @@ -90,7 +90,7 @@ LibraryJSEventLoop = { emClearImmediate(id); }, - emscripten_set_immediate_loop__sig: 'ipp' , + emscripten_set_immediate_loop__sig: 'vpp', emscripten_set_immediate_loop__deps: ['$polyfillSetImmediate', '$callUserCallback'], emscripten_set_immediate_loop: function(cb, userData) { polyfillSetImmediate(); diff --git a/src/library_glew.js b/src/library_glew.js index 2c0d3be7230d7..5e270c54623f4 100644 --- a/src/library_glew.js +++ b/src/library_glew.js @@ -127,7 +127,7 @@ var LibraryGLEW = { return GLEW.extensionIsSupported(UTF8ToString(name)); }, - glewGetErrorString__sig: 'ii', + glewGetErrorString__sig: 'pi', glewGetErrorString: function(error) { return GLEW.errorString(error); }, diff --git a/src/library_glut.js b/src/library_glut.js index 9ea0eed4636ac..5d37dd69f412e 100644 --- a/src/library_glut.js +++ b/src/library_glut.js @@ -307,7 +307,7 @@ var LibraryGLUT = { glutInit__deps: ['$Browser'], glutInit__proxy: 'sync', - glutInit__sig: 'vii', + glutInit__sig: 'vpp', glutInit: function(argcp, argv) { // Ignore arguments GLUT.initTime = Date.now(); @@ -419,7 +419,7 @@ var LibraryGLUT = { glutIdleFunc__proxy: 'sync', glutIdleFunc__deps: ['$safeSetTimeout'], - glutIdleFunc__sig: 'vi', + glutIdleFunc__sig: 'vp', glutIdleFunc: function(func) { function callback() { if (GLUT.idleFunc) { @@ -435,61 +435,61 @@ var LibraryGLUT = { glutTimerFunc__proxy: 'sync', glutTimerFunc__deps: ['$safeSetTimeout'], - glutTimerFunc__sig: 'viii', + glutTimerFunc__sig: 'vipi', glutTimerFunc: function(msec, func, value) { safeSetTimeout(function() { {{{ makeDynCall('vi', 'func') }}}(value); }, msec); }, glutDisplayFunc__proxy: 'sync', - glutDisplayFunc__sig: 'vi', + glutDisplayFunc__sig: 'vp', glutDisplayFunc: function(func) { GLUT.displayFunc = func; }, glutKeyboardFunc__proxy: 'sync', - glutKeyboardFunc__sig: 'vi', + glutKeyboardFunc__sig: 'vp', glutKeyboardFunc: function(func) { GLUT.keyboardFunc = func; }, glutKeyboardUpFunc__proxy: 'sync', - glutKeyboardUpFunc__sig: 'vi', + glutKeyboardUpFunc__sig: 'vp', glutKeyboardUpFunc: function(func) { GLUT.keyboardUpFunc = func; }, glutSpecialFunc__proxy: 'sync', - glutSpecialFunc__sig: 'vi', + glutSpecialFunc__sig: 'vp', glutSpecialFunc: function(func) { GLUT.specialFunc = func; }, glutSpecialUpFunc__proxy: 'sync', - glutSpecialUpFunc__sig: 'vi', + glutSpecialUpFunc__sig: 'vp', glutSpecialUpFunc: function(func) { GLUT.specialUpFunc = func; }, glutReshapeFunc__proxy: 'sync', - glutReshapeFunc__sig: 'vi', + glutReshapeFunc__sig: 'vp', glutReshapeFunc: function(func) { GLUT.reshapeFunc = func; }, glutMotionFunc__proxy: 'sync', - glutMotionFunc__sig: 'vi', + glutMotionFunc__sig: 'vp', glutMotionFunc: function(func) { GLUT.motionFunc = func; }, glutPassiveMotionFunc__proxy: 'sync', - glutPassiveMotionFunc__sig: 'vi', + glutPassiveMotionFunc__sig: 'vp', glutPassiveMotionFunc: function(func) { GLUT.passiveMotionFunc = func; }, glutMouseFunc__proxy: 'sync', - glutMouseFunc__sig: 'vi', + glutMouseFunc__sig: 'vp', glutMouseFunc: function(func) { GLUT.mouseFunc = func; }, @@ -573,7 +573,7 @@ var LibraryGLUT = { glutCreateWindow__proxy: 'sync', glutCreateWindow__deps: ['$Browser'], - glutCreateWindow__sig: 'ii', + glutCreateWindow__sig: 'ip', glutCreateWindow: function(name) { var contextAttributes = { antialias: ((GLUT.initDisplayMode & 0x0080 /*GLUT_MULTISAMPLE*/) != 0), @@ -591,7 +591,7 @@ var LibraryGLUT = { glutDestroyWindow__proxy: 'sync', glutDestroyWindow__deps: ['$Browser'], - glutDestroyWindow__sig: 'ii', + glutDestroyWindow__sig: 'vi', glutDestroyWindow: function(name) { Module.ctx = Browser.destroyContext(Module['canvas'], true, true); return 1; diff --git a/src/library_html5.js b/src/library_html5.js index 62e0c1fa8c065..b0a58ac35cebb 100644 --- a/src/library_html5.js +++ b/src/library_html5.js @@ -399,7 +399,7 @@ var LibraryHTML5 = { #endif emscripten_set_keypress_callback_on_thread__proxy: 'sync', - emscripten_set_keypress_callback_on_thread__sig: 'iiiiii', + emscripten_set_keypress_callback_on_thread__sig: 'ippipp', emscripten_set_keypress_callback_on_thread__deps: ['$registerKeyEventCallback'], emscripten_set_keypress_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerKeyEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_KEYPRESS') }}}, "keypress", targetThread); @@ -407,7 +407,7 @@ var LibraryHTML5 = { }, emscripten_set_keydown_callback_on_thread__proxy: 'sync', - emscripten_set_keydown_callback_on_thread__sig: 'iiiiii', + emscripten_set_keydown_callback_on_thread__sig: 'ippipp', emscripten_set_keydown_callback_on_thread__deps: ['$registerKeyEventCallback'], emscripten_set_keydown_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerKeyEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_KEYDOWN') }}}, "keydown", targetThread); @@ -415,7 +415,7 @@ var LibraryHTML5 = { }, emscripten_set_keyup_callback_on_thread__proxy: 'sync', - emscripten_set_keyup_callback_on_thread__sig: 'iiiiii', + emscripten_set_keyup_callback_on_thread__sig: 'ippipp', emscripten_set_keyup_callback_on_thread__deps: ['$registerKeyEventCallback'], emscripten_set_keyup_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerKeyEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_KEYUP') }}}, "keyup", targetThread); @@ -546,7 +546,7 @@ var LibraryHTML5 = { }, emscripten_set_click_callback_on_thread__proxy: 'sync', - emscripten_set_click_callback_on_thread__sig: 'iiiiii', + emscripten_set_click_callback_on_thread__sig: 'ippipp', emscripten_set_click_callback_on_thread__deps: ['$registerMouseEventCallback'], emscripten_set_click_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_CLICK') }}}, "click", targetThread); @@ -554,7 +554,7 @@ var LibraryHTML5 = { }, emscripten_set_mousedown_callback_on_thread__proxy: 'sync', - emscripten_set_mousedown_callback_on_thread__sig: 'iiiiii', + emscripten_set_mousedown_callback_on_thread__sig: 'ippipp', emscripten_set_mousedown_callback_on_thread__deps: ['$registerMouseEventCallback'], emscripten_set_mousedown_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_MOUSEDOWN') }}}, "mousedown", targetThread); @@ -562,7 +562,7 @@ var LibraryHTML5 = { }, emscripten_set_mouseup_callback_on_thread__proxy: 'sync', - emscripten_set_mouseup_callback_on_thread__sig: 'iiiiii', + emscripten_set_mouseup_callback_on_thread__sig: 'ippipp', emscripten_set_mouseup_callback_on_thread__deps: ['$registerMouseEventCallback'], emscripten_set_mouseup_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_MOUSEUP') }}}, "mouseup", targetThread); @@ -570,7 +570,7 @@ var LibraryHTML5 = { }, emscripten_set_dblclick_callback_on_thread__proxy: 'sync', - emscripten_set_dblclick_callback_on_thread__sig: 'iiiiii', + emscripten_set_dblclick_callback_on_thread__sig: 'ippipp', emscripten_set_dblclick_callback_on_thread__deps: ['$registerMouseEventCallback'], emscripten_set_dblclick_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_DBLCLICK') }}}, "dblclick", targetThread); @@ -578,7 +578,7 @@ var LibraryHTML5 = { }, emscripten_set_mousemove_callback_on_thread__proxy: 'sync', - emscripten_set_mousemove_callback_on_thread__sig: 'iiiiii', + emscripten_set_mousemove_callback_on_thread__sig: 'ippipp', emscripten_set_mousemove_callback_on_thread__deps: ['$registerMouseEventCallback'], emscripten_set_mousemove_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_MOUSEMOVE') }}}, "mousemove", targetThread); @@ -586,7 +586,7 @@ var LibraryHTML5 = { }, emscripten_set_mouseenter_callback_on_thread__proxy: 'sync', - emscripten_set_mouseenter_callback_on_thread__sig: 'iiiiii', + emscripten_set_mouseenter_callback_on_thread__sig: 'ippipp', emscripten_set_mouseenter_callback_on_thread__deps: ['$registerMouseEventCallback'], emscripten_set_mouseenter_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_MOUSEENTER') }}}, "mouseenter", targetThread); @@ -594,7 +594,7 @@ var LibraryHTML5 = { }, emscripten_set_mouseleave_callback_on_thread__proxy: 'sync', - emscripten_set_mouseleave_callback_on_thread__sig: 'iiiiii', + emscripten_set_mouseleave_callback_on_thread__sig: 'ippipp', emscripten_set_mouseleave_callback_on_thread__deps: ['$registerMouseEventCallback'], emscripten_set_mouseleave_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_MOUSELEAVE') }}}, "mouseleave", targetThread); @@ -602,7 +602,7 @@ var LibraryHTML5 = { }, emscripten_set_mouseover_callback_on_thread__proxy: 'sync', - emscripten_set_mouseover_callback_on_thread__sig: 'iiiiii', + emscripten_set_mouseover_callback_on_thread__sig: 'ippipp', emscripten_set_mouseover_callback_on_thread__deps: ['$registerMouseEventCallback'], emscripten_set_mouseover_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_MOUSEOVER') }}}, "mouseover", targetThread); @@ -610,7 +610,7 @@ var LibraryHTML5 = { }, emscripten_set_mouseout_callback_on_thread__proxy: 'sync', - emscripten_set_mouseout_callback_on_thread__sig: 'iiiiii', + emscripten_set_mouseout_callback_on_thread__sig: 'ippipp', emscripten_set_mouseout_callback_on_thread__deps: ['$registerMouseEventCallback'], emscripten_set_mouseout_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_MOUSEOUT') }}}, "mouseout", targetThread); @@ -618,7 +618,7 @@ var LibraryHTML5 = { }, emscripten_get_mouse_status__proxy: 'sync', - emscripten_get_mouse_status__sig: 'ii', + emscripten_get_mouse_status__sig: 'ip', emscripten_get_mouse_status__deps: ['$JSEvents'], emscripten_get_mouse_status: function(mouseState) { if (!JSEvents.mouseEvent) return {{{ cDefine('EMSCRIPTEN_RESULT_NO_DATA') }}}; @@ -689,7 +689,7 @@ var LibraryHTML5 = { }, emscripten_set_wheel_callback_on_thread__proxy: 'sync', - emscripten_set_wheel_callback_on_thread__sig: 'iiiiii', + emscripten_set_wheel_callback_on_thread__sig: 'ippipp', emscripten_set_wheel_callback_on_thread__deps: ['$JSEvents', '$registerWheelEventCallback', '$findEventTarget'], emscripten_set_wheel_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { target = findEventTarget(target); @@ -769,7 +769,7 @@ var LibraryHTML5 = { }, emscripten_set_resize_callback_on_thread__proxy: 'sync', - emscripten_set_resize_callback_on_thread__sig: 'iiiiii', + emscripten_set_resize_callback_on_thread__sig: 'ippipp', emscripten_set_resize_callback_on_thread__deps: ['$registerUiEventCallback'], emscripten_set_resize_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerUiEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_RESIZE') }}}, "resize", targetThread); @@ -777,7 +777,7 @@ var LibraryHTML5 = { }, emscripten_set_scroll_callback_on_thread__proxy: 'sync', - emscripten_set_scroll_callback_on_thread__sig: 'iiiiii', + emscripten_set_scroll_callback_on_thread__sig: 'ippipp', emscripten_set_scroll_callback_on_thread__deps: ['$registerUiEventCallback'], emscripten_set_scroll_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerUiEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_SCROLL') }}}, "scroll", targetThread); @@ -821,7 +821,7 @@ var LibraryHTML5 = { }, emscripten_set_blur_callback_on_thread__proxy: 'sync', - emscripten_set_blur_callback_on_thread__sig: 'iiiiii', + emscripten_set_blur_callback_on_thread__sig: 'ippipp', emscripten_set_blur_callback_on_thread__deps: ['$registerFocusEventCallback'], emscripten_set_blur_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_BLUR') }}}, "blur", targetThread); @@ -829,7 +829,7 @@ var LibraryHTML5 = { }, emscripten_set_focus_callback_on_thread__proxy: 'sync', - emscripten_set_focus_callback_on_thread__sig: 'iiiiii', + emscripten_set_focus_callback_on_thread__sig: 'ippipp', emscripten_set_focus_callback_on_thread__deps: ['$registerFocusEventCallback'], emscripten_set_focus_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_FOCUS') }}}, "focus", targetThread); @@ -837,7 +837,7 @@ var LibraryHTML5 = { }, emscripten_set_focusin_callback_on_thread__proxy: 'sync', - emscripten_set_focusin_callback_on_thread__sig: 'iiiiii', + emscripten_set_focusin_callback_on_thread__sig: 'ippipp', emscripten_set_focusin_callback_on_thread__deps: ['$registerFocusEventCallback'], emscripten_set_focusin_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_FOCUSIN') }}}, "focusin", targetThread); @@ -845,7 +845,7 @@ var LibraryHTML5 = { }, emscripten_set_focusout_callback_on_thread__proxy: 'sync', - emscripten_set_focusout_callback_on_thread__sig: 'iiiiii', + emscripten_set_focusout_callback_on_thread__sig: 'ippipp', emscripten_set_focusout_callback_on_thread__deps: ['$registerFocusEventCallback'], emscripten_set_focusout_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_FOCUSOUT') }}}, "focusout", targetThread); @@ -891,7 +891,7 @@ var LibraryHTML5 = { }, emscripten_set_deviceorientation_callback_on_thread__proxy: 'sync', - emscripten_set_deviceorientation_callback_on_thread__sig: 'iiiii', + emscripten_set_deviceorientation_callback_on_thread__sig: 'ipipp', emscripten_set_deviceorientation_callback_on_thread__deps: ['$registerDeviceOrientationEventCallback'], emscripten_set_deviceorientation_callback_on_thread: function(userData, useCapture, callbackfunc, targetThread) { registerDeviceOrientationEventCallback({{{ cDefine('EMSCRIPTEN_EVENT_TARGET_WINDOW') }}}, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_DEVICEORIENTATION') }}}, "deviceorientation", targetThread); @@ -899,7 +899,7 @@ var LibraryHTML5 = { }, emscripten_get_deviceorientation_status__proxy: 'sync', - emscripten_get_deviceorientation_status__sig: 'ii', + emscripten_get_deviceorientation_status__sig: 'ip', emscripten_get_deviceorientation_status__deps: ['$JSEvents', '$registerDeviceOrientationEventCallback'], emscripten_get_deviceorientation_status: function(orientationState) { if (!JSEvents.deviceOrientationEvent) return {{{ cDefine('EMSCRIPTEN_RESULT_NO_DATA') }}}; @@ -964,7 +964,7 @@ var LibraryHTML5 = { }, emscripten_set_devicemotion_callback_on_thread__proxy: 'sync', - emscripten_set_devicemotion_callback_on_thread__sig: 'iiiii', + emscripten_set_devicemotion_callback_on_thread__sig: 'ipipp', emscripten_set_devicemotion_callback_on_thread__deps: ['$registerDeviceMotionEventCallback'], emscripten_set_devicemotion_callback_on_thread: function(userData, useCapture, callbackfunc, targetThread) { registerDeviceMotionEventCallback({{{ cDefine('EMSCRIPTEN_EVENT_TARGET_WINDOW') }}}, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_DEVICEMOTION') }}}, "devicemotion", targetThread); @@ -972,7 +972,7 @@ var LibraryHTML5 = { }, emscripten_get_devicemotion_status__proxy: 'sync', - emscripten_get_devicemotion_status__sig: 'ii', + emscripten_get_devicemotion_status__sig: 'ip', emscripten_get_devicemotion_status__deps: ['$JSEvents'], emscripten_get_devicemotion_status: function(motionState) { if (!JSEvents.deviceMotionEvent) return {{{ cDefine('EMSCRIPTEN_RESULT_NO_DATA') }}}; @@ -1041,7 +1041,7 @@ var LibraryHTML5 = { }, emscripten_set_orientationchange_callback_on_thread__proxy: 'sync', - emscripten_set_orientationchange_callback_on_thread__sig: 'iiiii', + emscripten_set_orientationchange_callback_on_thread__sig: 'ipipp', emscripten_set_orientationchange_callback_on_thread__deps: ['$registerOrientationChangeEventCallback'], emscripten_set_orientationchange_callback_on_thread: function(userData, useCapture, callbackfunc, targetThread) { if (!screen || !screen['addEventListener']) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; @@ -1050,7 +1050,7 @@ var LibraryHTML5 = { }, emscripten_get_orientation_status__proxy: 'sync', - emscripten_get_orientation_status__sig: 'ii', + emscripten_get_orientation_status__sig: 'ip', emscripten_get_orientation_status__deps: ['$fillOrientationChangeEventData', '$screenOrientation'], emscripten_get_orientation_status: function(orientationChangeEvent) { if (!screenOrientation() && typeof orientation == 'undefined') return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; @@ -1161,7 +1161,7 @@ var LibraryHTML5 = { }, emscripten_set_fullscreenchange_callback_on_thread__proxy: 'sync', - emscripten_set_fullscreenchange_callback_on_thread__sig: 'iiiiii', + emscripten_set_fullscreenchange_callback_on_thread__sig: 'ippipp', emscripten_set_fullscreenchange_callback_on_thread__deps: ['$JSEvents', '$registerFullscreenChangeEventCallback', '$findEventTarget', '$specialHTMLTargets'], emscripten_set_fullscreenchange_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { if (!JSEvents.fullscreenEnabled()) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; @@ -1190,7 +1190,7 @@ var LibraryHTML5 = { }, emscripten_get_fullscreen_status__proxy: 'sync', - emscripten_get_fullscreen_status__sig: 'ii', + emscripten_get_fullscreen_status__sig: 'ip', emscripten_get_fullscreen_status__deps: ['$JSEvents', '$fillFullscreenChangeEventData'], emscripten_get_fullscreen_status: function(fullscreenStatus) { if (!JSEvents.fullscreenEnabled()) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; @@ -1559,7 +1559,7 @@ var LibraryHTML5 = { emscripten_request_fullscreen__deps: ['$doRequestFullscreen'], emscripten_request_fullscreen__proxy: 'sync', - emscripten_request_fullscreen__sig: 'iii', + emscripten_request_fullscreen__sig: 'ipi', emscripten_request_fullscreen: function(target, deferUntilInEventHandler) { var strategy = { // These options perform no added logic, but just bare request fullscreen. @@ -1576,7 +1576,7 @@ var LibraryHTML5 = { emscripten_request_fullscreen_strategy__deps: ['$doRequestFullscreen', '$currentFullscreenStrategy', '$registerRestoreOldStyle'], emscripten_request_fullscreen_strategy__proxy: 'sync', - emscripten_request_fullscreen_strategy__sig: 'iiii', + emscripten_request_fullscreen_strategy__sig: 'ipip', emscripten_request_fullscreen_strategy: function(target, deferUntilInEventHandler, fullscreenStrategy) { var strategy = { scaleMode: {{{ makeGetValue('fullscreenStrategy', C_STRUCTS.EmscriptenFullscreenStrategy.scaleMode, 'i32') }}}, @@ -1597,7 +1597,7 @@ var LibraryHTML5 = { emscripten_enter_soft_fullscreen__deps: ['$JSEvents', '$setLetterbox', '$hideEverythingExceptGivenElement', '$restoreOldWindowedStyle', '$registerRestoreOldStyle', '$restoreHiddenElements', '$currentFullscreenStrategy', '$softFullscreenResizeWebGLRenderTarget', '$getCanvasElementSize', '$setCanvasElementSize', '$JSEvents_resizeCanvasForFullscreen', '$findEventTarget'], emscripten_enter_soft_fullscreen__proxy: 'sync', - emscripten_enter_soft_fullscreen__sig: 'iii', + emscripten_enter_soft_fullscreen__sig: 'ipp', emscripten_enter_soft_fullscreen: function(target, fullscreenStrategy) { #if !DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR if (!target) target = '#canvas'; @@ -1745,7 +1745,7 @@ var LibraryHTML5 = { }, emscripten_set_pointerlockchange_callback_on_thread__proxy: 'sync', - emscripten_set_pointerlockchange_callback_on_thread__sig: 'iiiiii', + emscripten_set_pointerlockchange_callback_on_thread__sig: 'ippipp', emscripten_set_pointerlockchange_callback_on_thread__deps: ['$JSEvents', '$registerPointerlockChangeEventCallback', '$findEventTarget', '$specialHTMLTargets'], emscripten_set_pointerlockchange_callback_on_thread__docs: '/** @suppress {missingProperties} */', // Closure does not see document.body.mozRequestPointerLock etc. emscripten_set_pointerlockchange_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { @@ -1792,7 +1792,7 @@ var LibraryHTML5 = { }, emscripten_set_pointerlockerror_callback_on_thread__proxy: 'sync', - emscripten_set_pointerlockerror_callback_on_thread__sig: 'iiiiii', + emscripten_set_pointerlockerror_callback_on_thread__sig: 'ippipp', emscripten_set_pointerlockerror_callback_on_thread__deps: ['$JSEvents', '$registerPointerlockErrorEventCallback', '$findEventTarget', '$specialHTMLTargets'], emscripten_set_pointerlockerror_callback_on_thread__docs: '/** @suppress {missingProperties} */', // Closure does not see document.body.mozRequestPointerLock etc. emscripten_set_pointerlockerror_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { @@ -1816,7 +1816,7 @@ var LibraryHTML5 = { }, emscripten_get_pointerlock_status__proxy: 'sync', - emscripten_get_pointerlock_status__sig: 'ii', + emscripten_get_pointerlock_status__sig: 'ip', emscripten_get_pointerlock_status__deps: ['$fillPointerlockChangeEventData'], emscripten_get_pointerlock_status__docs: '/** @suppress {missingProperties} */', // Closure does not see document.body.mozRequestPointerLock etc. emscripten_get_pointerlock_status: function(pointerlockStatus) { @@ -1864,7 +1864,7 @@ var LibraryHTML5 = { }, emscripten_request_pointerlock__proxy: 'sync', - emscripten_request_pointerlock__sig: 'iii', + emscripten_request_pointerlock__sig: 'ipi', emscripten_request_pointerlock__deps: ['$JSEvents', '$requestPointerLock', '$findEventTarget'], emscripten_request_pointerlock: function(target, deferUntilInEventHandler) { #if !DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR @@ -1940,7 +1940,7 @@ var LibraryHTML5 = { }, emscripten_vibrate_pattern__proxy: 'sync', - emscripten_vibrate_pattern__sig: 'iii', + emscripten_vibrate_pattern__sig: 'ipi', emscripten_vibrate_pattern: function(msecsArray, numEntries) { if (!navigator.vibrate) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; @@ -1999,7 +1999,7 @@ var LibraryHTML5 = { }, emscripten_set_visibilitychange_callback_on_thread__proxy: 'sync', - emscripten_set_visibilitychange_callback_on_thread__sig: 'iiiii', + emscripten_set_visibilitychange_callback_on_thread__sig: 'ipipp', emscripten_set_visibilitychange_callback_on_thread__deps: ['$registerVisibilityChangeEventCallback', '$specialHTMLTargets'], emscripten_set_visibilitychange_callback_on_thread: function(userData, useCapture, callbackfunc, targetThread) { #if ENVIRONMENT_MAY_BE_WORKER || ENVIRONMENT_MAY_BE_NODE || ENVIRONMENT_MAY_BE_SHELL @@ -2012,7 +2012,7 @@ var LibraryHTML5 = { }, emscripten_get_visibility_status__proxy: 'sync', - emscripten_get_visibility_status__sig: 'ii', + emscripten_get_visibility_status__sig: 'ip', emscripten_get_visibility_status__deps: ['$fillVisibilityChangeEventData'], emscripten_get_visibility_status: function(visibilityStatus) { if (typeof document.visibilityState == 'undefined' && typeof document.hidden == 'undefined') { @@ -2122,7 +2122,7 @@ var LibraryHTML5 = { }, emscripten_set_touchstart_callback_on_thread__proxy: 'sync', - emscripten_set_touchstart_callback_on_thread__sig: 'iiiiii', + emscripten_set_touchstart_callback_on_thread__sig: 'ippipp', emscripten_set_touchstart_callback_on_thread__deps: ['$registerTouchEventCallback'], emscripten_set_touchstart_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_TOUCHSTART') }}}, "touchstart", targetThread); @@ -2130,7 +2130,7 @@ var LibraryHTML5 = { }, emscripten_set_touchend_callback_on_thread__proxy: 'sync', - emscripten_set_touchend_callback_on_thread__sig: 'iiiiii', + emscripten_set_touchend_callback_on_thread__sig: 'ippipp', emscripten_set_touchend_callback_on_thread__deps: ['$registerTouchEventCallback'], emscripten_set_touchend_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_TOUCHEND') }}}, "touchend", targetThread); @@ -2138,7 +2138,7 @@ var LibraryHTML5 = { }, emscripten_set_touchmove_callback_on_thread__proxy: 'sync', - emscripten_set_touchmove_callback_on_thread__sig: 'iiiiii', + emscripten_set_touchmove_callback_on_thread__sig: 'ippipp', emscripten_set_touchmove_callback_on_thread__deps: ['$registerTouchEventCallback'], emscripten_set_touchmove_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_TOUCHMOVE') }}}, "touchmove", targetThread); @@ -2146,7 +2146,7 @@ var LibraryHTML5 = { }, emscripten_set_touchcancel_callback_on_thread__proxy: 'sync', - emscripten_set_touchcancel_callback_on_thread__sig: 'iiiiii', + emscripten_set_touchcancel_callback_on_thread__sig: 'ippipp', emscripten_set_touchcancel_callback_on_thread__deps: ['$registerTouchEventCallback'], emscripten_set_touchcancel_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_TOUCHCANCEL') }}}, "touchcancel", targetThread); @@ -2220,7 +2220,7 @@ var LibraryHTML5 = { }, emscripten_set_gamepadconnected_callback_on_thread__proxy: 'sync', - emscripten_set_gamepadconnected_callback_on_thread__sig: 'iiiii', + emscripten_set_gamepadconnected_callback_on_thread__sig: 'ipipp', emscripten_set_gamepadconnected_callback_on_thread__deps: ['$registerGamepadEventCallback'], emscripten_set_gamepadconnected_callback_on_thread: function(userData, useCapture, callbackfunc, targetThread) { if (!navigator.getGamepads && !navigator.webkitGetGamepads) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; @@ -2229,7 +2229,7 @@ var LibraryHTML5 = { }, emscripten_set_gamepaddisconnected_callback_on_thread__proxy: 'sync', - emscripten_set_gamepaddisconnected_callback_on_thread__sig: 'iiiii', + emscripten_set_gamepaddisconnected_callback_on_thread__sig: 'ipipp', emscripten_set_gamepaddisconnected_callback_on_thread__deps: ['$registerGamepadEventCallback'], emscripten_set_gamepaddisconnected_callback_on_thread: function(userData, useCapture, callbackfunc, targetThread) { if (!navigator.getGamepads && !navigator.webkitGetGamepads) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; @@ -2258,7 +2258,7 @@ var LibraryHTML5 = { }, emscripten_get_gamepad_status__proxy: 'sync', - emscripten_get_gamepad_status__sig: 'iii', + emscripten_get_gamepad_status__sig: 'iip', emscripten_get_gamepad_status__deps: ['$JSEvents', '$fillGamepadEventData'], emscripten_get_gamepad_status: function(index, gamepadState) { #if ASSERTIONS @@ -2376,7 +2376,7 @@ var LibraryHTML5 = { }, emscripten_get_battery_status__proxy: 'sync', - emscripten_get_battery_status__sig: 'ii', + emscripten_get_battery_status__sig: 'ip', emscripten_get_battery_status__deps: ['$fillBatteryEventData', '$battery'], emscripten_get_battery_status: function(batteryState) { if (!battery()) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; @@ -2492,7 +2492,7 @@ var LibraryHTML5 = { emscripten_set_canvas_element_size_main_thread: function(target, width, height) { return _emscripten_set_canvas_element_size_calling_thread(target, width, height); }, emscripten_set_canvas_element_size__deps: ['$JSEvents', 'emscripten_set_canvas_element_size_calling_thread', 'emscripten_set_canvas_element_size_main_thread', '$findCanvasEventTarget'], - emscripten_set_canvas_element_size__sig: 'iiii', + emscripten_set_canvas_element_size__sig: 'ipii', emscripten_set_canvas_element_size: function(target, width, height) { #if GL_DEBUG dbg('emscripten_set_canvas_element_size(target='+target+',width='+width+',height='+height); @@ -2505,7 +2505,7 @@ var LibraryHTML5 = { }, #else emscripten_set_canvas_element_size__deps: ['$JSEvents', '$findCanvasEventTarget'], - emscripten_set_canvas_element_size__sig: 'iiii', + emscripten_set_canvas_element_size__sig: 'ipii', emscripten_set_canvas_element_size: function(target, width, height) { #if GL_DEBUG dbg('emscripten_set_canvas_element_size(target='+target+',width='+width+',height='+height); @@ -2577,7 +2577,7 @@ var LibraryHTML5 = { emscripten_get_canvas_element_size_main_thread__deps: ['emscripten_get_canvas_element_size_calling_thread'], emscripten_get_canvas_element_size_main_thread: function(target, width, height) { return _emscripten_get_canvas_element_size_calling_thread(target, width, height); }, - emscripten_get_canvas_element_size__sig: 'ipii', + emscripten_get_canvas_element_size__sig: 'ippp', emscripten_get_canvas_element_size__deps: ['$JSEvents', 'emscripten_get_canvas_element_size_calling_thread', 'emscripten_get_canvas_element_size_main_thread', '$findCanvasEventTarget'], emscripten_get_canvas_element_size: function(target, width, height) { var canvas = findCanvasEventTarget(target); @@ -2613,7 +2613,7 @@ var LibraryHTML5 = { }, emscripten_set_element_css_size__proxy: 'sync', - emscripten_set_element_css_size__sig: 'iiii', + emscripten_set_element_css_size__sig: 'ipdd', emscripten_set_element_css_size__deps: ['$JSEvents', '$findEventTarget'], emscripten_set_element_css_size: function(target, width, height) { #if DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR @@ -2630,7 +2630,7 @@ var LibraryHTML5 = { }, emscripten_get_element_css_size__proxy: 'sync', - emscripten_get_element_css_size__sig: 'iiii', + emscripten_get_element_css_size__sig: 'ippp', emscripten_get_element_css_size__deps: ['$JSEvents', '$findEventTarget', '$getBoundingClientRect'], emscripten_get_element_css_size: function(target, width, height) { #if DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR diff --git a/src/library_html5_webgl.js b/src/library_html5_webgl.js index 3e37197b25c23..2762b0ffb423e 100644 --- a/src/library_html5_webgl.js +++ b/src/library_html5_webgl.js @@ -61,7 +61,7 @@ var LibraryHtml5WebGL = { #else // When not in offscreen framebuffer mode, these functions are implemented // in JS and forwarded without any proxying. - emscripten_webgl_create_context__sig: 'iii', + emscripten_webgl_create_context__sig: 'ipp', emscripten_webgl_create_context: 'emscripten_webgl_do_create_context', emscripten_webgl_get_current_context__sig: 'i', @@ -84,7 +84,7 @@ var LibraryHtml5WebGL = { #endif '$JSEvents', '$emscripten_webgl_power_preferences', '$findEventTarget', '$findCanvasEventTarget'], // This function performs proxying manually, depending on the style of context that is to be created. - emscripten_webgl_do_create_context__sig: 'iii', + emscripten_webgl_do_create_context__sig: 'ipp', emscripten_webgl_do_create_context: function(target, attributes) { #if ASSERTIONS assert(attributes); @@ -243,7 +243,7 @@ var LibraryHtml5WebGL = { }, emscripten_webgl_get_drawing_buffer_size__proxy: 'sync_on_webgl_context_handle_thread', - emscripten_webgl_get_drawing_buffer_size__sig: 'iiii', + emscripten_webgl_get_drawing_buffer_size__sig: 'iipp', emscripten_webgl_get_drawing_buffer_size: function(contextHandle, width, height) { var GLContext = GL.getContext(contextHandle); @@ -290,7 +290,7 @@ var LibraryHtml5WebGL = { }, emscripten_webgl_get_context_attributes__proxy: 'sync_on_webgl_context_handle_thread', - emscripten_webgl_get_context_attributes__sig: 'iii', + emscripten_webgl_get_context_attributes__sig: 'iip', emscripten_webgl_get_context_attributes__deps: ['$emscripten_webgl_power_preferences'], emscripten_webgl_get_context_attributes: function(c, a) { if (!a) return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_PARAM') }}}; @@ -321,7 +321,7 @@ var LibraryHtml5WebGL = { }, emscripten_webgl_destroy_context__proxy: 'sync_on_webgl_context_handle_thread', - emscripten_webgl_destroy_context__sig: 'vi', + emscripten_webgl_destroy_context__sig: 'ii', emscripten_webgl_destroy_context: function(contextHandle) { if (GL.currentContext == contextHandle) GL.currentContext = 0; GL.deleteContext(contextHandle); @@ -351,7 +351,7 @@ var LibraryHtml5WebGL = { #endif ], emscripten_webgl_enable_extension__proxy: 'sync_on_webgl_context_handle_thread', - emscripten_webgl_enable_extension__sig: 'iii', + emscripten_webgl_enable_extension__sig: 'iip', emscripten_webgl_enable_extension: function(contextHandle, extension) { var context = GL.getContext(contextHandle); var extString = UTF8ToString(extension); @@ -436,7 +436,7 @@ var LibraryHtml5WebGL = { }, emscripten_set_webglcontextlost_callback_on_thread__proxy: 'sync', - emscripten_set_webglcontextlost_callback_on_thread__sig: 'iiiiii', + emscripten_set_webglcontextlost_callback_on_thread__sig: 'ippipp', emscripten_set_webglcontextlost_callback_on_thread__deps: ['$registerWebGlEventCallback'], emscripten_set_webglcontextlost_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerWebGlEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_WEBGLCONTEXTLOST') }}}, "webglcontextlost", targetThread); @@ -444,7 +444,7 @@ var LibraryHtml5WebGL = { }, emscripten_set_webglcontextrestored_callback_on_thread__proxy: 'sync', - emscripten_set_webglcontextrestored_callback_on_thread__sig: 'iiiiii', + emscripten_set_webglcontextrestored_callback_on_thread__sig: 'ippipp', emscripten_set_webglcontextrestored_callback_on_thread__deps: ['$registerWebGlEventCallback'], emscripten_set_webglcontextrestored_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerWebGlEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_WEBGLCONTEXTRESTORED') }}}, "webglcontextrestored", targetThread); @@ -457,47 +457,47 @@ var LibraryHtml5WebGL = { return !GL.contexts[contextHandle] || GL.contexts[contextHandle].GLctx.isContextLost(); // No context ~> lost context. }, - emscripten_webgl_get_supported_extensions__sig: 'i', + emscripten_webgl_get_supported_extensions__sig: 'p', emscripten_webgl_get_supported_extensions__proxy: 'sync_on_current_webgl_context_thread', emscripten_webgl_get_supported_extensions__deps: ['$stringToNewUTF8'], emscripten_webgl_get_supported_extensions: function() { return stringToNewUTF8(GLctx.getSupportedExtensions().join(' ')); }, - emscripten_webgl_get_program_parameter_d__sig: 'fii', + emscripten_webgl_get_program_parameter_d__sig: 'dii', emscripten_webgl_get_program_parameter_d__proxy: 'sync_on_current_webgl_context_thread', emscripten_webgl_get_program_parameter_d: function(program, param) { return GLctx.getProgramParameter(GL.programs[program], param); }, - emscripten_webgl_get_program_info_log_utf8__sig: 'ii', + emscripten_webgl_get_program_info_log_utf8__sig: 'pi', emscripten_webgl_get_program_info_log_utf8__proxy: 'sync_on_current_webgl_context_thread', emscripten_webgl_get_program_info_log_utf8__deps: ['$stringToNewUTF8'], emscripten_webgl_get_program_info_log_utf8: function(program) { return stringToNewUTF8(GLctx.getProgramInfoLog(GL.programs[program])); }, - emscripten_webgl_get_shader_parameter_d__sig: 'fii', + emscripten_webgl_get_shader_parameter_d__sig: 'dii', emscripten_webgl_get_shader_parameter_d__proxy: 'sync_on_current_webgl_context_thread', emscripten_webgl_get_shader_parameter_d: function(shader, param) { return GLctx.getShaderParameter(GL.shaders[shader], param); }, - emscripten_webgl_get_shader_info_log_utf8__sig: 'ii', + emscripten_webgl_get_shader_info_log_utf8__sig: 'pi', emscripten_webgl_get_shader_info_log_utf8__proxy: 'sync_on_current_webgl_context_thread', emscripten_webgl_get_shader_info_log_utf8__deps: ['$stringToNewUTF8'], emscripten_webgl_get_shader_info_log_utf8: function(shader) { return stringToNewUTF8(GLctx.getShaderInfoLog(GL.shaders[shader])); }, - emscripten_webgl_get_shader_source_utf8__sig: 'ii', + emscripten_webgl_get_shader_source_utf8__sig: 'pi', emscripten_webgl_get_shader_source_utf8__proxy: 'sync_on_current_webgl_context_thread', emscripten_webgl_get_shader_source_utf8__deps: ['$stringToNewUTF8'], emscripten_webgl_get_shader_source_utf8: function(shader) { return stringToNewUTF8(GLctx.getShaderSource(GL.shaders[shader])); }, - emscripten_webgl_get_vertex_attrib_d__sig: 'iii', + emscripten_webgl_get_vertex_attrib_d__sig: 'dii', emscripten_webgl_get_vertex_attrib_d__proxy: 'sync_on_current_webgl_context_thread', emscripten_webgl_get_vertex_attrib_d: function(index, param) { return GLctx.getVertexAttrib(index, param); @@ -510,35 +510,35 @@ var LibraryHtml5WebGL = { return obj && obj.name; }, - emscripten_webgl_get_vertex_attrib_v__sig: 'iiiiii', + emscripten_webgl_get_vertex_attrib_v__sig: 'iiipii', emscripten_webgl_get_vertex_attrib_v__proxy: 'sync_on_current_webgl_context_thread', emscripten_webgl_get_vertex_attrib_v__deps: ['$writeGLArray'], emscripten_webgl_get_vertex_attrib_v: function(index, param, dst, dstLength, dstType) { return writeGLArray(GLctx.getVertexAttrib(index, param), dst, dstLength, dstType); }, - emscripten_webgl_get_uniform_d__sig: 'fii', + emscripten_webgl_get_uniform_d__sig: 'dii', emscripten_webgl_get_uniform_d__proxy: 'sync_on_current_webgl_context_thread', emscripten_webgl_get_uniform_d__deps: ['$webglGetUniformLocation'], emscripten_webgl_get_uniform_d: function(program, location) { return GLctx.getUniform(GL.programs[program], webglGetUniformLocation(location)); }, - emscripten_webgl_get_uniform_v__sig: 'iiiiii', + emscripten_webgl_get_uniform_v__sig: 'iiipii', emscripten_webgl_get_uniform_v__proxy: 'sync_on_current_webgl_context_thread', emscripten_webgl_get_uniform_v__deps: ['$writeGLArray', '$webglGetUniformLocation'], emscripten_webgl_get_uniform_v: function(program, location, dst, dstLength, dstType) { return writeGLArray(GLctx.getUniform(GL.programs[program], webglGetUniformLocation(location)), dst, dstLength, dstType); }, - emscripten_webgl_get_parameter_v__sig: 'iiiii', + emscripten_webgl_get_parameter_v__sig: 'iipii', emscripten_webgl_get_parameter_v__proxy: 'sync_on_current_webgl_context_thread', emscripten_webgl_get_parameter_v__deps: ['$writeGLArray'], emscripten_webgl_get_parameter_v: function(param, dst, dstLength, dstType) { return writeGLArray(GLctx.getParameter(param), dst, dstLength, dstType); }, - emscripten_webgl_get_parameter_d__sig: 'fi', + emscripten_webgl_get_parameter_d__sig: 'di', emscripten_webgl_get_parameter_d__proxy: 'sync_on_current_webgl_context_thread', emscripten_webgl_get_parameter_d: function(param) { return GLctx.getParameter(param); @@ -551,14 +551,14 @@ var LibraryHtml5WebGL = { return obj && obj.name; }, - emscripten_webgl_get_parameter_utf8__sig: 'ii', + emscripten_webgl_get_parameter_utf8__sig: 'pi', emscripten_webgl_get_parameter_utf8__deps: ['$stringToNewUTF8'], emscripten_webgl_get_parameter_utf8__proxy: 'sync_on_current_webgl_context_thread', emscripten_webgl_get_parameter_utf8: function(param) { return stringToNewUTF8(GLctx.getParameter(param)); }, - emscripten_webgl_get_parameter_i64v__sig: 'vii', + emscripten_webgl_get_parameter_i64v__sig: 'vip', emscripten_webgl_get_parameter_i64v__proxy: 'sync_on_current_webgl_context_thread', emscripten_webgl_get_parameter_i64v__deps: ['$writeI53ToI64'], emscripten_webgl_get_parameter_i64v: function(param, dst) { diff --git a/src/library_math.js b/src/library_math.js index 17e03ebf53ac4..757314763d90d 100644 --- a/src/library_math.js +++ b/src/library_math.js @@ -65,7 +65,7 @@ mergeInto(LibraryManager.library, { emscripten_math_cosh: function(x) { return Math.cosh(x); }, - emscripten_math_hypot__sig: 'iip', + emscripten_math_hypot__sig: 'dip', emscripten_math_hypot: function(count, varargs) { var args = []; for (var i = 0; i < count; ++i) args.push(HEAPF64[(varargs>>3) + i]); diff --git a/src/library_openal.js b/src/library_openal.js index 09d700302f1b3..749214646cf80 100644 --- a/src/library_openal.js +++ b/src/library_openal.js @@ -1613,7 +1613,7 @@ var LibraryOpenAL = { // bufferFrameCapacity here for clarity. alcCaptureOpenDevice__deps: ['$autoResumeAudioContext'], alcCaptureOpenDevice__proxy: 'sync', - alcCaptureOpenDevice__sig: 'iiiii', + alcCaptureOpenDevice__sig: 'ppiii', alcCaptureOpenDevice: function(pDeviceName, requestedSampleRate, format, bufferFrameCapacity) { var resolvedDeviceName = AL.CAPTURE_DEVICE_NAME; @@ -1905,7 +1905,7 @@ var LibraryOpenAL = { }, alcCaptureCloseDevice__proxy: 'sync', - alcCaptureCloseDevice__sig: 'ii', + alcCaptureCloseDevice__sig: 'ip', alcCaptureCloseDevice: function(deviceId) { var c = AL.requireValidCaptureDevice(deviceId, 'alcCaptureCloseDevice'); if (!c) return false; @@ -1938,7 +1938,7 @@ var LibraryOpenAL = { }, alcCaptureStart__proxy: 'sync', - alcCaptureStart__sig: 'vi', + alcCaptureStart__sig: 'vp', alcCaptureStart: function(deviceId) { var c = AL.requireValidCaptureDevice(deviceId, 'alcCaptureStart'); if (!c) return; @@ -1959,7 +1959,7 @@ var LibraryOpenAL = { }, alcCaptureStop__proxy: 'sync', - alcCaptureStop__sig: 'vi', + alcCaptureStop__sig: 'vp', alcCaptureStop: function(deviceId) { var c = AL.requireValidCaptureDevice(deviceId, 'alcCaptureStop'); if (!c) return; @@ -1978,7 +1978,7 @@ var LibraryOpenAL = { // The last parameter is actually 'number of sample frames', so was // renamed accordingly here alcCaptureSamples__proxy: 'sync', - alcCaptureSamples__sig: 'viii', + alcCaptureSamples__sig: 'vppi', alcCaptureSamples: function(deviceId, pFrames, requestedFrameCount) { var c = AL.requireValidCaptureDevice(deviceId, 'alcCaptureSamples'); if (!c) return; @@ -2066,7 +2066,7 @@ var LibraryOpenAL = { // ------------------------------------------------------- alcOpenDevice__proxy: 'sync', - alcOpenDevice__sig: 'ii', + alcOpenDevice__sig: 'pp', alcOpenDevice: function(pDeviceName) { if (pDeviceName) { var name = UTF8ToString(pDeviceName); @@ -2084,7 +2084,7 @@ var LibraryOpenAL = { }, alcCloseDevice__proxy: 'sync', - alcCloseDevice__sig: 'ii', + alcCloseDevice__sig: 'ip', alcCloseDevice: function(deviceId) { if (!(deviceId in AL.deviceRefCounts) || AL.deviceRefCounts[deviceId] > 0) { return {{{ cDefine('ALC_FALSE') }}}; @@ -2097,7 +2097,7 @@ var LibraryOpenAL = { alcCreateContext__deps: ['$autoResumeAudioContext'], alcCreateContext__proxy: 'sync', - alcCreateContext__sig: 'iii', + alcCreateContext__sig: 'ppp', alcCreateContext: function(deviceId, pAttrList) { if (!(deviceId in AL.deviceRefCounts)) { #if OPENAL_DEBUG @@ -2252,7 +2252,7 @@ var LibraryOpenAL = { }, alcDestroyContext__proxy: 'sync', - alcDestroyContext__sig: 'vi', + alcDestroyContext__sig: 'vp', alcDestroyContext: function(contextId) { var ctx = AL.contexts[contextId]; if (AL.currentCtx === ctx) { @@ -2277,7 +2277,7 @@ var LibraryOpenAL = { // ------------------------------------------------------- alcGetError__proxy: 'sync', - alcGetError__sig: 'ii', + alcGetError__sig: 'ip', alcGetError: function(deviceId) { var err = AL.alcErr; AL.alcErr = {{{ cDefine('ALC_NO_ERROR') }}}; @@ -2285,7 +2285,7 @@ var LibraryOpenAL = { }, alcGetCurrentContext__proxy: 'sync', - alcGetCurrentContext__sig: 'i', + alcGetCurrentContext__sig: 'p', alcGetCurrentContext: function() { if (AL.currentCtx !== null) { return AL.currentCtx.id; @@ -2294,7 +2294,7 @@ var LibraryOpenAL = { }, alcMakeContextCurrent__proxy: 'sync', - alcMakeContextCurrent__sig: 'ii', + alcMakeContextCurrent__sig: 'ip', alcMakeContextCurrent: function(contextId) { if (contextId === 0) { AL.currentCtx = null; @@ -2305,7 +2305,7 @@ var LibraryOpenAL = { }, alcGetContextsDevice__proxy: 'sync', - alcGetContextsDevice__sig: 'ii', + alcGetContextsDevice__sig: 'pp', alcGetContextsDevice: function(contextId) { if (contextId in AL.contexts) { return AL.contexts[contextId].deviceId; @@ -2314,13 +2314,13 @@ var LibraryOpenAL = { }, // The spec is vague about what these are actually supposed to do, and NOP is a reasonable implementation - alcProcessContext__sig: 'vi', + alcProcessContext__sig: 'vp', alcProcessContext: function(contextId) {}, - alcSuspendContext__sig: 'vi', + alcSuspendContext__sig: 'vp', alcSuspendContext: function(contextId) {}, alcIsExtensionPresent__proxy: 'sync', - alcIsExtensionPresent__sig: 'iii', + alcIsExtensionPresent__sig: 'ipp', alcIsExtensionPresent: function(deviceId, pExtName) { var name = UTF8ToString(pExtName); @@ -2328,7 +2328,7 @@ var LibraryOpenAL = { }, alcGetEnumValue__proxy: 'sync', - alcGetEnumValue__sig: 'iii', + alcGetEnumValue__sig: 'ipp', alcGetEnumValue: function(deviceId, pEnumName) { // Spec says : // Using a NULL handle is legal, but only the @@ -2393,7 +2393,7 @@ var LibraryOpenAL = { }, alcGetString__proxy: 'sync', - alcGetString__sig: 'iii', + alcGetString__sig: 'ppi', alcGetString__deps: ['$allocateUTF8'], alcGetString: function(deviceId, param) { if (AL.alcStringCache[param]) { @@ -2474,7 +2474,7 @@ var LibraryOpenAL = { }, alcGetIntegerv__proxy: 'sync', - alcGetIntegerv__sig: 'viiii', + alcGetIntegerv__sig: 'vpiip', alcGetIntegerv: function(deviceId, param, size, pValues) { if (size === 0 || !pValues) { // Ignore the query, per the spec @@ -2751,7 +2751,7 @@ var LibraryOpenAL = { // ------------------------------------------------------- alGenBuffers__proxy: 'sync', - alGenBuffers__sig: 'vii', + alGenBuffers__sig: 'vip', alGenBuffers: function(count, pBufferIds) { if (!AL.currentCtx) { #if OPENAL_DEBUG @@ -2778,7 +2778,7 @@ var LibraryOpenAL = { }, alDeleteBuffers__proxy: 'sync', - alDeleteBuffers__sig: 'vii', + alDeleteBuffers__sig: 'vip', alDeleteBuffers: function(count, pBufferIds) { if (!AL.currentCtx) { #if OPENAL_DEBUG @@ -2826,7 +2826,7 @@ var LibraryOpenAL = { }, alGenSources__proxy: 'sync', - alGenSources__sig: 'vii', + alGenSources__sig: 'vip', alGenSources: function(count, pSourceIds) { if (!AL.currentCtx) { #if OPENAL_DEBUG @@ -2878,7 +2878,7 @@ var LibraryOpenAL = { alDeleteSources__deps: ['alSourcei'], alDeleteSources__proxy: 'sync', - alDeleteSources__sig: 'vii', + alDeleteSources__sig: 'vip', alDeleteSources: function(count, pSourceIds) { if (!AL.currentCtx) { #if OPENAL_DEBUG @@ -2924,7 +2924,7 @@ var LibraryOpenAL = { }, alIsExtensionPresent__proxy: 'sync', - alIsExtensionPresent__sig: 'ii', + alIsExtensionPresent__sig: 'ip', alIsExtensionPresent: function(pExtName) { var name = UTF8ToString(pExtName); @@ -2932,7 +2932,7 @@ var LibraryOpenAL = { }, alGetEnumValue__proxy: 'sync', - alGetEnumValue__sig: 'ii', + alGetEnumValue__sig: 'ip', alGetEnumValue: function(pEnumName) { if (!AL.currentCtx) { #if OPENAL_DEBUG @@ -3044,7 +3044,7 @@ var LibraryOpenAL = { }, alGetString__proxy: 'sync', - alGetString__sig: 'ii', + alGetString__sig: 'pi', alGetString__deps: ['$allocateUTF8'], alGetString: function(param) { if (AL.stringCache[param]) { @@ -3194,7 +3194,7 @@ var LibraryOpenAL = { }, alGetDoublev__proxy: 'sync', - alGetDoublev__sig: 'vii', + alGetDoublev__sig: 'vip', alGetDoublev: function(param, pValues) { var val = AL.getGlobalParam('alGetDoublev', param); // Silently ignore null destinations, as per the spec for global state functions @@ -3239,7 +3239,7 @@ var LibraryOpenAL = { }, alGetFloatv__proxy: 'sync', - alGetFloatv__sig: 'vii', + alGetFloatv__sig: 'vip', alGetFloatv: function(param, pValues) { var val = AL.getGlobalParam('alGetFloatv', param); // Silently ignore null destinations, as per the spec for global state functions @@ -3285,7 +3285,7 @@ var LibraryOpenAL = { }, alGetIntegerv__proxy: 'sync', - alGetIntegerv__sig: 'vii', + alGetIntegerv__sig: 'vip', alGetIntegerv: function(param, pValues) { var val = AL.getGlobalParam('alGetIntegerv', param); // Silently ignore null destinations, as per the spec for global state functions @@ -3331,7 +3331,7 @@ var LibraryOpenAL = { }, alGetBooleanv__proxy: 'sync', - alGetBooleanv__sig: 'vii', + alGetBooleanv__sig: 'vip', alGetBooleanv: function(param, pValues) { var val = AL.getGlobalParam('alGetBooleanv', param); // Silently ignore null destinations, as per the spec for global state functions @@ -3361,13 +3361,13 @@ var LibraryOpenAL = { }, alSpeedOfSound__proxy: 'sync', - alSpeedOfSound__sig: 'vi', + alSpeedOfSound__sig: 'vf', alSpeedOfSound: function(value) { AL.setGlobalParam('alSpeedOfSound', {{{ cDefine('AL_SPEED_OF_SOUND') }}}, value); }, alDopplerFactor__proxy: 'sync', - alDopplerFactor__sig: 'vi', + alDopplerFactor__sig: 'vf', alDopplerFactor: function(value) { AL.setGlobalParam('alDopplerFactor', {{{ cDefine('AL_DOPPLER_FACTOR') }}}, value); }, @@ -3377,7 +3377,7 @@ var LibraryOpenAL = { // It's deprecated since it's equivalent to directly calling // alSpeedOfSound() with an appropriately premultiplied value. alDopplerVelocity__proxy: 'sync', - alDopplerVelocity__sig: 'vi', + alDopplerVelocity__sig: 'vf', alDopplerVelocity: function(value) { warnOnce('alDopplerVelocity() is deprecated, and only kept for compatibility with OpenAL 1.0. Use alSpeedOfSound() instead.'); if (!AL.currentCtx) { @@ -3397,7 +3397,7 @@ var LibraryOpenAL = { // ------------------------------------------------------- alGetListenerf__proxy: 'sync', - alGetListenerf__sig: 'vii', + alGetListenerf__sig: 'vip', alGetListenerf: function(param, pValue) { var val = AL.getListenerParam('alGetListenerf', param); if (val === null) { @@ -3425,7 +3425,7 @@ var LibraryOpenAL = { }, alGetListener3f__proxy: 'sync', - alGetListener3f__sig: 'viiii', + alGetListener3f__sig: 'vippp', alGetListener3f: function(param, pValue0, pValue1, pValue2) { var val = AL.getListenerParam('alGetListener3f', param); if (val === null) { @@ -3456,7 +3456,7 @@ var LibraryOpenAL = { }, alGetListenerfv__proxy: 'sync', - alGetListenerfv__sig: 'vii', + alGetListenerfv__sig: 'vip', alGetListenerfv: function(param, pValues) { var val = AL.getListenerParam('alGetListenerfv', param); if (val === null) { @@ -3495,7 +3495,7 @@ var LibraryOpenAL = { }, alGetListeneri__proxy: 'sync', - alGetListeneri__sig: 'vii', + alGetListeneri__sig: 'vip', alGetListeneri: function(param, pValue) { var val = AL.getListenerParam('alGetListeneri', param); if (val === null) { @@ -3516,7 +3516,7 @@ var LibraryOpenAL = { }, alGetListener3i__proxy: 'sync', - alGetListener3i__sig: 'viiii', + alGetListener3i__sig: 'vippp', alGetListener3i: function(param, pValue0, pValue1, pValue2) { var val = AL.getListenerParam('alGetListener3i', param); if (val === null) { @@ -3547,7 +3547,7 @@ var LibraryOpenAL = { }, alGetListeneriv__proxy: 'sync', - alGetListeneriv__sig: 'vii', + alGetListeneriv__sig: 'vip', alGetListeneriv: function(param, pValues) { var val = AL.getListenerParam('alGetListeneriv', param); if (val === null) { @@ -3616,7 +3616,7 @@ var LibraryOpenAL = { }, alListenerfv__proxy: 'sync', - alListenerfv__sig: 'vii', + alListenerfv__sig: 'vip', alListenerfv: function(param, pValues) { if (!AL.currentCtx) { #if OPENAL_DEBUG @@ -3679,7 +3679,7 @@ var LibraryOpenAL = { }, alListeneriv__proxy: 'sync', - alListeneriv__sig: 'vii', + alListeneriv__sig: 'vip', alListeneriv: function(param, pValues) { if (!AL.currentCtx) { #if OPENAL_DEBUG @@ -3739,7 +3739,7 @@ var LibraryOpenAL = { }, alBufferData__proxy: 'sync', - alBufferData__sig: 'viiiii', + alBufferData__sig: 'viipii', alBufferData: function(bufferId, format, pData, size, freq) { if (!AL.currentCtx) { #if OPENAL_DEBUG @@ -3867,7 +3867,7 @@ var LibraryOpenAL = { }, alGetBufferf__proxy: 'sync', - alGetBufferf__sig: 'viii', + alGetBufferf__sig: 'viip', alGetBufferf: function(bufferId, param, pValue) { var val = AL.getBufferParam('alGetBufferf', bufferId, param); if (val === null) { @@ -3888,7 +3888,7 @@ var LibraryOpenAL = { }, alGetBuffer3f__proxy: 'sync', - alGetBuffer3f__sig: 'viiiii', + alGetBuffer3f__sig: 'viippp', alGetBuffer3f: function(bufferId, param, pValue0, pValue1, pValue2) { var val = AL.getBufferParam('alGetBuffer3f', bufferId, param); if (val === null) { @@ -3909,7 +3909,7 @@ var LibraryOpenAL = { }, alGetBufferfv__proxy: 'sync', - alGetBufferfv__sig: 'viii', + alGetBufferfv__sig: 'viip', alGetBufferfv: function(bufferId, param, pValues) { var val = AL.getBufferParam('alGetBufferfv', bufferId, param); if (val === null) { @@ -3930,7 +3930,7 @@ var LibraryOpenAL = { }, alGetBufferi__proxy: 'sync', - alGetBufferi__sig: 'viii', + alGetBufferi__sig: 'viip', alGetBufferi: function(bufferId, param, pValue) { var val = AL.getBufferParam('alGetBufferi', bufferId, param); if (val === null) { @@ -3961,7 +3961,7 @@ var LibraryOpenAL = { }, alGetBuffer3i__proxy: 'sync', - alGetBuffer3i__sig: 'viiiii', + alGetBuffer3i__sig: 'viippp', alGetBuffer3i: function(bufferId, param, pValue0, pValue1, pValue2) { var val = AL.getBufferParam('alGetBuffer3i', bufferId, param); if (val === null) { @@ -3982,7 +3982,7 @@ var LibraryOpenAL = { }, alGetBufferiv__proxy: 'sync', - alGetBufferiv__sig: 'viii', + alGetBufferiv__sig: 'viip', alGetBufferiv: function(bufferId, param, pValues) { var val = AL.getBufferParam('alGetBufferiv', bufferId, param); if (val === null) { @@ -4033,7 +4033,7 @@ var LibraryOpenAL = { }, alBufferfv__proxy: 'sync', - alBufferfv__sig: 'viii', + alBufferfv__sig: 'viip', alBufferfv: function(bufferId, param, pValues) { if (!AL.currentCtx) { #if OPENAL_DEBUG @@ -4065,7 +4065,7 @@ var LibraryOpenAL = { }, alBufferiv__proxy: 'sync', - alBufferiv__sig: 'viii', + alBufferiv__sig: 'viip', alBufferiv: function(bufferId, param, pValues) { if (!AL.currentCtx) { #if OPENAL_DEBUG @@ -4111,7 +4111,7 @@ var LibraryOpenAL = { }, alSourceQueueBuffers__proxy: 'sync', - alSourceQueueBuffers__sig: 'viii', + alSourceQueueBuffers__sig: 'viip', alSourceQueueBuffers: function(sourceId, count, pBufferIds) { if (!AL.currentCtx) { #if OPENAL_DEBUG @@ -4195,7 +4195,7 @@ var LibraryOpenAL = { }, alSourceUnqueueBuffers__proxy: 'sync', - alSourceUnqueueBuffers__sig: 'viii', + alSourceUnqueueBuffers__sig: 'viip', alSourceUnqueueBuffers: function(sourceId, count, pBufferIds) { if (!AL.currentCtx) { #if OPENAL_DEBUG @@ -4258,7 +4258,7 @@ var LibraryOpenAL = { }, alSourcePlayv__proxy: 'sync', - alSourcePlayv__sig: 'vii', + alSourcePlayv__sig: 'vip', alSourcePlayv: function(count, pSourceIds) { if (!AL.currentCtx) { #if OPENAL_DEBUG @@ -4309,7 +4309,7 @@ var LibraryOpenAL = { }, alSourceStopv__proxy: 'sync', - alSourceStopv__sig: 'vii', + alSourceStopv__sig: 'vip', alSourceStopv: function(count, pSourceIds) { if (!AL.currentCtx) { #if OPENAL_DEBUG @@ -4363,7 +4363,7 @@ var LibraryOpenAL = { }, alSourceRewindv__proxy: 'sync', - alSourceRewindv__sig: 'vii', + alSourceRewindv__sig: 'vip', alSourceRewindv: function(count, pSourceIds) { if (!AL.currentCtx) { #if OPENAL_DEBUG @@ -4414,7 +4414,7 @@ var LibraryOpenAL = { }, alSourcePausev__proxy: 'sync', - alSourcePausev__sig: 'vii', + alSourcePausev__sig: 'vip', alSourcePausev: function(count, pSourceIds) { if (!AL.currentCtx) { #if OPENAL_DEBUG @@ -4445,7 +4445,7 @@ var LibraryOpenAL = { }, alGetSourcef__proxy: 'sync', - alGetSourcef__sig: 'viii', + alGetSourcef__sig: 'viip', alGetSourcef: function(sourceId, param, pValue) { var val = AL.getSourceParam('alGetSourcef', sourceId, param); if (val === null) { @@ -4486,7 +4486,7 @@ var LibraryOpenAL = { }, alGetSource3f__proxy: 'sync', - alGetSource3f__sig: 'viiiii', + alGetSource3f__sig: 'viippp', alGetSource3f: function(sourceId, param, pValue0, pValue1, pValue2) { var val = AL.getSourceParam('alGetSource3f', sourceId, param); if (val === null) { @@ -4518,7 +4518,7 @@ var LibraryOpenAL = { }, alGetSourcefv__proxy: 'sync', - alGetSourcefv__sig: 'viii', + alGetSourcefv__sig: 'viip', alGetSourcefv: function(sourceId, param, pValues) { var val = AL.getSourceParam('alGetSourcefv', sourceId, param); if (val === null) { @@ -4566,7 +4566,7 @@ var LibraryOpenAL = { }, alGetSourcei__proxy: 'sync', - alGetSourcei__sig: 'viii', + alGetSourcei__sig: 'viip', alGetSourcei: function(sourceId, param, pValue) { var val = AL.getSourceParam('alGetSourcei', sourceId, param); if (val === null) { @@ -4612,7 +4612,7 @@ var LibraryOpenAL = { }, alGetSource3i__proxy: 'sync', - alGetSource3i__sig: 'viiiii', + alGetSource3i__sig: 'viippp', alGetSource3i: function(sourceId, param, pValue0, pValue1, pValue2) { var val = AL.getSourceParam('alGetSource3i', sourceId, param); if (val === null) { @@ -4644,7 +4644,7 @@ var LibraryOpenAL = { }, alGetSourceiv__proxy: 'sync', - alGetSourceiv__sig: 'viii', + alGetSourceiv__sig: 'viip', alGetSourceiv: function(sourceId, param, pValues) { var val = AL.getSourceParam('alGetSourceiv', sourceId, param); if (val === null) { @@ -4741,7 +4741,7 @@ var LibraryOpenAL = { }, alSourcefv__proxy: 'sync', - alSourcefv__sig: 'viii', + alSourcefv__sig: 'viip', alSourcefv: function(sourceId, param, pValues) { if (!AL.currentCtx) { #if OPENAL_DEBUG @@ -4835,7 +4835,7 @@ var LibraryOpenAL = { }, alSourceiv__proxy: 'sync', - alSourceiv__sig: 'viii', + alSourceiv__sig: 'viip', alSourceiv: function(sourceId, param, pValues) { if (!AL.currentCtx) { #if OPENAL_DEBUG diff --git a/src/library_sdl.js b/src/library_sdl.js index c51dbdaa4ba76..17af30575818d 100644 --- a/src/library_sdl.js +++ b/src/library_sdl.js @@ -1337,7 +1337,7 @@ var LibrarySDL = { }, SDL_Linked_Version__proxy: 'sync', - SDL_Linked_Version__sig: 'i', + SDL_Linked_Version__sig: 'p', SDL_Linked_Version: function() { if (SDL.version === null) { SDL.version = _malloc({{{ C_STRUCTS.SDL_version.__size__ }}}); @@ -1408,7 +1408,7 @@ var LibrarySDL = { SDL_GetVideoInfo__deps: ['$zeroMemory'], SDL_GetVideoInfo__proxy: 'sync', - SDL_GetVideoInfo__sig: 'i', + SDL_GetVideoInfo__sig: 'p', SDL_GetVideoInfo: function() { var ret = _malloc({{{ C_STRUCTS.SDL_VideoInfo.__size__ }}}); zeroMemory(ret, {{{ C_STRUCTS.SDL_version.__size__ }}}); @@ -1433,7 +1433,7 @@ var LibrarySDL = { }, SDL_VideoDriverName__proxy: 'sync', - SDL_VideoDriverName__sig: 'iii', + SDL_VideoDriverName__sig: 'ppi', SDL_VideoDriverName: function(buf, max_size) { if (SDL.startTime === null) { return 0; //return NULL @@ -1461,7 +1461,7 @@ var LibrarySDL = { SDL_SetVideoMode__deps: ['$GL'], SDL_SetVideoMode__proxy: 'sync', - SDL_SetVideoMode__sig: 'iiiii', + SDL_SetVideoMode__sig: 'piiii', SDL_SetVideoMode: function(width, height, depth, flags) { ['touchstart', 'touchend', 'touchmove', 'mousedown', 'mouseup', 'mousemove', 'DOMMouseScroll', 'mousewheel', 'wheel', 'mouseout'].forEach(function(event) { Module['canvas'].addEventListener(event, SDL.receiveEvent, true); @@ -1506,7 +1506,7 @@ var LibrarySDL = { }, SDL_GetVideoSurface__proxy: 'sync', - SDL_GetVideoSurface__sig: 'i', + SDL_GetVideoSurface__sig: 'p', SDL_GetVideoSurface: function() { return SDL.screen; }, @@ -1542,7 +1542,7 @@ var LibrarySDL = { // Copy data from the canvas backing to a C++-accessible storage SDL_LockSurface__proxy: 'sync', - SDL_LockSurface__sig: 'ii', + SDL_LockSurface__sig: 'ip', SDL_LockSurface: function(surf) { var surfData = SDL.surfaces[surf]; @@ -1612,7 +1612,7 @@ var LibrarySDL = { // Copy data from the C++-accessible storage to the canvas backing SDL_UnlockSurface__proxy: 'sync', - SDL_UnlockSurface__sig: 'vi', + SDL_UnlockSurface__sig: 'vp', SDL_UnlockSurface: function(surf) { assert(!SDL.GL); // in GL mode we do not keep around 2D canvases and contexts @@ -1746,7 +1746,7 @@ var LibrarySDL = { #endif SDL_WM_SetCaption__proxy: 'sync', - SDL_WM_SetCaption__sig: 'vii', + SDL_WM_SetCaption__sig: 'vpp', SDL_WM_SetCaption: function(title, icon) { if (title && typeof setWindowTitle != 'undefined') { setWindowTitle(UTF8ToString(title)); @@ -1759,7 +1759,7 @@ var LibrarySDL = { }, SDL_GetKeyboardState__proxy: 'sync', - SDL_GetKeyboardState__sig: 'ii', + SDL_GetKeyboardState__sig: 'pp', SDL_GetKeyboardState__docs: '/** @param {number=} numKeys */', SDL_GetKeyboardState: function(numKeys) { if (numKeys) { @@ -1774,7 +1774,7 @@ var LibrarySDL = { }, SDL_GetKeyName__proxy: 'sync', - SDL_GetKeyName__sig: 'ii', + SDL_GetKeyName__sig: 'pi', SDL_GetKeyName__deps: ['$allocateUTF8'], SDL_GetKeyName: function(key) { if (!SDL.keyName) { @@ -1790,7 +1790,7 @@ var LibrarySDL = { }, SDL_GetMouseState__proxy: 'sync', - SDL_GetMouseState__sig: 'iii', + SDL_GetMouseState__sig: 'ipp', SDL_GetMouseState: function(x, y) { if (x) {{{ makeSetValue('x', '0', 'Browser.mouseX', 'i32') }}}; if (y) {{{ makeSetValue('y', '0', 'Browser.mouseY', 'i32') }}}; @@ -1834,7 +1834,7 @@ var LibrarySDL = { }, SDL_GetError__proxy: 'sync', - SDL_GetError__sig: 'i', + SDL_GetError__sig: 'p', SDL_GetError__deps: ['$allocateUTF8'], SDL_GetError: function() { if (!SDL.errorMessage) { @@ -1847,13 +1847,13 @@ var LibrarySDL = { SDL_CreateRGBSurface__deps: ['malloc', 'free'], SDL_CreateRGBSurface__proxy: 'sync', - SDL_CreateRGBSurface__sig: 'iiiiiiiii', + SDL_CreateRGBSurface__sig: 'piiiiiiii', SDL_CreateRGBSurface: function(flags, width, height, depth, rmask, gmask, bmask, amask) { return SDL.makeSurface(width, height, flags, false, 'CreateRGBSurface', rmask, gmask, bmask, amask); }, SDL_CreateRGBSurfaceFrom__proxy: 'sync', - SDL_CreateRGBSurfaceFrom__sig: 'iiiiiiiiii', + SDL_CreateRGBSurfaceFrom__sig: 'ppiiiiiiii', SDL_CreateRGBSurfaceFrom: function(pixels, width, height, depth, pitch, rmask, gmask, bmask, amask) { var surf = SDL.makeSurface(width, height, 0, false, 'CreateRGBSurfaceFrom', rmask, gmask, bmask, amask); @@ -1883,7 +1883,7 @@ var LibrarySDL = { }, SDL_ConvertSurface__proxy: 'sync', - SDL_ConvertSurface__sig: 'iiii', + SDL_ConvertSurface__sig: 'pppi', SDL_ConvertSurface__docs: '/** @param {number=} format @param {number=} flags */', SDL_ConvertSurface: function(surf, format, flags) { if (format) { @@ -1906,19 +1906,19 @@ var LibrarySDL = { }, SDL_FreeSurface__proxy: 'sync', - SDL_FreeSurface__sig: 'vi', + SDL_FreeSurface__sig: 'vp', SDL_FreeSurface: function(surf) { if (surf) SDL.freeSurface(surf); }, SDL_UpperBlit__proxy: 'sync', - SDL_UpperBlit__sig: 'iiiii', + SDL_UpperBlit__sig: 'ipppp', SDL_UpperBlit: function(src, srcrect, dst, dstrect) { return SDL.blitSurface(src, srcrect, dst, dstrect, false); }, SDL_UpperBlitScaled__proxy: 'sync', - SDL_UpperBlitScaled__sig: 'iiiii', + SDL_UpperBlitScaled__sig: 'ipppp', SDL_UpperBlitScaled: function(src, srcrect, dst, dstrect) { return SDL.blitSurface(src, srcrect, dst, dstrect, true); }, @@ -1927,7 +1927,7 @@ var LibrarySDL = { SDL_LowerBlitScaled: 'SDL_UpperBlitScaled', SDL_GetClipRect__proxy: 'sync', - SDL_GetClipRect__sig: 'vii', + SDL_GetClipRect__sig: 'vpp', SDL_GetClipRect: function(surf, rect) { assert(rect); @@ -1937,7 +1937,7 @@ var LibrarySDL = { }, SDL_SetClipRect__proxy: 'sync', - SDL_SetClipRect__sig: 'iii', + SDL_SetClipRect__sig: 'ipp', SDL_SetClipRect: function(surf, rect) { var surfData = SDL.surfaces[surf]; @@ -1949,7 +1949,7 @@ var LibrarySDL = { }, SDL_FillRect__proxy: 'sync', - SDL_FillRect__sig: 'iiii', + SDL_FillRect__sig: 'ippi', SDL_FillRect: function(surf, rect, color) { var surfData = SDL.surfaces[surf]; assert(!surfData.locked); // but we could unlock and re-lock if we must.. @@ -2014,7 +2014,7 @@ var LibrarySDL = { }, SDL_SetAlpha__proxy: 'sync', - SDL_SetAlpha__sig: 'iiii', + SDL_SetAlpha__sig: 'ipii', SDL_SetAlpha: function(surf, flag, alpha) { var surfData = SDL.surfaces[surf]; surfData.alpha = alpha; @@ -2039,13 +2039,13 @@ var LibrarySDL = { }, SDL_PollEvent__proxy: 'sync', - SDL_PollEvent__sig: 'ii', + SDL_PollEvent__sig: 'ip', SDL_PollEvent: function(ptr) { return SDL.pollEvent(ptr); }, SDL_PushEvent__proxy: 'sync', - SDL_PushEvent__sig: 'ii', + SDL_PushEvent__sig: 'ip', SDL_PushEvent__deps: ['malloc'], SDL_PushEvent: function(ptr) { var copy = _malloc({{{ C_STRUCTS.SDL_KeyboardEvent.__size__ }}}); @@ -2055,7 +2055,7 @@ var LibrarySDL = { }, SDL_PeepEvents__proxy: 'sync', - SDL_PeepEvents__sig: 'iiiiii', + SDL_PeepEvents__sig: 'ipiiii', SDL_PeepEvents: function(events, requestedEventCount, action, from, to) { switch (action) { case 2: { // SDL_GETEVENT @@ -2098,7 +2098,7 @@ var LibrarySDL = { // Allow recording a callback that will be called for each received event. emscripten_SDL_SetEventHandler__proxy: 'sync', emscripten_SDL_SetEventHandler__deps: ['malloc'], - emscripten_SDL_SetEventHandler__sig: 'vii', + emscripten_SDL_SetEventHandler__sig: 'vpp', emscripten_SDL_SetEventHandler: function(handler, userdata) { SDL.eventHandler = handler; SDL.eventHandlerContext = userdata; @@ -2108,7 +2108,7 @@ var LibrarySDL = { }, SDL_SetColors__proxy: 'sync', - SDL_SetColors__sig: 'iiiii', + SDL_SetColors__sig: 'ippii', SDL_SetColors: function(surf, colors, firstColor, nColors) { var surfData = SDL.surfaces[surf]; @@ -2139,7 +2139,7 @@ var LibrarySDL = { }, SDL_MapRGB__proxy: 'sync', - SDL_MapRGB__sig: 'iiiii', + SDL_MapRGB__sig: 'ipiii', SDL_MapRGB: function(fmt, r, g, b) { SDL.checkPixelFormat(fmt); // We assume the machine is little-endian. @@ -2147,7 +2147,7 @@ var LibrarySDL = { }, SDL_MapRGBA__proxy: 'sync', - SDL_MapRGBA__sig: 'iiiiii', + SDL_MapRGBA__sig: 'ipiiii', SDL_MapRGBA: function(fmt, r, g, b, a) { SDL.checkPixelFormat(fmt); // We assume the machine is little-endian. @@ -2155,7 +2155,7 @@ var LibrarySDL = { }, SDL_GetRGB__proxy: 'sync', - SDL_GetRGB__sig: 'viiiii', + SDL_GetRGB__sig: 'vipppp', SDL_GetRGB: function(pixel, fmt, r, g, b) { SDL.checkPixelFormat(fmt); // We assume the machine is little-endian. @@ -2171,7 +2171,7 @@ var LibrarySDL = { }, SDL_GetRGBA__proxy: 'sync', - SDL_GetRGBA__sig: 'viiiiii', + SDL_GetRGBA__sig: 'vippppp', SDL_GetRGBA: function(pixel, fmt, r, g, b, a) { SDL.checkPixelFormat(fmt); // We assume the machine is little-endian. @@ -2208,7 +2208,7 @@ var LibrarySDL = { SDL_WM_GrabInput: function() {}, SDL_WM_ToggleFullScreen__proxy: 'sync', - SDL_WM_ToggleFullScreen__sig: 'ii', + SDL_WM_ToggleFullScreen__sig: 'ip', SDL_WM_ToggleFullScreen: function(surf) { if (Browser.exitFullscreen()) { return 1; @@ -2228,7 +2228,7 @@ var LibrarySDL = { IMG_Load_RW__deps: ['SDL_LockSurface', 'SDL_FreeRW', '$PATH_FS', 'malloc'], IMG_Load_RW__proxy: 'sync', - IMG_Load_RW__sig: 'iii', + IMG_Load_RW__sig: 'ppi', IMG_Load_RW: function(rwopsID, freeSrc) { try { // stb_image integration support @@ -2380,7 +2380,7 @@ var LibrarySDL = { IMG_Load__deps: ['IMG_Load_RW', 'SDL_RWFromFile'], IMG_Load__proxy: 'sync', - IMG_Load__sig: 'ii', + IMG_Load__sig: 'pp', IMG_Load: function(filename){ var rwops = _SDL_RWFromFile(filename); var result = _IMG_Load_RW(rwops, 1); @@ -2395,7 +2395,7 @@ var LibrarySDL = { SDL_OpenAudio__deps: ['$autoResumeAudioContext', '$safeSetTimeout', 'malloc'], SDL_OpenAudio__proxy: 'sync', - SDL_OpenAudio__sig: 'iii', + SDL_OpenAudio__sig: 'ipp', SDL_OpenAudio: function(desired, obtained) { try { SDL.audio = { @@ -2710,7 +2710,7 @@ var LibrarySDL = { }, Mix_ChannelFinished__proxy: 'sync', - Mix_ChannelFinished__sig: 'vi', + Mix_ChannelFinished__sig: 'vp', Mix_ChannelFinished: function(func) { SDL.channelFinished = func; }, @@ -2745,7 +2745,7 @@ var LibrarySDL = { Mix_LoadWAV_RW__deps: ['$PATH_FS', 'fileno'], Mix_LoadWAV_RW__proxy: 'sync', - Mix_LoadWAV_RW__sig: 'iii', + Mix_LoadWAV_RW__sig: 'ppi', Mix_LoadWAV_RW__docs: '/** @param {number|boolean=} freesrc */', Mix_LoadWAV_RW: function(rwopsID, freesrc) { var rwops = SDL.rwops[rwopsID]; @@ -2852,7 +2852,7 @@ var LibrarySDL = { Mix_LoadWAV__deps: ['Mix_LoadWAV_RW', 'SDL_RWFromFile', 'SDL_FreeRW'], Mix_LoadWAV__proxy: 'sync', - Mix_LoadWAV__sig: 'ii', + Mix_LoadWAV__sig: 'pp', Mix_LoadWAV: function(filename) { var rwops = _SDL_RWFromFile(filename); var result = _Mix_LoadWAV_RW(rwops); @@ -2861,7 +2861,7 @@ var LibrarySDL = { }, Mix_QuickLoad_RAW__proxy: 'sync', - Mix_QuickLoad_RAW__sig: 'iii', + Mix_QuickLoad_RAW__sig: 'ppi', Mix_QuickLoad_RAW: function(mem, len) { var audio; var webAudio; @@ -2895,7 +2895,7 @@ var LibrarySDL = { }, Mix_FreeChunk__proxy: 'sync', - Mix_FreeChunk__sig: 'vi', + Mix_FreeChunk__sig: 'vp', Mix_FreeChunk: function(id) { SDL.audios[id] = null; }, @@ -2905,7 +2905,7 @@ var LibrarySDL = { SDL.channelMinimumNumber = num; }, Mix_PlayChannelTimed__proxy: 'sync', - Mix_PlayChannelTimed__sig: 'iiiii', + Mix_PlayChannelTimed__sig: 'iipii', Mix_PlayChannelTimed: function(channel, id, loops, ticks) { // TODO: handle fixed amount of N loops. Currently loops either 0 or infinite times. assert(ticks == -1); @@ -2986,7 +2986,7 @@ var LibrarySDL = { Mix_HookMusicFinished__deps: ['Mix_HaltMusic'], Mix_HookMusicFinished__proxy: 'sync', - Mix_HookMusicFinished__sig: 'vi', + Mix_HookMusicFinished__sig: 'vp', Mix_HookMusicFinished: function(func) { SDL.hookMusicFinished = func; if (SDL.music.audio) { // ensure the callback will be called, if a music is already playing @@ -3005,7 +3005,7 @@ var LibrarySDL = { Mix_LoadMUS__deps: ['Mix_LoadMUS_RW', 'SDL_RWFromFile', 'SDL_FreeRW'], Mix_LoadMUS__proxy: 'sync', - Mix_LoadMUS__sig: 'ii', + Mix_LoadMUS__sig: 'pp', Mix_LoadMUS: function(filename) { var rwops = _SDL_RWFromFile(filename); var result = _Mix_LoadMUS_RW(rwops); @@ -3017,7 +3017,7 @@ var LibrarySDL = { Mix_PlayMusic__deps: ['Mix_HaltMusic'], Mix_PlayMusic__proxy: 'sync', - Mix_PlayMusic__sig: 'iii', + Mix_PlayMusic__sig: 'ipi', Mix_PlayMusic: function(id, loops) { // Pause old music if it exists. if (SDL.music.audio) { @@ -3191,7 +3191,7 @@ var LibrarySDL = { }, TTF_OpenFont__proxy: 'sync', - TTF_OpenFont__sig: 'iii', + TTF_OpenFont__sig: 'ppi', TTF_OpenFont: function(filename, size) { filename = PATH.normalize(UTF8ToString(filename)); var id = SDL.fonts.length; @@ -3203,13 +3203,13 @@ var LibrarySDL = { }, TTF_CloseFont__proxy: 'sync', - TTF_CloseFont__sig: 'vi', + TTF_CloseFont__sig: 'vp', TTF_CloseFont: function(font) { SDL.fonts[font] = null; }, TTF_RenderText_Solid__proxy: 'sync', - TTF_RenderText_Solid__sig: 'iiii', + TTF_RenderText_Solid__sig: 'pppp', TTF_RenderText_Solid: function(font, text, color) { // XXX the font and color are ignored text = UTF8ToString(text) || ' '; // if given an empty string, still return a valid surface @@ -3237,7 +3237,7 @@ var LibrarySDL = { TTF_SizeUTF8: 'TTF_SizeText', TTF_SizeText__proxy: 'sync', - TTF_SizeText__sig: 'iiiii', + TTF_SizeText__sig: 'ipppp', TTF_SizeText: function(font, text, w, h) { var fontData = SDL.fonts[font]; if (w) { @@ -3250,7 +3250,7 @@ var LibrarySDL = { }, TTF_GlyphMetrics__proxy: 'sync', - TTF_GlyphMetrics__sig: 'iiiiiiii', + TTF_GlyphMetrics__sig: 'ipippppp', TTF_GlyphMetrics: function(font, ch, minx, maxx, miny, maxy, advance) { var fontData = SDL.fonts[font]; var width = SDL.estimateTextWidth(fontData, String.fromCharCode(ch)); @@ -3273,21 +3273,21 @@ var LibrarySDL = { }, TTF_FontAscent__proxy: 'sync', - TTF_FontAscent__sig: 'ii', + TTF_FontAscent__sig: 'ip', TTF_FontAscent: function(font) { var fontData = SDL.fonts[font]; return (fontData.size*0.98)|0; // XXX }, TTF_FontDescent__proxy: 'sync', - TTF_FontDescent__sig: 'ii', + TTF_FontDescent__sig: 'ip', TTF_FontDescent: function(font) { var fontData = SDL.fonts[font]; return (fontData.size*0.02)|0; // XXX }, TTF_FontHeight__proxy: 'sync', - TTF_FontHeight__sig: 'ii', + TTF_FontHeight__sig: 'ip', TTF_FontHeight: function(font) { var fontData = SDL.fonts[font]; return fontData.size; @@ -3430,7 +3430,7 @@ var LibrarySDL = { }, SDL_GL_GetAttribute__proxy: 'sync', - SDL_GL_GetAttribute__sig: 'iii', + SDL_GL_GetAttribute__sig: 'iip', SDL_GL_GetAttribute: function(attr, value) { if (!(attr in SDL.glAttributes)) { abort('Unknown SDL GL attribute (' + attr + '). Please check if your SDL version is supported.'); @@ -3450,7 +3450,7 @@ var LibrarySDL = { // SDL 2 SDL_GL_ExtensionSupported__proxy: 'sync', - SDL_GL_ExtensionSupported__sig: 'ii', + SDL_GL_ExtensionSupported__sig: 'ip', SDL_GL_ExtensionSupported: function(extension) { return Module.ctx.getExtension(extension) | 0; }, @@ -3488,13 +3488,13 @@ var LibrarySDL = { }, SDL_SetWindowTitle__proxy: 'sync', - SDL_SetWindowTitle__sig: 'vii', + SDL_SetWindowTitle__sig: 'vpp', SDL_SetWindowTitle: function(window, title) { if (title) document.title = UTF8ToString(title); }, SDL_GetWindowSize__proxy: 'sync', - SDL_GetWindowSize__sig: 'viii', + SDL_GetWindowSize__sig: 'vppp', SDL_GetWindowSize: function(window, width, height){ var w = Module['canvas'].width; var h = Module['canvas'].height; @@ -3505,7 +3505,7 @@ var LibrarySDL = { SDL_LogSetOutputFunction: function(callback, userdata) {}, SDL_SetWindowFullscreen__proxy: 'sync', - SDL_SetWindowFullscreen__sig: 'iii', + SDL_SetWindowFullscreen__sig: 'ipi', SDL_SetWindowFullscreen: function(window, fullscreen) { if (Browser.isFullscreen) { Module['canvas'].exitFullscreen(); @@ -3541,7 +3541,7 @@ var LibrarySDL = { }, SDL_JoystickName__proxy: 'sync', - SDL_JoystickName__sig: 'ii', + SDL_JoystickName__sig: 'pi', SDL_JoystickName__deps: ['$allocateUTF8'], SDL_JoystickName: function(deviceIndex) { var gamepad = SDL.getGamepad(deviceIndex); @@ -3556,7 +3556,7 @@ var LibrarySDL = { }, SDL_JoystickOpen__proxy: 'sync', - SDL_JoystickOpen__sig: 'ii', + SDL_JoystickOpen__sig: 'pi', SDL_JoystickOpen: function(deviceIndex) { var gamepad = SDL.getGamepad(deviceIndex); if (gamepad) { @@ -3580,7 +3580,7 @@ var LibrarySDL = { }, SDL_JoystickNumAxes__proxy: 'sync', - SDL_JoystickNumAxes__sig: 'ii', + SDL_JoystickNumAxes__sig: 'ip', SDL_JoystickNumAxes: function(joystick) { var gamepad = SDL.getGamepad(joystick - 1); if (gamepad) { @@ -3594,7 +3594,7 @@ var LibrarySDL = { SDL_JoystickNumHats: function(joystick) { return 0; }, SDL_JoystickNumButtons__proxy: 'sync', - SDL_JoystickNumButtons__sig: 'ii', + SDL_JoystickNumButtons__sig: 'ip', SDL_JoystickNumButtons: function(joystick) { var gamepad = SDL.getGamepad(joystick - 1); if (gamepad) { @@ -3620,7 +3620,7 @@ var LibrarySDL = { }, SDL_JoystickGetAxis__proxy: 'sync', - SDL_JoystickGetAxis__sig: 'iii', + SDL_JoystickGetAxis__sig: 'ipi', SDL_JoystickGetAxis: function(joystick, axis) { var gamepad = SDL.getGamepad(joystick - 1); if (gamepad && gamepad.axes.length > axis) { @@ -3634,7 +3634,7 @@ var LibrarySDL = { SDL_JoystickGetBall: function(joystick, ball, dxptr, dyptr) { return -1; }, SDL_JoystickGetButton__proxy: 'sync', - SDL_JoystickGetButton__sig: 'iii', + SDL_JoystickGetButton__sig: 'ipi', SDL_JoystickGetButton: function(joystick, button) { var gamepad = SDL.getGamepad(joystick - 1); if (gamepad && gamepad.buttons.length > button) { @@ -3644,7 +3644,7 @@ var LibrarySDL = { }, SDL_JoystickClose__proxy: 'sync', - SDL_JoystickClose__sig: 'vi', + SDL_JoystickClose__sig: 'vp', SDL_JoystickClose: function(joystick) { delete SDL.lastJoystickState[joystick]; }, @@ -3654,7 +3654,7 @@ var LibrarySDL = { SDL_InitSubSystem: function(flags) { return 0 }, SDL_RWFromConstMem__proxy: 'sync', - SDL_RWFromConstMem__sig: 'iii', + SDL_RWFromConstMem__sig: 'ppi', SDL_RWFromConstMem: function(mem, size) { var id = SDL.rwops.length; // TODO: recycle ids when they are null SDL.rwops.push({ bytes: mem, count: size }); @@ -3663,7 +3663,7 @@ var LibrarySDL = { SDL_RWFromMem: 'SDL_RWFromConstMem', SDL_RWFromFile__proxy: 'sync', - SDL_RWFromFile__sig: 'iii', + SDL_RWFromFile__sig: 'ppp', SDL_RWFromFile__docs: '/** @param {number=} mode */', SDL_RWFromFile: function(_name, mode) { var id = SDL.rwops.length; // TODO: recycle ids when they are null @@ -3673,7 +3673,7 @@ var LibrarySDL = { }, SDL_FreeRW__proxy: 'sync', - SDL_FreeRW__sig: 'vi', + SDL_FreeRW__sig: 'vp', SDL_FreeRW: function(rwopsID) { SDL.rwops[rwopsID] = null; while (SDL.rwops.length > 0 && SDL.rwops[SDL.rwops.length-1] === null) { @@ -3702,7 +3702,7 @@ var LibrarySDL = { SDL_AddTimer__proxy: 'sync', SDL_AddTimer__deps: ['$safeSetTimeout'], - SDL_AddTimer__sig: 'iiii', + SDL_AddTimer__sig: 'iipp', SDL_AddTimer: function(interval, callback, param) { return safeSetTimeout( () => {{{ makeDynCall('iii', 'callback') }}}(interval, param), diff --git a/src/library_syscall.js b/src/library_syscall.js index 1b26f517d0381..bd68e9bc4ac5b 100644 --- a/src/library_syscall.js +++ b/src/library_syscall.js @@ -328,7 +328,7 @@ var SyscallsLibrary = { return 0; }, __syscall_connect__deps: ['$getSocketFromFD', '$getSocketAddress'], - __syscall_connect__sig: 'iipiiii', + __syscall_connect__sig: 'iippiii', __syscall_connect: function(fd, addr, addrlen, d1, d2, d3) { var sock = getSocketFromFD(fd); var info = getSocketAddress(addr, addrlen); @@ -353,7 +353,7 @@ var SyscallsLibrary = { return newsock.stream.fd; }, __syscall_bind__deps: ['$getSocketFromFD', '$getSocketAddress'], - __syscall_bind__sig: 'iipiiii', + __syscall_bind__sig: 'iippiii', __syscall_bind: function(fd, addr, addrlen, d1, d2, d3) { var sock = getSocketFromFD(fd); var info = getSocketAddress(addr, addrlen); @@ -381,7 +381,7 @@ var SyscallsLibrary = { return msg.buffer.byteLength; }, __syscall_sendto__deps: ['$getSocketFromFD', '$getSocketAddress'], - __syscall_sendto__sig: 'iipiipi', + __syscall_sendto__sig: 'iippipp', __syscall_sendto: function(fd, message, length, flags, addr, addr_len) { var sock = getSocketFromFD(fd); var dest = getSocketAddress(addr, addr_len, true); @@ -655,7 +655,7 @@ var SyscallsLibrary = { FS.fchown(fd, owner, group); return 0; }, - __syscall_getdents64__sig: 'iipi', + __syscall_getdents64__sig: 'iipp', __syscall_getdents64: function(fd, dirp, count) { var stream = SYSCALLS.getStreamFromFD(fd) if (!stream.getdents) { @@ -899,7 +899,7 @@ var SyscallsLibrary = { FS.symlink(target, linkpath); return 0; }, - __syscall_readlinkat__sig: 'vippp', + __syscall_readlinkat__sig: 'iippp', __syscall_readlinkat: function(dirfd, path, buf, bufsize) { path = SYSCALLS.getStr(path); path = SYSCALLS.calculateAt(dirfd, path); diff --git a/src/library_webaudio.js b/src/library_webaudio.js index bf2aedebbb7b8..149699838bb98 100644 --- a/src/library_webaudio.js +++ b/src/library_webaudio.js @@ -289,27 +289,51 @@ let LibraryWebAudio = { (audioContext ? EmAudio[audioContext].audioWorklet.bootstrapMessage.port : globalThis['messagePort']).postMessage({'_wsc': funcPtr, 'x': [] }); // "WaSm Call" }, - emscripten_audio_worklet_post_function_1__sig: 'vipd', - emscripten_audio_worklet_post_function_1: function(audioContext, funcPtr, arg0) { + $emscripten_audio_worklet_post_function_1: function(audioContext, funcPtr, arg0) { (audioContext ? EmAudio[audioContext].audioWorklet.bootstrapMessage.port : globalThis['messagePort']).postMessage({'_wsc': funcPtr, 'x': [arg0] }); // "WaSm Call" }, - emscripten_audio_worklet_post_function_vi: 'emscripten_audio_worklet_post_function_1', - emscripten_audio_worklet_post_function_vd: 'emscripten_audio_worklet_post_function_1', + emscripten_audio_worklet_post_function_vi__sig: 'vipi', + emscripten_audio_worklet_post_function_vi__deps: ['$emscripten_audio_worklet_post_function_1'], + emscripten_audio_worklet_post_function_vi(audioContext, funcPtr, arg0) { + emscripten_audio_worklet_post_function_1(audioContext, funcPtr, arg0) + }, + + emscripten_audio_worklet_post_function_vd__sig: 'vipd', + emscripten_audio_worklet_post_function_vd__deps: ['$emscripten_audio_worklet_post_function_1'], + emscripten_audio_worklet_post_function_vd(audioContext, funcPtr, arg0) { + emscripten_audio_worklet_post_function_1(audioContext, funcPtr, arg0) + }, - emscripten_audio_worklet_post_function_2__sig: 'vipdd', - emscripten_audio_worklet_post_function_2: function(audioContext, funcPtr, arg0, arg1) { + $emscripten_audio_worklet_post_function_2: function(audioContext, funcPtr, arg0, arg1) { (audioContext ? EmAudio[audioContext].audioWorklet.bootstrapMessage.port : globalThis['messagePort']).postMessage({'_wsc': funcPtr, 'x': [arg0, arg1] }); // "WaSm Call" }, - emscripten_audio_worklet_post_function_vii: 'emscripten_audio_worklet_post_function_2', - emscripten_audio_worklet_post_function_vdd: 'emscripten_audio_worklet_post_function_2', - emscripten_audio_worklet_post_function_3__sig: 'vipddd', - emscripten_audio_worklet_post_function_3: function(audioContext, funcPtr, arg0, arg1, arg2) { + emscripten_audio_worklet_post_function_vii__sig: 'vipii', + emscripten_audio_worklet_post_function_vii__deps: ['$emscripten_audio_worklet_post_function_2'], + emscripten_audio_worklet_post_function_vii: function(audioContext, funcPtr, arg0, arg1) { + emscripten_audio_worklet_post_function_2(audioContext, funcPtr, arg0, arg1); + }, + + emscripten_audio_worklet_post_function_vdd__sig: 'vipdd', + emscripten_audio_worklet_post_function_vdd__deps: ['$emscripten_audio_worklet_post_function_2'], + emscripten_audio_worklet_post_function_vdd: function(audioContext, funcPtr, arg0, arg1) { + emscripten_audio_worklet_post_function_2(audioContext, funcPtr, arg0, arg1); + }, + + $emscripten_audio_worklet_post_function_3: function(audioContext, funcPtr, arg0, arg1, arg2) { (audioContext ? EmAudio[audioContext].audioWorklet.bootstrapMessage.port : globalThis['messagePort']).postMessage({'_wsc': funcPtr, 'x': [arg0, arg1, arg2] }); // "WaSm Call" }, - emscripten_audio_worklet_post_function_viii: 'emscripten_audio_worklet_post_function_3', - emscripten_audio_worklet_post_function_vddd: 'emscripten_audio_worklet_post_function_3', + emscripten_audio_worklet_post_function_viii__sig: 'vipiii', + emscripten_audio_worklet_post_function_viii__deps: ['$emscripten_audio_worklet_post_function_3'], + emscripten_audio_worklet_post_function_viii: function(audioContext, funcPtr, arg0, arg1, arg2) { + emscripten_audio_worklet_post_function_3(audioContext, funcPtr, arg0, arg1, arg2); + }, + emscripten_audio_worklet_post_function_vddd__sig: 'vipddd', + emscripten_audio_worklet_post_function_vddd__deps: ['$emscripten_audio_worklet_post_function_3'], + emscripten_audio_worklet_post_function_vddd: function(audioContext, funcPtr, arg0, arg1, arg2) { + emscripten_audio_worklet_post_function_3(audioContext, funcPtr, arg0, arg1, arg2); + }, emscripten_audio_worklet_post_function_sig__deps: ['$readAsmConstArgs'], emscripten_audio_worklet_post_function_sig__sig: 'vippp', diff --git a/src/library_webgl.js b/src/library_webgl.js index 0a096b9add922..13d09d1e4e6e6 100644 --- a/src/library_webgl.js +++ b/src/library_webgl.js @@ -1149,7 +1149,7 @@ var LibraryGL = { GLctx.pixelStorei(pname, param); }, - glGetString__sig: 'ii', + glGetString__sig: 'pi', glGetString__deps: ['$stringToNewUTF8'], glGetString: function(name_) { var ret = GL.stringCache[name_]; @@ -1400,25 +1400,25 @@ var LibraryGL = { } }, - glGetIntegerv__sig: 'vii', + glGetIntegerv__sig: 'vip', glGetIntegerv__deps: ['$emscriptenWebGLGet'], glGetIntegerv: function(name_, p) { emscriptenWebGLGet(name_, p, {{{ cDefine('EM_FUNC_SIG_PARAM_I') }}}); }, - glGetFloatv__sig: 'vii', + glGetFloatv__sig: 'vip', glGetFloatv__deps: ['$emscriptenWebGLGet'], glGetFloatv: function(name_, p) { emscriptenWebGLGet(name_, p, {{{ cDefine('EM_FUNC_SIG_PARAM_F') }}}); }, - glGetBooleanv__sig: 'vii', + glGetBooleanv__sig: 'vip', glGetBooleanv__deps: ['$emscriptenWebGLGet'], glGetBooleanv: function(name_, p) { emscriptenWebGLGet(name_, p, {{{ cDefine('EM_FUNC_SIG_PARAM_B') }}}); }, - glDeleteTextures__sig: 'vii', + glDeleteTextures__sig: 'vip', glDeleteTextures: function(n, textures) { for (var i = 0; i < n; i++) { var id = {{{ makeGetValue('textures', 'i*4', 'i32') }}}; @@ -1430,7 +1430,7 @@ var LibraryGL = { } }, - glCompressedTexImage2D__sig: 'viiiiiiii', + glCompressedTexImage2D__sig: 'viiiiiiip', glCompressedTexImage2D: function(target, level, internalFormat, width, height, border, imageSize, data) { #if MAX_WEBGL_VERSION >= 2 if ({{{ isCurrentContextWebGL2() }}}) { // WebGL 2 provides new garbage-free entry points to call to WebGL. Use those always when possible. @@ -1446,7 +1446,7 @@ var LibraryGL = { }, - glCompressedTexSubImage2D__sig: 'viiiiiiiii', + glCompressedTexSubImage2D__sig: 'viiiiiiiip', glCompressedTexSubImage2D: function(target, level, xoffset, yoffset, width, height, format, imageSize, data) { #if MAX_WEBGL_VERSION >= 2 if ({{{ isCurrentContextWebGL2() }}}) { // WebGL 2 provides new garbage-free entry points to call to WebGL. Use those always when possible. @@ -1520,7 +1520,7 @@ var LibraryGL = { return heap.subarray(pixels >> shift, pixels + bytes >> shift); }, - glTexImage2D__sig: 'viiiiiiiii', + glTexImage2D__sig: 'viiiiiiiip', glTexImage2D__deps: ['$emscriptenWebGLGetTexPixelData' #if MAX_WEBGL_VERSION >= 2 , '$heapObjectForWebGLType', '$heapAccessShiftForWebGLHeap' @@ -1562,7 +1562,7 @@ var LibraryGL = { GLctx.texImage2D(target, level, internalFormat, width, height, border, format, type, pixels ? emscriptenWebGLGetTexPixelData(type, format, width, height, pixels, internalFormat) : null); }, - glTexSubImage2D__sig: 'viiiiiiiii', + glTexSubImage2D__sig: 'viiiiiiiip', glTexSubImage2D__deps: ['$emscriptenWebGLGetTexPixelData' #if MAX_WEBGL_VERSION >= 2 , '$heapObjectForWebGLType', '$heapAccessShiftForWebGLHeap' @@ -1596,7 +1596,7 @@ var LibraryGL = { GLctx.texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixelData); }, - glReadPixels__sig: 'viiiiiii', + glReadPixels__sig: 'viiiiiip', glReadPixels__deps: ['$emscriptenWebGLGetTexPixelData' #if MAX_WEBGL_VERSION >= 2 , '$heapObjectForWebGLType', '$heapAccessShiftForWebGLHeap' @@ -1633,7 +1633,7 @@ var LibraryGL = { GLctx.bindTexture(target, GL.textures[texture]); }, - glGetTexParameterfv__sig: 'viii', + glGetTexParameterfv__sig: 'viip', glGetTexParameterfv: function(target, pname, params) { if (!params) { // GLES2 specification does not specify how to behave if params is a null pointer. Since calling this function does not make sense @@ -1647,7 +1647,7 @@ var LibraryGL = { {{{ makeSetValue('params', '0', 'GLctx.getTexParameter(target, pname)', 'float') }}}; }, - glGetTexParameteriv__sig: 'viii', + glGetTexParameteriv__sig: 'viip', glGetTexParameteriv: function(target, pname, params) { if (!params) { // GLES2 specification does not specify how to behave if params is a null pointer. Since calling this function does not make sense @@ -1661,13 +1661,13 @@ var LibraryGL = { {{{ makeSetValue('params', '0', 'GLctx.getTexParameter(target, pname)', 'i32') }}}; }, - glTexParameterfv__sig: 'viii', + glTexParameterfv__sig: 'viip', glTexParameterfv: function(target, pname, params) { var param = {{{ makeGetValue('params', '0', 'float') }}}; GLctx.texParameterf(target, pname, param); }, - glTexParameteriv__sig: 'viii', + glTexParameteriv__sig: 'viip', glTexParameteriv: function(target, pname, params) { var param = {{{ makeGetValue('params', '0', 'i32') }}}; GLctx.texParameteri(target, pname, param); @@ -1707,7 +1707,7 @@ var LibraryGL = { }, glGenBuffers__deps: ['$__glGenObject'], - glGenBuffers__sig: 'vii', + glGenBuffers__sig: 'vip', glGenBuffers: function(n, buffers) { __glGenObject(n, buffers, 'createBuffer', GL.buffers #if GL_ASSERTIONS @@ -1717,7 +1717,7 @@ var LibraryGL = { }, glGenTextures__deps: ['$__glGenObject'], - glGenTextures__sig: 'vii', + glGenTextures__sig: 'vip', glGenTextures: function(n, textures) { __glGenObject(n, textures, 'createTexture', GL.textures #if GL_ASSERTIONS @@ -1726,7 +1726,7 @@ var LibraryGL = { ); }, - glDeleteBuffers__sig: 'vii', + glDeleteBuffers__sig: 'vip', glDeleteBuffers: function(n, buffers) { for (var i = 0; i < n; i++) { var id = {{{ makeGetValue('buffers', 'i*4', 'i32') }}}; @@ -1751,7 +1751,7 @@ var LibraryGL = { } }, - glGetBufferParameteriv__sig: 'viii', + glGetBufferParameteriv__sig: 'viip', glGetBufferParameteriv: function(target, value, data) { if (!data) { // GLES2 specification does not specify how to behave if data is a null pointer. Since calling this function does not make sense @@ -1765,7 +1765,7 @@ var LibraryGL = { {{{ makeSetValue('data', '0', 'GLctx.getBufferParameter(target, value)', 'i32') }}}; }, - glBufferData__sig: 'viiii', + glBufferData__sig: 'vippi', glBufferData: function(target, size, data, usage) { #if LEGACY_GL_EMULATION switch (usage) { // fix usages, WebGL 1 only has *_DRAW @@ -1804,7 +1804,7 @@ var LibraryGL = { #endif }, - glBufferSubData__sig: 'viiii', + glBufferSubData__sig: 'vippp', glBufferSubData: function(target, offset, size, data) { #if MAX_WEBGL_VERSION >= 2 if ({{{ isCurrentContextWebGL2() }}}) { // WebGL 2 provides new garbage-free entry points to call to WebGL. Use those always when possible. @@ -1962,7 +1962,7 @@ var LibraryGL = { return GLctx.isBuffer(b); }, - glGenRenderbuffers__sig: 'vii', + glGenRenderbuffers__sig: 'vip', glGenRenderbuffers__deps: ['$__glGenObject'], glGenRenderbuffers: function(n, renderbuffers) { __glGenObject(n, renderbuffers, 'createRenderbuffer', GL.renderbuffers @@ -1972,7 +1972,7 @@ var LibraryGL = { ); }, - glDeleteRenderbuffers__sig: 'vii', + glDeleteRenderbuffers__sig: 'vip', glDeleteRenderbuffers: function(n, renderbuffers) { for (var i = 0; i < n; i++) { var id = {{{ makeGetValue('renderbuffers', 'i*4', 'i32') }}}; @@ -1992,7 +1992,7 @@ var LibraryGL = { GLctx.bindRenderbuffer(target, GL.renderbuffers[renderbuffer]); }, - glGetRenderbufferParameteriv__sig: 'viii', + glGetRenderbufferParameteriv__sig: 'viip', glGetRenderbufferParameteriv: function(target, pname, params) { if (!params) { // GLES2 specification does not specify how to behave if params is a null pointer. Since calling this function does not make sense @@ -2053,13 +2053,13 @@ var LibraryGL = { } }, - glGetUniformfv__sig: 'viii', + glGetUniformfv__sig: 'viip', glGetUniformfv__deps: ['$emscriptenWebGLGetUniform'], glGetUniformfv: function(program, location, params) { emscriptenWebGLGetUniform(program, location, params, {{{ cDefine('EM_FUNC_SIG_PARAM_F') }}}); }, - glGetUniformiv__sig: 'viii', + glGetUniformiv__sig: 'viip', glGetUniformiv__deps: ['$emscriptenWebGLGetUniform'], glGetUniformiv: function(program, location, params) { emscriptenWebGLGetUniform(program, location, params, {{{ cDefine('EM_FUNC_SIG_PARAM_I') }}}); @@ -2151,7 +2151,7 @@ var LibraryGL = { return name.slice(-1) == ']' && name.lastIndexOf('['); }, - glGetUniformLocation__sig: 'iii', + glGetUniformLocation__sig: 'iip', glGetUniformLocation__deps: ['$jstoi_q', '$webglPrepareUniformLocationsBeforeFirstUse', '$webglGetLeftBracePos'], glGetUniformLocation: function(program, name) { @@ -2250,7 +2250,7 @@ var LibraryGL = { } }, - glGetVertexAttribfv__sig: 'viii', + glGetVertexAttribfv__sig: 'viip', glGetVertexAttribfv__deps: ['$emscriptenWebGLGetVertexAttrib'], glGetVertexAttribfv: function(index, pname, params) { // N.B. This function may only be called if the vertex attribute was specified using the function glVertexAttrib*f(), @@ -2258,7 +2258,7 @@ var LibraryGL = { emscriptenWebGLGetVertexAttrib(index, pname, params, {{{ cDefine('EM_FUNC_SIG_PARAM_F') }}}); }, - glGetVertexAttribiv__sig: 'viii', + glGetVertexAttribiv__sig: 'viip', glGetVertexAttribiv__deps: ['$emscriptenWebGLGetVertexAttrib'], glGetVertexAttribiv: function(index, pname, params) { // N.B. This function may only be called if the vertex attribute was specified using the function glVertexAttrib*f(), @@ -2266,7 +2266,7 @@ var LibraryGL = { emscriptenWebGLGetVertexAttrib(index, pname, params, {{{ cDefine('EM_FUNC_SIG_PARAM_F2I') }}}); }, - glGetVertexAttribPointerv__sig: 'viii', + glGetVertexAttribPointerv__sig: 'viip', glGetVertexAttribPointerv: function(index, pname, pointer) { if (!pointer) { // GLES2 specification does not specify how to behave if pointer is a null pointer. Since calling this function does not make sense @@ -2357,7 +2357,7 @@ var LibraryGL = { GLctx.uniform4i(webglGetUniformLocation(location), v0, v1, v2, v3); }, - glUniform1iv__sig: 'viii', + glUniform1iv__sig: 'viip', glUniform1iv__deps: ['$webglGetUniformLocation' #if GL_POOL_TEMP_BUFFERS && MIN_WEBGL_VERSION == 1 , '$miniTempWebGLIntBuffers' @@ -2402,7 +2402,7 @@ var LibraryGL = { #endif // MIN_WEBGL_VERSION >= 2 }, - glUniform2iv__sig: 'viii', + glUniform2iv__sig: 'viip', glUniform2iv__deps: ['$webglGetUniformLocation' #if GL_POOL_TEMP_BUFFERS && MIN_WEBGL_VERSION == 1 , '$miniTempWebGLIntBuffers' @@ -2448,7 +2448,7 @@ var LibraryGL = { #endif // MIN_WEBGL_VERSION >= 2 }, - glUniform3iv__sig: 'viii', + glUniform3iv__sig: 'viip', glUniform3iv__deps: ['$webglGetUniformLocation' #if GL_POOL_TEMP_BUFFERS && MIN_WEBGL_VERSION == 1 , '$miniTempWebGLIntBuffers' @@ -2495,7 +2495,7 @@ var LibraryGL = { #endif // MIN_WEBGL_VERSION >= 2 }, - glUniform4iv__sig: 'viii', + glUniform4iv__sig: 'viip', glUniform4iv__deps: ['$webglGetUniformLocation' #if GL_POOL_TEMP_BUFFERS && MIN_WEBGL_VERSION == 1 , '$miniTempWebGLIntBuffers' @@ -2543,7 +2543,7 @@ var LibraryGL = { #endif // MIN_WEBGL_VERSION >= 2 }, - glUniform1fv__sig: 'viii', + glUniform1fv__sig: 'viip', glUniform1fv__deps: ['$webglGetUniformLocation' #if GL_POOL_TEMP_BUFFERS && MIN_WEBGL_VERSION == 1 , '$miniTempWebGLFloatBuffers' @@ -2588,7 +2588,7 @@ var LibraryGL = { #endif // MIN_WEBGL_VERSION >= 2 }, - glUniform2fv__sig: 'viii', + glUniform2fv__sig: 'viip', glUniform2fv__deps: ['$webglGetUniformLocation' #if GL_POOL_TEMP_BUFFERS && MIN_WEBGL_VERSION == 1 , '$miniTempWebGLFloatBuffers' @@ -2634,7 +2634,7 @@ var LibraryGL = { #endif // MIN_WEBGL_VERSION >= 2 }, - glUniform3fv__sig: 'viii', + glUniform3fv__sig: 'viip', glUniform3fv__deps: ['$webglGetUniformLocation' #if GL_POOL_TEMP_BUFFERS && MIN_WEBGL_VERSION == 1 , '$miniTempWebGLFloatBuffers' @@ -2681,7 +2681,7 @@ var LibraryGL = { #endif // MIN_WEBGL_VERSION >= 2 }, - glUniform4fv__sig: 'viii', + glUniform4fv__sig: 'viip', glUniform4fv__deps: ['$webglGetUniformLocation' #if GL_POOL_TEMP_BUFFERS && MIN_WEBGL_VERSION == 1 , '$miniTempWebGLFloatBuffers' @@ -2733,7 +2733,7 @@ var LibraryGL = { #endif // MIN_WEBGL_VERSION >= 2 }, - glUniformMatrix2fv__sig: 'viiii', + glUniformMatrix2fv__sig: 'viiip', glUniformMatrix2fv__deps: ['$webglGetUniformLocation' #if GL_POOL_TEMP_BUFFERS && MIN_WEBGL_VERSION == 1 , '$miniTempWebGLFloatBuffers' @@ -2781,7 +2781,7 @@ var LibraryGL = { #endif // MIN_WEBGL_VERSION >= 2 }, - glUniformMatrix3fv__sig: 'viiii', + glUniformMatrix3fv__sig: 'viiip', glUniformMatrix3fv__deps: ['$webglGetUniformLocation' #if GL_POOL_TEMP_BUFFERS && MIN_WEBGL_VERSION == 1 , '$miniTempWebGLFloatBuffers' @@ -2834,7 +2834,7 @@ var LibraryGL = { #endif // MIN_WEBGL_VERSION >= 2 }, - glUniformMatrix4fv__sig: 'viiii', + glUniformMatrix4fv__sig: 'viiip', glUniformMatrix4fv__deps: ['$webglGetUniformLocation' #if GL_POOL_TEMP_BUFFERS && MIN_WEBGL_VERSION == 1 , '$miniTempWebGLFloatBuffers' @@ -2932,7 +2932,7 @@ var LibraryGL = { GLctx.bindBuffer(target, GL.buffers[buffer]); }, - glVertexAttrib1fv__sig: 'vii', + glVertexAttrib1fv__sig: 'vip', glVertexAttrib1fv: function(index, v) { #if GL_ASSERTIONS assert((v & 3) == 0, 'Pointer to float data passed to glVertexAttrib1fv must be aligned to four bytes!'); @@ -2942,7 +2942,7 @@ var LibraryGL = { GLctx.vertexAttrib1f(index, HEAPF32[v>>2]); }, - glVertexAttrib2fv__sig: 'vii', + glVertexAttrib2fv__sig: 'vip', glVertexAttrib2fv: function(index, v) { #if GL_ASSERTIONS assert((v & 3) == 0, 'Pointer to float data passed to glVertexAttrib2fv must be aligned to four bytes!'); @@ -2952,7 +2952,7 @@ var LibraryGL = { GLctx.vertexAttrib2f(index, HEAPF32[v>>2], HEAPF32[v+4>>2]); }, - glVertexAttrib3fv__sig: 'vii', + glVertexAttrib3fv__sig: 'vip', glVertexAttrib3fv: function(index, v) { #if GL_ASSERTIONS assert((v & 3) == 0, 'Pointer to float data passed to glVertexAttrib3fv must be aligned to four bytes!'); @@ -2962,7 +2962,7 @@ var LibraryGL = { GLctx.vertexAttrib3f(index, HEAPF32[v>>2], HEAPF32[v+4>>2], HEAPF32[v+8>>2]); }, - glVertexAttrib4fv__sig: 'vii', + glVertexAttrib4fv__sig: 'vip', glVertexAttrib4fv: function(index, v) { #if GL_ASSERTIONS assert((v & 3) == 0, 'Pointer to float data passed to glVertexAttrib4fv must be aligned to four bytes!'); @@ -2972,7 +2972,7 @@ var LibraryGL = { GLctx.vertexAttrib4f(index, HEAPF32[v>>2], HEAPF32[v+4>>2], HEAPF32[v+8>>2], HEAPF32[v+12>>2]); }, - glGetAttribLocation__sig: 'iii', + glGetAttribLocation__sig: 'iip', glGetAttribLocation: function(program, name) { return GLctx.getAttribLocation(GL.programs[program], UTF8ToString(name)); }, @@ -2991,13 +2991,13 @@ var LibraryGL = { } }, - glGetActiveAttrib__sig: 'viiiiiii', + glGetActiveAttrib__sig: 'viiipppp', glGetActiveAttrib__deps: ['$__glGetActiveAttribOrUniform'], glGetActiveAttrib: function(program, index, bufSize, length, size, type, name) { __glGetActiveAttribOrUniform('getActiveAttrib', program, index, bufSize, length, size, type, name); }, - glGetActiveUniform__sig: 'viiiiiii', + glGetActiveUniform__sig: 'viiipppp', glGetActiveUniform__deps: ['$__glGetActiveAttribOrUniform'], glGetActiveUniform: function(program, index, bufSize, length, size, type, name) { __glGetActiveAttribOrUniform('getActiveUniform', program, index, bufSize, length, size, type, name); @@ -3028,7 +3028,7 @@ var LibraryGL = { GL.shaders[id] = null; }, - glGetAttachedShaders__sig: 'viiii', + glGetAttachedShaders__sig: 'viipp', glGetAttachedShaders: function(program, maxCount, count, shaders) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.programs, program, 'glGetAttachedShaders', 'program'); @@ -3048,7 +3048,7 @@ var LibraryGL = { } }, - glShaderSource__sig: 'viiii', + glShaderSource__sig: 'viipp', #if GL_EXPLICIT_UNIFORM_LOCATION || GL_EXPLICIT_UNIFORM_BINDING glShaderSource__deps: ['$preprocess_c_code', '$remove_cpp_comments_in_shaders', '$jstoi_q', '$find_closing_parens_index'], #endif @@ -3213,7 +3213,7 @@ var LibraryGL = { GLctx.shaderSource(GL.shaders[shader], source); }, - glGetShaderSource__sig: 'viiii', + glGetShaderSource__sig: 'viipp', glGetShaderSource: function(shader, bufSize, length, source) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.shaders, shader, 'glGetShaderSource', 'shader'); @@ -3236,7 +3236,7 @@ var LibraryGL = { #endif }, - glGetShaderInfoLog__sig: 'viiii', + glGetShaderInfoLog__sig: 'viipp', glGetShaderInfoLog: function(shader, maxLength, length, infoLog) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.shaders, shader, 'glGetShaderInfoLog', 'shader'); @@ -3249,7 +3249,7 @@ var LibraryGL = { if (length) {{{ makeSetValue('length', '0', 'numBytesWrittenExclNull', 'i32') }}}; }, - glGetShaderiv__sig: 'viii', + glGetShaderiv__sig: 'viip', glGetShaderiv : function(shader, pname, p) { if (!p) { // GLES2 specification does not specify how to behave if p is a null pointer. Since calling this function does not make sense @@ -3285,7 +3285,7 @@ var LibraryGL = { } }, - glGetProgramiv__sig: 'viii', + glGetProgramiv__sig: 'viip', glGetProgramiv : function(program, pname, p) { if (!p) { // GLES2 specification does not specify how to behave if p is a null pointer. Since calling this function does not make sense @@ -3400,7 +3400,7 @@ var LibraryGL = { GLctx.detachShader(GL.programs[program], GL.shaders[shader]); }, - glGetShaderPrecisionFormat__sig: 'viiii', + glGetShaderPrecisionFormat__sig: 'viipp', glGetShaderPrecisionFormat: function(shaderType, precisionType, range, precision) { var result = GLctx.getShaderPrecisionFormat(shaderType, precisionType); {{{ makeSetValue('range', '0', 'result.rangeMin', 'i32') }}}; @@ -3463,7 +3463,7 @@ var LibraryGL = { #endif }, - glGetProgramInfoLog__sig: 'viiii', + glGetProgramInfoLog__sig: 'viipp', glGetProgramInfoLog: function(program, maxLength, length, infoLog) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.programs, program, 'glGetProgramInfoLog', 'program'); @@ -3550,7 +3550,7 @@ var LibraryGL = { return GLctx.isProgram(program); }, - glBindAttribLocation__sig: 'viii', + glBindAttribLocation__sig: 'viip', glBindAttribLocation: function(program, index, name) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.programs, program, 'glBindAttribLocation', 'program'); @@ -3575,7 +3575,7 @@ var LibraryGL = { }, - glGenFramebuffers__sig: 'vii', + glGenFramebuffers__sig: 'vip', glGenFramebuffers__deps: ['$__glGenObject'], glGenFramebuffers: function(n, ids) { __glGenObject(n, ids, 'createFramebuffer', GL.framebuffers @@ -3585,7 +3585,7 @@ var LibraryGL = { ); }, - glDeleteFramebuffers__sig: 'vii', + glDeleteFramebuffers__sig: 'vip', glDeleteFramebuffers: function(n, framebuffers) { for (var i = 0; i < n; ++i) { var id = {{{ makeGetValue('framebuffers', 'i*4', 'i32') }}}; @@ -3615,7 +3615,7 @@ var LibraryGL = { GL.textures[texture], level); }, - glGetFramebufferAttachmentParameteriv__sig: 'viiii', + glGetFramebufferAttachmentParameteriv__sig: 'viiip', glGetFramebufferAttachmentParameteriv: function(target, attachment, pname, params) { var result = GLctx.getFramebufferAttachmentParameter(target, attachment, pname); if (result instanceof WebGLRenderbuffer || @@ -3637,7 +3637,7 @@ var LibraryGL = { , 'emulGlGenVertexArrays' #endif ], - glGenVertexArrays__sig: 'vii', + glGenVertexArrays__sig: 'vip', glGenVertexArrays: function (n, arrays) { #if LEGACY_GL_EMULATION _emulGlGenVertexArrays(n, arrays); @@ -3656,7 +3656,7 @@ var LibraryGL = { #if LEGACY_GL_EMULATION glDeleteVertexArrays__deps: ['emulGlDeleteVertexArrays'], #endif - glDeleteVertexArrays__sig: 'vii', + glDeleteVertexArrays__sig: 'vip', glDeleteVertexArrays: function(n, vaos) { #if LEGACY_GL_EMULATION _emulGlDeleteVertexArrays(n, vaos); @@ -3727,7 +3727,7 @@ var LibraryGL = { // GLES2 emulation - glVertexAttribPointer__sig: 'viiiiii', + glVertexAttribPointer__sig: 'viiiiip', glVertexAttribPointer: function(index, size, type, normalized, stride, ptr) { #if FULL_ES2 var cb = GL.currentContext.clientBuffers[index]; @@ -3793,7 +3793,7 @@ var LibraryGL = { #endif }, - glDrawElements__sig: 'viiii', + glDrawElements__sig: 'viiip', glDrawElements: function(mode, count, type, indices) { #if FULL_ES2 var buf; @@ -3866,7 +3866,7 @@ var LibraryGL = { GLctx['drawArraysInstanced'](mode, first, count, primcount); }, - glDrawElementsInstanced__sig: 'viiiii', + glDrawElementsInstanced__sig: 'viiipi', glDrawElementsInstanced: function(mode, count, type, indices, primcount) { #if GL_ASSERTIONS assert(GLctx['drawElementsInstanced'], 'Must have ANGLE_instanced_arrays extension or WebGL 2 to use WebGL instancing'); @@ -3891,7 +3891,7 @@ var LibraryGL = { glDrawBuffers__deps: ['$tempFixedLengthArray'], - glDrawBuffers__sig: 'vii', + glDrawBuffers__sig: 'vip', glDrawBuffers: function(n, bufs) { #if GL_ASSERTIONS assert(GLctx['drawBuffers'], 'Must have WebGL2 or WEBGL_draw_buffers extension to use drawBuffers'); @@ -3925,12 +3925,12 @@ var LibraryGL = { GLctx.depthMask(!!flag); }, - glSampleCoverage__sig: 'vii', + glSampleCoverage__sig: 'vfi', glSampleCoverage: function(value, invert) { GLctx.sampleCoverage(value, !!invert); }, - glMultiDrawArraysWEBGL__sig: 'viiii', + glMultiDrawArraysWEBGL__sig: 'vippi', glMultiDrawArrays: 'glMultiDrawArraysWEBGL', glMultiDrawArraysANGLE: 'glMultiDrawArraysWEBGL', glMultiDrawArraysWEBGL: function(mode, firsts, counts, drawcount) { @@ -3957,7 +3957,7 @@ var LibraryGL = { drawcount); }, - glMultiDrawElementsWEBGL__sig: 'viiiii', + glMultiDrawElementsWEBGL__sig: 'vipipi', glMultiDrawElements: 'glMultiDrawElementsWEBGL', glMultiDrawElementsANGLE: 'glMultiDrawElementsWEBGL', glMultiDrawElementsWEBGL: function(mode, counts, type, offsets, drawcount) { @@ -4023,7 +4023,7 @@ var LibraryGL = { } }, - glMapBufferRange__sig: 'iiiii', + glMapBufferRange__sig: 'pippi', glMapBufferRange__deps: ['$emscriptenWebGLGetBufferBinding', '$emscriptenWebGLValidateMapBufferTarget'], glMapBufferRange: function(target, offset, length, access) { if ((access & (0x1/*GL_MAP_READ_BIT*/ | 0x20/*GL_MAP_UNSYNCHRONIZED_BIT*/)) != 0) { @@ -4059,7 +4059,7 @@ var LibraryGL = { return mem; }, - glGetBufferPointerv__sig: 'viii', + glGetBufferPointerv__sig: 'viip', glGetBufferPointerv__deps: ['$emscriptenWebGLGetBufferBinding'], glGetBufferPointerv: function(target, pname, params) { if (pname == 0x88BD/*GL_BUFFER_MAP_POINTER*/) { @@ -4075,7 +4075,7 @@ var LibraryGL = { } }, - glFlushMappedBufferRange__sig: 'viii', + glFlushMappedBufferRange__sig: 'vipp', glFlushMappedBufferRange__deps: ['$emscriptenWebGLGetBufferBinding', '$emscriptenWebGLValidateMapBufferTarget'], glFlushMappedBufferRange: function(target, offset, length) { if (!emscriptenWebGLValidateMapBufferTarget(target)) { diff --git a/src/library_websocket.js b/src/library_websocket.js index 7e56602085387..15b93244e6114 100644 --- a/src/library_websocket.js +++ b/src/library_websocket.js @@ -12,7 +12,7 @@ var LibraryWebSocket = { emscripten_websocket_get_ready_state__deps: ['$WS'], emscripten_websocket_get_ready_state__proxy: 'sync', - emscripten_websocket_get_ready_state__sig: 'iii', + emscripten_websocket_get_ready_state__sig: 'iip', emscripten_websocket_get_ready_state: function(socketId, readyState) { var socket = WS.sockets[socketId]; if (!socket) { @@ -28,7 +28,7 @@ var LibraryWebSocket = { emscripten_websocket_get_buffered_amount__deps: ['$WS'], emscripten_websocket_get_buffered_amount__proxy: 'sync', - emscripten_websocket_get_buffered_amount__sig: 'iii', + emscripten_websocket_get_buffered_amount__sig: 'iip', emscripten_websocket_get_buffered_amount: function(socketId, bufferedAmount) { var socket = WS.sockets[socketId]; if (!socket) { @@ -44,7 +44,7 @@ var LibraryWebSocket = { emscripten_websocket_get_extensions__deps: ['$WS'], emscripten_websocket_get_extensions__proxy: 'sync', - emscripten_websocket_get_extensions__sig: 'iiii', + emscripten_websocket_get_extensions__sig: 'iipi', emscripten_websocket_get_extensions: function(socketId, extensions, extensionsLength) { var socket = WS.sockets[socketId]; if (!socket) { @@ -60,7 +60,7 @@ var LibraryWebSocket = { emscripten_websocket_get_extensions_length__deps: ['$WS'], emscripten_websocket_get_extensions_length__proxy: 'sync', - emscripten_websocket_get_extensions_length__sig: 'iii', + emscripten_websocket_get_extensions_length__sig: 'iip', emscripten_websocket_get_extensions_length: function(socketId, extensionsLength) { var socket = WS.sockets[socketId]; if (!socket) { @@ -76,7 +76,7 @@ var LibraryWebSocket = { emscripten_websocket_get_protocol__deps: ['$WS'], emscripten_websocket_get_protocol__proxy: 'sync', - emscripten_websocket_get_protocol__sig: 'iiii', + emscripten_websocket_get_protocol__sig: 'iipi', emscripten_websocket_get_protocol: function(socketId, protocol, protocolLength) { var socket = WS.sockets[socketId]; if (!socket) { @@ -92,7 +92,7 @@ var LibraryWebSocket = { emscripten_websocket_get_protocol_length__deps: ['$WS'], emscripten_websocket_get_protocol_length__proxy: 'sync', - emscripten_websocket_get_protocol_length__sig: 'iii', + emscripten_websocket_get_protocol_length__sig: 'iip', emscripten_websocket_get_protocol_length: function(socketId, protocolLength) { var socket = WS.sockets[socketId]; if (!socket) { @@ -108,7 +108,7 @@ var LibraryWebSocket = { emscripten_websocket_get_url__deps: ['$WS'], emscripten_websocket_get_url__proxy: 'sync', - emscripten_websocket_get_url__sig: 'iiii', + emscripten_websocket_get_url__sig: 'iipi', emscripten_websocket_get_url: function(socketId, url, urlLength) { var socket = WS.sockets[socketId]; if (!socket) { @@ -124,7 +124,7 @@ var LibraryWebSocket = { emscripten_websocket_get_url_length__deps: ['$WS'], emscripten_websocket_get_url_length__proxy: 'sync', - emscripten_websocket_get_url_length__sig: 'iii', + emscripten_websocket_get_url_length__sig: 'iip', emscripten_websocket_get_url_length: function(socketId, urlLength) { var socket = WS.sockets[socketId]; if (!socket) { @@ -140,7 +140,7 @@ var LibraryWebSocket = { emscripten_websocket_set_onopen_callback_on_thread__deps: ['$WS'], emscripten_websocket_set_onopen_callback_on_thread__proxy: 'sync', - emscripten_websocket_set_onopen_callback_on_thread__sig: 'iiiii', + emscripten_websocket_set_onopen_callback_on_thread__sig: 'iippp', emscripten_websocket_set_onopen_callback_on_thread: function(socketId, userData, callbackFunc, thread) { // TODO: // if (thread == {{{ cDefine('EM_CALLBACK_THREAD_CONTEXT_CALLING_THREAD') }}} || @@ -171,7 +171,7 @@ var LibraryWebSocket = { emscripten_websocket_set_onerror_callback_on_thread__deps: ['$WS'], emscripten_websocket_set_onerror_callback_on_thread__proxy: 'sync', - emscripten_websocket_set_onerror_callback_on_thread__sig: 'iiiii', + emscripten_websocket_set_onerror_callback_on_thread__sig: 'iippp', emscripten_websocket_set_onerror_callback_on_thread: function(socketId, userData, callbackFunc, thread) { if (!WS.socketEvent) WS.socketEvent = _malloc(1024); // TODO: sizeof(EmscriptenWebSocketCloseEvent), which is the largest event struct @@ -198,7 +198,7 @@ var LibraryWebSocket = { emscripten_websocket_set_onclose_callback_on_thread__deps: ['$WS'], emscripten_websocket_set_onclose_callback_on_thread__proxy: 'sync', - emscripten_websocket_set_onclose_callback_on_thread__sig: 'iiiii', + emscripten_websocket_set_onclose_callback_on_thread__sig: 'iippp', emscripten_websocket_set_onclose_callback_on_thread: function(socketId, userData, callbackFunc, thread) { if (!WS.socketEvent) WS.socketEvent = _malloc(1024); // TODO: sizeof(EmscriptenWebSocketCloseEvent), which is the largest event struct @@ -228,7 +228,7 @@ var LibraryWebSocket = { emscripten_websocket_set_onmessage_callback_on_thread__deps: ['$WS'], emscripten_websocket_set_onmessage_callback_on_thread__proxy: 'sync', - emscripten_websocket_set_onmessage_callback_on_thread__sig: 'iiiii', + emscripten_websocket_set_onmessage_callback_on_thread__sig: 'iippp', emscripten_websocket_set_onmessage_callback_on_thread: function(socketId, userData, callbackFunc, thread) { if (!WS.socketEvent) WS.socketEvent = _malloc(1024); // TODO: sizeof(EmscriptenWebSocketCloseEvent), which is the largest event struct @@ -283,7 +283,7 @@ var LibraryWebSocket = { emscripten_websocket_new__deps: ['$WS'], emscripten_websocket_new__proxy: 'sync', - emscripten_websocket_new__sig: 'ii', + emscripten_websocket_new__sig: 'ip', emscripten_websocket_new: function(createAttributes) { if (typeof WebSocket == 'undefined') { #if WEBSOCKET_DEBUG @@ -319,7 +319,7 @@ var LibraryWebSocket = { emscripten_websocket_send_utf8_text__deps: ['$WS'], emscripten_websocket_send_utf8_text__proxy: 'sync', - emscripten_websocket_send_utf8_text__sig: 'iii', + emscripten_websocket_send_utf8_text__sig: 'iip', emscripten_websocket_send_utf8_text: function(socketId, textData) { var socket = WS.sockets[socketId]; if (!socket) { @@ -343,7 +343,7 @@ var LibraryWebSocket = { emscripten_websocket_send_binary__deps: ['$WS'], emscripten_websocket_send_binary__proxy: 'sync', - emscripten_websocket_send_binary__sig: 'iiii', + emscripten_websocket_send_binary__sig: 'iipi', emscripten_websocket_send_binary: function(socketId, binaryData, dataLength) { var socket = WS.sockets[socketId]; if (!socket) { @@ -375,7 +375,7 @@ var LibraryWebSocket = { emscripten_websocket_close__deps: ['$WS'], emscripten_websocket_close__proxy: 'sync', - emscripten_websocket_close__sig: 'iiii', + emscripten_websocket_close__sig: 'iiip', emscripten_websocket_close: function(socketId, code, reason) { var socket = WS.sockets[socketId]; if (!socket) { diff --git a/src/library_wget.js b/src/library_wget.js index fb906f7f24d4b..37ce96522212f 100644 --- a/src/library_wget.js +++ b/src/library_wget.js @@ -18,7 +18,7 @@ var LibraryWget = { emscripten_async_wget__deps: ['$PATH_FS', '$wget', '$callUserCallback', '$Browser', '$withStackSave', '$allocateUTF8OnStack'], emscripten_async_wget__proxy: 'sync', - emscripten_async_wget__sig: 'viiii', + emscripten_async_wget__sig: 'vpppp', emscripten_async_wget: function(url, file, onload, onerror) { {{{ runtimeKeepalivePush() }}} @@ -61,7 +61,7 @@ var LibraryWget = { emscripten_async_wget_data__deps: ['$asyncLoad', 'malloc', 'free', '$callUserCallback'], emscripten_async_wget_data__proxy: 'sync', - emscripten_async_wget_data__sig: 'viiii', + emscripten_async_wget_data__sig: 'vpppp', emscripten_async_wget_data: function(url, arg, onload, onerror) { {{{ runtimeKeepalivePush() }}} asyncLoad(UTF8ToString(url), function(byteArray) { @@ -84,7 +84,7 @@ var LibraryWget = { emscripten_async_wget2__deps: ['$PATH_FS', '$wget', '$withStackSave', '$allocateUTF8OnStack'], emscripten_async_wget2__proxy: 'sync', - emscripten_async_wget2__sig: 'iiiiiiiii', + emscripten_async_wget2__sig: 'ipppppppp', emscripten_async_wget2: function(url, file, request, param, arg, onload, onerror, onprogress) { {{{ runtimeKeepalivePush() }}} @@ -163,7 +163,7 @@ var LibraryWget = { emscripten_async_wget2_data__deps: ['$wget', 'malloc', 'free'], emscripten_async_wget2_data__proxy: 'sync', - emscripten_async_wget2_data__sig: 'iiiiiiiii', + emscripten_async_wget2_data__sig: 'ippppippp', emscripten_async_wget2_data: function(url, request, param, arg, free, onload, onerror, onprogress) { var _url = UTF8ToString(url); var _request = UTF8ToString(request); From 04eb42db6435b7f7d15f91bc7a708767714f9af8 Mon Sep 17 00:00:00 2001 From: Jesse Wright <63333554+jeswr@users.noreply.github.com> Date: Tue, 21 Mar 2023 04:34:20 +1100 Subject: [PATCH 0028/1523] Update ChangeLog.md (#18940) --- ChangeLog.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ChangeLog.md b/ChangeLog.md index ead54a346cbae..eb67abe2524e8 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -36,6 +36,10 @@ See docs/process.md for more on how version tagging works. - The prefered way to enable pthread is now to just the the standard `-pthread` flag. The `-sUSE_PTHREADS` setting still works but is marked as legacy and will generate a warning in `-sSTRICT` mode. +- When targeting node, and using `-sMODULARIZE`, we no longer internally catch + unhandled promise rejections or exit status code. That is to say the, + `NODEJS_CATCH_REJECTION` and `NODEJS_CATCH_EXIT` are no longer compatible + with `-sMODULARIZE`. 3.1.33 - 03/08/23 ----------------- From 0f494e6c9ef17c1aa52f4b0d2b4efcd38f2f728c Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 20 Mar 2023 10:46:39 -0700 Subject: [PATCH 0029/1523] Fix a few signature that were using `long` types. NFC (#18998) The emscripten_request_animation_frame sig was just wrong since that Web API returns WebIDL `long` defined as i32. For emscripten_webgl_get_parameter_i64v use GLint64 rather than `long long` to me more explicit. For `emscripten_websocket_get_buffered_amount` using `size_t` since we already include `stdint.h` in this header anyway. I found all of these while working on #18985 which detectes the use of `long`, `size_t` or pointers and marks tham a `p` in their `__sig` attribute. --- src/library_websocket.js | 2 +- system/include/emscripten/html5.h | 4 ++-- system/include/emscripten/html5_webgl.h | 6 ++++-- system/include/emscripten/websocket.h | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/library_websocket.js b/src/library_websocket.js index 15b93244e6114..ff6fbc55c9b4b 100644 --- a/src/library_websocket.js +++ b/src/library_websocket.js @@ -38,7 +38,7 @@ var LibraryWebSocket = { return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; } - {{{ makeSetValue('bufferedAmount', '0', 'socket.bufferedAmount', 'i64') }}}; + {{{ makeSetValue('bufferedAmount', '0', 'socket.bufferedAmount', '*') }}}; return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; }, diff --git a/system/include/emscripten/html5.h b/system/include/emscripten/html5.h index 032162161c756..1b3481d7f83ff 100644 --- a/system/include/emscripten/html5.h +++ b/system/include/emscripten/html5.h @@ -476,8 +476,8 @@ void emscripten_html5_remove_all_event_listeners(void); #define emscripten_set_batterylevelchange_callback(userData, callback) emscripten_set_batterylevelchange_callback_on_thread( (userData), (callback), EM_CALLBACK_THREAD_CONTEXT_CALLING_THREAD) #define emscripten_set_beforeunload_callback(userData, callback) emscripten_set_beforeunload_callback_on_thread( (userData), (callback), EM_CALLBACK_THREAD_CONTEXT_MAIN_RUNTIME_THREAD) -long emscripten_request_animation_frame(EM_BOOL (*cb)(double time, void *userData), void *userData); -void emscripten_cancel_animation_frame(long requestAnimationFrameId); +int emscripten_request_animation_frame(EM_BOOL (*cb)(double time, void *userData), void *userData); +void emscripten_cancel_animation_frame(int requestAnimationFrameId); void emscripten_request_animation_frame_loop(EM_BOOL (*cb)(double time, void *userData), void *userData); double emscripten_date_now(void); diff --git a/system/include/emscripten/html5_webgl.h b/system/include/emscripten/html5_webgl.h index 41a45e75160c2..ed20cbd8f0931 100644 --- a/system/include/emscripten/html5_webgl.h +++ b/system/include/emscripten/html5_webgl.h @@ -100,6 +100,7 @@ void *emscripten_webgl_get_proc_address(const char *name __attribute__((nonnull) #define GLint int #define GLenum int +#define GLint64 long long int #define EMSCRIPTEN_WEBGL_PARAM_TYPE int #define EMSCRIPTEN_WEBGL_PARAM_TYPE_INT 0 @@ -188,12 +189,13 @@ GLint emscripten_webgl_get_parameter_o(GLenum param); char *emscripten_webgl_get_parameter_utf8(GLenum param); // Calls GLctx.getParameter(): -// Returns the given WebGL context state as long long, written to the given heap location. +// Returns the given WebGL context state as GLint64, written to the given heap location. // Call this function only for values of 'param' that return a WebGL Number type. -void emscripten_webgl_get_parameter_i64v(GLenum param, long long *dst __attribute__((nonnull))); +void emscripten_webgl_get_parameter_i64v(GLenum param, GLint64 *dst __attribute__((nonnull))); #undef GLint #undef GLenum +#undef GLint64 #ifdef __cplusplus } // ~extern "C" diff --git a/system/include/emscripten/websocket.h b/system/include/emscripten/websocket.h index 679e32478ec6f..11cf8a4024291 100644 --- a/system/include/emscripten/websocket.h +++ b/system/include/emscripten/websocket.h @@ -23,7 +23,7 @@ extern "C" { EMSCRIPTEN_RESULT emscripten_websocket_get_ready_state(EMSCRIPTEN_WEBSOCKET_T socket, unsigned short *readyState __attribute__((nonnull))); // Returns the WebSocket.bufferedAmount field into bufferedAmount. bufferedAmount must not be a null pointer. -EMSCRIPTEN_RESULT emscripten_websocket_get_buffered_amount(EMSCRIPTEN_WEBSOCKET_T socket, unsigned long long *bufferedAmount __attribute__((nonnull))); +EMSCRIPTEN_RESULT emscripten_websocket_get_buffered_amount(EMSCRIPTEN_WEBSOCKET_T socket, size_t *bufferedAmount __attribute__((nonnull))); // Writes the WebSocket.url field as a UTF-8 string to the memory area pointed by url. The memory area must contain at least urlLength bytes of free space. If this memory area cannot // fit the url string, it will be truncated. Call emscripten_websocket_get_url_length() to determine how large memory area will be required to store the url. From e5e97d2acf9a04731096c25094c908f0298e0724 Mon Sep 17 00:00:00 2001 From: juj Date: Mon, 20 Mar 2023 21:02:14 +0200 Subject: [PATCH 0030/1523] Add brotli support to emrun.py (#19011) * Add brotli support to emrun.py * Remove lookup to Accept-Encoding for gzip --- emrun.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/emrun.py b/emrun.py index 59a95b40317b8..41254e5be05e8 100644 --- a/emrun.py +++ b/emrun.py @@ -637,12 +637,18 @@ def send_head(self): # gzipped file, instead of having the browser decompress it immediately, # then it can't use the suffix .gz when using emrun. # To work around, one can use the suffix .gzip instead. - if 'Accept-Encoding' in self.headers and 'gzip' in self.headers['Accept-Encoding'] and path.lower().endswith('gz'): + if path.lower().endswith('gz'): self.send_header('Content-Encoding', 'gzip') logv('Serving ' + path + ' as gzip-compressed.') guess_file_type = guess_file_type[:-2] if guess_file_type.endswith('.'): guess_file_type = guess_file_type[:-1] + elif path.lower().endswith('br'): + self.send_header('Content-Encoding', 'br') + logv('Serving ' + path + ' as brotli-compressed.') + guess_file_type = guess_file_type[:-2] + if guess_file_type.endswith('.'): + guess_file_type = guess_file_type[:-1] ctype = self.guess_type(guess_file_type) if guess_file_type.lower().endswith('.wasm'): From 1accb153d9509145de75b39ab4dcba71720a18c4 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 20 Mar 2023 15:36:29 -0700 Subject: [PATCH 0031/1523] Fix signature of _emval_as_int64/_emval_as_uint64 in JS. NFC (#19005) Split out from #18995 since I noticed that it wasn't just the `__sig` by actually the argument list that was wrong in this case. --- src/embind/emval.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/embind/emval.js b/src/embind/emval.js index c540fc64e2a2e..42f95b54071ac 100644 --- a/src/embind/emval.js +++ b/src/embind/emval.js @@ -328,7 +328,7 @@ var LibraryEmVal = { _emval_as_int64__deps: ['$Emval', '$requireRegisteredType'], _emval_as_int64__sig: 'jpp', - _emval_as_int64: function(handle, returnType, destructorsRef) { + _emval_as_int64: function(handle, returnType) { handle = Emval.toValue(handle); returnType = requireRegisteredType(returnType, 'emval::as'); return returnType['toWireType'](null, handle); @@ -336,7 +336,7 @@ var LibraryEmVal = { _emval_as_uint64__deps: ['$Emval', '$requireRegisteredType'], _emval_as_uint64__sig: 'jpp', - _emval_as_uint64: function(handle, returnType, destructorsRef) { + _emval_as_uint64: function(handle, returnType) { handle = Emval.toValue(handle); returnType = requireRegisteredType(returnType, 'emval::as'); return returnType['toWireType'](null, handle); From 385e037476cca8d45bb3fbcb85a5a72e42a296bc Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 20 Mar 2023 15:47:56 -0700 Subject: [PATCH 0032/1523] Use new cDefs proxy object rather than cDefines function. NFC (#19015) This allows for less syntax when specifying C defines in JS code. We still need the ugly triple braces but we can avoid the extra quotation marks and function call braces. This is how we already use the `cStructs` object. --- ChangeLog.md | 2 + src/Fetch.js | 28 +- src/library.js | 632 +++++++++++++++---------------- src/library_dylink.js | 6 +- src/library_fs.js | 298 +++++++-------- src/library_html5.js | 420 ++++++++++---------- src/library_html5_webgl.js | 40 +- src/library_lz4.js | 26 +- src/library_memfs.js | 26 +- src/library_nodefs.js | 44 +-- src/library_noderawfs.js | 22 +- src/library_openal.js | 596 ++++++++++++++--------------- src/library_pipefs.js | 22 +- src/library_promise.js | 16 +- src/library_proxyfs.js | 4 +- src/library_pthread.js | 18 +- src/library_sdl.js | 30 +- src/library_sockfs.js | 94 ++--- src/library_syscall.js | 190 +++++----- src/library_tty.js | 12 +- src/library_uuid.js | 4 +- src/library_wasi.js | 52 +-- src/library_wasmfs.js | 20 +- src/library_wasmfs_fetch.js | 2 +- src/library_wasmfs_js_file.js | 2 +- src/library_wasmfs_opfs.js | 52 +-- src/library_webgl.js | 50 +-- src/library_webgl2.js | 18 +- src/library_websocket.js | 82 ++-- src/library_workerfs.js | 24 +- src/modules.js | 26 +- src/worker.js | 2 +- test/test_other.py | 13 + tools/maint/check_struct_info.py | 2 +- 34 files changed, 1455 insertions(+), 1420 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index eb67abe2524e8..7eb007aa20c47 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -27,6 +27,8 @@ See docs/process.md for more on how version tagging works. folks who had JS files with lines that start with `#` so can't be run through the pre-processor. If folks want to re-enable this we can looks into ways to make it conditional/optional. +- The `{{{ cDefine('name') }}}` helper macro can now be simplified to just `{{{ + cDefs.name }}}`. 3.1.34 - 03/14/23 ----------------- diff --git a/src/Fetch.js b/src/Fetch.js index 1913b5fe24568..ed8970ffd4669 100644 --- a/src/Fetch.js +++ b/src/Fetch.js @@ -253,15 +253,15 @@ function fetchXHR(fetch, onsuccess, onerror, onprogress, onreadystatechange) { var dataPtr = HEAPU32[fetch_attr + {{{ C_STRUCTS.emscripten_fetch_attr_t.requestData }}} >> 2]; var dataLength = HEAPU32[fetch_attr + {{{ C_STRUCTS.emscripten_fetch_attr_t.requestDataSize }}} >> 2]; - var fetchAttrLoadToMemory = !!(fetchAttributes & {{{ cDefine('EMSCRIPTEN_FETCH_LOAD_TO_MEMORY') }}}); - var fetchAttrStreamData = !!(fetchAttributes & {{{ cDefine('EMSCRIPTEN_FETCH_STREAM_DATA') }}}); + var fetchAttrLoadToMemory = !!(fetchAttributes & {{{ cDefs.EMSCRIPTEN_FETCH_LOAD_TO_MEMORY }}}); + var fetchAttrStreamData = !!(fetchAttributes & {{{ cDefs.EMSCRIPTEN_FETCH_STREAM_DATA }}}); #if FETCH_SUPPORT_INDEXEDDB - var fetchAttrPersistFile = !!(fetchAttributes & {{{ cDefine('EMSCRIPTEN_FETCH_PERSIST_FILE') }}}); + var fetchAttrPersistFile = !!(fetchAttributes & {{{ cDefs.EMSCRIPTEN_FETCH_PERSIST_FILE }}}); #endif - var fetchAttrAppend = !!(fetchAttributes & {{{ cDefine('EMSCRIPTEN_FETCH_APPEND') }}}); - var fetchAttrReplace = !!(fetchAttributes & {{{ cDefine('EMSCRIPTEN_FETCH_REPLACE') }}}); - var fetchAttrSynchronous = !!(fetchAttributes & {{{ cDefine('EMSCRIPTEN_FETCH_SYNCHRONOUS') }}}); - var fetchAttrWaitable = !!(fetchAttributes & {{{ cDefine('EMSCRIPTEN_FETCH_WAITABLE') }}}); + var fetchAttrAppend = !!(fetchAttributes & {{{ cDefs.EMSCRIPTEN_FETCH_APPEND }}}); + var fetchAttrReplace = !!(fetchAttributes & {{{ cDefs.EMSCRIPTEN_FETCH_REPLACE }}}); + var fetchAttrSynchronous = !!(fetchAttributes & {{{ cDefs.EMSCRIPTEN_FETCH_SYNCHRONOUS }}}); + var fetchAttrWaitable = !!(fetchAttributes & {{{ cDefs.EMSCRIPTEN_FETCH_WAITABLE }}}); var userNameStr = userName ? UTF8ToString(userName) : undefined; var passwordStr = password ? UTF8ToString(password) : undefined; @@ -449,15 +449,15 @@ function startFetch(fetch, successcb, errorcb, progresscb, readystatechangecb) { var onprogress = HEAPU32[fetch_attr + {{{ C_STRUCTS.emscripten_fetch_attr_t.onprogress }}} >> 2]; var onreadystatechange = HEAPU32[fetch_attr + {{{ C_STRUCTS.emscripten_fetch_attr_t.onreadystatechange }}} >> 2]; var fetchAttributes = HEAPU32[fetch_attr + {{{ C_STRUCTS.emscripten_fetch_attr_t.attributes }}} >> 2]; - var fetchAttrLoadToMemory = !!(fetchAttributes & {{{ cDefine('EMSCRIPTEN_FETCH_LOAD_TO_MEMORY') }}}); - var fetchAttrStreamData = !!(fetchAttributes & {{{ cDefine('EMSCRIPTEN_FETCH_STREAM_DATA') }}}); + var fetchAttrLoadToMemory = !!(fetchAttributes & {{{ cDefs.EMSCRIPTEN_FETCH_LOAD_TO_MEMORY }}}); + var fetchAttrStreamData = !!(fetchAttributes & {{{ cDefs.EMSCRIPTEN_FETCH_STREAM_DATA }}}); #if FETCH_SUPPORT_INDEXEDDB - var fetchAttrPersistFile = !!(fetchAttributes & {{{ cDefine('EMSCRIPTEN_FETCH_PERSIST_FILE') }}}); - var fetchAttrNoDownload = !!(fetchAttributes & {{{ cDefine('EMSCRIPTEN_FETCH_NO_DOWNLOAD') }}}); + var fetchAttrPersistFile = !!(fetchAttributes & {{{ cDefs.EMSCRIPTEN_FETCH_PERSIST_FILE }}}); + var fetchAttrNoDownload = !!(fetchAttributes & {{{ cDefs.EMSCRIPTEN_FETCH_NO_DOWNLOAD }}}); #endif - var fetchAttrAppend = !!(fetchAttributes & {{{ cDefine('EMSCRIPTEN_FETCH_APPEND') }}}); - var fetchAttrReplace = !!(fetchAttributes & {{{ cDefine('EMSCRIPTEN_FETCH_REPLACE') }}}); - var fetchAttrSynchronous = !!(fetchAttributes & {{{ cDefine('EMSCRIPTEN_FETCH_SYNCHRONOUS') }}}); + var fetchAttrAppend = !!(fetchAttributes & {{{ cDefs.EMSCRIPTEN_FETCH_APPEND }}}); + var fetchAttrReplace = !!(fetchAttributes & {{{ cDefs.EMSCRIPTEN_FETCH_REPLACE }}}); + var fetchAttrSynchronous = !!(fetchAttributes & {{{ cDefs.EMSCRIPTEN_FETCH_SYNCHRONOUS }}}); function doCallback(f) { if (fetchAttrSynchronous) { diff --git a/src/library.js b/src/library.js index 4e80f15ca8aa4..94f9d5c72720e 100644 --- a/src/library.js +++ b/src/library.js @@ -362,7 +362,7 @@ mergeInto(LibraryManager.library, { // http://pubs.opengroup.org/onlinepubs/000095399/functions/system.html // Can't call external programs. if (!command) return 0; // no shell available - setErrNo({{{ cDefine('ENOSYS') }}}); + setErrNo({{{ cDefs.ENOSYS }}}); return -1; }, @@ -1280,251 +1280,251 @@ mergeInto(LibraryManager.library, { // ========================================================================== $ERRNO_CODES__postset: `ERRNO_CODES = { - 'EPERM': {{{ cDefine('EPERM') }}}, - 'ENOENT': {{{ cDefine('ENOENT') }}}, - 'ESRCH': {{{ cDefine('ESRCH') }}}, - 'EINTR': {{{ cDefine('EINTR') }}}, - 'EIO': {{{ cDefine('EIO') }}}, - 'ENXIO': {{{ cDefine('ENXIO') }}}, - 'E2BIG': {{{ cDefine('E2BIG') }}}, - 'ENOEXEC': {{{ cDefine('ENOEXEC') }}}, - 'EBADF': {{{ cDefine('EBADF') }}}, - 'ECHILD': {{{ cDefine('ECHILD') }}}, - 'EAGAIN': {{{ cDefine('EAGAIN') }}}, - 'EWOULDBLOCK': {{{ cDefine('EWOULDBLOCK') }}}, - 'ENOMEM': {{{ cDefine('ENOMEM') }}}, - 'EACCES': {{{ cDefine('EACCES') }}}, - 'EFAULT': {{{ cDefine('EFAULT') }}}, - 'ENOTBLK': {{{ cDefine('ENOTBLK') }}}, - 'EBUSY': {{{ cDefine('EBUSY') }}}, - 'EEXIST': {{{ cDefine('EEXIST') }}}, - 'EXDEV': {{{ cDefine('EXDEV') }}}, - 'ENODEV': {{{ cDefine('ENODEV') }}}, - 'ENOTDIR': {{{ cDefine('ENOTDIR') }}}, - 'EISDIR': {{{ cDefine('EISDIR') }}}, - 'EINVAL': {{{ cDefine('EINVAL') }}}, - 'ENFILE': {{{ cDefine('ENFILE') }}}, - 'EMFILE': {{{ cDefine('EMFILE') }}}, - 'ENOTTY': {{{ cDefine('ENOTTY') }}}, - 'ETXTBSY': {{{ cDefine('ETXTBSY') }}}, - 'EFBIG': {{{ cDefine('EFBIG') }}}, - 'ENOSPC': {{{ cDefine('ENOSPC') }}}, - 'ESPIPE': {{{ cDefine('ESPIPE') }}}, - 'EROFS': {{{ cDefine('EROFS') }}}, - 'EMLINK': {{{ cDefine('EMLINK') }}}, - 'EPIPE': {{{ cDefine('EPIPE') }}}, - 'EDOM': {{{ cDefine('EDOM') }}}, - 'ERANGE': {{{ cDefine('ERANGE') }}}, - 'ENOMSG': {{{ cDefine('ENOMSG') }}}, - 'EIDRM': {{{ cDefine('EIDRM') }}}, - 'ECHRNG': {{{ cDefine('ECHRNG') }}}, - 'EL2NSYNC': {{{ cDefine('EL2NSYNC') }}}, - 'EL3HLT': {{{ cDefine('EL3HLT') }}}, - 'EL3RST': {{{ cDefine('EL3RST') }}}, - 'ELNRNG': {{{ cDefine('ELNRNG') }}}, - 'EUNATCH': {{{ cDefine('EUNATCH') }}}, - 'ENOCSI': {{{ cDefine('ENOCSI') }}}, - 'EL2HLT': {{{ cDefine('EL2HLT') }}}, - 'EDEADLK': {{{ cDefine('EDEADLK') }}}, - 'ENOLCK': {{{ cDefine('ENOLCK') }}}, - 'EBADE': {{{ cDefine('EBADE') }}}, - 'EBADR': {{{ cDefine('EBADR') }}}, - 'EXFULL': {{{ cDefine('EXFULL') }}}, - 'ENOANO': {{{ cDefine('ENOANO') }}}, - 'EBADRQC': {{{ cDefine('EBADRQC') }}}, - 'EBADSLT': {{{ cDefine('EBADSLT') }}}, - 'EDEADLOCK': {{{ cDefine('EDEADLOCK') }}}, - 'EBFONT': {{{ cDefine('EBFONT') }}}, - 'ENOSTR': {{{ cDefine('ENOSTR') }}}, - 'ENODATA': {{{ cDefine('ENODATA') }}}, - 'ETIME': {{{ cDefine('ETIME') }}}, - 'ENOSR': {{{ cDefine('ENOSR') }}}, - 'ENONET': {{{ cDefine('ENONET') }}}, - 'ENOPKG': {{{ cDefine('ENOPKG') }}}, - 'EREMOTE': {{{ cDefine('EREMOTE') }}}, - 'ENOLINK': {{{ cDefine('ENOLINK') }}}, - 'EADV': {{{ cDefine('EADV') }}}, - 'ESRMNT': {{{ cDefine('ESRMNT') }}}, - 'ECOMM': {{{ cDefine('ECOMM') }}}, - 'EPROTO': {{{ cDefine('EPROTO') }}}, - 'EMULTIHOP': {{{ cDefine('EMULTIHOP') }}}, - 'EDOTDOT': {{{ cDefine('EDOTDOT') }}}, - 'EBADMSG': {{{ cDefine('EBADMSG') }}}, - 'ENOTUNIQ': {{{ cDefine('ENOTUNIQ') }}}, - 'EBADFD': {{{ cDefine('EBADFD') }}}, - 'EREMCHG': {{{ cDefine('EREMCHG') }}}, - 'ELIBACC': {{{ cDefine('ELIBACC') }}}, - 'ELIBBAD': {{{ cDefine('ELIBBAD') }}}, - 'ELIBSCN': {{{ cDefine('ELIBSCN') }}}, - 'ELIBMAX': {{{ cDefine('ELIBMAX') }}}, - 'ELIBEXEC': {{{ cDefine('ELIBEXEC') }}}, - 'ENOSYS': {{{ cDefine('ENOSYS') }}}, - 'ENOTEMPTY': {{{ cDefine('ENOTEMPTY') }}}, - 'ENAMETOOLONG': {{{ cDefine('ENAMETOOLONG') }}}, - 'ELOOP': {{{ cDefine('ELOOP') }}}, - 'EOPNOTSUPP': {{{ cDefine('EOPNOTSUPP') }}}, - 'EPFNOSUPPORT': {{{ cDefine('EPFNOSUPPORT') }}}, - 'ECONNRESET': {{{ cDefine('ECONNRESET') }}}, - 'ENOBUFS': {{{ cDefine('ENOBUFS') }}}, - 'EAFNOSUPPORT': {{{ cDefine('EAFNOSUPPORT') }}}, - 'EPROTOTYPE': {{{ cDefine('EPROTOTYPE') }}}, - 'ENOTSOCK': {{{ cDefine('ENOTSOCK') }}}, - 'ENOPROTOOPT': {{{ cDefine('ENOPROTOOPT') }}}, - 'ESHUTDOWN': {{{ cDefine('ESHUTDOWN') }}}, - 'ECONNREFUSED': {{{ cDefine('ECONNREFUSED') }}}, - 'EADDRINUSE': {{{ cDefine('EADDRINUSE') }}}, - 'ECONNABORTED': {{{ cDefine('ECONNABORTED') }}}, - 'ENETUNREACH': {{{ cDefine('ENETUNREACH') }}}, - 'ENETDOWN': {{{ cDefine('ENETDOWN') }}}, - 'ETIMEDOUT': {{{ cDefine('ETIMEDOUT') }}}, - 'EHOSTDOWN': {{{ cDefine('EHOSTDOWN') }}}, - 'EHOSTUNREACH': {{{ cDefine('EHOSTUNREACH') }}}, - 'EINPROGRESS': {{{ cDefine('EINPROGRESS') }}}, - 'EALREADY': {{{ cDefine('EALREADY') }}}, - 'EDESTADDRREQ': {{{ cDefine('EDESTADDRREQ') }}}, - 'EMSGSIZE': {{{ cDefine('EMSGSIZE') }}}, - 'EPROTONOSUPPORT': {{{ cDefine('EPROTONOSUPPORT') }}}, - 'ESOCKTNOSUPPORT': {{{ cDefine('ESOCKTNOSUPPORT') }}}, - 'EADDRNOTAVAIL': {{{ cDefine('EADDRNOTAVAIL') }}}, - 'ENETRESET': {{{ cDefine('ENETRESET') }}}, - 'EISCONN': {{{ cDefine('EISCONN') }}}, - 'ENOTCONN': {{{ cDefine('ENOTCONN') }}}, - 'ETOOMANYREFS': {{{ cDefine('ETOOMANYREFS') }}}, - 'EUSERS': {{{ cDefine('EUSERS') }}}, - 'EDQUOT': {{{ cDefine('EDQUOT') }}}, - 'ESTALE': {{{ cDefine('ESTALE') }}}, - 'ENOTSUP': {{{ cDefine('ENOTSUP') }}}, - 'ENOMEDIUM': {{{ cDefine('ENOMEDIUM') }}}, - 'EILSEQ': {{{ cDefine('EILSEQ') }}}, - 'EOVERFLOW': {{{ cDefine('EOVERFLOW') }}}, - 'ECANCELED': {{{ cDefine('ECANCELED') }}}, - 'ENOTRECOVERABLE': {{{ cDefine('ENOTRECOVERABLE') }}}, - 'EOWNERDEAD': {{{ cDefine('EOWNERDEAD') }}}, - 'ESTRPIPE': {{{ cDefine('ESTRPIPE') }}}, + 'EPERM': {{{ cDefs.EPERM }}}, + 'ENOENT': {{{ cDefs.ENOENT }}}, + 'ESRCH': {{{ cDefs.ESRCH }}}, + 'EINTR': {{{ cDefs.EINTR }}}, + 'EIO': {{{ cDefs.EIO }}}, + 'ENXIO': {{{ cDefs.ENXIO }}}, + 'E2BIG': {{{ cDefs.E2BIG }}}, + 'ENOEXEC': {{{ cDefs.ENOEXEC }}}, + 'EBADF': {{{ cDefs.EBADF }}}, + 'ECHILD': {{{ cDefs.ECHILD }}}, + 'EAGAIN': {{{ cDefs.EAGAIN }}}, + 'EWOULDBLOCK': {{{ cDefs.EWOULDBLOCK }}}, + 'ENOMEM': {{{ cDefs.ENOMEM }}}, + 'EACCES': {{{ cDefs.EACCES }}}, + 'EFAULT': {{{ cDefs.EFAULT }}}, + 'ENOTBLK': {{{ cDefs.ENOTBLK }}}, + 'EBUSY': {{{ cDefs.EBUSY }}}, + 'EEXIST': {{{ cDefs.EEXIST }}}, + 'EXDEV': {{{ cDefs.EXDEV }}}, + 'ENODEV': {{{ cDefs.ENODEV }}}, + 'ENOTDIR': {{{ cDefs.ENOTDIR }}}, + 'EISDIR': {{{ cDefs.EISDIR }}}, + 'EINVAL': {{{ cDefs.EINVAL }}}, + 'ENFILE': {{{ cDefs.ENFILE }}}, + 'EMFILE': {{{ cDefs.EMFILE }}}, + 'ENOTTY': {{{ cDefs.ENOTTY }}}, + 'ETXTBSY': {{{ cDefs.ETXTBSY }}}, + 'EFBIG': {{{ cDefs.EFBIG }}}, + 'ENOSPC': {{{ cDefs.ENOSPC }}}, + 'ESPIPE': {{{ cDefs.ESPIPE }}}, + 'EROFS': {{{ cDefs.EROFS }}}, + 'EMLINK': {{{ cDefs.EMLINK }}}, + 'EPIPE': {{{ cDefs.EPIPE }}}, + 'EDOM': {{{ cDefs.EDOM }}}, + 'ERANGE': {{{ cDefs.ERANGE }}}, + 'ENOMSG': {{{ cDefs.ENOMSG }}}, + 'EIDRM': {{{ cDefs.EIDRM }}}, + 'ECHRNG': {{{ cDefs.ECHRNG }}}, + 'EL2NSYNC': {{{ cDefs.EL2NSYNC }}}, + 'EL3HLT': {{{ cDefs.EL3HLT }}}, + 'EL3RST': {{{ cDefs.EL3RST }}}, + 'ELNRNG': {{{ cDefs.ELNRNG }}}, + 'EUNATCH': {{{ cDefs.EUNATCH }}}, + 'ENOCSI': {{{ cDefs.ENOCSI }}}, + 'EL2HLT': {{{ cDefs.EL2HLT }}}, + 'EDEADLK': {{{ cDefs.EDEADLK }}}, + 'ENOLCK': {{{ cDefs.ENOLCK }}}, + 'EBADE': {{{ cDefs.EBADE }}}, + 'EBADR': {{{ cDefs.EBADR }}}, + 'EXFULL': {{{ cDefs.EXFULL }}}, + 'ENOANO': {{{ cDefs.ENOANO }}}, + 'EBADRQC': {{{ cDefs.EBADRQC }}}, + 'EBADSLT': {{{ cDefs.EBADSLT }}}, + 'EDEADLOCK': {{{ cDefs.EDEADLOCK }}}, + 'EBFONT': {{{ cDefs.EBFONT }}}, + 'ENOSTR': {{{ cDefs.ENOSTR }}}, + 'ENODATA': {{{ cDefs.ENODATA }}}, + 'ETIME': {{{ cDefs.ETIME }}}, + 'ENOSR': {{{ cDefs.ENOSR }}}, + 'ENONET': {{{ cDefs.ENONET }}}, + 'ENOPKG': {{{ cDefs.ENOPKG }}}, + 'EREMOTE': {{{ cDefs.EREMOTE }}}, + 'ENOLINK': {{{ cDefs.ENOLINK }}}, + 'EADV': {{{ cDefs.EADV }}}, + 'ESRMNT': {{{ cDefs.ESRMNT }}}, + 'ECOMM': {{{ cDefs.ECOMM }}}, + 'EPROTO': {{{ cDefs.EPROTO }}}, + 'EMULTIHOP': {{{ cDefs.EMULTIHOP }}}, + 'EDOTDOT': {{{ cDefs.EDOTDOT }}}, + 'EBADMSG': {{{ cDefs.EBADMSG }}}, + 'ENOTUNIQ': {{{ cDefs.ENOTUNIQ }}}, + 'EBADFD': {{{ cDefs.EBADFD }}}, + 'EREMCHG': {{{ cDefs.EREMCHG }}}, + 'ELIBACC': {{{ cDefs.ELIBACC }}}, + 'ELIBBAD': {{{ cDefs.ELIBBAD }}}, + 'ELIBSCN': {{{ cDefs.ELIBSCN }}}, + 'ELIBMAX': {{{ cDefs.ELIBMAX }}}, + 'ELIBEXEC': {{{ cDefs.ELIBEXEC }}}, + 'ENOSYS': {{{ cDefs.ENOSYS }}}, + 'ENOTEMPTY': {{{ cDefs.ENOTEMPTY }}}, + 'ENAMETOOLONG': {{{ cDefs.ENAMETOOLONG }}}, + 'ELOOP': {{{ cDefs.ELOOP }}}, + 'EOPNOTSUPP': {{{ cDefs.EOPNOTSUPP }}}, + 'EPFNOSUPPORT': {{{ cDefs.EPFNOSUPPORT }}}, + 'ECONNRESET': {{{ cDefs.ECONNRESET }}}, + 'ENOBUFS': {{{ cDefs.ENOBUFS }}}, + 'EAFNOSUPPORT': {{{ cDefs.EAFNOSUPPORT }}}, + 'EPROTOTYPE': {{{ cDefs.EPROTOTYPE }}}, + 'ENOTSOCK': {{{ cDefs.ENOTSOCK }}}, + 'ENOPROTOOPT': {{{ cDefs.ENOPROTOOPT }}}, + 'ESHUTDOWN': {{{ cDefs.ESHUTDOWN }}}, + 'ECONNREFUSED': {{{ cDefs.ECONNREFUSED }}}, + 'EADDRINUSE': {{{ cDefs.EADDRINUSE }}}, + 'ECONNABORTED': {{{ cDefs.ECONNABORTED }}}, + 'ENETUNREACH': {{{ cDefs.ENETUNREACH }}}, + 'ENETDOWN': {{{ cDefs.ENETDOWN }}}, + 'ETIMEDOUT': {{{ cDefs.ETIMEDOUT }}}, + 'EHOSTDOWN': {{{ cDefs.EHOSTDOWN }}}, + 'EHOSTUNREACH': {{{ cDefs.EHOSTUNREACH }}}, + 'EINPROGRESS': {{{ cDefs.EINPROGRESS }}}, + 'EALREADY': {{{ cDefs.EALREADY }}}, + 'EDESTADDRREQ': {{{ cDefs.EDESTADDRREQ }}}, + 'EMSGSIZE': {{{ cDefs.EMSGSIZE }}}, + 'EPROTONOSUPPORT': {{{ cDefs.EPROTONOSUPPORT }}}, + 'ESOCKTNOSUPPORT': {{{ cDefs.ESOCKTNOSUPPORT }}}, + 'EADDRNOTAVAIL': {{{ cDefs.EADDRNOTAVAIL }}}, + 'ENETRESET': {{{ cDefs.ENETRESET }}}, + 'EISCONN': {{{ cDefs.EISCONN }}}, + 'ENOTCONN': {{{ cDefs.ENOTCONN }}}, + 'ETOOMANYREFS': {{{ cDefs.ETOOMANYREFS }}}, + 'EUSERS': {{{ cDefs.EUSERS }}}, + 'EDQUOT': {{{ cDefs.EDQUOT }}}, + 'ESTALE': {{{ cDefs.ESTALE }}}, + 'ENOTSUP': {{{ cDefs.ENOTSUP }}}, + 'ENOMEDIUM': {{{ cDefs.ENOMEDIUM }}}, + 'EILSEQ': {{{ cDefs.EILSEQ }}}, + 'EOVERFLOW': {{{ cDefs.EOVERFLOW }}}, + 'ECANCELED': {{{ cDefs.ECANCELED }}}, + 'ENOTRECOVERABLE': {{{ cDefs.ENOTRECOVERABLE }}}, + 'EOWNERDEAD': {{{ cDefs.EOWNERDEAD }}}, + 'ESTRPIPE': {{{ cDefs.ESTRPIPE }}}, };`, $ERRNO_CODES: {}, $ERRNO_MESSAGES: { 0: 'Success', - {{{ cDefine('EPERM') }}}: 'Not super-user', - {{{ cDefine('ENOENT') }}}: 'No such file or directory', - {{{ cDefine('ESRCH') }}}: 'No such process', - {{{ cDefine('EINTR') }}}: 'Interrupted system call', - {{{ cDefine('EIO') }}}: 'I/O error', - {{{ cDefine('ENXIO') }}}: 'No such device or address', - {{{ cDefine('E2BIG') }}}: 'Arg list too long', - {{{ cDefine('ENOEXEC') }}}: 'Exec format error', - {{{ cDefine('EBADF') }}}: 'Bad file number', - {{{ cDefine('ECHILD') }}}: 'No children', - {{{ cDefine('EWOULDBLOCK') }}}: 'No more processes', - {{{ cDefine('ENOMEM') }}}: 'Not enough core', - {{{ cDefine('EACCES') }}}: 'Permission denied', - {{{ cDefine('EFAULT') }}}: 'Bad address', - {{{ cDefine('ENOTBLK') }}}: 'Block device required', - {{{ cDefine('EBUSY') }}}: 'Mount device busy', - {{{ cDefine('EEXIST') }}}: 'File exists', - {{{ cDefine('EXDEV') }}}: 'Cross-device link', - {{{ cDefine('ENODEV') }}}: 'No such device', - {{{ cDefine('ENOTDIR') }}}: 'Not a directory', - {{{ cDefine('EISDIR') }}}: 'Is a directory', - {{{ cDefine('EINVAL') }}}: 'Invalid argument', - {{{ cDefine('ENFILE') }}}: 'Too many open files in system', - {{{ cDefine('EMFILE') }}}: 'Too many open files', - {{{ cDefine('ENOTTY') }}}: 'Not a typewriter', - {{{ cDefine('ETXTBSY') }}}: 'Text file busy', - {{{ cDefine('EFBIG') }}}: 'File too large', - {{{ cDefine('ENOSPC') }}}: 'No space left on device', - {{{ cDefine('ESPIPE') }}}: 'Illegal seek', - {{{ cDefine('EROFS') }}}: 'Read only file system', - {{{ cDefine('EMLINK') }}}: 'Too many links', - {{{ cDefine('EPIPE') }}}: 'Broken pipe', - {{{ cDefine('EDOM') }}}: 'Math arg out of domain of func', - {{{ cDefine('ERANGE') }}}: 'Math result not representable', - {{{ cDefine('ENOMSG') }}}: 'No message of desired type', - {{{ cDefine('EIDRM') }}}: 'Identifier removed', - {{{ cDefine('ECHRNG') }}}: 'Channel number out of range', - {{{ cDefine('EL2NSYNC') }}}: 'Level 2 not synchronized', - {{{ cDefine('EL3HLT') }}}: 'Level 3 halted', - {{{ cDefine('EL3RST') }}}: 'Level 3 reset', - {{{ cDefine('ELNRNG') }}}: 'Link number out of range', - {{{ cDefine('EUNATCH') }}}: 'Protocol driver not attached', - {{{ cDefine('ENOCSI') }}}: 'No CSI structure available', - {{{ cDefine('EL2HLT') }}}: 'Level 2 halted', - {{{ cDefine('EDEADLK') }}}: 'Deadlock condition', - {{{ cDefine('ENOLCK') }}}: 'No record locks available', - {{{ cDefine('EBADE') }}}: 'Invalid exchange', - {{{ cDefine('EBADR') }}}: 'Invalid request descriptor', - {{{ cDefine('EXFULL') }}}: 'Exchange full', - {{{ cDefine('ENOANO') }}}: 'No anode', - {{{ cDefine('EBADRQC') }}}: 'Invalid request code', - {{{ cDefine('EBADSLT') }}}: 'Invalid slot', - {{{ cDefine('EDEADLOCK') }}}: 'File locking deadlock error', - {{{ cDefine('EBFONT') }}}: 'Bad font file fmt', - {{{ cDefine('ENOSTR') }}}: 'Device not a stream', - {{{ cDefine('ENODATA') }}}: 'No data (for no delay io)', - {{{ cDefine('ETIME') }}}: 'Timer expired', - {{{ cDefine('ENOSR') }}}: 'Out of streams resources', - {{{ cDefine('ENONET') }}}: 'Machine is not on the network', - {{{ cDefine('ENOPKG') }}}: 'Package not installed', - {{{ cDefine('EREMOTE') }}}: 'The object is remote', - {{{ cDefine('ENOLINK') }}}: 'The link has been severed', - {{{ cDefine('EADV') }}}: 'Advertise error', - {{{ cDefine('ESRMNT') }}}: 'Srmount error', - {{{ cDefine('ECOMM') }}}: 'Communication error on send', - {{{ cDefine('EPROTO') }}}: 'Protocol error', - {{{ cDefine('EMULTIHOP') }}}: 'Multihop attempted', - {{{ cDefine('EDOTDOT') }}}: 'Cross mount point (not really error)', - {{{ cDefine('EBADMSG') }}}: 'Trying to read unreadable message', - {{{ cDefine('ENOTUNIQ') }}}: 'Given log. name not unique', - {{{ cDefine('EBADFD') }}}: 'f.d. invalid for this operation', - {{{ cDefine('EREMCHG') }}}: 'Remote address changed', - {{{ cDefine('ELIBACC') }}}: 'Can access a needed shared lib', - {{{ cDefine('ELIBBAD') }}}: 'Accessing a corrupted shared lib', - {{{ cDefine('ELIBSCN') }}}: '.lib section in a.out corrupted', - {{{ cDefine('ELIBMAX') }}}: 'Attempting to link in too many libs', - {{{ cDefine('ELIBEXEC') }}}: 'Attempting to exec a shared library', - {{{ cDefine('ENOSYS') }}}: 'Function not implemented', - {{{ cDefine('ENOTEMPTY') }}}: 'Directory not empty', - {{{ cDefine('ENAMETOOLONG') }}}: 'File or path name too long', - {{{ cDefine('ELOOP') }}}: 'Too many symbolic links', - {{{ cDefine('EOPNOTSUPP') }}}: 'Operation not supported on transport endpoint', - {{{ cDefine('EPFNOSUPPORT') }}}: 'Protocol family not supported', - {{{ cDefine('ECONNRESET') }}}: 'Connection reset by peer', - {{{ cDefine('ENOBUFS') }}}: 'No buffer space available', - {{{ cDefine('EAFNOSUPPORT') }}}: 'Address family not supported by protocol family', - {{{ cDefine('EPROTOTYPE') }}}: 'Protocol wrong type for socket', - {{{ cDefine('ENOTSOCK') }}}: 'Socket operation on non-socket', - {{{ cDefine('ENOPROTOOPT') }}}: 'Protocol not available', - {{{ cDefine('ESHUTDOWN') }}}: 'Can\'t send after socket shutdown', - {{{ cDefine('ECONNREFUSED') }}}: 'Connection refused', - {{{ cDefine('EADDRINUSE') }}}: 'Address already in use', - {{{ cDefine('ECONNABORTED') }}}: 'Connection aborted', - {{{ cDefine('ENETUNREACH') }}}: 'Network is unreachable', - {{{ cDefine('ENETDOWN') }}}: 'Network interface is not configured', - {{{ cDefine('ETIMEDOUT') }}}: 'Connection timed out', - {{{ cDefine('EHOSTDOWN') }}}: 'Host is down', - {{{ cDefine('EHOSTUNREACH') }}}: 'Host is unreachable', - {{{ cDefine('EINPROGRESS') }}}: 'Connection already in progress', - {{{ cDefine('EALREADY') }}}: 'Socket already connected', - {{{ cDefine('EDESTADDRREQ') }}}: 'Destination address required', - {{{ cDefine('EMSGSIZE') }}}: 'Message too long', - {{{ cDefine('EPROTONOSUPPORT') }}}: 'Unknown protocol', - {{{ cDefine('ESOCKTNOSUPPORT') }}}: 'Socket type not supported', - {{{ cDefine('EADDRNOTAVAIL') }}}: 'Address not available', - {{{ cDefine('ENETRESET') }}}: 'Connection reset by network', - {{{ cDefine('EISCONN') }}}: 'Socket is already connected', - {{{ cDefine('ENOTCONN') }}}: 'Socket is not connected', - {{{ cDefine('ETOOMANYREFS') }}}: 'Too many references', - {{{ cDefine('EUSERS') }}}: 'Too many users', - {{{ cDefine('EDQUOT') }}}: 'Quota exceeded', - {{{ cDefine('ESTALE') }}}: 'Stale file handle', - {{{ cDefine('ENOTSUP') }}}: 'Not supported', - {{{ cDefine('ENOMEDIUM') }}}: 'No medium (in tape drive)', - {{{ cDefine('EILSEQ') }}}: 'Illegal byte sequence', - {{{ cDefine('EOVERFLOW') }}}: 'Value too large for defined data type', - {{{ cDefine('ECANCELED') }}}: 'Operation canceled', - {{{ cDefine('ENOTRECOVERABLE') }}}: 'State not recoverable', - {{{ cDefine('EOWNERDEAD') }}}: 'Previous owner died', - {{{ cDefine('ESTRPIPE') }}}: 'Streams pipe error', + {{{ cDefs.EPERM }}}: 'Not super-user', + {{{ cDefs.ENOENT }}}: 'No such file or directory', + {{{ cDefs.ESRCH }}}: 'No such process', + {{{ cDefs.EINTR }}}: 'Interrupted system call', + {{{ cDefs.EIO }}}: 'I/O error', + {{{ cDefs.ENXIO }}}: 'No such device or address', + {{{ cDefs.E2BIG }}}: 'Arg list too long', + {{{ cDefs.ENOEXEC }}}: 'Exec format error', + {{{ cDefs.EBADF }}}: 'Bad file number', + {{{ cDefs.ECHILD }}}: 'No children', + {{{ cDefs.EWOULDBLOCK }}}: 'No more processes', + {{{ cDefs.ENOMEM }}}: 'Not enough core', + {{{ cDefs.EACCES }}}: 'Permission denied', + {{{ cDefs.EFAULT }}}: 'Bad address', + {{{ cDefs.ENOTBLK }}}: 'Block device required', + {{{ cDefs.EBUSY }}}: 'Mount device busy', + {{{ cDefs.EEXIST }}}: 'File exists', + {{{ cDefs.EXDEV }}}: 'Cross-device link', + {{{ cDefs.ENODEV }}}: 'No such device', + {{{ cDefs.ENOTDIR }}}: 'Not a directory', + {{{ cDefs.EISDIR }}}: 'Is a directory', + {{{ cDefs.EINVAL }}}: 'Invalid argument', + {{{ cDefs.ENFILE }}}: 'Too many open files in system', + {{{ cDefs.EMFILE }}}: 'Too many open files', + {{{ cDefs.ENOTTY }}}: 'Not a typewriter', + {{{ cDefs.ETXTBSY }}}: 'Text file busy', + {{{ cDefs.EFBIG }}}: 'File too large', + {{{ cDefs.ENOSPC }}}: 'No space left on device', + {{{ cDefs.ESPIPE }}}: 'Illegal seek', + {{{ cDefs.EROFS }}}: 'Read only file system', + {{{ cDefs.EMLINK }}}: 'Too many links', + {{{ cDefs.EPIPE }}}: 'Broken pipe', + {{{ cDefs.EDOM }}}: 'Math arg out of domain of func', + {{{ cDefs.ERANGE }}}: 'Math result not representable', + {{{ cDefs.ENOMSG }}}: 'No message of desired type', + {{{ cDefs.EIDRM }}}: 'Identifier removed', + {{{ cDefs.ECHRNG }}}: 'Channel number out of range', + {{{ cDefs.EL2NSYNC }}}: 'Level 2 not synchronized', + {{{ cDefs.EL3HLT }}}: 'Level 3 halted', + {{{ cDefs.EL3RST }}}: 'Level 3 reset', + {{{ cDefs.ELNRNG }}}: 'Link number out of range', + {{{ cDefs.EUNATCH }}}: 'Protocol driver not attached', + {{{ cDefs.ENOCSI }}}: 'No CSI structure available', + {{{ cDefs.EL2HLT }}}: 'Level 2 halted', + {{{ cDefs.EDEADLK }}}: 'Deadlock condition', + {{{ cDefs.ENOLCK }}}: 'No record locks available', + {{{ cDefs.EBADE }}}: 'Invalid exchange', + {{{ cDefs.EBADR }}}: 'Invalid request descriptor', + {{{ cDefs.EXFULL }}}: 'Exchange full', + {{{ cDefs.ENOANO }}}: 'No anode', + {{{ cDefs.EBADRQC }}}: 'Invalid request code', + {{{ cDefs.EBADSLT }}}: 'Invalid slot', + {{{ cDefs.EDEADLOCK }}}: 'File locking deadlock error', + {{{ cDefs.EBFONT }}}: 'Bad font file fmt', + {{{ cDefs.ENOSTR }}}: 'Device not a stream', + {{{ cDefs.ENODATA }}}: 'No data (for no delay io)', + {{{ cDefs.ETIME }}}: 'Timer expired', + {{{ cDefs.ENOSR }}}: 'Out of streams resources', + {{{ cDefs.ENONET }}}: 'Machine is not on the network', + {{{ cDefs.ENOPKG }}}: 'Package not installed', + {{{ cDefs.EREMOTE }}}: 'The object is remote', + {{{ cDefs.ENOLINK }}}: 'The link has been severed', + {{{ cDefs.EADV }}}: 'Advertise error', + {{{ cDefs.ESRMNT }}}: 'Srmount error', + {{{ cDefs.ECOMM }}}: 'Communication error on send', + {{{ cDefs.EPROTO }}}: 'Protocol error', + {{{ cDefs.EMULTIHOP }}}: 'Multihop attempted', + {{{ cDefs.EDOTDOT }}}: 'Cross mount point (not really error)', + {{{ cDefs.EBADMSG }}}: 'Trying to read unreadable message', + {{{ cDefs.ENOTUNIQ }}}: 'Given log. name not unique', + {{{ cDefs.EBADFD }}}: 'f.d. invalid for this operation', + {{{ cDefs.EREMCHG }}}: 'Remote address changed', + {{{ cDefs.ELIBACC }}}: 'Can access a needed shared lib', + {{{ cDefs.ELIBBAD }}}: 'Accessing a corrupted shared lib', + {{{ cDefs.ELIBSCN }}}: '.lib section in a.out corrupted', + {{{ cDefs.ELIBMAX }}}: 'Attempting to link in too many libs', + {{{ cDefs.ELIBEXEC }}}: 'Attempting to exec a shared library', + {{{ cDefs.ENOSYS }}}: 'Function not implemented', + {{{ cDefs.ENOTEMPTY }}}: 'Directory not empty', + {{{ cDefs.ENAMETOOLONG }}}: 'File or path name too long', + {{{ cDefs.ELOOP }}}: 'Too many symbolic links', + {{{ cDefs.EOPNOTSUPP }}}: 'Operation not supported on transport endpoint', + {{{ cDefs.EPFNOSUPPORT }}}: 'Protocol family not supported', + {{{ cDefs.ECONNRESET }}}: 'Connection reset by peer', + {{{ cDefs.ENOBUFS }}}: 'No buffer space available', + {{{ cDefs.EAFNOSUPPORT }}}: 'Address family not supported by protocol family', + {{{ cDefs.EPROTOTYPE }}}: 'Protocol wrong type for socket', + {{{ cDefs.ENOTSOCK }}}: 'Socket operation on non-socket', + {{{ cDefs.ENOPROTOOPT }}}: 'Protocol not available', + {{{ cDefs.ESHUTDOWN }}}: 'Can\'t send after socket shutdown', + {{{ cDefs.ECONNREFUSED }}}: 'Connection refused', + {{{ cDefs.EADDRINUSE }}}: 'Address already in use', + {{{ cDefs.ECONNABORTED }}}: 'Connection aborted', + {{{ cDefs.ENETUNREACH }}}: 'Network is unreachable', + {{{ cDefs.ENETDOWN }}}: 'Network interface is not configured', + {{{ cDefs.ETIMEDOUT }}}: 'Connection timed out', + {{{ cDefs.EHOSTDOWN }}}: 'Host is down', + {{{ cDefs.EHOSTUNREACH }}}: 'Host is unreachable', + {{{ cDefs.EINPROGRESS }}}: 'Connection already in progress', + {{{ cDefs.EALREADY }}}: 'Socket already connected', + {{{ cDefs.EDESTADDRREQ }}}: 'Destination address required', + {{{ cDefs.EMSGSIZE }}}: 'Message too long', + {{{ cDefs.EPROTONOSUPPORT }}}: 'Unknown protocol', + {{{ cDefs.ESOCKTNOSUPPORT }}}: 'Socket type not supported', + {{{ cDefs.EADDRNOTAVAIL }}}: 'Address not available', + {{{ cDefs.ENETRESET }}}: 'Connection reset by network', + {{{ cDefs.EISCONN }}}: 'Socket is already connected', + {{{ cDefs.ENOTCONN }}}: 'Socket is not connected', + {{{ cDefs.ETOOMANYREFS }}}: 'Too many references', + {{{ cDefs.EUSERS }}}: 'Too many users', + {{{ cDefs.EDQUOT }}}: 'Quota exceeded', + {{{ cDefs.ESTALE }}}: 'Stale file handle', + {{{ cDefs.ENOTSUP }}}: 'Not supported', + {{{ cDefs.ENOMEDIUM }}}: 'No medium (in tape drive)', + {{{ cDefs.EILSEQ }}}: 'Illegal byte sequence', + {{{ cDefs.EOVERFLOW }}}: 'Value too large for defined data type', + {{{ cDefs.ECANCELED }}}: 'Operation canceled', + {{{ cDefs.ENOTRECOVERABLE }}}: 'State not recoverable', + {{{ cDefs.EOWNERDEAD }}}: 'Previous owner died', + {{{ cDefs.ESTRPIPE }}}: 'Streams pipe error', }, #if SUPPORT_ERRNO $setErrNo__deps: ['__errno_location'], @@ -1720,16 +1720,16 @@ mergeInto(LibraryManager.library, { var addr; switch (family) { - case {{{ cDefine('AF_INET') }}}: + case {{{ cDefs.AF_INET }}}: if (salen !== {{{ C_STRUCTS.sockaddr_in.__size__ }}}) { - return { errno: {{{ cDefine('EINVAL') }}} }; + return { errno: {{{ cDefs.EINVAL }}} }; } addr = {{{ makeGetValue('sa', C_STRUCTS.sockaddr_in.sin_addr.s_addr, 'i32') }}}; addr = inetNtop4(addr); break; - case {{{ cDefine('AF_INET6') }}}: + case {{{ cDefs.AF_INET6 }}}: if (salen !== {{{ C_STRUCTS.sockaddr_in6.__size__ }}}) { - return { errno: {{{ cDefine('EINVAL') }}} }; + return { errno: {{{ cDefs.EINVAL }}} }; } addr = [ {{{ makeGetValue('sa', C_STRUCTS.sockaddr_in6.sin6_addr.__in6_union.__s6_addr+0, 'i32') }}}, @@ -1740,7 +1740,7 @@ mergeInto(LibraryManager.library, { addr = inetNtop6(addr); break; default: - return { errno: {{{ cDefine('EAFNOSUPPORT') }}} }; + return { errno: {{{ cDefs.EAFNOSUPPORT }}} }; } return { family: family, addr: addr, port: port }; @@ -1749,7 +1749,7 @@ mergeInto(LibraryManager.library, { $writeSockaddr__deps: ['$Sockets', '$inetPton4', '$inetPton6', '$zeroMemory'], $writeSockaddr: function (sa, family, addr, port, addrlen) { switch (family) { - case {{{ cDefine('AF_INET') }}}: + case {{{ cDefs.AF_INET }}}: addr = inetPton4(addr); zeroMemory(sa, {{{ C_STRUCTS.sockaddr_in.__size__ }}}); if (addrlen) { @@ -1759,7 +1759,7 @@ mergeInto(LibraryManager.library, { {{{ makeSetValue('sa', C_STRUCTS.sockaddr_in.sin_addr.s_addr, 'addr', 'i32') }}}; {{{ makeSetValue('sa', C_STRUCTS.sockaddr_in.sin_port, '_htons(port)', 'i16') }}}; break; - case {{{ cDefine('AF_INET6') }}}: + case {{{ cDefs.AF_INET6 }}}: addr = inetPton6(addr); zeroMemory(sa, {{{ C_STRUCTS.sockaddr_in6.__size__ }}}); if (addrlen) { @@ -1773,7 +1773,7 @@ mergeInto(LibraryManager.library, { {{{ makeSetValue('sa', C_STRUCTS.sockaddr_in6.sin6_port, '_htons(port)', 'i16') }}}; break; default: - return {{{ cDefine('EAFNOSUPPORT') }}}; + return {{{ cDefs.EAFNOSUPPORT }}}; } return 0; }, @@ -1833,8 +1833,8 @@ mergeInto(LibraryManager.library, { gethostbyaddr__proxy: 'sync', gethostbyaddr__sig: 'ppii', gethostbyaddr: function (addr, addrlen, type) { - if (type !== {{{ cDefine('AF_INET') }}}) { - setErrNo({{{ cDefine('EAFNOSUPPORT') }}}); + if (type !== {{{ cDefs.AF_INET }}}) { + setErrNo({{{ cDefs.EAFNOSUPPORT }}}); // TODO: set h_errno return null; } @@ -1864,7 +1864,7 @@ mergeInto(LibraryManager.library, { var aliasesBuf = _malloc(4); {{{ makeSetValue('aliasesBuf', '0', '0', POINTER_TYPE) }}}; {{{ makeSetValue('ret', C_STRUCTS.hostent.h_aliases, 'aliasesBuf', 'i8**') }}}; - var afinet = {{{ cDefine('AF_INET') }}}; + var afinet = {{{ cDefs.AF_INET }}}; {{{ makeSetValue('ret', C_STRUCTS.hostent.h_addrtype, 'afinet', 'i32') }}}; {{{ makeSetValue('ret', C_STRUCTS.hostent.h_length, '4', 'i32') }}}; var addrListBuf = _malloc(12); @@ -1899,7 +1899,7 @@ mergeInto(LibraryManager.library, { var addr = 0; var port = 0; var flags = 0; - var family = {{{ cDefine('AF_UNSPEC') }}}; + var family = {{{ cDefs.AF_UNSPEC }}}; var type = 0; var proto = 0; var ai, last; @@ -1908,10 +1908,10 @@ mergeInto(LibraryManager.library, { var sa, salen, ai; var errno; - salen = family === {{{ cDefine('AF_INET6') }}} ? + salen = family === {{{ cDefs.AF_INET6 }}} ? {{{ C_STRUCTS.sockaddr_in6.__size__ }}} : {{{ C_STRUCTS.sockaddr_in.__size__ }}}; - addr = family === {{{ cDefine('AF_INET6') }}} ? + addr = family === {{{ cDefs.AF_INET6 }}} ? inetNtop6(addr) : inetNtop4(addr); sa = _malloc(salen); @@ -1924,7 +1924,7 @@ mergeInto(LibraryManager.library, { {{{ makeSetValue('ai', C_STRUCTS.addrinfo.ai_protocol, 'proto', 'i32') }}}; {{{ makeSetValue('ai', C_STRUCTS.addrinfo.ai_canonname, 'canon', 'i32') }}}; {{{ makeSetValue('ai', C_STRUCTS.addrinfo.ai_addr, 'sa', '*') }}}; - if (family === {{{ cDefine('AF_INET6') }}}) { + if (family === {{{ cDefs.AF_INET6 }}}) { {{{ makeSetValue('ai', C_STRUCTS.addrinfo.ai_addrlen, C_STRUCTS.sockaddr_in6.__size__, 'i32') }}}; } else { {{{ makeSetValue('ai', C_STRUCTS.addrinfo.ai_addrlen, C_STRUCTS.sockaddr_in.__size__, 'i32') }}}; @@ -1941,40 +1941,40 @@ mergeInto(LibraryManager.library, { proto = {{{ makeGetValue('hint', C_STRUCTS.addrinfo.ai_protocol, 'i32') }}}; } if (type && !proto) { - proto = type === {{{ cDefine('SOCK_DGRAM') }}} ? {{{ cDefine('IPPROTO_UDP') }}} : {{{ cDefine('IPPROTO_TCP') }}}; + proto = type === {{{ cDefs.SOCK_DGRAM }}} ? {{{ cDefs.IPPROTO_UDP }}} : {{{ cDefs.IPPROTO_TCP }}}; } if (!type && proto) { - type = proto === {{{ cDefine('IPPROTO_UDP') }}} ? {{{ cDefine('SOCK_DGRAM') }}} : {{{ cDefine('SOCK_STREAM') }}}; + type = proto === {{{ cDefs.IPPROTO_UDP }}} ? {{{ cDefs.SOCK_DGRAM }}} : {{{ cDefs.SOCK_STREAM }}}; } // If type or proto are set to zero in hints we should really be returning multiple addrinfo values, but for // now default to a TCP STREAM socket so we can at least return a sensible addrinfo given NULL hints. if (proto === 0) { - proto = {{{ cDefine('IPPROTO_TCP') }}}; + proto = {{{ cDefs.IPPROTO_TCP }}}; } if (type === 0) { - type = {{{ cDefine('SOCK_STREAM') }}}; + type = {{{ cDefs.SOCK_STREAM }}}; } if (!node && !service) { - return {{{ cDefine('EAI_NONAME') }}}; + return {{{ cDefs.EAI_NONAME }}}; } - if (flags & ~({{{ cDefine('AI_PASSIVE') }}}|{{{ cDefine('AI_CANONNAME') }}}|{{{ cDefine('AI_NUMERICHOST') }}}| - {{{ cDefine('AI_NUMERICSERV') }}}|{{{ cDefine('AI_V4MAPPED') }}}|{{{ cDefine('AI_ALL') }}}|{{{ cDefine('AI_ADDRCONFIG') }}})) { - return {{{ cDefine('EAI_BADFLAGS') }}}; + if (flags & ~({{{ cDefs.AI_PASSIVE }}}|{{{ cDefs.AI_CANONNAME }}}|{{{ cDefs.AI_NUMERICHOST }}}| + {{{ cDefs.AI_NUMERICSERV }}}|{{{ cDefs.AI_V4MAPPED }}}|{{{ cDefs.AI_ALL }}}|{{{ cDefs.AI_ADDRCONFIG }}})) { + return {{{ cDefs.EAI_BADFLAGS }}}; } - if (hint !== 0 && ({{{ makeGetValue('hint', C_STRUCTS.addrinfo.ai_flags, 'i32') }}} & {{{ cDefine('AI_CANONNAME') }}}) && !node) { - return {{{ cDefine('EAI_BADFLAGS') }}}; + if (hint !== 0 && ({{{ makeGetValue('hint', C_STRUCTS.addrinfo.ai_flags, 'i32') }}} & {{{ cDefs.AI_CANONNAME }}}) && !node) { + return {{{ cDefs.EAI_BADFLAGS }}}; } - if (flags & {{{ cDefine('AI_ADDRCONFIG') }}}) { + if (flags & {{{ cDefs.AI_ADDRCONFIG }}}) { // TODO - return {{{ cDefine('EAI_NONAME') }}}; + return {{{ cDefs.EAI_NONAME }}}; } - if (type !== 0 && type !== {{{ cDefine('SOCK_STREAM') }}} && type !== {{{ cDefine('SOCK_DGRAM') }}}) { - return {{{ cDefine('EAI_SOCKTYPE') }}}; + if (type !== 0 && type !== {{{ cDefs.SOCK_STREAM }}} && type !== {{{ cDefs.SOCK_DGRAM }}}) { + return {{{ cDefs.EAI_SOCKTYPE }}}; } - if (family !== {{{ cDefine('AF_UNSPEC') }}} && family !== {{{ cDefine('AF_INET') }}} && family !== {{{ cDefine('AF_INET6') }}}) { - return {{{ cDefine('EAI_FAMILY') }}}; + if (family !== {{{ cDefs.AF_UNSPEC }}} && family !== {{{ cDefs.AF_INET }}} && family !== {{{ cDefs.AF_INET6 }}}) { + return {{{ cDefs.EAI_FAMILY }}}; } if (service) { @@ -1982,22 +1982,22 @@ mergeInto(LibraryManager.library, { port = parseInt(service, 10); if (isNaN(port)) { - if (flags & {{{ cDefine('AI_NUMERICSERV') }}}) { - return {{{ cDefine('EAI_NONAME') }}}; + if (flags & {{{ cDefs.AI_NUMERICSERV }}}) { + return {{{ cDefs.EAI_NONAME }}}; } // TODO support resolving well-known service names from: // http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.txt - return {{{ cDefine('EAI_SERVICE') }}}; + return {{{ cDefs.EAI_SERVICE }}}; } } if (!node) { - if (family === {{{ cDefine('AF_UNSPEC') }}}) { - family = {{{ cDefine('AF_INET') }}}; + if (family === {{{ cDefs.AF_UNSPEC }}}) { + family = {{{ cDefs.AF_INET }}}; } - if ((flags & {{{ cDefine('AI_PASSIVE') }}}) === 0) { - if (family === {{{ cDefine('AF_INET') }}}) { - addr = _htonl({{{ cDefine('INADDR_LOOPBACK') }}}); + if ((flags & {{{ cDefs.AI_PASSIVE }}}) === 0) { + if (family === {{{ cDefs.AF_INET }}}) { + addr = _htonl({{{ cDefs.INADDR_LOOPBACK }}}); } else { addr = [0, 0, 0, 1]; } @@ -2014,23 +2014,23 @@ mergeInto(LibraryManager.library, { addr = inetPton4(node); if (addr !== null) { // incoming node is a valid ipv4 address - if (family === {{{ cDefine('AF_UNSPEC') }}} || family === {{{ cDefine('AF_INET') }}}) { - family = {{{ cDefine('AF_INET') }}}; + if (family === {{{ cDefs.AF_UNSPEC }}} || family === {{{ cDefs.AF_INET }}}) { + family = {{{ cDefs.AF_INET }}}; } - else if (family === {{{ cDefine('AF_INET6') }}} && (flags & {{{ cDefine('AI_V4MAPPED') }}})) { + else if (family === {{{ cDefs.AF_INET6 }}} && (flags & {{{ cDefs.AI_V4MAPPED }}})) { addr = [0, 0, _htonl(0xffff), addr]; - family = {{{ cDefine('AF_INET6') }}}; + family = {{{ cDefs.AF_INET6 }}}; } else { - return {{{ cDefine('EAI_NONAME') }}}; + return {{{ cDefs.EAI_NONAME }}}; } } else { addr = inetPton6(node); if (addr !== null) { // incoming node is a valid ipv6 address - if (family === {{{ cDefine('AF_UNSPEC') }}} || family === {{{ cDefine('AF_INET6') }}}) { - family = {{{ cDefine('AF_INET6') }}}; + if (family === {{{ cDefs.AF_UNSPEC }}} || family === {{{ cDefs.AF_INET6 }}}) { + family = {{{ cDefs.AF_INET6 }}}; } else { - return {{{ cDefine('EAI_NONAME') }}}; + return {{{ cDefs.EAI_NONAME }}}; } } } @@ -2039,8 +2039,8 @@ mergeInto(LibraryManager.library, { {{{ makeSetValue('out', '0', 'ai', '*') }}}; return 0; } - if (flags & {{{ cDefine('AI_NUMERICHOST') }}}) { - return {{{ cDefine('EAI_NONAME') }}}; + if (flags & {{{ cDefs.AI_NUMERICHOST }}}) { + return {{{ cDefs.EAI_NONAME }}}; } // @@ -2049,9 +2049,9 @@ mergeInto(LibraryManager.library, { // resolve the hostname to a temporary fake address node = DNS.lookup_name(node); addr = inetPton4(node); - if (family === {{{ cDefine('AF_UNSPEC') }}}) { - family = {{{ cDefine('AF_INET') }}}; - } else if (family === {{{ cDefine('AF_INET6') }}}) { + if (family === {{{ cDefs.AF_UNSPEC }}}) { + family = {{{ cDefs.AF_INET }}}; + } else if (family === {{{ cDefs.AF_INET6 }}}) { addr = [0, 0, _htonl(0xffff), addr]; } ai = allocaddrinfo(family, type, proto, null, addr, port); @@ -2064,7 +2064,7 @@ mergeInto(LibraryManager.library, { getnameinfo: function (sa, salen, node, nodelen, serv, servlen, flags) { var info = readSockaddr(sa, salen); if (info.errno) { - return {{{ cDefine('EAI_FAMILY') }}}; + return {{{ cDefs.EAI_FAMILY }}}; } var port = info.port; var addr = info.addr; @@ -2073,9 +2073,9 @@ mergeInto(LibraryManager.library, { if (node && nodelen) { var lookup; - if ((flags & {{{ cDefine('NI_NUMERICHOST') }}}) || !(lookup = DNS.lookup_addr(addr))) { - if (flags & {{{ cDefine('NI_NAMEREQD') }}}) { - return {{{ cDefine('EAI_NONAME') }}}; + if ((flags & {{{ cDefs.NI_NUMERICHOST }}}) || !(lookup = DNS.lookup_addr(addr))) { + if (flags & {{{ cDefs.NI_NAMEREQD }}}) { + return {{{ cDefs.EAI_NONAME }}}; } } else { addr = lookup; @@ -2098,7 +2098,7 @@ mergeInto(LibraryManager.library, { if (overflowed) { // Note: even when we overflow, getnameinfo() is specced to write out the truncated results. - return {{{ cDefine('EAI_OVERFLOW') }}}; + return {{{ cDefs.EAI_OVERFLOW }}}; } return 0; @@ -2488,20 +2488,20 @@ mergeInto(LibraryManager.library, { var iNextLine = callstack.indexOf('\n', Math.max(iThisFunc, iThisFunc2))+1; callstack = callstack.slice(iNextLine); - if (flags & {{{ cDefine('EM_LOG_DEMANGLE') }}}) { + if (flags & {{{ cDefs.EM_LOG_DEMANGLE }}}) { warnOnce('EM_LOG_DEMANGLE is deprecated; ignoring'); } // If user requested to see the original source stack, but no source map // information is available, just fall back to showing the JS stack. - if (flags & {{{ cDefine('EM_LOG_C_STACK') }}} && typeof emscripten_source_map == 'undefined') { + if (flags & {{{ cDefs.EM_LOG_C_STACK }}} && typeof emscripten_source_map == 'undefined') { warnOnce('Source map information is not available, emscripten_log with EM_LOG_C_STACK will be ignored. Build with "--pre-js $EMSCRIPTEN/src/emscripten-source-map.min.js" linker flag to add source map loading to code.'); - flags ^= {{{ cDefine('EM_LOG_C_STACK') }}}; - flags |= {{{ cDefine('EM_LOG_JS_STACK') }}}; + flags ^= {{{ cDefs.EM_LOG_C_STACK }}}; + flags |= {{{ cDefs.EM_LOG_JS_STACK }}}; } var stack_args = null; - if (flags & {{{ cDefine('EM_LOG_FUNC_PARAMS') }}}) { + if (flags & {{{ cDefs.EM_LOG_FUNC_PARAMS }}}) { // To get the actual parameters to the functions, traverse the stack via // the unfortunately deprecated 'arguments.callee' method, if it works: stack_args = traverseStack(arguments); @@ -2556,18 +2556,18 @@ mergeInto(LibraryManager.library, { var haveSourceMap = false; - if (flags & {{{ cDefine('EM_LOG_C_STACK') }}}) { + if (flags & {{{ cDefs.EM_LOG_C_STACK }}}) { var orig = emscripten_source_map.originalPositionFor({line: lineno, column: column}); haveSourceMap = (orig && orig.source); if (haveSourceMap) { - if (flags & {{{ cDefine('EM_LOG_NO_PATHS') }}}) { + if (flags & {{{ cDefs.EM_LOG_NO_PATHS }}}) { orig.source = orig.source.substring(orig.source.replace(/\\/g, "/").lastIndexOf('/')+1); } callstack += ' at ' + symbolName + ' (' + orig.source + ':' + orig.line + ':' + orig.column + ')\n'; } } - if ((flags & {{{ cDefine('EM_LOG_JS_STACK') }}}) || !haveSourceMap) { - if (flags & {{{ cDefine('EM_LOG_NO_PATHS') }}}) { + if ((flags & {{{ cDefs.EM_LOG_JS_STACK }}}) || !haveSourceMap) { + if (flags & {{{ cDefs.EM_LOG_NO_PATHS }}}) { file = file.substring(file.replace(/\\/g, "/").lastIndexOf('/')+1); } callstack += (haveSourceMap ? (' = ' + symbolName) : (' at '+ symbolName)) + ' (' + file + ':' + lineno + ':' + column + ')\n'; @@ -2575,7 +2575,7 @@ mergeInto(LibraryManager.library, { // If we are still keeping track with the callstack by traversing via // 'arguments.callee', print the function parameters as well. - if (flags & {{{ cDefine('EM_LOG_FUNC_PARAMS') }}} && stack_args[0]) { + if (flags & {{{ cDefs.EM_LOG_FUNC_PARAMS }}} && stack_args[0]) { if (stack_args[1] == symbolName && stack_args[2].length > 0) { callstack = callstack.replace(/\s+$/, ''); callstack += ' with values: ' + stack_args[1] + stack_args[2] + '\n'; @@ -2608,24 +2608,24 @@ mergeInto(LibraryManager.library, { $emscriptenLog__deps: ['$getCallstack'], $emscriptenLog: function(flags, str) { - if (flags & {{{ cDefine('EM_LOG_C_STACK') | cDefine('EM_LOG_JS_STACK') }}}) { + if (flags & {{{ cDefs.EM_LOG_C_STACK | cDefs.EM_LOG_JS_STACK }}}) { str = str.replace(/\s+$/, ''); // Ensure the message and the callstack are joined cleanly with exactly one newline. str += (str.length > 0 ? '\n' : '') + getCallstack(flags); } - if (flags & {{{ cDefine('EM_LOG_CONSOLE') }}}) { - if (flags & {{{ cDefine('EM_LOG_ERROR') }}}) { + if (flags & {{{ cDefs.EM_LOG_CONSOLE }}}) { + if (flags & {{{ cDefs.EM_LOG_ERROR }}}) { console.error(str); - } else if (flags & {{{ cDefine('EM_LOG_WARN') }}}) { + } else if (flags & {{{ cDefs.EM_LOG_WARN }}}) { console.warn(str); - } else if (flags & {{{ cDefine('EM_LOG_INFO') }}}) { + } else if (flags & {{{ cDefs.EM_LOG_INFO }}}) { console.info(str); - } else if (flags & {{{ cDefine('EM_LOG_DEBUG') }}}) { + } else if (flags & {{{ cDefs.EM_LOG_DEBUG }}}) { console.debug(str); } else { console.log(str); } - } else if (flags & {{{ cDefine('EM_LOG_ERROR') | cDefine('EM_LOG_WARN') }}}) { + } else if (flags & {{{ cDefs.EM_LOG_ERROR | cDefs.EM_LOG_WARN }}}) { err(str); } else { out(str); diff --git a/src/library_dylink.js b/src/library_dylink.js index a35bb52ed5b12..d48a31a01d737 100644 --- a/src/library_dylink.js +++ b/src/library_dylink.js @@ -292,7 +292,7 @@ var LibraryDylink = { loadedLibsByName: {}, // handle -> dso; Used by dlsym loadedLibsByHandle: {}, - init: () => newDSO('__main__', {{{ cDefine('RTLD_DEFAULT') }}}, wasmImports), + init: () => newDSO('__main__', {{{ cDefs.RTLD_DEFAULT }}}, wasmImports), }, $dlSetError__internal: true, @@ -1060,13 +1060,13 @@ var LibraryDylink = { } } - var global = Boolean(flags & {{{ cDefine('RTLD_GLOBAL') }}}); + var global = Boolean(flags & {{{ cDefs.RTLD_GLOBAL }}}); var localScope = global ? null : {}; // We don't care about RTLD_NOW and RTLD_LAZY. var combinedFlags = { global, - nodelete: Boolean(flags & {{{ cDefine('RTLD_NODELETE') }}}), + nodelete: Boolean(flags & {{{ cDefs.RTLD_NODELETE }}}), loadAsync: jsflags.loadAsync, fs: jsflags.fs, } diff --git a/src/library_fs.js b/src/library_fs.js index 05d307bf7dad0..517c10c417cba 100644 --- a/src/library_fs.js +++ b/src/library_fs.js @@ -54,8 +54,8 @@ var FSNode = /** @constructor */ function(parent, name, mode, rdev) { this.stream_ops = {}; this.rdev = rdev; }; -var readMode = 292/*{{{ cDefine("S_IRUGO") }}}*/ | 73/*{{{ cDefine("S_IXUGO") }}}*/; -var writeMode = 146/*{{{ cDefine("S_IWUGO") }}}*/; +var readMode = 292/*{{{ cDefs.S_IRUGO }}}*/ | 73/*{{{ cDefs.S_IXUGO }}}*/; +var writeMode = 146/*{{{ cDefs.S_IWUGO }}}*/; Object.defineProperties(FSNode.prototype, { read: { get: /** @this{FSNode} */function() { @@ -130,7 +130,7 @@ FS.staticInit();` + opts = Object.assign(defaults, opts) if (opts.recurse_count > 8) { // max recursive lookup of 8 - throw new FS.ErrnoError({{{ cDefine('ELOOP') }}}); + throw new FS.ErrnoError({{{ cDefs.ELOOP }}}); } // split the absolute path @@ -169,7 +169,7 @@ FS.staticInit();` + current = lookup.node; if (count++ > 40) { // limit max consecutive symlinks to 40 (SYMLOOP_MAX). - throw new FS.ErrnoError({{{ cDefine('ELOOP') }}}); + throw new FS.ErrnoError({{{ cDefs.ELOOP }}}); } } } @@ -266,25 +266,25 @@ FS.staticInit();` + return !!node.mounted; }, isFile: (mode) => { - return (mode & {{{ cDefine('S_IFMT') }}}) === {{{ cDefine('S_IFREG') }}}; + return (mode & {{{ cDefs.S_IFMT }}}) === {{{ cDefs.S_IFREG }}}; }, isDir: (mode) => { - return (mode & {{{ cDefine('S_IFMT') }}}) === {{{ cDefine('S_IFDIR') }}}; + return (mode & {{{ cDefs.S_IFMT }}}) === {{{ cDefs.S_IFDIR }}}; }, isLink: (mode) => { - return (mode & {{{ cDefine('S_IFMT') }}}) === {{{ cDefine('S_IFLNK') }}}; + return (mode & {{{ cDefs.S_IFMT }}}) === {{{ cDefs.S_IFLNK }}}; }, isChrdev: (mode) => { - return (mode & {{{ cDefine('S_IFMT') }}}) === {{{ cDefine('S_IFCHR') }}}; + return (mode & {{{ cDefs.S_IFMT }}}) === {{{ cDefs.S_IFCHR }}}; }, isBlkdev: (mode) => { - return (mode & {{{ cDefine('S_IFMT') }}}) === {{{ cDefine('S_IFBLK') }}}; + return (mode & {{{ cDefs.S_IFMT }}}) === {{{ cDefs.S_IFBLK }}}; }, isFIFO: (mode) => { - return (mode & {{{ cDefine('S_IFMT') }}}) === {{{ cDefine('S_IFIFO') }}}; + return (mode & {{{ cDefs.S_IFMT }}}) === {{{ cDefs.S_IFIFO }}}; }, isSocket: (mode) => { - return (mode & {{{ cDefine('S_IFSOCK') }}}) === {{{ cDefine('S_IFSOCK') }}}; + return (mode & {{{ cDefs.S_IFSOCK }}}) === {{{ cDefs.S_IFSOCK }}}; }, // @@ -294,12 +294,12 @@ FS.staticInit();` + // Extra quotes used here on the keys to this object otherwise jsifier will // erase them in the process of reading and then writing the JS library // code. - '"r"': {{{ cDefine('O_RDONLY') }}}, - '"r+"': {{{ cDefine('O_RDWR') }}}, - '"w"': {{{ cDefine('O_TRUNC') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_WRONLY') }}}, - '"w+"': {{{ cDefine('O_TRUNC') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_RDWR') }}}, - '"a"': {{{ cDefine('O_APPEND') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_WRONLY') }}}, - '"a+"': {{{ cDefine('O_APPEND') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_RDWR') }}}, + '"r"': {{{ cDefs.O_RDONLY }}}, + '"r+"': {{{ cDefs.O_RDWR }}}, + '"w"': {{{ cDefs.O_TRUNC }}} | {{{ cDefs.O_CREAT }}} | {{{ cDefs.O_WRONLY }}}, + '"w+"': {{{ cDefs.O_TRUNC }}} | {{{ cDefs.O_CREAT }}} | {{{ cDefs.O_RDWR }}}, + '"a"': {{{ cDefs.O_APPEND }}} | {{{ cDefs.O_CREAT }}} | {{{ cDefs.O_WRONLY }}}, + '"a+"': {{{ cDefs.O_APPEND }}} | {{{ cDefs.O_CREAT }}} | {{{ cDefs.O_RDWR }}}, }, // convert the 'r', 'r+', etc. to it's corresponding set of O_* flags modeStringToFlags: (str) => { @@ -312,7 +312,7 @@ FS.staticInit();` + // convert O_* bitmask to a string for nodePermissions flagsToPermissionString: (flag) => { var perms = ['r', 'w', 'rw'][flag & 3]; - if ((flag & {{{ cDefine('O_TRUNC') }}})) { + if ((flag & {{{ cDefs.O_TRUNC }}})) { perms += 'w'; } return perms; @@ -322,25 +322,25 @@ FS.staticInit();` + return 0; } // return 0 if any user, group or owner bits are set. - if (perms.includes('r') && !(node.mode & {{{ cDefine('S_IRUGO') }}})) { - return {{{ cDefine('EACCES') }}}; - } else if (perms.includes('w') && !(node.mode & {{{ cDefine('S_IWUGO') }}})) { - return {{{ cDefine('EACCES') }}}; - } else if (perms.includes('x') && !(node.mode & {{{ cDefine('S_IXUGO') }}})) { - return {{{ cDefine('EACCES') }}}; + if (perms.includes('r') && !(node.mode & {{{ cDefs.S_IRUGO }}})) { + return {{{ cDefs.EACCES }}}; + } else if (perms.includes('w') && !(node.mode & {{{ cDefs.S_IWUGO }}})) { + return {{{ cDefs.EACCES }}}; + } else if (perms.includes('x') && !(node.mode & {{{ cDefs.S_IXUGO }}})) { + return {{{ cDefs.EACCES }}}; } return 0; }, mayLookup: (dir) => { var errCode = FS.nodePermissions(dir, 'x'); if (errCode) return errCode; - if (!dir.node_ops.lookup) return {{{ cDefine('EACCES') }}}; + if (!dir.node_ops.lookup) return {{{ cDefs.EACCES }}}; return 0; }, mayCreate: (dir, name) => { try { var node = FS.lookupNode(dir, name); - return {{{ cDefine('EEXIST') }}}; + return {{{ cDefs.EEXIST }}}; } catch (e) { } return FS.nodePermissions(dir, 'wx'); @@ -358,28 +358,28 @@ FS.staticInit();` + } if (isdir) { if (!FS.isDir(node.mode)) { - return {{{ cDefine('ENOTDIR') }}}; + return {{{ cDefs.ENOTDIR }}}; } if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) { - return {{{ cDefine('EBUSY') }}}; + return {{{ cDefs.EBUSY }}}; } } else { if (FS.isDir(node.mode)) { - return {{{ cDefine('EISDIR') }}}; + return {{{ cDefs.EISDIR }}}; } } return 0; }, mayOpen: (node, flags) => { if (!node) { - return {{{ cDefine('ENOENT') }}}; + return {{{ cDefs.ENOENT }}}; } if (FS.isLink(node.mode)) { - return {{{ cDefine('ELOOP') }}}; + return {{{ cDefs.ELOOP }}}; } else if (FS.isDir(node.mode)) { if (FS.flagsToPermissionString(flags) !== 'r' || // opening for write - (flags & {{{ cDefine('O_TRUNC') }}})) { // TODO: check for O_SEARCH? (== search for dir only) - return {{{ cDefine('EISDIR') }}}; + (flags & {{{ cDefs.O_TRUNC }}})) { // TODO: check for O_SEARCH? (== search for dir only) + return {{{ cDefs.EISDIR }}}; } } return FS.nodePermissions(node, FS.flagsToPermissionString(flags)); @@ -395,7 +395,7 @@ FS.staticInit();` + return fd; } } - throw new FS.ErrnoError({{{ cDefine('EMFILE') }}}); + throw new FS.ErrnoError({{{ cDefs.EMFILE }}}); }, getStream: (fd) => FS.streams[fd], // TODO parameterize this function such that a stream @@ -416,15 +416,15 @@ FS.staticInit();` + }, isRead: { /** @this {FS.FSStream} */ - get: function() { return (this.flags & {{{ cDefine('O_ACCMODE') }}}) !== {{{ cDefine('O_WRONLY') }}}; } + get: function() { return (this.flags & {{{ cDefs.O_ACCMODE }}}) !== {{{ cDefs.O_WRONLY }}}; } }, isWrite: { /** @this {FS.FSStream} */ - get: function() { return (this.flags & {{{ cDefine('O_ACCMODE') }}}) !== {{{ cDefine('O_RDONLY') }}}; } + get: function() { return (this.flags & {{{ cDefs.O_ACCMODE }}}) !== {{{ cDefs.O_RDONLY }}}; } }, isAppend: { /** @this {FS.FSStream} */ - get: function() { return (this.flags & {{{ cDefine('O_APPEND') }}}); } + get: function() { return (this.flags & {{{ cDefs.O_APPEND }}}); } }, flags: { /** @this {FS.FSStream} */ @@ -471,7 +471,7 @@ FS.staticInit();` + } }, llseek: () => { - throw new FS.ErrnoError({{{ cDefine('ESPIPE') }}}); + throw new FS.ErrnoError({{{ cDefs.ESPIPE }}}); } }, major: (dev) => ((dev) >> 8), @@ -556,7 +556,7 @@ FS.staticInit();` + var node; if (root && FS.root) { - throw new FS.ErrnoError({{{ cDefine('EBUSY') }}}); + throw new FS.ErrnoError({{{ cDefs.EBUSY }}}); } else if (!root && !pseudo) { var lookup = FS.lookupPath(mountpoint, { follow_mount: false }); @@ -564,11 +564,11 @@ FS.staticInit();` + node = lookup.node; if (FS.isMountpoint(node)) { - throw new FS.ErrnoError({{{ cDefine('EBUSY') }}}); + throw new FS.ErrnoError({{{ cDefs.EBUSY }}}); } if (!FS.isDir(node.mode)) { - throw new FS.ErrnoError({{{ cDefine('ENOTDIR') }}}); + throw new FS.ErrnoError({{{ cDefs.ENOTDIR }}}); } } @@ -602,7 +602,7 @@ FS.staticInit();` + var lookup = FS.lookupPath(mountpoint, { follow_mount: false }); if (!FS.isMountpoint(lookup.node)) { - throw new FS.ErrnoError({{{ cDefine('EINVAL') }}}); + throw new FS.ErrnoError({{{ cDefs.EINVAL }}}); } // destroy the nodes for this mount, and all its child mounts @@ -643,28 +643,28 @@ FS.staticInit();` + var parent = lookup.node; var name = PATH.basename(path); if (!name || name === '.' || name === '..') { - throw new FS.ErrnoError({{{ cDefine('EINVAL') }}}); + throw new FS.ErrnoError({{{ cDefs.EINVAL }}}); } var errCode = FS.mayCreate(parent, name); if (errCode) { throw new FS.ErrnoError(errCode); } if (!parent.node_ops.mknod) { - throw new FS.ErrnoError({{{ cDefine('EPERM') }}}); + throw new FS.ErrnoError({{{ cDefs.EPERM }}}); } return parent.node_ops.mknod(parent, name, mode, dev); }, // helpers to create specific types of nodes create: (path, mode) => { mode = mode !== undefined ? mode : 438 /* 0666 */; - mode &= {{{ cDefine('S_IALLUGO') }}}; - mode |= {{{ cDefine('S_IFREG') }}}; + mode &= {{{ cDefs.S_IALLUGO }}}; + mode |= {{{ cDefs.S_IFREG }}}; return FS.mknod(path, mode, 0); }, mkdir: (path, mode) => { mode = mode !== undefined ? mode : 511 /* 0777 */; - mode &= {{{ cDefine('S_IRWXUGO') }}} | {{{ cDefine('S_ISVTX') }}}; - mode |= {{{ cDefine('S_IFDIR') }}}; + mode &= {{{ cDefs.S_IRWXUGO }}} | {{{ cDefs.S_ISVTX }}}; + mode |= {{{ cDefs.S_IFDIR }}}; #if FS_DEBUG if (FS.trackingDelegate['onMakeDirectory']) { FS.trackingDelegate['onMakeDirectory'](path, mode); @@ -682,7 +682,7 @@ FS.staticInit();` + try { FS.mkdir(d, mode); } catch(e) { - if (e.errno != {{{ cDefine('EEXIST') }}}) throw e; + if (e.errno != {{{ cDefs.EEXIST }}}) throw e; } } }, @@ -691,17 +691,17 @@ FS.staticInit();` + dev = mode; mode = 438 /* 0666 */; } - mode |= {{{ cDefine('S_IFCHR') }}}; + mode |= {{{ cDefs.S_IFCHR }}}; return FS.mknod(path, mode, dev); }, symlink: (oldpath, newpath) => { if (!PATH_FS.resolve(oldpath)) { - throw new FS.ErrnoError({{{ cDefine('ENOENT') }}}); + throw new FS.ErrnoError({{{ cDefs.ENOENT }}}); } var lookup = FS.lookupPath(newpath, { parent: true }); var parent = lookup.node; if (!parent) { - throw new FS.ErrnoError({{{ cDefine('ENOENT') }}}); + throw new FS.ErrnoError({{{ cDefs.ENOENT }}}); } var newname = PATH.basename(newpath); var errCode = FS.mayCreate(parent, newname); @@ -709,7 +709,7 @@ FS.staticInit();` + throw new FS.ErrnoError(errCode); } if (!parent.node_ops.symlink) { - throw new FS.ErrnoError({{{ cDefine('EPERM') }}}); + throw new FS.ErrnoError({{{ cDefs.EPERM }}}); } #if FS_DEBUG if (FS.trackingDelegate['onMakeSymlink']) { @@ -732,22 +732,22 @@ FS.staticInit();` + lookup = FS.lookupPath(new_path, { parent: true }); new_dir = lookup.node; - if (!old_dir || !new_dir) throw new FS.ErrnoError({{{ cDefine('ENOENT') }}}); + if (!old_dir || !new_dir) throw new FS.ErrnoError({{{ cDefs.ENOENT }}}); // need to be part of the same mount if (old_dir.mount !== new_dir.mount) { - throw new FS.ErrnoError({{{ cDefine('EXDEV') }}}); + throw new FS.ErrnoError({{{ cDefs.EXDEV }}}); } // source must exist var old_node = FS.lookupNode(old_dir, old_name); // old path should not be an ancestor of the new path var relative = PATH_FS.relative(old_path, new_dirname); if (relative.charAt(0) !== '.') { - throw new FS.ErrnoError({{{ cDefine('EINVAL') }}}); + throw new FS.ErrnoError({{{ cDefs.EINVAL }}}); } // new path should not be an ancestor of the old path relative = PATH_FS.relative(new_path, old_dirname); if (relative.charAt(0) !== '.') { - throw new FS.ErrnoError({{{ cDefine('ENOTEMPTY') }}}); + throw new FS.ErrnoError({{{ cDefs.ENOTEMPTY }}}); } // see if the new path already exists var new_node; @@ -775,10 +775,10 @@ FS.staticInit();` + throw new FS.ErrnoError(errCode); } if (!old_dir.node_ops.rename) { - throw new FS.ErrnoError({{{ cDefine('EPERM') }}}); + throw new FS.ErrnoError({{{ cDefs.EPERM }}}); } if (FS.isMountpoint(old_node) || (new_node && FS.isMountpoint(new_node))) { - throw new FS.ErrnoError({{{ cDefine('EBUSY') }}}); + throw new FS.ErrnoError({{{ cDefs.EBUSY }}}); } // if we are going to change the parent, check write permissions if (new_dir !== old_dir) { @@ -820,10 +820,10 @@ FS.staticInit();` + throw new FS.ErrnoError(errCode); } if (!parent.node_ops.rmdir) { - throw new FS.ErrnoError({{{ cDefine('EPERM') }}}); + throw new FS.ErrnoError({{{ cDefs.EPERM }}}); } if (FS.isMountpoint(node)) { - throw new FS.ErrnoError({{{ cDefine('EBUSY') }}}); + throw new FS.ErrnoError({{{ cDefs.EBUSY }}}); } #if FS_DEBUG if (FS.trackingDelegate['willDeletePath']) { @@ -842,7 +842,7 @@ FS.staticInit();` + var lookup = FS.lookupPath(path, { follow: true }); var node = lookup.node; if (!node.node_ops.readdir) { - throw new FS.ErrnoError({{{ cDefine('ENOTDIR') }}}); + throw new FS.ErrnoError({{{ cDefs.ENOTDIR }}}); } return node.node_ops.readdir(node); }, @@ -850,7 +850,7 @@ FS.staticInit();` + var lookup = FS.lookupPath(path, { parent: true }); var parent = lookup.node; if (!parent) { - throw new FS.ErrnoError({{{ cDefine('ENOENT') }}}); + throw new FS.ErrnoError({{{ cDefs.ENOENT }}}); } var name = PATH.basename(path); var node = FS.lookupNode(parent, name); @@ -862,10 +862,10 @@ FS.staticInit();` + throw new FS.ErrnoError(errCode); } if (!parent.node_ops.unlink) { - throw new FS.ErrnoError({{{ cDefine('EPERM') }}}); + throw new FS.ErrnoError({{{ cDefs.EPERM }}}); } if (FS.isMountpoint(node)) { - throw new FS.ErrnoError({{{ cDefine('EBUSY') }}}); + throw new FS.ErrnoError({{{ cDefs.EBUSY }}}); } #if FS_DEBUG if (FS.trackingDelegate['willDeletePath']) { @@ -884,10 +884,10 @@ FS.staticInit();` + var lookup = FS.lookupPath(path); var link = lookup.node; if (!link) { - throw new FS.ErrnoError({{{ cDefine('ENOENT') }}}); + throw new FS.ErrnoError({{{ cDefs.ENOENT }}}); } if (!link.node_ops.readlink) { - throw new FS.ErrnoError({{{ cDefine('EINVAL') }}}); + throw new FS.ErrnoError({{{ cDefs.EINVAL }}}); } return PATH_FS.resolve(FS.getPath(link.parent), link.node_ops.readlink(link)); }, @@ -895,10 +895,10 @@ FS.staticInit();` + var lookup = FS.lookupPath(path, { follow: !dontFollow }); var node = lookup.node; if (!node) { - throw new FS.ErrnoError({{{ cDefine('ENOENT') }}}); + throw new FS.ErrnoError({{{ cDefs.ENOENT }}}); } if (!node.node_ops.getattr) { - throw new FS.ErrnoError({{{ cDefine('EPERM') }}}); + throw new FS.ErrnoError({{{ cDefs.EPERM }}}); } return node.node_ops.getattr(node); }, @@ -914,10 +914,10 @@ FS.staticInit();` + node = path; } if (!node.node_ops.setattr) { - throw new FS.ErrnoError({{{ cDefine('EPERM') }}}); + throw new FS.ErrnoError({{{ cDefs.EPERM }}}); } node.node_ops.setattr(node, { - mode: (mode & {{{ cDefine('S_IALLUGO') }}}) | (node.mode & ~{{{ cDefine('S_IALLUGO') }}}), + mode: (mode & {{{ cDefs.S_IALLUGO }}}) | (node.mode & ~{{{ cDefs.S_IALLUGO }}}), timestamp: Date.now() }); }, @@ -927,7 +927,7 @@ FS.staticInit();` + fchmod: (fd, mode) => { var stream = FS.getStream(fd); if (!stream) { - throw new FS.ErrnoError({{{ cDefine('EBADF') }}}); + throw new FS.ErrnoError({{{ cDefs.EBADF }}}); } FS.chmod(stream.node, mode); }, @@ -940,7 +940,7 @@ FS.staticInit();` + node = path; } if (!node.node_ops.setattr) { - throw new FS.ErrnoError({{{ cDefine('EPERM') }}}); + throw new FS.ErrnoError({{{ cDefs.EPERM }}}); } node.node_ops.setattr(node, { timestamp: Date.now() @@ -953,13 +953,13 @@ FS.staticInit();` + fchown: (fd, uid, gid) => { var stream = FS.getStream(fd); if (!stream) { - throw new FS.ErrnoError({{{ cDefine('EBADF') }}}); + throw new FS.ErrnoError({{{ cDefs.EBADF }}}); } FS.chown(stream.node, uid, gid); }, truncate: (path, len) => { if (len < 0) { - throw new FS.ErrnoError({{{ cDefine('EINVAL') }}}); + throw new FS.ErrnoError({{{ cDefs.EINVAL }}}); } var node; if (typeof path == 'string') { @@ -969,13 +969,13 @@ FS.staticInit();` + node = path; } if (!node.node_ops.setattr) { - throw new FS.ErrnoError({{{ cDefine('EPERM') }}}); + throw new FS.ErrnoError({{{ cDefs.EPERM }}}); } if (FS.isDir(node.mode)) { - throw new FS.ErrnoError({{{ cDefine('EISDIR') }}}); + throw new FS.ErrnoError({{{ cDefs.EISDIR }}}); } if (!FS.isFile(node.mode)) { - throw new FS.ErrnoError({{{ cDefine('EINVAL') }}}); + throw new FS.ErrnoError({{{ cDefs.EINVAL }}}); } var errCode = FS.nodePermissions(node, 'w'); if (errCode) { @@ -989,10 +989,10 @@ FS.staticInit();` + ftruncate: (fd, len) => { var stream = FS.getStream(fd); if (!stream) { - throw new FS.ErrnoError({{{ cDefine('EBADF') }}}); + throw new FS.ErrnoError({{{ cDefs.EBADF }}}); } - if ((stream.flags & {{{ cDefine('O_ACCMODE') }}}) === {{{ cDefine('O_RDONLY')}}}) { - throw new FS.ErrnoError({{{ cDefine('EINVAL') }}}); + if ((stream.flags & {{{ cDefs.O_ACCMODE }}}) === {{{ cDefs.O_RDONLY}}}) { + throw new FS.ErrnoError({{{ cDefs.EINVAL }}}); } FS.truncate(stream.node, len); }, @@ -1005,12 +1005,12 @@ FS.staticInit();` + }, open: (path, flags, mode) => { if (path === "") { - throw new FS.ErrnoError({{{ cDefine('ENOENT') }}}); + throw new FS.ErrnoError({{{ cDefs.ENOENT }}}); } flags = typeof flags == 'string' ? FS.modeStringToFlags(flags) : flags; mode = typeof mode == 'undefined' ? 438 /* 0666 */ : mode; - if ((flags & {{{ cDefine('O_CREAT') }}})) { - mode = (mode & {{{ cDefine('S_IALLUGO') }}}) | {{{ cDefine('S_IFREG') }}}; + if ((flags & {{{ cDefs.O_CREAT }}})) { + mode = (mode & {{{ cDefs.S_IALLUGO }}}) | {{{ cDefs.S_IFREG }}}; } else { mode = 0; } @@ -1021,7 +1021,7 @@ FS.staticInit();` + path = PATH.normalize(path); try { var lookup = FS.lookupPath(path, { - follow: !(flags & {{{ cDefine('O_NOFOLLOW') }}}) + follow: !(flags & {{{ cDefs.O_NOFOLLOW }}}) }); node = lookup.node; } catch (e) { @@ -1030,11 +1030,11 @@ FS.staticInit();` + } // perhaps we need to create the node var created = false; - if ((flags & {{{ cDefine('O_CREAT') }}})) { + if ((flags & {{{ cDefs.O_CREAT }}})) { if (node) { // if O_CREAT and O_EXCL are set, error out if the node already exists - if ((flags & {{{ cDefine('O_EXCL') }}})) { - throw new FS.ErrnoError({{{ cDefine('EEXIST') }}}); + if ((flags & {{{ cDefs.O_EXCL }}})) { + throw new FS.ErrnoError({{{ cDefs.EEXIST }}}); } } else { // node doesn't exist, try to create it @@ -1043,15 +1043,15 @@ FS.staticInit();` + } } if (!node) { - throw new FS.ErrnoError({{{ cDefine('ENOENT') }}}); + throw new FS.ErrnoError({{{ cDefs.ENOENT }}}); } // can't truncate a device if (FS.isChrdev(node.mode)) { - flags &= ~{{{ cDefine('O_TRUNC') }}}; + flags &= ~{{{ cDefs.O_TRUNC }}}; } // if asked only for a directory, then this must be one - if ((flags & {{{ cDefine('O_DIRECTORY') }}}) && !FS.isDir(node.mode)) { - throw new FS.ErrnoError({{{ cDefine('ENOTDIR') }}}); + if ((flags & {{{ cDefs.O_DIRECTORY }}}) && !FS.isDir(node.mode)) { + throw new FS.ErrnoError({{{ cDefs.ENOTDIR }}}); } // check permissions, if this is not a file we just created now (it is ok to // create and write to a file with read-only permissions; it is read-only @@ -1063,14 +1063,14 @@ FS.staticInit();` + } } // do truncation if necessary - if ((flags & {{{ cDefine('O_TRUNC')}}}) && !created) { + if ((flags & {{{ cDefs.O_TRUNC}}}) && !created) { FS.truncate(node, 0); } #if FS_DEBUG var trackingFlags = flags #endif // we've already handled these, don't pass down to the underlying vfs - flags &= ~({{{ cDefine('O_EXCL') }}} | {{{ cDefine('O_TRUNC') }}} | {{{ cDefine('O_NOFOLLOW') }}}); + flags &= ~({{{ cDefs.O_EXCL }}} | {{{ cDefs.O_TRUNC }}} | {{{ cDefs.O_NOFOLLOW }}}); // register the stream with the filesystem var stream = FS.createStream({ @@ -1088,7 +1088,7 @@ FS.staticInit();` + if (stream.stream_ops.open) { stream.stream_ops.open(stream); } - if (Module['logReadFiles'] && !(flags & {{{ cDefine('O_WRONLY')}}})) { + if (Module['logReadFiles'] && !(flags & {{{ cDefs.O_WRONLY}}})) { if (!FS.readFiles) FS.readFiles = {}; if (!(path in FS.readFiles)) { FS.readFiles[path] = 1; @@ -1106,7 +1106,7 @@ FS.staticInit();` + }, close: (stream) => { if (FS.isClosed(stream)) { - throw new FS.ErrnoError({{{ cDefine('EBADF') }}}); + throw new FS.ErrnoError({{{ cDefs.EBADF }}}); } if (stream.getdents) stream.getdents = null; // free readdir state try { @@ -1130,13 +1130,13 @@ FS.staticInit();` + }, llseek: (stream, offset, whence) => { if (FS.isClosed(stream)) { - throw new FS.ErrnoError({{{ cDefine('EBADF') }}}); + throw new FS.ErrnoError({{{ cDefs.EBADF }}}); } if (!stream.seekable || !stream.stream_ops.llseek) { - throw new FS.ErrnoError({{{ cDefine('ESPIPE') }}}); + throw new FS.ErrnoError({{{ cDefs.ESPIPE }}}); } - if (whence != {{{ cDefine('SEEK_SET') }}} && whence != {{{ cDefine('SEEK_CUR') }}} && whence != {{{ cDefine('SEEK_END') }}}) { - throw new FS.ErrnoError({{{ cDefine('EINVAL') }}}); + if (whence != {{{ cDefs.SEEK_SET }}} && whence != {{{ cDefs.SEEK_CUR }}} && whence != {{{ cDefs.SEEK_END }}}) { + throw new FS.ErrnoError({{{ cDefs.EINVAL }}}); } stream.position = stream.stream_ops.llseek(stream, offset, whence); stream.ungotten = []; @@ -1152,25 +1152,25 @@ FS.staticInit();` + offset >>>= 0; #endif if (length < 0 || position < 0) { - throw new FS.ErrnoError({{{ cDefine('EINVAL') }}}); + throw new FS.ErrnoError({{{ cDefs.EINVAL }}}); } if (FS.isClosed(stream)) { - throw new FS.ErrnoError({{{ cDefine('EBADF') }}}); + throw new FS.ErrnoError({{{ cDefs.EBADF }}}); } - if ((stream.flags & {{{ cDefine('O_ACCMODE') }}}) === {{{ cDefine('O_WRONLY')}}}) { - throw new FS.ErrnoError({{{ cDefine('EBADF') }}}); + if ((stream.flags & {{{ cDefs.O_ACCMODE }}}) === {{{ cDefs.O_WRONLY}}}) { + throw new FS.ErrnoError({{{ cDefs.EBADF }}}); } if (FS.isDir(stream.node.mode)) { - throw new FS.ErrnoError({{{ cDefine('EISDIR') }}}); + throw new FS.ErrnoError({{{ cDefs.EISDIR }}}); } if (!stream.stream_ops.read) { - throw new FS.ErrnoError({{{ cDefine('EINVAL') }}}); + throw new FS.ErrnoError({{{ cDefs.EINVAL }}}); } var seeking = typeof position != 'undefined'; if (!seeking) { position = stream.position; } else if (!stream.seekable) { - throw new FS.ErrnoError({{{ cDefine('ESPIPE') }}}); + throw new FS.ErrnoError({{{ cDefs.ESPIPE }}}); } var bytesRead = stream.stream_ops.read(stream, buffer, offset, length, position); if (!seeking) stream.position += bytesRead; @@ -1186,29 +1186,29 @@ FS.staticInit();` + offset >>>= 0; #endif if (length < 0 || position < 0) { - throw new FS.ErrnoError({{{ cDefine('EINVAL') }}}); + throw new FS.ErrnoError({{{ cDefs.EINVAL }}}); } if (FS.isClosed(stream)) { - throw new FS.ErrnoError({{{ cDefine('EBADF') }}}); + throw new FS.ErrnoError({{{ cDefs.EBADF }}}); } - if ((stream.flags & {{{ cDefine('O_ACCMODE') }}}) === {{{ cDefine('O_RDONLY')}}}) { - throw new FS.ErrnoError({{{ cDefine('EBADF') }}}); + if ((stream.flags & {{{ cDefs.O_ACCMODE }}}) === {{{ cDefs.O_RDONLY}}}) { + throw new FS.ErrnoError({{{ cDefs.EBADF }}}); } if (FS.isDir(stream.node.mode)) { - throw new FS.ErrnoError({{{ cDefine('EISDIR') }}}); + throw new FS.ErrnoError({{{ cDefs.EISDIR }}}); } if (!stream.stream_ops.write) { - throw new FS.ErrnoError({{{ cDefine('EINVAL') }}}); + throw new FS.ErrnoError({{{ cDefs.EINVAL }}}); } - if (stream.seekable && stream.flags & {{{ cDefine('O_APPEND') }}}) { + if (stream.seekable && stream.flags & {{{ cDefs.O_APPEND }}}) { // seek to the end before writing in append mode - FS.llseek(stream, 0, {{{ cDefine('SEEK_END') }}}); + FS.llseek(stream, 0, {{{ cDefs.SEEK_END }}}); } var seeking = typeof position != 'undefined'; if (!seeking) { position = stream.position; } else if (!stream.seekable) { - throw new FS.ErrnoError({{{ cDefine('ESPIPE') }}}); + throw new FS.ErrnoError({{{ cDefs.ESPIPE }}}); } var bytesWritten = stream.stream_ops.write(stream, buffer, offset, length, position, canOwn); if (!seeking) stream.position += bytesWritten; @@ -1221,19 +1221,19 @@ FS.staticInit();` + }, allocate: (stream, offset, length) => { if (FS.isClosed(stream)) { - throw new FS.ErrnoError({{{ cDefine('EBADF') }}}); + throw new FS.ErrnoError({{{ cDefs.EBADF }}}); } if (offset < 0 || length <= 0) { - throw new FS.ErrnoError({{{ cDefine('EINVAL') }}}); + throw new FS.ErrnoError({{{ cDefs.EINVAL }}}); } - if ((stream.flags & {{{ cDefine('O_ACCMODE') }}}) === {{{ cDefine('O_RDONLY')}}}) { - throw new FS.ErrnoError({{{ cDefine('EBADF') }}}); + if ((stream.flags & {{{ cDefs.O_ACCMODE }}}) === {{{ cDefs.O_RDONLY}}}) { + throw new FS.ErrnoError({{{ cDefs.EBADF }}}); } if (!FS.isFile(stream.node.mode) && !FS.isDir(stream.node.mode)) { - throw new FS.ErrnoError({{{ cDefine('ENODEV') }}}); + throw new FS.ErrnoError({{{ cDefs.ENODEV }}}); } if (!stream.stream_ops.allocate) { - throw new FS.ErrnoError({{{ cDefine('EOPNOTSUPP') }}}); + throw new FS.ErrnoError({{{ cDefs.EOPNOTSUPP }}}); } stream.stream_ops.allocate(stream, offset, length); }, @@ -1244,16 +1244,16 @@ FS.staticInit();` + // to write to file opened in read-only mode with MAP_PRIVATE flag, // as all modifications will be visible only in the memory of // the current process. - if ((prot & {{{ cDefine('PROT_WRITE') }}}) !== 0 - && (flags & {{{ cDefine('MAP_PRIVATE')}}}) === 0 - && (stream.flags & {{{ cDefine('O_ACCMODE') }}}) !== {{{ cDefine('O_RDWR')}}}) { - throw new FS.ErrnoError({{{ cDefine('EACCES') }}}); + if ((prot & {{{ cDefs.PROT_WRITE }}}) !== 0 + && (flags & {{{ cDefs.MAP_PRIVATE}}}) === 0 + && (stream.flags & {{{ cDefs.O_ACCMODE }}}) !== {{{ cDefs.O_RDWR}}}) { + throw new FS.ErrnoError({{{ cDefs.EACCES }}}); } - if ((stream.flags & {{{ cDefine('O_ACCMODE') }}}) === {{{ cDefine('O_WRONLY')}}}) { - throw new FS.ErrnoError({{{ cDefine('EACCES') }}}); + if ((stream.flags & {{{ cDefs.O_ACCMODE }}}) === {{{ cDefs.O_WRONLY}}}) { + throw new FS.ErrnoError({{{ cDefs.EACCES }}}); } if (!stream.stream_ops.mmap) { - throw new FS.ErrnoError({{{ cDefine('ENODEV') }}}); + throw new FS.ErrnoError({{{ cDefs.ENODEV }}}); } return stream.stream_ops.mmap(stream, length, position, prot, flags); }, @@ -1269,12 +1269,12 @@ FS.staticInit();` + munmap: (stream) => 0, ioctl: (stream, cmd, arg) => { if (!stream.stream_ops.ioctl) { - throw new FS.ErrnoError({{{ cDefine('ENOTTY') }}}); + throw new FS.ErrnoError({{{ cDefs.ENOTTY }}}); } return stream.stream_ops.ioctl(stream, cmd, arg); }, readFile: (path, opts = {}) => { - opts.flags = opts.flags || {{{ cDefine('O_RDONLY') }}}; + opts.flags = opts.flags || {{{ cDefs.O_RDONLY }}}; opts.encoding = opts.encoding || 'binary'; if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') { throw new Error('Invalid encoding type "' + opts.encoding + '"'); @@ -1294,7 +1294,7 @@ FS.staticInit();` + return ret; }, writeFile: (path, data, opts = {}) => { - opts.flags = opts.flags || {{{ cDefine('O_TRUNC') | cDefine('O_CREAT') | cDefine('O_WRONLY') }}}; + opts.flags = opts.flags || {{{ cDefs.O_TRUNC | cDefs.O_CREAT | cDefs.O_WRONLY }}}; var stream = FS.open(path, opts.flags, opts.mode); if (typeof data == 'string') { var buf = new Uint8Array(lengthBytesUTF8(data)+1); @@ -1315,10 +1315,10 @@ FS.staticInit();` + chdir: (path) => { var lookup = FS.lookupPath(path, { follow: true }); if (lookup.node === null) { - throw new FS.ErrnoError({{{ cDefine('ENOENT') }}}); + throw new FS.ErrnoError({{{ cDefs.ENOENT }}}); } if (!FS.isDir(lookup.node.mode)) { - throw new FS.ErrnoError({{{ cDefine('ENOTDIR') }}}); + throw new FS.ErrnoError({{{ cDefs.ENOTDIR }}}); } var errCode = FS.nodePermissions(lookup.node, 'x'); if (errCode) { @@ -1364,12 +1364,12 @@ FS.staticInit();` + FS.mkdir('/proc/self/fd'); FS.mount({ mount: () => { - var node = FS.createNode(proc_self, 'fd', {{{ cDefine('S_IFDIR') }}} | 511 /* 0777 */, {{{ cDefine('S_IXUGO') }}}); + var node = FS.createNode(proc_self, 'fd', {{{ cDefs.S_IFDIR }}} | 511 /* 0777 */, {{{ cDefs.S_IXUGO }}}); node.node_ops = { lookup: (parent, name) => { var fd = +name; var stream = FS.getStream(fd); - if (!stream) throw new FS.ErrnoError({{{ cDefine('EBADF') }}}); + if (!stream) throw new FS.ErrnoError({{{ cDefs.EBADF }}}); var ret = { parent: null, mount: { mountpoint: 'fake' }, @@ -1409,9 +1409,9 @@ FS.staticInit();` + } // open default streams for the stdin, stdout and stderr devices - var stdin = FS.open('/dev/stdin', {{{ cDefine('O_RDONLY') }}}); - var stdout = FS.open('/dev/stdout', {{{ cDefine('O_WRONLY') }}}); - var stderr = FS.open('/dev/stderr', {{{ cDefine('O_WRONLY') }}}); + var stdin = FS.open('/dev/stdin', {{{ cDefs.O_RDONLY }}}); + var stdout = FS.open('/dev/stdout', {{{ cDefs.O_WRONLY }}}); + var stderr = FS.open('/dev/stderr', {{{ cDefs.O_WRONLY }}}); #if ASSERTIONS assert(stdin.fd === 0, 'invalid handle for stdin (' + stdin.fd + ')'); assert(stdout.fd === 1, 'invalid handle for stdout (' + stdout.fd + ')'); @@ -1460,7 +1460,7 @@ FS.staticInit();` + FS.ErrnoError.prototype = new Error(); FS.ErrnoError.prototype.constructor = FS.ErrnoError; // Some errors may happen quite a bit, to avoid overhead we reuse them (and suffer a lack of stack info) - [{{{ cDefine('ENOENT') }}}].forEach((code) => { + [{{{ cDefs.ENOENT }}}].forEach((code) => { FS.genericErrors[code] = new FS.ErrnoError(code); FS.genericErrors[code].stack = ''; }); @@ -1528,8 +1528,8 @@ FS.staticInit();` + // getMode: (canRead, canWrite) => { var mode = 0; - if (canRead) mode |= {{{ cDefine('S_IRUGO') }}} | {{{ cDefine('S_IXUGO') }}}; - if (canWrite) mode |= {{{ cDefine('S_IWUGO') }}}; + if (canRead) mode |= {{{ cDefs.S_IRUGO }}} | {{{ cDefs.S_IXUGO }}}; + if (canWrite) mode |= {{{ cDefs.S_IWUGO }}}; return mode; }, findObject: (path, dontResolveLastLink) => { @@ -1603,8 +1603,8 @@ FS.staticInit();` + data = arr; } // make sure we can write to the file - FS.chmod(node, mode | {{{ cDefine('S_IWUGO') }}}); - var stream = FS.open(node, {{{ cDefine('O_TRUNC') | cDefine('O_CREAT') | cDefine('O_WRONLY') }}}); + FS.chmod(node, mode | {{{ cDefs.S_IWUGO }}}); + var stream = FS.open(node, {{{ cDefs.O_TRUNC | cDefs.O_CREAT | cDefs.O_WRONLY }}}); FS.write(stream, data, 0, data.length, 0, canOwn); FS.close(stream); FS.chmod(node, mode); @@ -1635,10 +1635,10 @@ FS.staticInit();` + try { result = input(); } catch (e) { - throw new FS.ErrnoError({{{ cDefine('EIO') }}}); + throw new FS.ErrnoError({{{ cDefs.EIO }}}); } if (result === undefined && bytesRead === 0) { - throw new FS.ErrnoError({{{ cDefine('EAGAIN') }}}); + throw new FS.ErrnoError({{{ cDefs.EAGAIN }}}); } if (result === null || result === undefined) break; bytesRead++; @@ -1654,7 +1654,7 @@ FS.staticInit();` + try { output(buffer[offset+i]); } catch (e) { - throw new FS.ErrnoError({{{ cDefine('EIO') }}}); + throw new FS.ErrnoError({{{ cDefs.EIO }}}); } } if (length) { @@ -1679,7 +1679,7 @@ FS.staticInit();` + obj.contents = intArrayFromString(read_(obj.url), true); obj.usedBytes = obj.contents.length; } catch (e) { - throw new FS.ErrnoError({{{ cDefine('EIO') }}}); + throw new FS.ErrnoError({{{ cDefs.EIO }}}); } } else { throw new Error('Cannot load without read() or XMLHttpRequest.'); @@ -1854,7 +1854,7 @@ FS.staticInit();` + FS.forceLoadFile(node); var ptr = mmapAlloc(length); if (!ptr) { - throw new FS.ErrnoError({{{ cDefine('ENOMEM') }}}); + throw new FS.ErrnoError({{{ cDefs.ENOMEM }}}); } writeChunks(stream, HEAP8, ptr, length, position); return { ptr: ptr, allocated: true }; diff --git a/src/library_html5.js b/src/library_html5.js index b0a58ac35cebb..36853a1b06fc3 100644 --- a/src/library_html5.js +++ b/src/library_html5.js @@ -194,7 +194,7 @@ var LibraryHTML5 = { {{{ makeSetValue('varargs', 0, 'eventTypeId', 'i32') }}}; {{{ makeSetValue('varargs', 4, 'eventData', 'i32') }}}; {{{ makeSetValue('varargs', 8, 'userData', 'i32') }}}; - _emscripten_dispatch_to_thread_(targetThread, {{{ cDefine('EM_FUNC_SIG_IIII') }}}, eventHandlerFunc, eventData, varargs); + _emscripten_dispatch_to_thread_(targetThread, {{{ cDefs.EM_FUNC_SIG_IIII }}}, eventHandlerFunc, eventData, varargs); }); }, #endif @@ -202,8 +202,8 @@ var LibraryHTML5 = { #if PTHREADS getTargetThreadForEventCallback: function(targetThread) { switch (targetThread) { - case {{{ cDefine('EM_CALLBACK_THREAD_CONTEXT_MAIN_RUNTIME_THREAD') }}}: return 0; // The event callback for the current event should be called on the main browser thread. (0 == don't proxy) - case {{{ cDefine('EM_CALLBACK_THREAD_CONTEXT_CALLING_THREAD') }}}: return PThread.currentProxiedOperationCallerThread; // The event callback for the current event should be backproxied to the thread that is registering the event. + case {{{ cDefs.EM_CALLBACK_THREAD_CONTEXT_MAIN_RUNTIME_THREAD }}}: return 0; // The event callback for the current event should be called on the main browser thread. (0 == don't proxy) + case {{{ cDefs.EM_CALLBACK_THREAD_CONTEXT_CALLING_THREAD }}}: return PThread.currentProxiedOperationCallerThread; // The event callback for the current event should be backproxied to the thread that is registering the event. default: return targetThread; // The event callback for the current event should be proxied to the given specific thread. } }, @@ -265,10 +265,10 @@ var LibraryHTML5 = { HEAP32[idx + {{{ C_STRUCTS.EmscriptenKeyboardEvent.charCode / 4}}}] = e.charCode; HEAP32[idx + {{{ C_STRUCTS.EmscriptenKeyboardEvent.keyCode / 4}}}] = e.keyCode; HEAP32[idx + {{{ C_STRUCTS.EmscriptenKeyboardEvent.which / 4}}}] = e.which; - stringToUTF8(e.key || '', keyEventData + {{{ C_STRUCTS.EmscriptenKeyboardEvent.key }}}, {{{ cDefine('EM_HTML5_SHORT_STRING_LEN_BYTES') }}}); - stringToUTF8(e.code || '', keyEventData + {{{ C_STRUCTS.EmscriptenKeyboardEvent.code }}}, {{{ cDefine('EM_HTML5_SHORT_STRING_LEN_BYTES') }}}); - stringToUTF8(e.char || '', keyEventData + {{{ C_STRUCTS.EmscriptenKeyboardEvent.charValue }}}, {{{ cDefine('EM_HTML5_SHORT_STRING_LEN_BYTES') }}}); - stringToUTF8(e.locale || '', keyEventData + {{{ C_STRUCTS.EmscriptenKeyboardEvent.locale }}}, {{{ cDefine('EM_HTML5_SHORT_STRING_LEN_BYTES') }}}); + stringToUTF8(e.key || '', keyEventData + {{{ C_STRUCTS.EmscriptenKeyboardEvent.key }}}, {{{ cDefs.EM_HTML5_SHORT_STRING_LEN_BYTES }}}); + stringToUTF8(e.code || '', keyEventData + {{{ C_STRUCTS.EmscriptenKeyboardEvent.code }}}, {{{ cDefs.EM_HTML5_SHORT_STRING_LEN_BYTES }}}); + stringToUTF8(e.char || '', keyEventData + {{{ C_STRUCTS.EmscriptenKeyboardEvent.charValue }}}, {{{ cDefs.EM_HTML5_SHORT_STRING_LEN_BYTES }}}); + stringToUTF8(e.locale || '', keyEventData + {{{ C_STRUCTS.EmscriptenKeyboardEvent.locale }}}, {{{ cDefs.EM_HTML5_SHORT_STRING_LEN_BYTES }}}); #if PTHREADS if (targetThread) JSEvents.queueEventHandlerOnThread_iiii(targetThread, callbackfunc, eventTypeId, keyEventData, userData); @@ -402,24 +402,24 @@ var LibraryHTML5 = { emscripten_set_keypress_callback_on_thread__sig: 'ippipp', emscripten_set_keypress_callback_on_thread__deps: ['$registerKeyEventCallback'], emscripten_set_keypress_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerKeyEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_KEYPRESS') }}}, "keypress", targetThread); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + registerKeyEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_KEYPRESS }}}, "keypress", targetThread); + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_set_keydown_callback_on_thread__proxy: 'sync', emscripten_set_keydown_callback_on_thread__sig: 'ippipp', emscripten_set_keydown_callback_on_thread__deps: ['$registerKeyEventCallback'], emscripten_set_keydown_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerKeyEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_KEYDOWN') }}}, "keydown", targetThread); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + registerKeyEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_KEYDOWN }}}, "keydown", targetThread); + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_set_keyup_callback_on_thread__proxy: 'sync', emscripten_set_keyup_callback_on_thread__sig: 'ippipp', emscripten_set_keyup_callback_on_thread__deps: ['$registerKeyEventCallback'], emscripten_set_keyup_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerKeyEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_KEYUP') }}}, "keyup", targetThread); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + registerKeyEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_KEYUP }}}, "keyup", targetThread); + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, // Outline access to function .getBoundingClientRect() since it is a long string. Closure compiler does not outline access to it by itself, but it can inline access if @@ -549,84 +549,84 @@ var LibraryHTML5 = { emscripten_set_click_callback_on_thread__sig: 'ippipp', emscripten_set_click_callback_on_thread__deps: ['$registerMouseEventCallback'], emscripten_set_click_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_CLICK') }}}, "click", targetThread); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_CLICK }}}, "click", targetThread); + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_set_mousedown_callback_on_thread__proxy: 'sync', emscripten_set_mousedown_callback_on_thread__sig: 'ippipp', emscripten_set_mousedown_callback_on_thread__deps: ['$registerMouseEventCallback'], emscripten_set_mousedown_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_MOUSEDOWN') }}}, "mousedown", targetThread); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_MOUSEDOWN }}}, "mousedown", targetThread); + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_set_mouseup_callback_on_thread__proxy: 'sync', emscripten_set_mouseup_callback_on_thread__sig: 'ippipp', emscripten_set_mouseup_callback_on_thread__deps: ['$registerMouseEventCallback'], emscripten_set_mouseup_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_MOUSEUP') }}}, "mouseup", targetThread); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_MOUSEUP }}}, "mouseup", targetThread); + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_set_dblclick_callback_on_thread__proxy: 'sync', emscripten_set_dblclick_callback_on_thread__sig: 'ippipp', emscripten_set_dblclick_callback_on_thread__deps: ['$registerMouseEventCallback'], emscripten_set_dblclick_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_DBLCLICK') }}}, "dblclick", targetThread); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_DBLCLICK }}}, "dblclick", targetThread); + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_set_mousemove_callback_on_thread__proxy: 'sync', emscripten_set_mousemove_callback_on_thread__sig: 'ippipp', emscripten_set_mousemove_callback_on_thread__deps: ['$registerMouseEventCallback'], emscripten_set_mousemove_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_MOUSEMOVE') }}}, "mousemove", targetThread); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_MOUSEMOVE }}}, "mousemove", targetThread); + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_set_mouseenter_callback_on_thread__proxy: 'sync', emscripten_set_mouseenter_callback_on_thread__sig: 'ippipp', emscripten_set_mouseenter_callback_on_thread__deps: ['$registerMouseEventCallback'], emscripten_set_mouseenter_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_MOUSEENTER') }}}, "mouseenter", targetThread); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_MOUSEENTER }}}, "mouseenter", targetThread); + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_set_mouseleave_callback_on_thread__proxy: 'sync', emscripten_set_mouseleave_callback_on_thread__sig: 'ippipp', emscripten_set_mouseleave_callback_on_thread__deps: ['$registerMouseEventCallback'], emscripten_set_mouseleave_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_MOUSELEAVE') }}}, "mouseleave", targetThread); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_MOUSELEAVE }}}, "mouseleave", targetThread); + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_set_mouseover_callback_on_thread__proxy: 'sync', emscripten_set_mouseover_callback_on_thread__sig: 'ippipp', emscripten_set_mouseover_callback_on_thread__deps: ['$registerMouseEventCallback'], emscripten_set_mouseover_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_MOUSEOVER') }}}, "mouseover", targetThread); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_MOUSEOVER }}}, "mouseover", targetThread); + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_set_mouseout_callback_on_thread__proxy: 'sync', emscripten_set_mouseout_callback_on_thread__sig: 'ippipp', emscripten_set_mouseout_callback_on_thread__deps: ['$registerMouseEventCallback'], emscripten_set_mouseout_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_MOUSEOUT') }}}, "mouseout", targetThread); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_MOUSEOUT }}}, "mouseout", targetThread); + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_get_mouse_status__proxy: 'sync', emscripten_get_mouse_status__sig: 'ip', emscripten_get_mouse_status__deps: ['$JSEvents'], emscripten_get_mouse_status: function(mouseState) { - if (!JSEvents.mouseEvent) return {{{ cDefine('EMSCRIPTEN_RESULT_NO_DATA') }}}; + if (!JSEvents.mouseEvent) return {{{ cDefs.EMSCRIPTEN_RESULT_NO_DATA }}}; // HTML5 does not really have a polling API for mouse events, so implement one manually by // returning the data from the most recently received event. This requires that user has registered // at least some no-op function as an event handler to any of the mouse function. HEAP8.set(HEAP8.subarray(JSEvents.mouseEvent, JSEvents.mouseEvent + {{{ C_STRUCTS.EmscriptenMouseEvent.__size__ }}}), mouseState); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, $registerWheelEventCallback__deps: ['$JSEvents', '$fillMouseEventData', '$findEventTarget'], @@ -694,15 +694,15 @@ var LibraryHTML5 = { emscripten_set_wheel_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { target = findEventTarget(target); if (typeof target.onwheel != 'undefined') { - registerWheelEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_WHEEL') }}}, "wheel", targetThread); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + registerWheelEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_WHEEL }}}, "wheel", targetThread); + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; #if MIN_IE_VERSION <= 8 || MIN_SAFARI_VERSION < 60100 // Browsers that do not support https://caniuse.com/#feat=mdn-api_wheelevent } else if (typeof target.onmousewheel != 'undefined') { - registerWheelEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_WHEEL') }}}, "mousewheel", targetThread); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + registerWheelEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_WHEEL }}}, "mousewheel", targetThread); + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; #endif } else { - return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; } }, @@ -772,16 +772,16 @@ var LibraryHTML5 = { emscripten_set_resize_callback_on_thread__sig: 'ippipp', emscripten_set_resize_callback_on_thread__deps: ['$registerUiEventCallback'], emscripten_set_resize_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerUiEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_RESIZE') }}}, "resize", targetThread); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + registerUiEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_RESIZE }}}, "resize", targetThread); + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_set_scroll_callback_on_thread__proxy: 'sync', emscripten_set_scroll_callback_on_thread__sig: 'ippipp', emscripten_set_scroll_callback_on_thread__deps: ['$registerUiEventCallback'], emscripten_set_scroll_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerUiEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_SCROLL') }}}, "scroll", targetThread); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + registerUiEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_SCROLL }}}, "scroll", targetThread); + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, $registerFocusEventCallback__deps: ['$JSEvents', '$findEventTarget'], @@ -800,8 +800,8 @@ var LibraryHTML5 = { #else var focusEvent = JSEvents.focusEvent; #endif - stringToUTF8(nodeName, focusEvent + {{{ C_STRUCTS.EmscriptenFocusEvent.nodeName }}}, {{{ cDefine('EM_HTML5_LONG_STRING_LEN_BYTES') }}}); - stringToUTF8(id, focusEvent + {{{ C_STRUCTS.EmscriptenFocusEvent.id }}}, {{{ cDefine('EM_HTML5_LONG_STRING_LEN_BYTES') }}}); + stringToUTF8(nodeName, focusEvent + {{{ C_STRUCTS.EmscriptenFocusEvent.nodeName }}}, {{{ cDefs.EM_HTML5_LONG_STRING_LEN_BYTES }}}); + stringToUTF8(id, focusEvent + {{{ C_STRUCTS.EmscriptenFocusEvent.id }}}, {{{ cDefs.EM_HTML5_LONG_STRING_LEN_BYTES }}}); #if PTHREADS if (targetThread) JSEvents.queueEventHandlerOnThread_iiii(targetThread, callbackfunc, eventTypeId, focusEvent, userData); @@ -824,32 +824,32 @@ var LibraryHTML5 = { emscripten_set_blur_callback_on_thread__sig: 'ippipp', emscripten_set_blur_callback_on_thread__deps: ['$registerFocusEventCallback'], emscripten_set_blur_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_BLUR') }}}, "blur", targetThread); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_BLUR }}}, "blur", targetThread); + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_set_focus_callback_on_thread__proxy: 'sync', emscripten_set_focus_callback_on_thread__sig: 'ippipp', emscripten_set_focus_callback_on_thread__deps: ['$registerFocusEventCallback'], emscripten_set_focus_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_FOCUS') }}}, "focus", targetThread); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_FOCUS }}}, "focus", targetThread); + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_set_focusin_callback_on_thread__proxy: 'sync', emscripten_set_focusin_callback_on_thread__sig: 'ippipp', emscripten_set_focusin_callback_on_thread__deps: ['$registerFocusEventCallback'], emscripten_set_focusin_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_FOCUSIN') }}}, "focusin", targetThread); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_FOCUSIN }}}, "focusin", targetThread); + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_set_focusout_callback_on_thread__proxy: 'sync', emscripten_set_focusout_callback_on_thread__sig: 'ippipp', emscripten_set_focusout_callback_on_thread__deps: ['$registerFocusEventCallback'], emscripten_set_focusout_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_FOCUSOUT') }}}, "focusout", targetThread); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_FOCUSOUT }}}, "focusout", targetThread); + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, $fillDeviceOrientationEventData__deps: ['$JSEvents'], @@ -894,31 +894,31 @@ var LibraryHTML5 = { emscripten_set_deviceorientation_callback_on_thread__sig: 'ipipp', emscripten_set_deviceorientation_callback_on_thread__deps: ['$registerDeviceOrientationEventCallback'], emscripten_set_deviceorientation_callback_on_thread: function(userData, useCapture, callbackfunc, targetThread) { - registerDeviceOrientationEventCallback({{{ cDefine('EMSCRIPTEN_EVENT_TARGET_WINDOW') }}}, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_DEVICEORIENTATION') }}}, "deviceorientation", targetThread); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + registerDeviceOrientationEventCallback({{{ cDefs.EMSCRIPTEN_EVENT_TARGET_WINDOW }}}, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_DEVICEORIENTATION }}}, "deviceorientation", targetThread); + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_get_deviceorientation_status__proxy: 'sync', emscripten_get_deviceorientation_status__sig: 'ip', emscripten_get_deviceorientation_status__deps: ['$JSEvents', '$registerDeviceOrientationEventCallback'], emscripten_get_deviceorientation_status: function(orientationState) { - if (!JSEvents.deviceOrientationEvent) return {{{ cDefine('EMSCRIPTEN_RESULT_NO_DATA') }}}; + if (!JSEvents.deviceOrientationEvent) return {{{ cDefs.EMSCRIPTEN_RESULT_NO_DATA }}}; // HTML5 does not really have a polling API for device orientation events, so implement one manually by // returning the data from the most recently received event. This requires that user has registered // at least some no-op function as an event handler. HEAP32.set(HEAP32.subarray(JSEvents.deviceOrientationEvent, {{{ C_STRUCTS.EmscriptenDeviceOrientationEvent.__size__ }}}), orientationState); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, $fillDeviceMotionEventData__deps: ['$JSEvents'], $fillDeviceMotionEventData: function(eventStruct, e, target) { var supportedFields = 0; var a = e['acceleration']; - supportedFields |= a && {{{ cDefine('EMSCRIPTEN_DEVICE_MOTION_EVENT_SUPPORTS_ACCELERATION') }}}; + supportedFields |= a && {{{ cDefs.EMSCRIPTEN_DEVICE_MOTION_EVENT_SUPPORTS_ACCELERATION }}}; var ag = e['accelerationIncludingGravity']; - supportedFields |= ag && {{{ cDefine('EMSCRIPTEN_DEVICE_MOTION_EVENT_SUPPORTS_ACCELERATION_INCLUDING_GRAVITY') }}}; + supportedFields |= ag && {{{ cDefs.EMSCRIPTEN_DEVICE_MOTION_EVENT_SUPPORTS_ACCELERATION_INCLUDING_GRAVITY }}}; var rr = e['rotationRate']; - supportedFields |= rr && {{{ cDefine('EMSCRIPTEN_DEVICE_MOTION_EVENT_SUPPORTS_ROTATION_RATE') }}}; + supportedFields |= rr && {{{ cDefs.EMSCRIPTEN_DEVICE_MOTION_EVENT_SUPPORTS_ROTATION_RATE }}}; a = a || {}; ag = ag || {}; rr = rr || {}; @@ -967,20 +967,20 @@ var LibraryHTML5 = { emscripten_set_devicemotion_callback_on_thread__sig: 'ipipp', emscripten_set_devicemotion_callback_on_thread__deps: ['$registerDeviceMotionEventCallback'], emscripten_set_devicemotion_callback_on_thread: function(userData, useCapture, callbackfunc, targetThread) { - registerDeviceMotionEventCallback({{{ cDefine('EMSCRIPTEN_EVENT_TARGET_WINDOW') }}}, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_DEVICEMOTION') }}}, "devicemotion", targetThread); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + registerDeviceMotionEventCallback({{{ cDefs.EMSCRIPTEN_EVENT_TARGET_WINDOW }}}, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_DEVICEMOTION }}}, "devicemotion", targetThread); + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_get_devicemotion_status__proxy: 'sync', emscripten_get_devicemotion_status__sig: 'ip', emscripten_get_devicemotion_status__deps: ['$JSEvents'], emscripten_get_devicemotion_status: function(motionState) { - if (!JSEvents.deviceMotionEvent) return {{{ cDefine('EMSCRIPTEN_RESULT_NO_DATA') }}}; + if (!JSEvents.deviceMotionEvent) return {{{ cDefs.EMSCRIPTEN_RESULT_NO_DATA }}}; // HTML5 does not really have a polling API for device motion events, so implement one manually by // returning the data from the most recently received event. This requires that user has registered // at least some no-op function as an event handler. HEAP32.set(HEAP32.subarray(JSEvents.deviceMotionEvent, {{{ C_STRUCTS.EmscriptenDeviceMotionEvent.__size__ }}}), motionState); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, $screenOrientation: function() { @@ -1044,18 +1044,18 @@ var LibraryHTML5 = { emscripten_set_orientationchange_callback_on_thread__sig: 'ipipp', emscripten_set_orientationchange_callback_on_thread__deps: ['$registerOrientationChangeEventCallback'], emscripten_set_orientationchange_callback_on_thread: function(userData, useCapture, callbackfunc, targetThread) { - if (!screen || !screen['addEventListener']) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; - registerOrientationChangeEventCallback(screen, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_ORIENTATIONCHANGE') }}}, "orientationchange", targetThread); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + if (!screen || !screen['addEventListener']) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; + registerOrientationChangeEventCallback(screen, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_ORIENTATIONCHANGE }}}, "orientationchange", targetThread); + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_get_orientation_status__proxy: 'sync', emscripten_get_orientation_status__sig: 'ip', emscripten_get_orientation_status__deps: ['$fillOrientationChangeEventData', '$screenOrientation'], emscripten_get_orientation_status: function(orientationChangeEvent) { - if (!screenOrientation() && typeof orientation == 'undefined') return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + if (!screenOrientation() && typeof orientation == 'undefined') return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; fillOrientationChangeEventData(orientationChangeEvent); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_lock_orientation__proxy: 'sync', @@ -1076,12 +1076,12 @@ var LibraryHTML5 = { } else if (screen.msLockOrientation) { succeeded = screen.msLockOrientation(orientations); } else { - return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; } if (succeeded) { - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; } - return {{{ cDefine('EMSCRIPTEN_RESULT_FAILED') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_FAILED }}}; }, emscripten_unlock_orientation__proxy: 'sync', @@ -1096,9 +1096,9 @@ var LibraryHTML5 = { } else if (screen.msUnlockOrientation) { screen.msUnlockOrientation(); } else { - return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; } - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, $fillFullscreenChangeEventData__deps: ['$JSEvents'], @@ -1116,8 +1116,8 @@ var LibraryHTML5 = { var reportedElement = isFullscreen ? fullscreenElement : JSEvents.previousFullscreenElement; var nodeName = JSEvents.getNodeNameForTarget(reportedElement); var id = (reportedElement && reportedElement.id) ? reportedElement.id : ''; - stringToUTF8(nodeName, eventStruct + {{{ C_STRUCTS.EmscriptenFullscreenChangeEvent.nodeName }}}, {{{ cDefine('EM_HTML5_LONG_STRING_LEN_BYTES') }}}); - stringToUTF8(id, eventStruct + {{{ C_STRUCTS.EmscriptenFullscreenChangeEvent.id }}}, {{{ cDefine('EM_HTML5_LONG_STRING_LEN_BYTES') }}}); + stringToUTF8(nodeName, eventStruct + {{{ C_STRUCTS.EmscriptenFullscreenChangeEvent.nodeName }}}, {{{ cDefs.EM_HTML5_LONG_STRING_LEN_BYTES }}}); + stringToUTF8(id, eventStruct + {{{ C_STRUCTS.EmscriptenFullscreenChangeEvent.id }}}, {{{ cDefs.EM_HTML5_LONG_STRING_LEN_BYTES }}}); {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenFullscreenChangeEvent.elementWidth, 'reportedElement ? reportedElement.clientWidth : 0', 'i32') }}}; {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenFullscreenChangeEvent.elementHeight, 'reportedElement ? reportedElement.clientHeight : 0', 'i32') }}}; {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenFullscreenChangeEvent.screenWidth, 'screen.width', 'i32') }}}; @@ -1164,44 +1164,44 @@ var LibraryHTML5 = { emscripten_set_fullscreenchange_callback_on_thread__sig: 'ippipp', emscripten_set_fullscreenchange_callback_on_thread__deps: ['$JSEvents', '$registerFullscreenChangeEventCallback', '$findEventTarget', '$specialHTMLTargets'], emscripten_set_fullscreenchange_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - if (!JSEvents.fullscreenEnabled()) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + if (!JSEvents.fullscreenEnabled()) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; #if DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR target = findEventTarget(target); #else - target = target ? findEventTarget(target) : specialHTMLTargets[{{{ cDefine('EMSCRIPTEN_EVENT_TARGET_DOCUMENT') }}}]; + target = target ? findEventTarget(target) : specialHTMLTargets[{{{ cDefs.EMSCRIPTEN_EVENT_TARGET_DOCUMENT }}}]; #endif - if (!target) return {{{ cDefine('EMSCRIPTEN_RESULT_UNKNOWN_TARGET') }}}; - registerFullscreenChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_FULLSCREENCHANGE') }}}, "fullscreenchange", targetThread); + if (!target) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}}; + registerFullscreenChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_FULLSCREENCHANGE }}}, "fullscreenchange", targetThread); #if MIN_FIREFOX_VERSION <= 63 // https://caniuse.com/#feat=mdn-api_element_fullscreenchange_event - registerFullscreenChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_FULLSCREENCHANGE') }}}, "mozfullscreenchange", targetThread); + registerFullscreenChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_FULLSCREENCHANGE }}}, "mozfullscreenchange", targetThread); #endif #if MIN_CHROME_VERSION < 71 || MIN_SAFARI_VERSION != TARGET_NOT_SUPPORTED // Unprefixed Fullscreen API shipped in Chromium 71 (https://bugs.chromium.org/p/chromium/issues/detail?id=383813) // As of Safari 13.0.3 on macOS Catalina 10.15.1 still ships with prefixed webkitfullscreenchange. TODO: revisit this check once Safari ships unprefixed version. - registerFullscreenChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_FULLSCREENCHANGE') }}}, "webkitfullscreenchange", targetThread); + registerFullscreenChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_FULLSCREENCHANGE }}}, "webkitfullscreenchange", targetThread); #endif #if MIN_IE_VERSION != TARGET_NOT_SUPPORTED // https://caniuse.com/#feat=mdn-api_document_fullscreenchange_event - registerFullscreenChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_FULLSCREENCHANGE') }}}, "MSFullscreenChange", targetThread); + registerFullscreenChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_FULLSCREENCHANGE }}}, "MSFullscreenChange", targetThread); #endif - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_get_fullscreen_status__proxy: 'sync', emscripten_get_fullscreen_status__sig: 'ip', emscripten_get_fullscreen_status__deps: ['$JSEvents', '$fillFullscreenChangeEventData'], emscripten_get_fullscreen_status: function(fullscreenStatus) { - if (!JSEvents.fullscreenEnabled()) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + if (!JSEvents.fullscreenEnabled()) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; fillFullscreenChangeEventData(fullscreenStatus); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, $JSEvents_requestFullscreen__deps: ['$JSEvents', '$JSEvents_resizeCanvasForFullscreen'], $JSEvents_requestFullscreen: function(target, strategy) { // EMSCRIPTEN_FULLSCREEN_SCALE_DEFAULT + EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_NONE is a mode where no extra logic is performed to the DOM elements. - if (strategy.scaleMode != {{{ cDefine('EMSCRIPTEN_FULLSCREEN_SCALE_DEFAULT') }}} || strategy.canvasResolutionScaleMode != {{{ cDefine('EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_NONE') }}}) { + if (strategy.scaleMode != {{{ cDefs.EMSCRIPTEN_FULLSCREEN_SCALE_DEFAULT }}} || strategy.canvasResolutionScaleMode != {{{ cDefs.EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_NONE }}}) { JSEvents_resizeCanvasForFullscreen(target, strategy); } @@ -1222,20 +1222,20 @@ var LibraryHTML5 = { target.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT); #endif } else { - return JSEvents.fullscreenEnabled() ? {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}} : {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + return JSEvents.fullscreenEnabled() ? {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}} : {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; } currentFullscreenStrategy = strategy; if (strategy.canvasResizedCallback) { #if PTHREADS - if (strategy.canvasResizedCallbackTargetThread) JSEvents.queueEventHandlerOnThread_iiii(strategy.canvasResizedCallbackTargetThread, strategy.canvasResizedCallback, {{{ cDefine('EMSCRIPTEN_EVENT_CANVASRESIZED') }}}, 0, strategy.canvasResizedCallbackUserData); + if (strategy.canvasResizedCallbackTargetThread) JSEvents.queueEventHandlerOnThread_iiii(strategy.canvasResizedCallbackTargetThread, strategy.canvasResizedCallback, {{{ cDefs.EMSCRIPTEN_EVENT_CANVASRESIZED }}}, 0, strategy.canvasResizedCallbackUserData); else #endif - {{{ makeDynCall('iiii', 'strategy.canvasResizedCallback') }}}({{{ cDefine('EMSCRIPTEN_EVENT_CANVASRESIZED') }}}, 0, strategy.canvasResizedCallbackUserData); + {{{ makeDynCall('iiii', 'strategy.canvasResizedCallback') }}}({{{ cDefs.EMSCRIPTEN_EVENT_CANVASRESIZED }}}, 0, strategy.canvasResizedCallbackUserData); } - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, $JSEvents_resizeCanvasForFullscreen__deps: ['$registerRestoreOldStyle', '$getCanvasElementSize', '$setLetterbox', '$setCanvasElementSize', '$getBoundingClientRect'], @@ -1257,11 +1257,11 @@ var LibraryHTML5 = { var windowedRttWidth = canvasSize[0]; var windowedRttHeight = canvasSize[1]; - if (strategy.scaleMode == {{{ cDefine('EMSCRIPTEN_FULLSCREEN_SCALE_CENTER') }}}) { + if (strategy.scaleMode == {{{ cDefs.EMSCRIPTEN_FULLSCREEN_SCALE_CENTER }}}) { setLetterbox(target, (cssHeight - windowedCssHeight) / 2, (cssWidth - windowedCssWidth) / 2); cssWidth = windowedCssWidth; cssHeight = windowedCssHeight; - } else if (strategy.scaleMode == {{{ cDefine('EMSCRIPTEN_FULLSCREEN_SCALE_ASPECT') }}}) { + } else if (strategy.scaleMode == {{{ cDefs.EMSCRIPTEN_FULLSCREEN_SCALE_ASPECT }}}) { if (cssWidth*windowedRttHeight < windowedRttWidth*cssHeight) { var desiredCssHeight = windowedRttHeight * cssWidth / windowedRttWidth; setLetterbox(target, (cssHeight - desiredCssHeight) / 2, 0); @@ -1283,7 +1283,7 @@ var LibraryHTML5 = { target.style.width = cssWidth + 'px'; target.style.height = cssHeight + 'px'; - if (strategy.filteringMode == {{{ cDefine('EMSCRIPTEN_FULLSCREEN_FILTERING_NEAREST') }}}) { + if (strategy.filteringMode == {{{ cDefs.EMSCRIPTEN_FULLSCREEN_FILTERING_NEAREST }}}) { target.style.imageRendering = 'optimizeSpeed'; target.style.imageRendering = '-moz-crisp-edges'; target.style.imageRendering = '-o-crisp-edges'; @@ -1293,8 +1293,8 @@ var LibraryHTML5 = { target.style.imageRendering = 'pixelated'; } - var dpiScale = (strategy.canvasResolutionScaleMode == {{{ cDefine('EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_HIDEF') }}}) ? devicePixelRatio : 1; - if (strategy.canvasResolutionScaleMode != {{{ cDefine('EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_NONE') }}}) { + var dpiScale = (strategy.canvasResolutionScaleMode == {{{ cDefs.EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_HIDEF }}}) ? devicePixelRatio : 1; + if (strategy.canvasResolutionScaleMode != {{{ cDefs.EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_NONE }}}) { var newWidth = (cssWidth * dpiScale)|0; var newHeight = (cssHeight * dpiScale)|0; setCanvasElementSize(target, newWidth, newHeight); @@ -1381,10 +1381,10 @@ var LibraryHTML5 = { if (currentFullscreenStrategy.canvasResizedCallback) { #if PTHREADS - if (currentFullscreenStrategy.canvasResizedCallbackTargetThread) JSEvents.queueEventHandlerOnThread_iiii(currentFullscreenStrategy.canvasResizedCallbackTargetThread, currentFullscreenStrategy.canvasResizedCallback, {{{ cDefine('EMSCRIPTEN_EVENT_CANVASRESIZED') }}}, 0, currentFullscreenStrategy.canvasResizedCallbackUserData); + if (currentFullscreenStrategy.canvasResizedCallbackTargetThread) JSEvents.queueEventHandlerOnThread_iiii(currentFullscreenStrategy.canvasResizedCallbackTargetThread, currentFullscreenStrategy.canvasResizedCallback, {{{ cDefs.EMSCRIPTEN_EVENT_CANVASRESIZED }}}, 0, currentFullscreenStrategy.canvasResizedCallbackUserData); else #endif - {{{ makeDynCall('iiii', 'currentFullscreenStrategy.canvasResizedCallback') }}}({{{ cDefine('EMSCRIPTEN_EVENT_CANVASRESIZED') }}}, 0, currentFullscreenStrategy.canvasResizedCallbackUserData); + {{{ makeDynCall('iiii', 'currentFullscreenStrategy.canvasResizedCallback') }}}({{{ cDefs.EMSCRIPTEN_EVENT_CANVASRESIZED }}}, 0, currentFullscreenStrategy.canvasResizedCallbackUserData); } } } @@ -1460,10 +1460,10 @@ var LibraryHTML5 = { $softFullscreenResizeWebGLRenderTarget__deps: ['$JSEvents', '$setLetterbox', '$currentFullscreenStrategy', '$getCanvasElementSize', '$setCanvasElementSize', '$jstoi_q'], $softFullscreenResizeWebGLRenderTarget: function() { var dpr = devicePixelRatio; - var inHiDPIFullscreenMode = currentFullscreenStrategy.canvasResolutionScaleMode == {{{ cDefine('EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_HIDEF') }}}; - var inAspectRatioFixedFullscreenMode = currentFullscreenStrategy.scaleMode == {{{ cDefine('EMSCRIPTEN_FULLSCREEN_SCALE_ASPECT') }}}; - var inPixelPerfectFullscreenMode = currentFullscreenStrategy.canvasResolutionScaleMode != {{{ cDefine('EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_NONE') }}}; - var inCenteredWithoutScalingFullscreenMode = currentFullscreenStrategy.scaleMode == {{{ cDefine('EMSCRIPTEN_FULLSCREEN_SCALE_CENTER') }}}; + var inHiDPIFullscreenMode = currentFullscreenStrategy.canvasResolutionScaleMode == {{{ cDefs.EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_HIDEF }}}; + var inAspectRatioFixedFullscreenMode = currentFullscreenStrategy.scaleMode == {{{ cDefs.EMSCRIPTEN_FULLSCREEN_SCALE_ASPECT }}}; + var inPixelPerfectFullscreenMode = currentFullscreenStrategy.canvasResolutionScaleMode != {{{ cDefs.EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_NONE }}}; + var inCenteredWithoutScalingFullscreenMode = currentFullscreenStrategy.scaleMode == {{{ cDefs.EMSCRIPTEN_FULLSCREEN_SCALE_CENTER }}}; var screenWidth = inHiDPIFullscreenMode ? Math.round(innerWidth*dpr) : innerWidth; var screenHeight = inHiDPIFullscreenMode ? Math.round(innerHeight*dpr) : innerHeight; var w = screenWidth; @@ -1509,22 +1509,22 @@ var LibraryHTML5 = { if (!inCenteredWithoutScalingFullscreenMode && currentFullscreenStrategy.canvasResizedCallback) { #if PTHREADS - if (currentFullscreenStrategy.canvasResizedCallbackTargetThread) JSEvents.queueEventHandlerOnThread_iiii(currentFullscreenStrategy.canvasResizedCallbackTargetThread, currentFullscreenStrategy.canvasResizedCallback, {{{ cDefine('EMSCRIPTEN_EVENT_CANVASRESIZED') }}}, 0, currentFullscreenStrategy.canvasResizedCallbackUserData); + if (currentFullscreenStrategy.canvasResizedCallbackTargetThread) JSEvents.queueEventHandlerOnThread_iiii(currentFullscreenStrategy.canvasResizedCallbackTargetThread, currentFullscreenStrategy.canvasResizedCallback, {{{ cDefs.EMSCRIPTEN_EVENT_CANVASRESIZED }}}, 0, currentFullscreenStrategy.canvasResizedCallbackUserData); else #endif - {{{ makeDynCall('iiii', 'currentFullscreenStrategy.canvasResizedCallback') }}}({{{ cDefine('EMSCRIPTEN_EVENT_CANVASRESIZED') }}}, 0, currentFullscreenStrategy.canvasResizedCallbackUserData); + {{{ makeDynCall('iiii', 'currentFullscreenStrategy.canvasResizedCallback') }}}({{{ cDefs.EMSCRIPTEN_EVENT_CANVASRESIZED }}}, 0, currentFullscreenStrategy.canvasResizedCallbackUserData); } }, // https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Using_full_screen_mode $doRequestFullscreen__deps: ['$JSEvents', '$setLetterbox', 'emscripten_set_canvas_element_size', 'emscripten_get_canvas_element_size', '$getCanvasElementSize', '$setCanvasElementSize', '$JSEvents_requestFullscreen', '$findEventTarget'], $doRequestFullscreen: function(target, strategy) { - if (!JSEvents.fullscreenEnabled()) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + if (!JSEvents.fullscreenEnabled()) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; #if !DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR if (!target) target = '#canvas'; #endif target = findEventTarget(target); - if (!target) return {{{ cDefine('EMSCRIPTEN_RESULT_UNKNOWN_TARGET') }}}; + if (!target) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}}; if (!target.requestFullscreen #if MIN_IE_VERSION != TARGET_NOT_SUPPORTED // https://caniuse.com/#feat=fullscreen @@ -1538,7 +1538,7 @@ var LibraryHTML5 = { && !target.webkitRequestFullscreen #endif ) { - return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}}; } #if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS @@ -1548,9 +1548,9 @@ var LibraryHTML5 = { if (!canPerformRequests) { if (strategy.deferUntilInEventHandler) { JSEvents.deferCall(JSEvents_requestFullscreen, 1 /* priority over pointer lock */, [target, strategy]); - return {{{ cDefine('EMSCRIPTEN_RESULT_DEFERRED') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_DEFERRED }}}; } - return {{{ cDefine('EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED }}}; } #endif @@ -1563,13 +1563,13 @@ var LibraryHTML5 = { emscripten_request_fullscreen: function(target, deferUntilInEventHandler) { var strategy = { // These options perform no added logic, but just bare request fullscreen. - scaleMode: {{{ cDefine('EMSCRIPTEN_FULLSCREEN_SCALE_DEFAULT') }}}, - canvasResolutionScaleMode: {{{ cDefine('EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_NONE') }}}, - filteringMode: {{{ cDefine('EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT') }}}, + scaleMode: {{{ cDefs.EMSCRIPTEN_FULLSCREEN_SCALE_DEFAULT }}}, + canvasResolutionScaleMode: {{{ cDefs.EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_NONE }}}, + filteringMode: {{{ cDefs.EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT }}}, #if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS deferUntilInEventHandler: deferUntilInEventHandler, #endif - canvasResizedCallbackTargetThread: {{{ cDefine('EM_CALLBACK_THREAD_CONTEXT_CALLING_THREAD') }}} + canvasResizedCallbackTargetThread: {{{ cDefs.EM_CALLBACK_THREAD_CONTEXT_CALLING_THREAD }}} }; return doRequestFullscreen(target, strategy); }, @@ -1603,7 +1603,7 @@ var LibraryHTML5 = { if (!target) target = '#canvas'; #endif target = findEventTarget(target); - if (!target) return {{{ cDefine('EMSCRIPTEN_RESULT_UNKNOWN_TARGET') }}}; + if (!target) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}}; var strategy = { scaleMode: {{{ makeGetValue('fullscreenStrategy', C_STRUCTS.EmscriptenFullscreenStrategy.scaleMode, 'i32') }}}, @@ -1632,10 +1632,10 @@ var LibraryHTML5 = { removeEventListener('resize', softFullscreenResizeWebGLRenderTarget); if (strategy.canvasResizedCallback) { #if PTHREADS - if (strategy.canvasResizedCallbackTargetThread) JSEvents.queueEventHandlerOnThread_iiii(strategy.canvasResizedCallbackTargetThread, strategy.canvasResizedCallback, {{{ cDefine('EMSCRIPTEN_EVENT_CANVASRESIZED') }}}, 0, strategy.canvasResizedCallbackUserData); + if (strategy.canvasResizedCallbackTargetThread) JSEvents.queueEventHandlerOnThread_iiii(strategy.canvasResizedCallbackTargetThread, strategy.canvasResizedCallback, {{{ cDefs.EMSCRIPTEN_EVENT_CANVASRESIZED }}}, 0, strategy.canvasResizedCallbackUserData); else #endif - {{{ makeDynCall('iiii', 'strategy.canvasResizedCallback') }}}({{{ cDefine('EMSCRIPTEN_EVENT_CANVASRESIZED') }}}, 0, strategy.canvasResizedCallbackUserData); + {{{ makeDynCall('iiii', 'strategy.canvasResizedCallback') }}}({{{ cDefs.EMSCRIPTEN_EVENT_CANVASRESIZED }}}, 0, strategy.canvasResizedCallbackUserData); } currentFullscreenStrategy = 0; } @@ -1646,13 +1646,13 @@ var LibraryHTML5 = { // Inform the caller that the canvas size has changed. if (strategy.canvasResizedCallback) { #if PTHREADS - if (strategy.canvasResizedCallbackTargetThread) JSEvents.queueEventHandlerOnThread_iiii(strategy.canvasResizedCallbackTargetThread, strategy.canvasResizedCallback, {{{ cDefine('EMSCRIPTEN_EVENT_CANVASRESIZED') }}}, 0, strategy.canvasResizedCallbackUserData); + if (strategy.canvasResizedCallbackTargetThread) JSEvents.queueEventHandlerOnThread_iiii(strategy.canvasResizedCallbackTargetThread, strategy.canvasResizedCallback, {{{ cDefs.EMSCRIPTEN_EVENT_CANVASRESIZED }}}, 0, strategy.canvasResizedCallbackUserData); else #endif - {{{ makeDynCall('iiii', 'strategy.canvasResizedCallback') }}}({{{ cDefine('EMSCRIPTEN_EVENT_CANVASRESIZED') }}}, 0, strategy.canvasResizedCallbackUserData); + {{{ makeDynCall('iiii', 'strategy.canvasResizedCallback') }}}({{{ cDefs.EMSCRIPTEN_EVENT_CANVASRESIZED }}}, 0, strategy.canvasResizedCallbackUserData); } - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_exit_soft_fullscreen__deps: ['$restoreOldWindowedStyle'], @@ -1662,20 +1662,20 @@ var LibraryHTML5 = { if (restoreOldWindowedStyle) restoreOldWindowedStyle(); restoreOldWindowedStyle = null; - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_exit_fullscreen__deps: ['$JSEvents', '$currentFullscreenStrategy', '$JSEvents_requestFullscreen', '$specialHTMLTargets'], emscripten_exit_fullscreen__proxy: 'sync', emscripten_exit_fullscreen__sig: 'i', emscripten_exit_fullscreen: function() { - if (!JSEvents.fullscreenEnabled()) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + if (!JSEvents.fullscreenEnabled()) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; #if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS // Make sure no queued up calls will fire after this. JSEvents.removeDeferredCalls(JSEvents_requestFullscreen); #endif - var d = specialHTMLTargets[{{{ cDefine('EMSCRIPTEN_EVENT_TARGET_DOCUMENT') }}}]; + var d = specialHTMLTargets[{{{ cDefs.EMSCRIPTEN_EVENT_TARGET_DOCUMENT }}}]; if (d.exitFullscreen) { d.fullscreenElement && d.exitFullscreen(); #if MIN_IE_VERSION != TARGET_NOT_SUPPORTED // https://caniuse.com/#feat=mdn-api_document_exitfullscreen @@ -1691,10 +1691,10 @@ var LibraryHTML5 = { d.webkitFullscreenElement && d.webkitExitFullscreen(); #endif } else { - return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; } - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, $fillPointerlockChangeEventData__deps: ['$JSEvents'], @@ -1708,8 +1708,8 @@ var LibraryHTML5 = { {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenPointerlockChangeEvent.isActive, 'isPointerlocked', 'i32') }}}; var nodeName = JSEvents.getNodeNameForTarget(pointerLockElement); var id = (pointerLockElement && pointerLockElement.id) ? pointerLockElement.id : ''; - stringToUTF8(nodeName, eventStruct + {{{ C_STRUCTS.EmscriptenPointerlockChangeEvent.nodeName }}}, {{{ cDefine('EM_HTML5_LONG_STRING_LEN_BYTES') }}}); - stringToUTF8(id, eventStruct + {{{ C_STRUCTS.EmscriptenPointerlockChangeEvent.id }}}, {{{ cDefine('EM_HTML5_LONG_STRING_LEN_BYTES') }}}); + stringToUTF8(nodeName, eventStruct + {{{ C_STRUCTS.EmscriptenPointerlockChangeEvent.nodeName }}}, {{{ cDefs.EM_HTML5_LONG_STRING_LEN_BYTES }}}); + stringToUTF8(id, eventStruct + {{{ C_STRUCTS.EmscriptenPointerlockChangeEvent.id }}}, {{{ cDefs.EM_HTML5_LONG_STRING_LEN_BYTES }}}); }, $registerPointerlockChangeEventCallback__deps: ['$JSEvents', '$fillPointerlockChangeEventData', '$findEventTarget'], @@ -1751,20 +1751,20 @@ var LibraryHTML5 = { emscripten_set_pointerlockchange_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { // TODO: Currently not supported in pthreads or in --proxy-to-worker mode. (In pthreads mode, document object is not defined) if (!document || !document.body || (!document.body.requestPointerLock && !document.body.mozRequestPointerLock && !document.body.webkitRequestPointerLock && !document.body.msRequestPointerLock)) { - return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; } #if DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR target = findEventTarget(target); #else - target = target ? findEventTarget(target) : specialHTMLTargets[{{{ cDefine('EMSCRIPTEN_EVENT_TARGET_DOCUMENT') }}}]; // Pointer lock change events need to be captured from 'document' by default instead of 'window' + target = target ? findEventTarget(target) : specialHTMLTargets[{{{ cDefs.EMSCRIPTEN_EVENT_TARGET_DOCUMENT }}}]; // Pointer lock change events need to be captured from 'document' by default instead of 'window' #endif - if (!target) return {{{ cDefine('EMSCRIPTEN_RESULT_UNKNOWN_TARGET') }}}; - registerPointerlockChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_POINTERLOCKCHANGE') }}}, "pointerlockchange", targetThread); - registerPointerlockChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_POINTERLOCKCHANGE') }}}, "mozpointerlockchange", targetThread); - registerPointerlockChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_POINTERLOCKCHANGE') }}}, "webkitpointerlockchange", targetThread); - registerPointerlockChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_POINTERLOCKCHANGE') }}}, "mspointerlockchange", targetThread); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + if (!target) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}}; + registerPointerlockChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_POINTERLOCKCHANGE }}}, "pointerlockchange", targetThread); + registerPointerlockChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_POINTERLOCKCHANGE }}}, "mozpointerlockchange", targetThread); + registerPointerlockChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_POINTERLOCKCHANGE }}}, "webkitpointerlockchange", targetThread); + registerPointerlockChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_POINTERLOCKCHANGE }}}, "mspointerlockchange", targetThread); + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, $registerPointerlockErrorEventCallback__deps: ['$JSEvents', '$findEventTarget', '$specialHTMLTargets'], @@ -1798,21 +1798,21 @@ var LibraryHTML5 = { emscripten_set_pointerlockerror_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { // TODO: Currently not supported in pthreads or in --proxy-to-worker mode. (In pthreads mode, document object is not defined) if (!document || !document.body.requestPointerLock && !document.body.mozRequestPointerLock && !document.body.webkitRequestPointerLock && !document.body.msRequestPointerLock) { - return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; } #if DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR target = findEventTarget(target); #else - target = target ? findEventTarget(target) : specialHTMLTargets[{{{ cDefine('EMSCRIPTEN_EVENT_TARGET_DOCUMENT') }}}]; // Pointer lock change events need to be captured from 'document' by default instead of 'window' + target = target ? findEventTarget(target) : specialHTMLTargets[{{{ cDefs.EMSCRIPTEN_EVENT_TARGET_DOCUMENT }}}]; // Pointer lock change events need to be captured from 'document' by default instead of 'window' #endif - if (!target) return {{{ cDefine('EMSCRIPTEN_RESULT_UNKNOWN_TARGET') }}}; - registerPointerlockErrorEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_POINTERLOCKERROR') }}}, "pointerlockerror", targetThread); - registerPointerlockErrorEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_POINTERLOCKERROR') }}}, "mozpointerlockerror", targetThread); - registerPointerlockErrorEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_POINTERLOCKERROR') }}}, "webkitpointerlockerror", targetThread); - registerPointerlockErrorEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_POINTERLOCKERROR') }}}, "mspointerlockerror", targetThread); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + if (!target) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}}; + registerPointerlockErrorEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_POINTERLOCKERROR }}}, "pointerlockerror", targetThread); + registerPointerlockErrorEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_POINTERLOCKERROR }}}, "mozpointerlockerror", targetThread); + registerPointerlockErrorEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_POINTERLOCKERROR }}}, "webkitpointerlockerror", targetThread); + registerPointerlockErrorEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_POINTERLOCKERROR }}}, "mspointerlockerror", targetThread); + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_get_pointerlock_status__proxy: 'sync', @@ -1822,9 +1822,9 @@ var LibraryHTML5 = { emscripten_get_pointerlock_status: function(pointerlockStatus) { if (pointerlockStatus) fillPointerlockChangeEventData(pointerlockStatus); if (!document.body || (!document.body.requestPointerLock && !document.body.mozRequestPointerLock && !document.body.webkitRequestPointerLock && !document.body.msRequestPointerLock)) { - return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; } - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, $requestPointerLock: function(target) { @@ -1856,11 +1856,11 @@ var LibraryHTML5 = { || document.body.msRequestPointerLock #endif ) { - return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}}; } - return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; } - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_request_pointerlock__proxy: 'sync', @@ -1871,7 +1871,7 @@ var LibraryHTML5 = { if (!target) target = '#canvas'; #endif target = findEventTarget(target); - if (!target) return {{{ cDefine('EMSCRIPTEN_RESULT_UNKNOWN_TARGET') }}}; + if (!target) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}}; if (!target.requestPointerLock #if MIN_FIREFOX_VERSION <= 40 // https://caniuse.com/#feat=pointerlock && !target.mozRequestPointerLock @@ -1883,7 +1883,7 @@ var LibraryHTML5 = { && !target.msRequestPointerLock #endif ) { - return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; } #if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS @@ -1893,9 +1893,9 @@ var LibraryHTML5 = { if (!canPerformRequests) { if (deferUntilInEventHandler) { JSEvents.deferCall(requestPointerLock, 2 /* priority below fullscreen */, [target]); - return {{{ cDefine('EMSCRIPTEN_RESULT_DEFERRED') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_DEFERRED }}}; } - return {{{ cDefine('EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED }}}; } #endif @@ -1926,23 +1926,23 @@ var LibraryHTML5 = { document.webkitExitPointerLock(); #endif } else { - return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; } - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_vibrate__proxy: 'sync', emscripten_vibrate__sig: 'ii', emscripten_vibrate: function(msecs) { - if (!navigator.vibrate) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + if (!navigator.vibrate) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; navigator.vibrate(msecs); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_vibrate_pattern__proxy: 'sync', emscripten_vibrate_pattern__sig: 'ipi', emscripten_vibrate_pattern: function(msecsArray, numEntries) { - if (!navigator.vibrate) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + if (!navigator.vibrate) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; var vibrateList = []; for (var i = 0; i < numEntries; ++i) { @@ -1950,7 +1950,7 @@ var LibraryHTML5 = { vibrateList.push(msecs); } navigator.vibrate(vibrateList); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, $fillVisibilityChangeEventData: function(eventStruct) { @@ -2003,12 +2003,12 @@ var LibraryHTML5 = { emscripten_set_visibilitychange_callback_on_thread__deps: ['$registerVisibilityChangeEventCallback', '$specialHTMLTargets'], emscripten_set_visibilitychange_callback_on_thread: function(userData, useCapture, callbackfunc, targetThread) { #if ENVIRONMENT_MAY_BE_WORKER || ENVIRONMENT_MAY_BE_NODE || ENVIRONMENT_MAY_BE_SHELL - if (!specialHTMLTargets[{{{ cDefine('EMSCRIPTEN_EVENT_TARGET_DOCUMENT') }}}]) { - return {{{ cDefine('EMSCRIPTEN_RESULT_UNKNOWN_TARGET') }}}; + if (!specialHTMLTargets[{{{ cDefs.EMSCRIPTEN_EVENT_TARGET_DOCUMENT }}}]) { + return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}}; } #endif - registerVisibilityChangeEventCallback(specialHTMLTargets[{{{ cDefine('EMSCRIPTEN_EVENT_TARGET_DOCUMENT') }}}], userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_VISIBILITYCHANGE') }}}, "visibilitychange", targetThread); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + registerVisibilityChangeEventCallback(specialHTMLTargets[{{{ cDefs.EMSCRIPTEN_EVENT_TARGET_DOCUMENT }}}], userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_VISIBILITYCHANGE }}}, "visibilitychange", targetThread); + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_get_visibility_status__proxy: 'sync', @@ -2016,10 +2016,10 @@ var LibraryHTML5 = { emscripten_get_visibility_status__deps: ['$fillVisibilityChangeEventData'], emscripten_get_visibility_status: function(visibilityStatus) { if (typeof document.visibilityState == 'undefined' && typeof document.hidden == 'undefined') { - return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; } fillVisibilityChangeEventData(visibilityStatus); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, $registerTouchEventCallback__deps: ['$JSEvents', '$findEventTarget', '$getBoundingClientRect'], @@ -2125,32 +2125,32 @@ var LibraryHTML5 = { emscripten_set_touchstart_callback_on_thread__sig: 'ippipp', emscripten_set_touchstart_callback_on_thread__deps: ['$registerTouchEventCallback'], emscripten_set_touchstart_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_TOUCHSTART') }}}, "touchstart", targetThread); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_TOUCHSTART }}}, "touchstart", targetThread); + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_set_touchend_callback_on_thread__proxy: 'sync', emscripten_set_touchend_callback_on_thread__sig: 'ippipp', emscripten_set_touchend_callback_on_thread__deps: ['$registerTouchEventCallback'], emscripten_set_touchend_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_TOUCHEND') }}}, "touchend", targetThread); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_TOUCHEND }}}, "touchend", targetThread); + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_set_touchmove_callback_on_thread__proxy: 'sync', emscripten_set_touchmove_callback_on_thread__sig: 'ippipp', emscripten_set_touchmove_callback_on_thread__deps: ['$registerTouchEventCallback'], emscripten_set_touchmove_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_TOUCHMOVE') }}}, "touchmove", targetThread); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_TOUCHMOVE }}}, "touchmove", targetThread); + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_set_touchcancel_callback_on_thread__proxy: 'sync', emscripten_set_touchcancel_callback_on_thread__sig: 'ippipp', emscripten_set_touchcancel_callback_on_thread__deps: ['$registerTouchEventCallback'], emscripten_set_touchcancel_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_TOUCHCANCEL') }}}, "touchcancel", targetThread); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_TOUCHCANCEL }}}, "touchcancel", targetThread); + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, $fillGamepadEventData: function(eventStruct, e) { @@ -2180,8 +2180,8 @@ var LibraryHTML5 = { {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenGamepadEvent.index, 'e.index', 'i32') }}}; {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenGamepadEvent.numAxes, 'e.axes.length', 'i32') }}}; {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenGamepadEvent.numButtons, 'e.buttons.length', 'i32') }}}; - stringToUTF8(e.id, eventStruct + {{{ C_STRUCTS.EmscriptenGamepadEvent.id }}}, {{{ cDefine('EM_HTML5_MEDIUM_STRING_LEN_BYTES') }}}); - stringToUTF8(e.mapping, eventStruct + {{{ C_STRUCTS.EmscriptenGamepadEvent.mapping }}}, {{{ cDefine('EM_HTML5_MEDIUM_STRING_LEN_BYTES') }}}); + stringToUTF8(e.id, eventStruct + {{{ C_STRUCTS.EmscriptenGamepadEvent.id }}}, {{{ cDefs.EM_HTML5_MEDIUM_STRING_LEN_BYTES }}}); + stringToUTF8(e.mapping, eventStruct + {{{ C_STRUCTS.EmscriptenGamepadEvent.mapping }}}, {{{ cDefs.EM_HTML5_MEDIUM_STRING_LEN_BYTES }}}); }, $registerGamepadEventCallback__deps: ['$JSEvents', '$fillGamepadEventData', '$findEventTarget'], @@ -2223,18 +2223,18 @@ var LibraryHTML5 = { emscripten_set_gamepadconnected_callback_on_thread__sig: 'ipipp', emscripten_set_gamepadconnected_callback_on_thread__deps: ['$registerGamepadEventCallback'], emscripten_set_gamepadconnected_callback_on_thread: function(userData, useCapture, callbackfunc, targetThread) { - if (!navigator.getGamepads && !navigator.webkitGetGamepads) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; - registerGamepadEventCallback({{{ cDefine('EMSCRIPTEN_EVENT_TARGET_WINDOW') }}}, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_GAMEPADCONNECTED') }}}, "gamepadconnected", targetThread); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + if (!navigator.getGamepads && !navigator.webkitGetGamepads) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; + registerGamepadEventCallback({{{ cDefs.EMSCRIPTEN_EVENT_TARGET_WINDOW }}}, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_GAMEPADCONNECTED }}}, "gamepadconnected", targetThread); + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_set_gamepaddisconnected_callback_on_thread__proxy: 'sync', emscripten_set_gamepaddisconnected_callback_on_thread__sig: 'ipipp', emscripten_set_gamepaddisconnected_callback_on_thread__deps: ['$registerGamepadEventCallback'], emscripten_set_gamepaddisconnected_callback_on_thread: function(userData, useCapture, callbackfunc, targetThread) { - if (!navigator.getGamepads && !navigator.webkitGetGamepads) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; - registerGamepadEventCallback({{{ cDefine('EMSCRIPTEN_EVENT_TARGET_WINDOW') }}}, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_GAMEPADDISCONNECTED') }}}, "gamepaddisconnected", targetThread); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + if (!navigator.getGamepads && !navigator.webkitGetGamepads) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; + registerGamepadEventCallback({{{ cDefs.EMSCRIPTEN_EVENT_TARGET_WINDOW }}}, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_GAMEPADDISCONNECTED }}}, "gamepaddisconnected", targetThread); + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_sample_gamepad_data__proxy: 'sync', @@ -2242,7 +2242,7 @@ var LibraryHTML5 = { emscripten_sample_gamepad_data__deps: ['$JSEvents'], emscripten_sample_gamepad_data: function() { return (JSEvents.lastGamepadState = (navigator.getGamepads ? navigator.getGamepads() : (navigator.webkitGetGamepads ? navigator.webkitGetGamepads() : null))) - ? {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}} : {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + ? {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}} : {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; }, emscripten_get_num_gamepads__proxy: 'sync', @@ -2266,16 +2266,16 @@ var LibraryHTML5 = { #endif // INVALID_PARAM is returned on a Gamepad index that never was there. - if (index < 0 || index >= JSEvents.lastGamepadState.length) return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_PARAM') }}}; + if (index < 0 || index >= JSEvents.lastGamepadState.length) return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_PARAM }}}; // NO_DATA is returned on a Gamepad index that was removed. // For previously disconnected gamepads there should be an empty slot (null/undefined/false) at the index. // This is because gamepads must keep their original position in the array. // For example, removing the first of two gamepads produces [null/undefined/false, gamepad]. - if (!JSEvents.lastGamepadState[index]) return {{{ cDefine('EMSCRIPTEN_RESULT_NO_DATA') }}}; + if (!JSEvents.lastGamepadState[index]) return {{{ cDefs.EMSCRIPTEN_RESULT_NO_DATA }}}; fillGamepadEventData(gamepadState, JSEvents.lastGamepadState[index]); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, $registerBeforeUnloadEventCallback__deps: ['$JSEvents', '$findEventTarget'], @@ -2308,12 +2308,12 @@ var LibraryHTML5 = { emscripten_set_beforeunload_callback_on_thread__sig: 'ippp', emscripten_set_beforeunload_callback_on_thread__deps: ['$registerBeforeUnloadEventCallback'], emscripten_set_beforeunload_callback_on_thread: function(userData, callbackfunc, targetThread) { - if (typeof onbeforeunload == 'undefined') return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + if (typeof onbeforeunload == 'undefined') return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; // beforeunload callback can only be registered on the main browser thread, because the page will go away immediately after returning from the handler, // and there is no time to start proxying it anywhere. - if (targetThread !== {{{ cDefine('EM_CALLBACK_THREAD_CONTEXT_MAIN_RUNTIME_THREAD') }}}) return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_PARAM') }}}; - registerBeforeUnloadEventCallback({{{ cDefine('EMSCRIPTEN_EVENT_TARGET_WINDOW') }}}, userData, true, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_BEFOREUNLOAD') }}}, "beforeunload"); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + if (targetThread !== {{{ cDefs.EM_CALLBACK_THREAD_CONTEXT_MAIN_RUNTIME_THREAD }}}) return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_PARAM }}}; + registerBeforeUnloadEventCallback({{{ cDefs.EMSCRIPTEN_EVENT_TARGET_WINDOW }}}, userData, true, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_BEFOREUNLOAD }}}, "beforeunload"); + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, $fillBatteryEventData: function(eventStruct, e) { @@ -2361,27 +2361,27 @@ var LibraryHTML5 = { emscripten_set_batterychargingchange_callback_on_thread__sig: 'ippp', emscripten_set_batterychargingchange_callback_on_thread__deps: ['$registerBatteryEventCallback', '$battery', 'malloc'], emscripten_set_batterychargingchange_callback_on_thread: function(userData, callbackfunc, targetThread) { - if (!battery()) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; - registerBatteryEventCallback(battery(), userData, true, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_BATTERYCHARGINGCHANGE') }}}, "chargingchange", targetThread); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + if (!battery()) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; + registerBatteryEventCallback(battery(), userData, true, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_BATTERYCHARGINGCHANGE }}}, "chargingchange", targetThread); + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_set_batterylevelchange_callback_on_thread__proxy: 'sync', emscripten_set_batterylevelchange_callback_on_thread__sig: 'ippp', emscripten_set_batterylevelchange_callback_on_thread__deps: ['$registerBatteryEventCallback', '$battery', 'malloc'], emscripten_set_batterylevelchange_callback_on_thread: function(userData, callbackfunc, targetThread) { - if (!battery()) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; - registerBatteryEventCallback(battery(), userData, true, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_BATTERYLEVELCHANGE') }}}, "levelchange", targetThread); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + if (!battery()) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; + registerBatteryEventCallback(battery(), userData, true, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_BATTERYLEVELCHANGE }}}, "levelchange", targetThread); + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_get_battery_status__proxy: 'sync', emscripten_get_battery_status__sig: 'ip', emscripten_get_battery_status__deps: ['$fillBatteryEventData', '$battery'], emscripten_get_battery_status: function(batteryState) { - if (!battery()) return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + if (!battery()) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; fillBatteryEventData(batteryState, battery()); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, #if PTHREADS @@ -2393,7 +2393,7 @@ var LibraryHTML5 = { '$findCanvasEventTarget'], emscripten_set_canvas_element_size_calling_thread: function(target, width, height) { var canvas = findCanvasEventTarget(target); - if (!canvas) return {{{ cDefine('EMSCRIPTEN_RESULT_UNKNOWN_TARGET') }}}; + if (!canvas) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}}; #if OFFSCREENCANVAS_SUPPORT if (canvas.canvasSharedPtr) { @@ -2435,18 +2435,18 @@ var LibraryHTML5 = { } else if (canvas.canvasSharedPtr) { var targetThread = {{{ makeGetValue('canvas.canvasSharedPtr', 8, 'i32') }}}; _emscripten_set_offscreencanvas_size_on_target_thread(targetThread, target, width, height); - return {{{ cDefine('EMSCRIPTEN_RESULT_DEFERRED') }}}; // This will have to be done asynchronously + return {{{ cDefs.EMSCRIPTEN_RESULT_DEFERRED }}}; // This will have to be done asynchronously #endif } else { #if GL_DEBUG dbg('canvas.controlTransferredOffscreen but we do not own the canvas, and do not know who has (no canvas.canvasSharedPtr present, an internal bug?)!\n'); #endif - return {{{ cDefine('EMSCRIPTEN_RESULT_UNKNOWN_TARGET') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}}; } #if OFFSCREEN_FRAMEBUFFER if (canvas.GLctxObject) GL.resizeOffscreenFramebuffer(canvas.GLctxObject); #endif - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, _emscripten_set_offscreencanvas_size__sig: 'iiii', @@ -2468,7 +2468,7 @@ var LibraryHTML5 = { // these two threads will deadlock. At the moment, we'd like to consider that this kind of deadlock would be an Emscripten runtime bug, although if // emscripten_set_canvas_element_size() was documented to require running an event in the queue of thread that owns the OffscreenCanvas, then that might be ok. // (safer this way however) - _emscripten_dispatch_to_thread_(targetThread, {{{ cDefine('EM_PROXIED_RESIZE_OFFSCREENCANVAS') }}}, 0, targetCanvasPtr /* satellite data */, varargs); + _emscripten_dispatch_to_thread_(targetThread, {{{ cDefs.EM_PROXIED_RESIZE_OFFSCREENCANVAS }}}, 0, targetCanvasPtr /* satellite data */, varargs); }); }, @@ -2482,7 +2482,7 @@ var LibraryHTML5 = { #if ASSERTIONS err('emscripten_set_offscreencanvas_size: Build with -sOFFSCREENCANVAS_SUPPORT=1 to enable transferring canvases to pthreads.'); #endif - return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; }, #endif @@ -2511,13 +2511,13 @@ var LibraryHTML5 = { dbg('emscripten_set_canvas_element_size(target='+target+',width='+width+',height='+height); #endif var canvas = findCanvasEventTarget(target); - if (!canvas) return {{{ cDefine('EMSCRIPTEN_RESULT_UNKNOWN_TARGET') }}}; + if (!canvas) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}}; canvas.width = width; canvas.height = height; #if OFFSCREEN_FRAMEBUFFER if (canvas.GLctxObject) GL.resizeOffscreenFramebuffer(canvas.GLctxObject); #endif - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, #endif @@ -2544,7 +2544,7 @@ var LibraryHTML5 = { emscripten_get_canvas_element_size_calling_thread__deps: ['$JSEvents', '$findCanvasEventTarget'], emscripten_get_canvas_element_size_calling_thread: function(target, width, height) { var canvas = findCanvasEventTarget(target); - if (!canvas) return {{{ cDefine('EMSCRIPTEN_RESULT_UNKNOWN_TARGET') }}}; + if (!canvas) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}}; #if OFFSCREENCANVAS_SUPPORT if (canvas.canvasSharedPtr) { @@ -2567,9 +2567,9 @@ var LibraryHTML5 = { #if GL_DEBUG dbg('canvas.controlTransferredOffscreen but we do not own the canvas, and do not know who has (no canvas.canvasSharedPtr present, an internal bug?)!\n'); #endif - return {{{ cDefine('EMSCRIPTEN_RESULT_UNKNOWN_TARGET') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}}; } - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_get_canvas_element_size_main_thread__proxy: 'sync', @@ -2591,7 +2591,7 @@ var LibraryHTML5 = { emscripten_get_canvas_element_size__sig: 'ippp', emscripten_get_canvas_element_size: function(target, width, height) { var canvas = findCanvasEventTarget(target); - if (!canvas) return {{{ cDefine('EMSCRIPTEN_RESULT_UNKNOWN_TARGET') }}}; + if (!canvas) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}}; {{{ makeSetValue('width', '0', 'canvas.width', 'i32') }}}; {{{ makeSetValue('height', '0', 'canvas.height', 'i32') }}}; }, @@ -2621,12 +2621,12 @@ var LibraryHTML5 = { #else target = target ? findEventTarget(target) : Module['canvas']; #endif - if (!target) return {{{ cDefine('EMSCRIPTEN_RESULT_UNKNOWN_TARGET') }}}; + if (!target) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}}; target.style.width = width + "px"; target.style.height = height + "px"; - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_get_element_css_size__proxy: 'sync', @@ -2638,7 +2638,7 @@ var LibraryHTML5 = { #else target = target ? findEventTarget(target) : Module['canvas']; #endif - if (!target) return {{{ cDefine('EMSCRIPTEN_RESULT_UNKNOWN_TARGET') }}}; + if (!target) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}}; var rect = getBoundingClientRect(target); #if MIN_IE_VERSION < 9 @@ -2651,7 +2651,7 @@ var LibraryHTML5 = { {{{ makeSetValue('height', '0', 'rect.height', 'double') }}}; #endif - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_html5_remove_all_event_listeners__sig: 'v', diff --git a/src/library_html5_webgl.js b/src/library_html5_webgl.js index 2762b0ffb423e..5edd57452040c 100644 --- a/src/library_html5_webgl.js +++ b/src/library_html5_webgl.js @@ -118,14 +118,14 @@ var LibraryHtml5WebGL = { #if PTHREADS && OFFSCREEN_FRAMEBUFFER // Create a WebGL context that is proxied to main thread if canvas was not found on worker, or if explicitly requested to do so. if (ENVIRONMENT_IS_PTHREAD) { - if (contextAttributes.proxyContextToMainThread === {{{ cDefine('EMSCRIPTEN_WEBGL_CONTEXT_PROXY_ALWAYS') }}} || - (!canvas && contextAttributes.proxyContextToMainThread === {{{ cDefine('EMSCRIPTEN_WEBGL_CONTEXT_PROXY_FALLBACK') }}})) { + if (contextAttributes.proxyContextToMainThread === {{{ cDefs.EMSCRIPTEN_WEBGL_CONTEXT_PROXY_ALWAYS }}} || + (!canvas && contextAttributes.proxyContextToMainThread === {{{ cDefs.EMSCRIPTEN_WEBGL_CONTEXT_PROXY_FALLBACK }}})) { // When WebGL context is being proxied via the main thread, we must render using an offscreen FBO render target to avoid WebGL's // "implicit swap when callback exits" behavior. TODO: If OffscreenCanvas is supported, explicitSwapControl=true and still proxying, // then this can be avoided, since OffscreenCanvas enables explicit swap control. #if GL_DEBUG - if (contextAttributes.proxyContextToMainThread === {{{ cDefine('EMSCRIPTEN_WEBGL_CONTEXT_PROXY_ALWAYS') }}}) dbg('EMSCRIPTEN_WEBGL_CONTEXT_PROXY_ALWAYS enabled, proxying WebGL rendering from pthread to main thread.'); - if (!canvas && contextAttributes.proxyContextToMainThread === {{{ cDefine('EMSCRIPTEN_WEBGL_CONTEXT_PROXY_FALLBACK') }}}) dbg('Specified canvas target "' + targetStr + '" is not an OffscreenCanvas in the current pthread, but EMSCRIPTEN_WEBGL_CONTEXT_PROXY_FALLBACK is set. Proxying WebGL rendering from pthread to main thread.'); + if (contextAttributes.proxyContextToMainThread === {{{ cDefs.EMSCRIPTEN_WEBGL_CONTEXT_PROXY_ALWAYS }}}) dbg('EMSCRIPTEN_WEBGL_CONTEXT_PROXY_ALWAYS enabled, proxying WebGL rendering from pthread to main thread.'); + if (!canvas && contextAttributes.proxyContextToMainThread === {{{ cDefs.EMSCRIPTEN_WEBGL_CONTEXT_PROXY_FALLBACK }}}) dbg('Specified canvas target "' + targetStr + '" is not an OffscreenCanvas in the current pthread, but EMSCRIPTEN_WEBGL_CONTEXT_PROXY_FALLBACK is set. Proxying WebGL rendering from pthread to main thread.'); dbg('Performance warning: forcing renderViaOffscreenBackBuffer=true and preserveDrawingBuffer=true since proxying WebGL rendering.'); #endif // We will be proxying - if OffscreenCanvas is supported, we can proxy a bit more efficiently by avoiding having to create an Offscreen FBO. @@ -220,7 +220,7 @@ var LibraryHtml5WebGL = { emscripten_webgl_make_context_current_calling_thread: function(contextHandle) { var success = GL.makeContextCurrent(contextHandle); if (success) GL.currentContextIsProxied = false; // If succeeded above, we will have a local GL context from this thread (worker or main). - return success ? {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}} : {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_PARAM') }}}; + return success ? {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}} : {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_PARAM }}}; }, // This function gets called in a pthread, after it has successfully activated (with make_current()) a proxied GL context to itself from the main thread. // In this scenario, the pthread does not hold a high-level JS object to the GL context, because it lives on the main thread, in which case we record @@ -234,7 +234,7 @@ var LibraryHtml5WebGL = { emscripten_webgl_make_context_current__sig: 'ii', emscripten_webgl_make_context_current: function(contextHandle) { var success = GL.makeContextCurrent(contextHandle); - return success ? {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}} : {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_PARAM') }}}; + return success ? {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}} : {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_PARAM }}}; }, #endif @@ -248,11 +248,11 @@ var LibraryHtml5WebGL = { var GLContext = GL.getContext(contextHandle); if (!GLContext || !GLContext.GLctx || !width || !height) { - return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_PARAM') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_PARAM }}}; } {{{ makeSetValue('width', '0', 'GLContext.GLctx.drawingBufferWidth', 'i32') }}}; {{{ makeSetValue('height', '0', 'GLContext.GLctx.drawingBufferHeight', 'i32') }}}; - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_webgl_do_commit_frame__sig: 'i', @@ -265,7 +265,7 @@ var LibraryHtml5WebGL = { #if GL_DEBUG dbg('emscripten_webgl_commit_frame() failed: no GL context set current via emscripten_webgl_make_context_current()!'); #endif - return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}}; } #if OFFSCREEN_FRAMEBUFFER @@ -274,30 +274,30 @@ var LibraryHtml5WebGL = { #if GL_DEBUG && OFFSCREENCANVAS_SUPPORT if (GL.currentContext.GLctx.commit) dbg('emscripten_webgl_commit_frame(): Offscreen framebuffer should never have gotten created when canvas is in OffscreenCanvas mode, since it is redundant and not necessary'); #endif - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; } #endif if (!GL.currentContext.attributes.explicitSwapControl) { #if GL_DEBUG dbg('emscripten_webgl_commit_frame() cannot be called for canvases with implicit swap control mode!'); #endif - return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}}; } // We would do GL.currentContext.GLctx.commit(); here, but the current implementation // in browsers has removed it - swap is implicit, so this function is a no-op for now // (until/unless the spec changes). - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_webgl_get_context_attributes__proxy: 'sync_on_webgl_context_handle_thread', emscripten_webgl_get_context_attributes__sig: 'iip', emscripten_webgl_get_context_attributes__deps: ['$emscripten_webgl_power_preferences'], emscripten_webgl_get_context_attributes: function(c, a) { - if (!a) return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_PARAM') }}}; + if (!a) return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_PARAM }}}; c = GL.contexts[c]; - if (!c) return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; + if (!c) return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}}; var t = c.GLctx; - if (!t) return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; + if (!t) return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}}; t = t.getContextAttributes(); {{{ makeSetValue('a', C_STRUCTS.EmscriptenWebGLContextAttributes.alpha, 't.alpha', 'i32') }}}; @@ -317,7 +317,7 @@ var LibraryHtml5WebGL = { #if GL_SUPPORT_EXPLICIT_SWAP_CONTROL {{{ makeSetValue('a', C_STRUCTS.EmscriptenWebGLContextAttributes.explicitSwapControl, 'c.attributes.explicitSwapControl', 'i32') }}}; #endif - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_webgl_destroy_context__proxy: 'sync_on_webgl_context_handle_thread', @@ -439,16 +439,16 @@ var LibraryHtml5WebGL = { emscripten_set_webglcontextlost_callback_on_thread__sig: 'ippipp', emscripten_set_webglcontextlost_callback_on_thread__deps: ['$registerWebGlEventCallback'], emscripten_set_webglcontextlost_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerWebGlEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_WEBGLCONTEXTLOST') }}}, "webglcontextlost", targetThread); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + registerWebGlEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_WEBGLCONTEXTLOST }}}, "webglcontextlost", targetThread); + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_set_webglcontextrestored_callback_on_thread__proxy: 'sync', emscripten_set_webglcontextrestored_callback_on_thread__sig: 'ippipp', emscripten_set_webglcontextrestored_callback_on_thread__deps: ['$registerWebGlEventCallback'], emscripten_set_webglcontextrestored_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerWebGlEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefine('EMSCRIPTEN_EVENT_WEBGLCONTEXTRESTORED') }}}, "webglcontextrestored", targetThread); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + registerWebGlEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_WEBGLCONTEXTRESTORED }}}, "webglcontextrestored", targetThread); + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_is_webgl_context_lost__proxy: 'sync_on_webgl_context_handle_thread', diff --git a/src/library_lz4.js b/src/library_lz4.js index 91d5dc7d7761c..dce368890a89b 100644 --- a/src/library_lz4.js +++ b/src/library_lz4.js @@ -8,8 +8,8 @@ mergeInto(LibraryManager.library, { $LZ4__deps: ['$FS'], $LZ4: { - DIR_MODE: {{{ cDefine('S_IFDIR') }}} | 511 /* 0777 */, - FILE_MODE: {{{ cDefine('S_IFREG') }}} | 511 /* 0777 */, + DIR_MODE: {{{ cDefs.S_IFDIR }}} | 511 /* 0777 */, + FILE_MODE: {{{ cDefs.S_IFREG }}} | 511 /* 0777 */, CHUNK_SIZE: -1, codec: null, init: function() { @@ -114,25 +114,25 @@ mergeInto(LibraryManager.library, { } }, lookup: function(parent, name) { - throw new FS.ErrnoError({{{ cDefine('ENOENT') }}}); + throw new FS.ErrnoError({{{ cDefs.ENOENT }}}); }, mknod: function (parent, name, mode, dev) { - throw new FS.ErrnoError({{{ cDefine('EPERM') }}}); + throw new FS.ErrnoError({{{ cDefs.EPERM }}}); }, rename: function (oldNode, newDir, newName) { - throw new FS.ErrnoError({{{ cDefine('EPERM') }}}); + throw new FS.ErrnoError({{{ cDefs.EPERM }}}); }, unlink: function(parent, name) { - throw new FS.ErrnoError({{{ cDefine('EPERM') }}}); + throw new FS.ErrnoError({{{ cDefs.EPERM }}}); }, rmdir: function(parent, name) { - throw new FS.ErrnoError({{{ cDefine('EPERM') }}}); + throw new FS.ErrnoError({{{ cDefs.EPERM }}}); }, readdir: function(node) { - throw new FS.ErrnoError({{{ cDefine('EPERM') }}}); + throw new FS.ErrnoError({{{ cDefs.EPERM }}}); }, symlink: function(parent, newName, oldPath) { - throw new FS.ErrnoError({{{ cDefine('EPERM') }}}); + throw new FS.ErrnoError({{{ cDefs.EPERM }}}); }, }, stream_ops: { @@ -184,19 +184,19 @@ mergeInto(LibraryManager.library, { return written; }, write: function (stream, buffer, offset, length, position) { - throw new FS.ErrnoError({{{ cDefine('EIO') }}}); + throw new FS.ErrnoError({{{ cDefs.EIO }}}); }, llseek: function (stream, offset, whence) { var position = offset; - if (whence === {{{ cDefine('SEEK_CUR') }}}) { + if (whence === {{{ cDefs.SEEK_CUR }}}) { position += stream.position; - } else if (whence === {{{ cDefine('SEEK_END') }}}) { + } else if (whence === {{{ cDefs.SEEK_END }}}) { if (FS.isFile(stream.node.mode)) { position += stream.node.size; } } if (position < 0) { - throw new FS.ErrnoError({{{ cDefine('EINVAL') }}}); + throw new FS.ErrnoError({{{ cDefs.EINVAL }}}); } return position; }, diff --git a/src/library_memfs.js b/src/library_memfs.js index b009ee74e739b..8d8f5debb7aed 100644 --- a/src/library_memfs.js +++ b/src/library_memfs.js @@ -9,12 +9,12 @@ mergeInto(LibraryManager.library, { $MEMFS: { ops_table: null, mount: function(mount) { - return MEMFS.createNode(null, '/', {{{ cDefine('S_IFDIR') }}} | 511 /* 0777 */, 0); + return MEMFS.createNode(null, '/', {{{ cDefs.S_IFDIR }}} | 511 /* 0777 */, 0); }, createNode: function(parent, name, mode, dev) { if (FS.isBlkdev(mode) || FS.isFIFO(mode)) { // no supported - throw new FS.ErrnoError({{{ cDefine('EPERM') }}}); + throw new FS.ErrnoError({{{ cDefs.EPERM }}}); } if (!MEMFS.ops_table) { MEMFS.ops_table = { @@ -181,7 +181,7 @@ mergeInto(LibraryManager.library, { } }, lookup: function(parent, name) { - throw FS.genericErrors[{{{ cDefine('ENOENT') }}}]; + throw FS.genericErrors[{{{ cDefs.ENOENT }}}]; }, mknod: function(parent, name, mode, dev) { return MEMFS.createNode(parent, name, mode, dev); @@ -196,7 +196,7 @@ mergeInto(LibraryManager.library, { } if (new_node) { for (var i in new_node.contents) { - throw new FS.ErrnoError({{{ cDefine('ENOTEMPTY') }}}); + throw new FS.ErrnoError({{{ cDefs.ENOTEMPTY }}}); } } } @@ -215,7 +215,7 @@ mergeInto(LibraryManager.library, { rmdir: function(parent, name) { var node = FS.lookupNode(parent, name); for (var i in node.contents) { - throw new FS.ErrnoError({{{ cDefine('ENOTEMPTY') }}}); + throw new FS.ErrnoError({{{ cDefs.ENOTEMPTY }}}); } delete parent.contents[name]; parent.timestamp = Date.now(); @@ -231,13 +231,13 @@ mergeInto(LibraryManager.library, { return entries; }, symlink: function(parent, newname, oldpath) { - var node = MEMFS.createNode(parent, newname, 511 /* 0777 */ | {{{ cDefine('S_IFLNK') }}}, 0); + var node = MEMFS.createNode(parent, newname, 511 /* 0777 */ | {{{ cDefs.S_IFLNK }}}, 0); node.link = oldpath; return node; }, readlink: function(node) { if (!FS.isLink(node.mode)) { - throw new FS.ErrnoError({{{ cDefine('EINVAL') }}}); + throw new FS.ErrnoError({{{ cDefs.EINVAL }}}); } return node.link; }, @@ -317,15 +317,15 @@ mergeInto(LibraryManager.library, { llseek: function(stream, offset, whence) { var position = offset; - if (whence === {{{ cDefine('SEEK_CUR') }}}) { + if (whence === {{{ cDefs.SEEK_CUR }}}) { position += stream.position; - } else if (whence === {{{ cDefine('SEEK_END') }}}) { + } else if (whence === {{{ cDefs.SEEK_END }}}) { if (FS.isFile(stream.node.mode)) { position += stream.node.usedBytes; } } if (position < 0) { - throw new FS.ErrnoError({{{ cDefine('EINVAL') }}}); + throw new FS.ErrnoError({{{ cDefs.EINVAL }}}); } return position; }, @@ -335,13 +335,13 @@ mergeInto(LibraryManager.library, { }, mmap: function(stream, length, position, prot, flags) { if (!FS.isFile(stream.node.mode)) { - throw new FS.ErrnoError({{{ cDefine('ENODEV') }}}); + throw new FS.ErrnoError({{{ cDefs.ENODEV }}}); } var ptr; var allocated; var contents = stream.node.contents; // Only make a new copy when MAP_PRIVATE is specified. - if (!(flags & {{{ cDefine('MAP_PRIVATE') }}}) && contents.buffer === HEAP8.buffer) { + if (!(flags & {{{ cDefs.MAP_PRIVATE }}}) && contents.buffer === HEAP8.buffer) { // We can't emulate MAP_SHARED when the file is not backed by the // buffer we're mapping to (e.g. the HEAP buffer). allocated = false; @@ -358,7 +358,7 @@ mergeInto(LibraryManager.library, { allocated = true; ptr = mmapAlloc(length); if (!ptr) { - throw new FS.ErrnoError({{{ cDefine('ENOMEM') }}}); + throw new FS.ErrnoError({{{ cDefs.ENOMEM }}}); } #if CAN_ADDRESS_2GB ptr >>>= 0; diff --git a/src/library_nodefs.js b/src/library_nodefs.js index 97f9f3fb75eaa..1a67b6822fb2f 100644 --- a/src/library_nodefs.js +++ b/src/library_nodefs.js @@ -17,16 +17,16 @@ mergeInto(LibraryManager.library, { flags = flags["fs"]; } NODEFS.flagsForNodeMap = { - "{{{ cDefine('O_APPEND') }}}": flags["O_APPEND"], - "{{{ cDefine('O_CREAT') }}}": flags["O_CREAT"], - "{{{ cDefine('O_EXCL') }}}": flags["O_EXCL"], - "{{{ cDefine('O_NOCTTY') }}}": flags["O_NOCTTY"], - "{{{ cDefine('O_RDONLY') }}}": flags["O_RDONLY"], - "{{{ cDefine('O_RDWR') }}}": flags["O_RDWR"], - "{{{ cDefine('O_DSYNC') }}}": flags["O_SYNC"], - "{{{ cDefine('O_TRUNC') }}}": flags["O_TRUNC"], - "{{{ cDefine('O_WRONLY') }}}": flags["O_WRONLY"], - "{{{ cDefine('O_NOFOLLOW') }}}": flags["O_NOFOLLOW"], + "{{{ cDefs.O_APPEND }}}": flags["O_APPEND"], + "{{{ cDefs.O_CREAT }}}": flags["O_CREAT"], + "{{{ cDefs.O_EXCL }}}": flags["O_EXCL"], + "{{{ cDefs.O_NOCTTY }}}": flags["O_NOCTTY"], + "{{{ cDefs.O_RDONLY }}}": flags["O_RDONLY"], + "{{{ cDefs.O_RDWR }}}": flags["O_RDWR"], + "{{{ cDefs.O_DSYNC }}}": flags["O_SYNC"], + "{{{ cDefs.O_TRUNC }}}": flags["O_TRUNC"], + "{{{ cDefs.O_WRONLY }}}": flags["O_WRONLY"], + "{{{ cDefs.O_NOFOLLOW }}}": flags["O_NOFOLLOW"], }; #if ASSERTIONS // The 0 define must match on both sides, as otherwise we would not @@ -49,7 +49,7 @@ mergeInto(LibraryManager.library, { }, createNode: (parent, name, mode, dev) => { if (!FS.isDir(mode) && !FS.isFile(mode) && !FS.isLink(mode)) { - throw new FS.ErrnoError({{{ cDefine('EINVAL') }}}); + throw new FS.ErrnoError({{{ cDefs.EINVAL }}}); } var node = FS.createNode(parent, name, mode); node.node_ops = NODEFS.node_ops; @@ -84,11 +84,11 @@ mergeInto(LibraryManager.library, { // This maps the integer permission modes from http://linux.die.net/man/3/open // to node.js-specific file open permission strings at http://nodejs.org/api/fs.html#fs_fs_open_path_flags_mode_callback flagsForNode: (flags) => { - flags &= ~{{{ cDefine('O_PATH') }}}; // Ignore this flag from musl, otherwise node.js fails to open the file. - flags &= ~{{{ cDefine('O_NONBLOCK') }}}; // Ignore this flag from musl, otherwise node.js fails to open the file. - flags &= ~{{{ cDefine('O_LARGEFILE') }}}; // Ignore this flag from musl, otherwise node.js fails to open the file. - flags &= ~{{{ cDefine('O_CLOEXEC') }}}; // Some applications may pass it; it makes no sense for a single process. - flags &= ~{{{ cDefine('O_DIRECTORY') }}}; // Node.js doesn't need this passed in, it errors. + flags &= ~{{{ cDefs.O_PATH }}}; // Ignore this flag from musl, otherwise node.js fails to open the file. + flags &= ~{{{ cDefs.O_NONBLOCK }}}; // Ignore this flag from musl, otherwise node.js fails to open the file. + flags &= ~{{{ cDefs.O_LARGEFILE }}}; // Ignore this flag from musl, otherwise node.js fails to open the file. + flags &= ~{{{ cDefs.O_CLOEXEC }}}; // Some applications may pass it; it makes no sense for a single process. + flags &= ~{{{ cDefs.O_DIRECTORY }}}; // Node.js doesn't need this passed in, it errors. var newFlags = 0; for (var k in NODEFS.flagsForNodeMap) { if (flags & k) { @@ -97,7 +97,7 @@ mergeInto(LibraryManager.library, { } } if (flags) { - throw new FS.ErrnoError({{{ cDefine('EINVAL') }}}); + throw new FS.ErrnoError({{{ cDefs.EINVAL }}}); } return newFlags; }, @@ -233,7 +233,7 @@ mergeInto(LibraryManager.library, { if (!e.code) throw e; // node under windows can return code 'UNKNOWN' here: // https://github.com/emscripten-core/emscripten/issues/15468 - if (e.code === 'UNKNOWN') throw new FS.ErrnoError({{{ cDefine('EINVAL') }}}); + if (e.code === 'UNKNOWN') throw new FS.ErrnoError({{{ cDefs.EINVAL }}}); throw new FS.ErrnoError(NODEFS.convertNodeCode(e)); } }, @@ -278,9 +278,9 @@ mergeInto(LibraryManager.library, { }, llseek: (stream, offset, whence) => { var position = offset; - if (whence === {{{ cDefine('SEEK_CUR') }}}) { + if (whence === {{{ cDefs.SEEK_CUR }}}) { position += stream.position; - } else if (whence === {{{ cDefine('SEEK_END') }}}) { + } else if (whence === {{{ cDefs.SEEK_END }}}) { if (FS.isFile(stream.node.mode)) { try { var stat = fs.fstatSync(stream.nfd); @@ -292,14 +292,14 @@ mergeInto(LibraryManager.library, { } if (position < 0) { - throw new FS.ErrnoError({{{ cDefine('EINVAL') }}}); + throw new FS.ErrnoError({{{ cDefs.EINVAL }}}); } return position; }, mmap: (stream, length, position, prot, flags) => { if (!FS.isFile(stream.node.mode)) { - throw new FS.ErrnoError({{{ cDefine('ENODEV') }}}); + throw new FS.ErrnoError({{{ cDefs.ENODEV }}}); } var ptr = mmapAlloc(length); diff --git a/src/library_noderawfs.js b/src/library_noderawfs.js index 03cd9e982878d..3bb943febe1cf 100644 --- a/src/library_noderawfs.js +++ b/src/library_noderawfs.js @@ -76,7 +76,7 @@ mergeInto(LibraryManager.library, { ftruncate: function(fd, len) { // See https://github.com/nodejs/node/issues/35632 if (len < 0) { - throw new FS.ErrnoError({{{ cDefine('EINVAL') }}}); + throw new FS.ErrnoError({{{ cDefs.EINVAL }}}); } fs.ftruncateSync.apply(void 0, arguments); }, @@ -88,7 +88,7 @@ mergeInto(LibraryManager.library, { var pathTruncated = path.split('/').map(function(s) { return s.substr(0, 255); }).join('/'); var nfd = fs.openSync(pathTruncated, NODEFS.flagsForNode(flags), mode); var st = fs.fstatSync(nfd); - if (flags & {{{ cDefine('O_DIRECTORY') }}} && !st.isDirectory()) { + if (flags & {{{ cDefs.O_DIRECTORY }}} && !st.isDirectory()) { fs.closeSync(nfd); throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR); } @@ -128,16 +128,16 @@ mergeInto(LibraryManager.library, { return VFS.llseek(stream, offset, whence); } var position = offset; - if (whence === {{{ cDefine('SEEK_CUR') }}}) { + if (whence === {{{ cDefs.SEEK_CUR }}}) { position += stream.position; - } else if (whence === {{{ cDefine('SEEK_END') }}}) { + } else if (whence === {{{ cDefs.SEEK_END }}}) { position += fs.fstatSync(stream.nfd).size; - } else if (whence !== {{{ cDefine('SEEK_SET') }}}) { - throw new FS.ErrnoError({{{ cDefine('EINVAL') }}}); + } else if (whence !== {{{ cDefs.SEEK_SET }}}) { + throw new FS.ErrnoError({{{ cDefs.EINVAL }}}); } if (position < 0) { - throw new FS.ErrnoError({{{ cDefine('EINVAL') }}}); + throw new FS.ErrnoError({{{ cDefs.EINVAL }}}); } stream.position = position; return position; @@ -159,9 +159,9 @@ mergeInto(LibraryManager.library, { // this stream is created by in-memory filesystem return VFS.write(stream, buffer, offset, length, position); } - if (stream.flags & +"{{{ cDefine('O_APPEND') }}}") { + if (stream.flags & +"{{{ cDefs.O_APPEND }}}") { // seek to the end before writing in append mode - FS.llseek(stream, 0, +"{{{ cDefine('SEEK_END') }}}"); + FS.llseek(stream, 0, +"{{{ cDefs.SEEK_END }}}"); } var seeking = typeof position != 'undefined'; if (!seeking && stream.seekable) position = stream.position; @@ -171,7 +171,7 @@ mergeInto(LibraryManager.library, { return bytesWritten; }, allocate: function() { - throw new FS.ErrnoError({{{ cDefine('EOPNOTSUPP') }}}); + throw new FS.ErrnoError({{{ cDefs.EOPNOTSUPP }}}); }, mmap: function(stream, length, position, prot, flags) { if (stream.stream_ops) { @@ -197,7 +197,7 @@ mergeInto(LibraryManager.library, { return 0; }, ioctl: function() { - throw new FS.ErrnoError({{{ cDefine('ENOTTY') }}}); + throw new FS.ErrnoError({{{ cDefs.ENOTTY }}}); } } }); diff --git a/src/library_openal.js b/src/library_openal.js index 749214646cf80..e89642506a1dc 100644 --- a/src/library_openal.js +++ b/src/library_openal.js @@ -46,7 +46,7 @@ var LibraryOpenAL = { }, set alcErr(val) { // Errors should not be overwritten by later errors until they are cleared by a query. - if (this._alcErr === {{{ cDefine('ALC_NO_ERROR') }}} || val === {{{ cDefine('ALC_NO_ERROR') }}}) { + if (this._alcErr === {{{ cDefs.ALC_NO_ERROR }}} || val === {{{ cDefs.ALC_NO_ERROR }}}) { this._alcErr = val; } }, @@ -407,7 +407,7 @@ var LibraryOpenAL = { } } // Create a panner if AL_SOURCE_SPATIALIZE_SOFT is set to true, or alternatively if it's set to auto and the source is mono - if (src.spatialize === {{{ cDefine('AL_TRUE') }}} || (src.spatialize === 2 /* AL_AUTO_SOFT */ && templateBuf.channels === 1)) { + if (src.spatialize === {{{ cDefs.AL_TRUE }}} || (src.spatialize === 2 /* AL_AUTO_SOFT */ && templateBuf.channels === 1)) { if (src.panner) { return; } @@ -452,7 +452,7 @@ var LibraryOpenAL = { // Use the source's distance model if AL_SOURCE_DISTANCE_MODEL is enabled var distanceModel = src.context.sourceDistanceModel ? src.distanceModel : src.context.distanceModel; switch (distanceModel) { - case {{{ cDefine('AL_NONE') }}}: + case {{{ cDefs.AL_NONE }}}: panner.distanceModel = 'inverse'; panner.refDistance = 3.40282e38 /* FLT_MAX */; break; @@ -753,17 +753,17 @@ var LibraryOpenAL = { } switch (param) { - case {{{ cDefine('AL_DOPPLER_FACTOR') }}}: + case {{{ cDefs.AL_DOPPLER_FACTOR }}}: return AL.currentCtx.dopplerFactor; - case {{{ cDefine('AL_SPEED_OF_SOUND') }}}: + case {{{ cDefs.AL_SPEED_OF_SOUND }}}: return AL.currentCtx.speedOfSound; - case {{{ cDefine('AL_DISTANCE_MODEL') }}}: + case {{{ cDefs.AL_DISTANCE_MODEL }}}: return AL.currentCtx.distanceModel; default: #if OPENAL_DEBUG dbg(funcname + '() param ' + ptrToString(param) + ' is unknown or not implemented'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_ENUM') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return null; } }, @@ -777,33 +777,33 @@ var LibraryOpenAL = { } switch (param) { - case {{{ cDefine('AL_DOPPLER_FACTOR') }}}: + case {{{ cDefs.AL_DOPPLER_FACTOR }}}: if (!Number.isFinite(value) || value < 0.0) { // Strictly negative values are disallowed #if OPENAL_DEBUG dbg(funcname + '() value ' + value + ' is out of range'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } AL.currentCtx.dopplerFactor = value; AL.updateListenerSpace(AL.currentCtx); break; - case {{{ cDefine('AL_SPEED_OF_SOUND') }}}: + case {{{ cDefs.AL_SPEED_OF_SOUND }}}: if (!Number.isFinite(value) || value <= 0.0) { // Negative or zero values are disallowed #if OPENAL_DEBUG dbg(funcname + '() value ' + value + ' is out of range'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } AL.currentCtx.speedOfSound = value; AL.updateListenerSpace(AL.currentCtx); break; - case {{{ cDefine('AL_DISTANCE_MODEL') }}}: + case {{{ cDefs.AL_DISTANCE_MODEL }}}: switch (value) { - case {{{ cDefine('AL_NONE') }}}: + case {{{ cDefs.AL_NONE }}}: case 0xd001 /* AL_INVERSE_DISTANCE */: case 0xd002 /* AL_INVERSE_DISTANCE_CLAMPED */: case 0xd003 /* AL_LINEAR_DISTANCE */: @@ -817,7 +817,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg(funcname + '() value ' + value + ' is out of range'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } break; @@ -825,7 +825,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg(funcname + '() param ' + ptrToString(param) + ' is unknown or not implemented'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_ENUM') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; } }, @@ -839,19 +839,19 @@ var LibraryOpenAL = { } switch (param) { - case {{{ cDefine('AL_POSITION') }}}: + case {{{ cDefs.AL_POSITION }}}: return AL.currentCtx.listener.position; - case {{{ cDefine('AL_VELOCITY') }}}: + case {{{ cDefs.AL_VELOCITY }}}: return AL.currentCtx.listener.velocity; - case {{{ cDefine('AL_ORIENTATION') }}}: + case {{{ cDefs.AL_ORIENTATION }}}: return AL.currentCtx.listener.direction.concat(AL.currentCtx.listener.up); - case {{{ cDefine('AL_GAIN') }}}: + case {{{ cDefs.AL_GAIN }}}: return AL.currentCtx.gain.gain.value; default: #if OPENAL_DEBUG dbg(funcname + '() param ' + ptrToString(param) + ' is unknown or not implemented'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_ENUM') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return null; } }, @@ -867,18 +867,18 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg(funcname + '(): param ' + ptrToString(param) + ' has wrong signature'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_ENUM') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; } var listener = AL.currentCtx.listener; switch (param) { - case {{{ cDefine('AL_POSITION') }}}: + case {{{ cDefs.AL_POSITION }}}: if (!Number.isFinite(value[0]) || !Number.isFinite(value[1]) || !Number.isFinite(value[2])) { #if OPENAL_DEBUG dbg(funcname + '() param AL_POSITION value ' + value + ' is out of range'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } @@ -887,12 +887,12 @@ var LibraryOpenAL = { listener.position[2] = value[2]; AL.updateListenerSpace(AL.currentCtx); break; - case {{{ cDefine('AL_VELOCITY') }}}: + case {{{ cDefs.AL_VELOCITY }}}: if (!Number.isFinite(value[0]) || !Number.isFinite(value[1]) || !Number.isFinite(value[2])) { #if OPENAL_DEBUG dbg(funcname + '() param AL_VELOCITY value ' + value + ' is out of range'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } @@ -901,25 +901,25 @@ var LibraryOpenAL = { listener.velocity[2] = value[2]; AL.updateListenerSpace(AL.currentCtx); break; - case {{{ cDefine('AL_GAIN') }}}: + case {{{ cDefs.AL_GAIN }}}: if (!Number.isFinite(value) || value < 0.0) { #if OPENAL_DEBUG dbg(funcname + '() param AL_GAIN value ' + value + ' is out of range'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } AL.currentCtx.gain.gain.value = value; break; - case {{{ cDefine('AL_ORIENTATION') }}}: + case {{{ cDefs.AL_ORIENTATION }}}: if (!Number.isFinite(value[0]) || !Number.isFinite(value[1]) || !Number.isFinite(value[2]) || !Number.isFinite(value[3]) || !Number.isFinite(value[4]) || !Number.isFinite(value[5]) ) { #if OPENAL_DEBUG dbg(funcname + '() param AL_ORIENTATION value ' + value + ' is out of range'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } @@ -935,7 +935,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg(funcname + '() param ' + ptrToString(param) + ' is unknown or not implemented'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_ENUM') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; } }, @@ -952,7 +952,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg(funcname + '() called with an invalid buffer'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_NAME') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_NAME }}}; return; } @@ -977,7 +977,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg(funcname + '() param ' + ptrToString(param) + ' is unknown or not implemented'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_ENUM') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return null; } }, @@ -994,14 +994,14 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg(funcname + '() called with an invalid buffer'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_NAME') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_NAME }}}; return; } if (value === null) { #if OPENAL_DEBUG dbg(funcname + '(): param ' + ptrToString(param) + ' has wrong signature'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_ENUM') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; } @@ -1011,7 +1011,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg(funcname + '() param AL_SIZE value ' + value + ' is out of range'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } @@ -1022,14 +1022,14 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg(funcname + '() param AL_LOOP_POINTS_SOFT value ' + value + ' is out of range'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } if (buf.refCount > 0) { #if OPENAL_DEBUG dbg(funcname + '() param AL_LOOP_POINTS_SOFT set on bound buffer'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_OPERATION') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_OPERATION }}}; return; } @@ -1042,7 +1042,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg(funcname + '() param ' + ptrToString(param) + ' is unknown or not implemented'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_ENUM') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; } }, @@ -1059,7 +1059,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg(funcname + '() called with an invalid source'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_NAME') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_NAME }}}; return null; } @@ -1072,11 +1072,11 @@ var LibraryOpenAL = { return src.coneOuterAngle; case 0x1003 /* AL_PITCH */: return src.pitch; - case {{{ cDefine('AL_POSITION') }}}: + case {{{ cDefs.AL_POSITION }}}: return src.position; - case {{{ cDefine('AL_DIRECTION') }}}: + case {{{ cDefs.AL_DIRECTION }}}: return src.direction; - case {{{ cDefine('AL_VELOCITY') }}}: + case {{{ cDefs.AL_VELOCITY }}}: return src.velocity; case 0x1007 /* AL_LOOPING */: return src.looping; @@ -1085,7 +1085,7 @@ var LibraryOpenAL = { return src.bufQueue[0].id; } return 0; - case {{{ cDefine('AL_GAIN') }}}: + case {{{ cDefs.AL_GAIN }}}: return src.gain.gain.value; case 0x100D /* AL_MIN_GAIN */: return src.minGain; @@ -1147,13 +1147,13 @@ var LibraryOpenAL = { return length; case 0x200B /* AL_SEC_LENGTH_SOFT */: return AL.sourceDuration(src); - case {{{ cDefine('AL_DISTANCE_MODEL') }}}: + case {{{ cDefs.AL_DISTANCE_MODEL }}}: return src.distanceModel; default: #if OPENAL_DEBUG dbg(funcname + '() param ' + ptrToString(param) + ' is unknown or not implemented'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_ENUM') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return null; } }, @@ -1170,30 +1170,30 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alSourcef() called with an invalid source'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_NAME') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_NAME }}}; return; } if (value === null) { #if OPENAL_DEBUG dbg(funcname + '(): param ' + ptrToString(param) + ' has wrong signature'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_ENUM') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; } switch (param) { case 0x202 /* AL_SOURCE_RELATIVE */: - if (value === {{{ cDefine('AL_TRUE') }}}) { + if (value === {{{ cDefs.AL_TRUE }}}) { src.relative = true; AL.updateSourceSpace(src); - } else if (value === {{{ cDefine('AL_FALSE') }}}) { + } else if (value === {{{ cDefs.AL_FALSE }}}) { src.relative = false; AL.updateSourceSpace(src); } else { #if OPENAL_DEBUG dbg(funcname + '() param AL_SOURCE_RELATIVE value ' + value + ' is out of range'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } break; @@ -1202,7 +1202,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg(funcname + '() param AL_CONE_INNER_ANGLE value ' + value + ' is out of range'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } @@ -1216,7 +1216,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg(funcname + '() param AL_CONE_OUTER_ANGLE value ' + value + ' is out of range'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } @@ -1230,7 +1230,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg(funcname + '() param AL_PITCH value ' + value + ' is out of range'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } @@ -1241,12 +1241,12 @@ var LibraryOpenAL = { src.pitch = value; AL.updateSourceRate(src); break; - case {{{ cDefine('AL_POSITION') }}}: + case {{{ cDefs.AL_POSITION }}}: if (!Number.isFinite(value[0]) || !Number.isFinite(value[1]) || !Number.isFinite(value[2])) { #if OPENAL_DEBUG dbg(funcname + '() param AL_POSITION value ' + value + ' is out of range'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } @@ -1255,12 +1255,12 @@ var LibraryOpenAL = { src.position[2] = value[2]; AL.updateSourceSpace(src); break; - case {{{ cDefine('AL_DIRECTION') }}}: + case {{{ cDefs.AL_DIRECTION }}}: if (!Number.isFinite(value[0]) || !Number.isFinite(value[1]) || !Number.isFinite(value[2])) { #if OPENAL_DEBUG dbg(funcname + '() param AL_DIRECTION value ' + value + ' is out of range'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } @@ -1269,12 +1269,12 @@ var LibraryOpenAL = { src.direction[2] = value[2]; AL.updateSourceSpace(src); break; - case {{{ cDefine('AL_VELOCITY') }}}: + case {{{ cDefs.AL_VELOCITY }}}: if (!Number.isFinite(value[0]) || !Number.isFinite(value[1]) || !Number.isFinite(value[2])) { #if OPENAL_DEBUG dbg(funcname + '() param AL_VELOCITY value ' + value + ' is out of range'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } @@ -1284,7 +1284,7 @@ var LibraryOpenAL = { AL.updateSourceSpace(src); break; case 0x1007 /* AL_LOOPING */: - if (value === {{{ cDefine('AL_TRUE') }}}) { + if (value === {{{ cDefs.AL_TRUE }}}) { src.looping = true; AL.updateSourceTime(src); if (src.type === 0x1028 /* AL_STATIC */ && src.audioQueue.length > 0) { @@ -1292,7 +1292,7 @@ var LibraryOpenAL = { audioSrc.loop = true; audioSrc._duration = Number.POSITIVE_INFINITY; } - } else if (value === {{{ cDefine('AL_FALSE') }}}) { + } else if (value === {{{ cDefs.AL_FALSE }}}) { src.looping = false; var currentTime = AL.updateSourceTime(src); if (src.type === 0x1028 /* AL_STATIC */ && src.audioQueue.length > 0) { @@ -1305,7 +1305,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg(funcname + '() param AL_LOOPING value ' + value + ' is out of range'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } break; @@ -1314,7 +1314,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg(funcname + '(AL_BUFFER) called while source is playing or paused'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_OPERATION') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_OPERATION }}}; return; } @@ -1333,7 +1333,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alSourcei(AL_BUFFER) called with an invalid buffer'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } @@ -1351,12 +1351,12 @@ var LibraryOpenAL = { AL.initSourcePanner(src); AL.scheduleSourceAudio(src); break; - case {{{ cDefine('AL_GAIN') }}}: + case {{{ cDefs.AL_GAIN }}}: if (!Number.isFinite(value) || value < 0.0) { #if OPENAL_DEBUG dbg(funcname + '() param AL_GAIN value ' + value + ' is out of range'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } src.gain.gain.value = value; @@ -1366,7 +1366,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg(funcname + '() param AL_MIN_GAIN value ' + value + ' is out of range'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } #if OPENAL_DEBUG @@ -1379,7 +1379,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg(funcname + '() param AL_MAX_GAIN value ' + value + ' is out of range'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } #if OPENAL_DEBUG @@ -1392,7 +1392,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg(funcname + '() param AL_REFERENCE_DISTANCE value ' + value + ' is out of range'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } src.refDistance = value; @@ -1405,7 +1405,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg(funcname + '() param AL_ROLLOFF_FACTOR value ' + value + ' is out of range'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } src.rolloffFactor = value; @@ -1418,7 +1418,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg(funcname + '() param AL_CORE_OUTER_GAIN value ' + value + ' is out of range'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } src.coneOuterGain = value; @@ -1431,7 +1431,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg(funcname + '() param AL_MAX_DISTANCE value ' + value + ' is out of range'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } src.maxDistance = value; @@ -1444,7 +1444,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg(funcname + '() param AL_SEC_OFFSET value ' + value + ' is out of range'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } @@ -1466,7 +1466,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg(funcname + '() param AL_SAMPLE_OFFSET value ' + value + ' is out of range'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } @@ -1489,18 +1489,18 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg(funcname + '() param AL_BYTE_OFFSET value ' + value + ' is out of range'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } AL.sourceSeek(src, value); break; case 0x1214 /* AL_SOURCE_SPATIALIZE_SOFT */: - if (value !== {{{ cDefine('AL_FALSE') }}} && value !== {{{ cDefine('AL_TRUE') }}} && value !== 2 /* AL_AUTO_SOFT */) { + if (value !== {{{ cDefs.AL_FALSE }}} && value !== {{{ cDefs.AL_TRUE }}} && value !== 2 /* AL_AUTO_SOFT */) { #if OPENAL_DEBUG dbg(funcname + '() param AL_SOURCE_SPATIALIZE_SOFT value ' + value + ' is out of range'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } @@ -1513,11 +1513,11 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg(funcname + '() param AL_*_LENGTH_SOFT is read only'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_OPERATION') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_OPERATION }}}; break; - case {{{ cDefine('AL_DISTANCE_MODEL') }}}: + case {{{ cDefs.AL_DISTANCE_MODEL }}}: switch (value) { - case {{{ cDefine('AL_NONE') }}}: + case {{{ cDefs.AL_NONE }}}: case 0xd001 /* AL_INVERSE_DISTANCE */: case 0xd002 /* AL_INVERSE_DISTANCE_CLAMPED */: case 0xd003 /* AL_LINEAR_DISTANCE */: @@ -1533,7 +1533,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg(funcname + '() param AL_DISTANCE_MODEL value ' + value + ' is out of range'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } break; @@ -1541,7 +1541,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg(funcname + '() param ' + ptrToString(param) + ' is unknown or not implemented'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_ENUM') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; } }, @@ -1567,7 +1567,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg(funcname+'() on a NULL device is an error'); #endif - AL.alcErr = {{{ cDefine('ALC_INVALID_DEVICE') }}}; + AL.alcErr = {{{ cDefs.ALC_INVALID_DEVICE }}}; return null; } var c = AL.captures[deviceId]; @@ -1575,7 +1575,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg(funcname+'() on an invalid device'); #endif - AL.alcErr = {{{ cDefine('ALC_INVALID_DEVICE') }}}; + AL.alcErr = {{{ cDefs.ALC_INVALID_DEVICE }}}; return null; } var err = c.mediaStreamError; @@ -1593,7 +1593,7 @@ var LibraryOpenAL = { break; } #endif - AL.alcErr = {{{ cDefine('ALC_INVALID_DEVICE') }}}; + AL.alcErr = {{{ cDefs.ALC_INVALID_DEVICE }}}; return null; } return c; @@ -1640,7 +1640,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alcCaptureOpenDevice() with negative bufferSize'); #endif - AL.alcErr = {{{ cDefine('ALC_INVALID_VALUE') }}}; + AL.alcErr = {{{ cDefs.ALC_INVALID_VALUE }}}; return 0; } @@ -1695,7 +1695,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alcCaptureOpenDevice() with unsupported format ' + format); #endif - AL.alcErr = {{{ cDefine('ALC_INVALID_VALUE') }}}; + AL.alcErr = {{{ cDefs.ALC_INVALID_VALUE }}}; return 0; } @@ -1999,7 +1999,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alcCaptureSamples() with invalid bufferSize'); #endif - AL.alcErr = {{{ cDefine('ALC_INVALID_VALUE') }}}; + AL.alcErr = {{{ cDefs.ALC_INVALID_VALUE }}}; return; } @@ -2087,12 +2087,12 @@ var LibraryOpenAL = { alcCloseDevice__sig: 'ip', alcCloseDevice: function(deviceId) { if (!(deviceId in AL.deviceRefCounts) || AL.deviceRefCounts[deviceId] > 0) { - return {{{ cDefine('ALC_FALSE') }}}; + return {{{ cDefs.ALC_FALSE }}}; } delete AL.deviceRefCounts[deviceId]; AL.freeIds.push(deviceId); - return {{{ cDefine('ALC_TRUE') }}}; + return {{{ cDefs.ALC_TRUE }}}; }, alcCreateContext__deps: ['$autoResumeAudioContext'], @@ -2137,10 +2137,10 @@ var LibraryOpenAL = { break case 0x1992 /* ALC_HRTF_SOFT */: switch (val) { - case {{{ cDefine('ALC_FALSE') }}}: + case {{{ cDefs.ALC_FALSE }}}: hrtf = false; break; - case {{{ cDefine('ALC_TRUE') }}}: + case {{{ cDefs.ALC_TRUE }}}: hrtf = true; break; case 2 /* ALC_DONT_CARE_SOFT */: @@ -2149,7 +2149,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('Unsupported ALC_HRTF_SOFT mode ' + val); #endif - AL.alcErr = {{{ cDefine('ALC_INVALID_VALUE') }}}; + AL.alcErr = {{{ cDefs.ALC_INVALID_VALUE }}}; return 0; } break; @@ -2158,7 +2158,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('Invalid ALC_HRTF_ID_SOFT index ' + val); #endif - AL.alcErr = {{{ cDefine('ALC_INVALID_VALUE') }}}; + AL.alcErr = {{{ cDefs.ALC_INVALID_VALUE }}}; return 0; } break; @@ -2229,7 +2229,7 @@ var LibraryOpenAL = { }, set err(val) { // Errors should not be overwritten by later errors until they are cleared by a query. - if (this._err === {{{ cDefine('AL_NO_ERROR') }}} || val === {{{ cDefine('AL_NO_ERROR') }}}) { + if (this._err === {{{ cDefs.AL_NO_ERROR }}} || val === {{{ cDefs.AL_NO_ERROR }}}) { this._err = val; } } @@ -2280,7 +2280,7 @@ var LibraryOpenAL = { alcGetError__sig: 'ip', alcGetError: function(deviceId) { var err = AL.alcErr; - AL.alcErr = {{{ cDefine('ALC_NO_ERROR') }}}; + AL.alcErr = {{{ cDefs.ALC_NO_ERROR }}}; return err; }, @@ -2301,7 +2301,7 @@ var LibraryOpenAL = { } else { AL.currentCtx = AL.contexts[contextId]; } - return {{{ cDefine('ALC_TRUE') }}}; + return {{{ cDefs.ALC_TRUE }}}; }, alcGetContextsDevice__proxy: 'sync', @@ -2341,7 +2341,7 @@ var LibraryOpenAL = { // this function, sadly. return 0; } else if (!pEnumName) { - AL.alcErr = {{{ cDefine('ALC_INVALID_VALUE') }}}; + AL.alcErr = {{{ cDefs.ALC_INVALID_VALUE }}}; return 0; } var name = UTF8ToString(pEnumName); @@ -2387,8 +2387,8 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('No value for `' + pEnumName + '` is known by alcGetEnumValue()'); #endif - AL.alcErr = {{{ cDefine('ALC_INVALID_VALUE') }}}; - return {{{ cDefine('AL_NONE') }}}; + AL.alcErr = {{{ cDefs.ALC_INVALID_VALUE }}}; + return {{{ cDefs.AL_NONE }}}; } }, @@ -2402,19 +2402,19 @@ var LibraryOpenAL = { var ret; switch (param) { - case {{{ cDefine('ALC_NO_ERROR') }}}: + case {{{ cDefs.ALC_NO_ERROR }}}: ret = 'No Error'; break; - case {{{ cDefine('ALC_INVALID_DEVICE') }}}: + case {{{ cDefs.ALC_INVALID_DEVICE }}}: ret = 'Invalid Device'; break; case 0xA002 /* ALC_INVALID_CONTEXT */: ret = 'Invalid Context'; break; - case {{{ cDefine('ALC_INVALID_ENUM') }}}: + case {{{ cDefs.ALC_INVALID_ENUM }}}: ret = 'Invalid Enum'; break; - case {{{ cDefine('ALC_INVALID_VALUE') }}}: + case {{{ cDefs.ALC_INVALID_VALUE }}}: ret = 'Invalid Value'; break; case 0xA005 /* ALC_OUT_OF_MEMORY */: @@ -2452,7 +2452,7 @@ var LibraryOpenAL = { break; case 0x1006 /* ALC_EXTENSIONS */: if (!deviceId) { - AL.alcErr = {{{ cDefine('ALC_INVALID_DEVICE') }}}; + AL.alcErr = {{{ cDefs.ALC_INVALID_DEVICE }}}; return 0; } @@ -2464,7 +2464,7 @@ var LibraryOpenAL = { ret = ret.trim(); break; default: - AL.alcErr = {{{ cDefine('ALC_INVALID_ENUM') }}}; + AL.alcErr = {{{ cDefs.ALC_INVALID_ENUM }}}; return 0; } @@ -2490,7 +2490,7 @@ var LibraryOpenAL = { break; case 0x1002 /* ALC_ATTRIBUTES_SIZE */: if (!(deviceId in AL.deviceRefCounts)) { - AL.alcErr = {{{ cDefine('ALC_INVALID_DEVICE') }}}; + AL.alcErr = {{{ cDefs.ALC_INVALID_DEVICE }}}; return; } if (!AL.currentCtx) { @@ -2502,7 +2502,7 @@ var LibraryOpenAL = { break; case 0x1003 /* ALC_ALL_ATTRIBUTES */: if (!(deviceId in AL.deviceRefCounts)) { - AL.alcErr = {{{ cDefine('ALC_INVALID_DEVICE') }}}; + AL.alcErr = {{{ cDefs.ALC_INVALID_DEVICE }}}; return; } if (!AL.currentCtx) { @@ -2516,7 +2516,7 @@ var LibraryOpenAL = { break; case 0x1007 /* ALC_FREQUENCY */: if (!(deviceId in AL.deviceRefCounts)) { - AL.alcErr = {{{ cDefine('ALC_INVALID_DEVICE') }}}; + AL.alcErr = {{{ cDefs.ALC_INVALID_DEVICE }}}; return; } if (!AL.currentCtx) { @@ -2529,7 +2529,7 @@ var LibraryOpenAL = { case 0x1010 /* ALC_MONO_SOURCES */: case 0x1011 /* ALC_STEREO_SOURCES */: if (!(deviceId in AL.deviceRefCounts)) { - AL.alcErr = {{{ cDefine('ALC_INVALID_DEVICE') }}}; + AL.alcErr = {{{ cDefs.ALC_INVALID_DEVICE }}}; return; } if (!AL.currentCtx) { @@ -2542,7 +2542,7 @@ var LibraryOpenAL = { case 0x1992 /* ALC_HRTF_SOFT */: case 0x1993 /* ALC_HRTF_STATUS_SOFT */: if (!(deviceId in AL.deviceRefCounts)) { - AL.alcErr = {{{ cDefine('ALC_INVALID_DEVICE') }}}; + AL.alcErr = {{{ cDefs.ALC_INVALID_DEVICE }}}; return; } @@ -2557,14 +2557,14 @@ var LibraryOpenAL = { break; case 0x1994 /* ALC_NUM_HRTF_SPECIFIERS_SOFT */: if (!(deviceId in AL.deviceRefCounts)) { - AL.alcErr = {{{ cDefine('ALC_INVALID_DEVICE') }}}; + AL.alcErr = {{{ cDefs.ALC_INVALID_DEVICE }}}; return; } {{{ makeSetValue('pValues', '0', '1', 'i32') }}}; break; case 0x20003 /* ALC_MAX_AUXILIARY_SENDS */: if (!(deviceId in AL.deviceRefCounts)) { - AL.alcErr = {{{ cDefine('ALC_INVALID_DEVICE') }}}; + AL.alcErr = {{{ cDefs.ALC_INVALID_DEVICE }}}; return; } if (!AL.currentCtx) { @@ -2588,7 +2588,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alcGetIntegerv() with param ' + ptrToString(param) + ' not implemented yet'); #endif - AL.alcErr = {{{ cDefine('ALC_INVALID_ENUM') }}}; + AL.alcErr = {{{ cDefs.ALC_INVALID_ENUM }}}; return; } }, @@ -2600,7 +2600,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alcDevicePauseSOFT() called with an invalid device'); #endif - AL.alcErr = {{{ cDefine('ALC_INVALID_DEVICE') }}}; + AL.alcErr = {{{ cDefs.ALC_INVALID_DEVICE }}}; return; } @@ -2628,7 +2628,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alcDeviceResumeSOFT() called with an invalid device'); #endif - AL.alcErr = {{{ cDefine('ALC_INVALID_DEVICE') }}}; + AL.alcErr = {{{ cDefs.ALC_INVALID_DEVICE }}}; return; } @@ -2656,7 +2656,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alcGetStringiSOFT() called with an invalid device'); #endif - AL.alcErr = {{{ cDefine('ALC_INVALID_DEVICE') }}}; + AL.alcErr = {{{ cDefs.ALC_INVALID_DEVICE }}}; return 0; } @@ -2673,7 +2673,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alcGetStringiSOFT() with param ALC_HRTF_SPECIFIER_SOFT index ' + index + ' is out of range'); #endif - AL.alcErr = {{{ cDefine('ALC_INVALID_VALUE') }}}; + AL.alcErr = {{{ cDefs.ALC_INVALID_VALUE }}}; return 0; } break; @@ -2682,7 +2682,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alcGetStringiSOFT() with param ' + ptrToString(param) + ' not implemented yet'); #endif - AL.alcErr = {{{ cDefine('ALC_INVALID_ENUM') }}}; + AL.alcErr = {{{ cDefs.ALC_INVALID_ENUM }}}; return 0; } return _alcGetString(deviceId, param); @@ -2700,8 +2700,8 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alcResetDeviceSOFT() called with an invalid device'); #endif - AL.alcErr = {{{ cDefine('ALC_INVALID_DEVICE') }}}; - return {{{ cDefine('ALC_FALSE') }}}; + AL.alcErr = {{{ cDefs.ALC_INVALID_DEVICE }}}; + return {{{ cDefs.ALC_FALSE }}}; } var hrtf = null; @@ -2718,9 +2718,9 @@ var LibraryOpenAL = { switch (attr) { case 0x1992 /* ALC_HRTF_SOFT */: - if (val === {{{ cDefine('ALC_TRUE') }}}) { + if (val === {{{ cDefs.ALC_TRUE }}}) { hrtf = true; - } else if (val === {{{ cDefine('ALC_FALSE') }}}) { + } else if (val === {{{ cDefs.ALC_FALSE }}}) { hrtf = false; } break; @@ -2739,7 +2739,7 @@ var LibraryOpenAL = { } } - return {{{ cDefine('ALC_TRUE') }}}; + return {{{ cDefs.ALC_TRUE }}}; }, // *************************************************************************** @@ -2799,7 +2799,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alDeleteBuffers() called with an invalid buffer'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_NAME') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_NAME }}}; return; } @@ -2808,7 +2808,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alDeleteBuffers() called with a used buffer'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_OPERATION') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_OPERATION }}}; return; } } @@ -2893,7 +2893,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alDeleteSources() called with an invalid source'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_NAME') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_NAME }}}; return; } } @@ -2915,11 +2915,11 @@ var LibraryOpenAL = { alGetError__sig: 'i', alGetError: function() { if (!AL.currentCtx) { - return {{{ cDefine('AL_INVALID_OPERATION') }}}; + return {{{ cDefs.AL_INVALID_OPERATION }}}; } // Reset error on get. var err = AL.currentCtx.err; - AL.currentCtx.err = {{{ cDefine('AL_NO_ERROR') }}}; + AL.currentCtx.err = {{{ cDefs.AL_NO_ERROR }}}; return err; }, @@ -2945,8 +2945,8 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alGetEnumValue() called with null pointer'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; - return {{{ cDefine('AL_NONE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; + return {{{ cDefs.AL_NONE }}}; } var name = UTF8ToString(pEnumName); @@ -3038,7 +3038,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('No value for `' + name + '` is known by alGetEnumValue()'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return 0; } }, @@ -3053,19 +3053,19 @@ var LibraryOpenAL = { var ret; switch (param) { - case {{{ cDefine('AL_NO_ERROR') }}}: + case {{{ cDefs.AL_NO_ERROR }}}: ret = 'No Error'; break; - case {{{ cDefine('AL_INVALID_NAME') }}}: + case {{{ cDefs.AL_INVALID_NAME }}}: ret = 'Invalid Name'; break; - case {{{ cDefine('AL_INVALID_ENUM') }}}: + case {{{ cDefs.AL_INVALID_ENUM }}}: ret = 'Invalid Enum'; break; - case {{{ cDefine('AL_INVALID_VALUE') }}}: + case {{{ cDefs.AL_INVALID_VALUE }}}: ret = 'Invalid Value'; break; - case {{{ cDefine('AL_INVALID_OPERATION') }}}: + case {{{ cDefs.AL_INVALID_OPERATION }}}: ret = 'Invalid Operation'; break; case 0xA005 /* AL_OUT_OF_MEMORY */: @@ -3090,7 +3090,7 @@ var LibraryOpenAL = { break; default: if (AL.currentCtx) { - AL.currentCtx.err = {{{ cDefine('AL_INVALID_ENUM') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; } else { #if OPENAL_DEBUG dbg('alGetString() called without a valid context'); @@ -3122,7 +3122,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alEnable() with param ' + ptrToString(param) + ' not implemented yet'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_ENUM') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; } }, @@ -3145,7 +3145,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alDisable() with param ' + ptrToString(param) + ' not implemented yet'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_ENUM') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; } }, @@ -3161,12 +3161,12 @@ var LibraryOpenAL = { } switch (param) { case 'AL_SOURCE_DISTANCE_MODEL': - return AL.currentCtx.sourceDistanceModel ? {{{ cDefine('AL_FALSE') }}} : {{{ cDefine('AL_TRUE') }}}; + return AL.currentCtx.sourceDistanceModel ? {{{ cDefs.AL_FALSE }}} : {{{ cDefs.AL_TRUE }}}; default: #if OPENAL_DEBUG dbg('alIsEnabled() with param ' + ptrToString(param) + ' not implemented yet'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_ENUM') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return 0; } }, @@ -3180,15 +3180,15 @@ var LibraryOpenAL = { } switch (param) { - case {{{ cDefine('AL_DOPPLER_FACTOR') }}}: - case {{{ cDefine('AL_SPEED_OF_SOUND') }}}: - case {{{ cDefine('AL_DISTANCE_MODEL') }}}: + case {{{ cDefs.AL_DOPPLER_FACTOR }}}: + case {{{ cDefs.AL_SPEED_OF_SOUND }}}: + case {{{ cDefs.AL_DISTANCE_MODEL }}}: return val; default: #if OPENAL_DEBUG dbg('alGetDouble(): param ' + ptrToString(param) + ' has wrong signature'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_ENUM') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return 0.0; } }, @@ -3203,16 +3203,16 @@ var LibraryOpenAL = { } switch (param) { - case {{{ cDefine('AL_DOPPLER_FACTOR') }}}: - case {{{ cDefine('AL_SPEED_OF_SOUND') }}}: - case {{{ cDefine('AL_DISTANCE_MODEL') }}}: + case {{{ cDefs.AL_DOPPLER_FACTOR }}}: + case {{{ cDefs.AL_SPEED_OF_SOUND }}}: + case {{{ cDefs.AL_DISTANCE_MODEL }}}: {{{ makeSetValue('pValues', '0', 'val', 'double') }}}; break; default: #if OPENAL_DEBUG dbg('alGetDoublev(): param ' + ptrToString(param) + ' has wrong signature'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_ENUM') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; } }, @@ -3226,9 +3226,9 @@ var LibraryOpenAL = { } switch (param) { - case {{{ cDefine('AL_DOPPLER_FACTOR') }}}: - case {{{ cDefine('AL_SPEED_OF_SOUND') }}}: - case {{{ cDefine('AL_DISTANCE_MODEL') }}}: + case {{{ cDefs.AL_DOPPLER_FACTOR }}}: + case {{{ cDefs.AL_SPEED_OF_SOUND }}}: + case {{{ cDefs.AL_DISTANCE_MODEL }}}: return val; default: #if OPENAL_DEBUG @@ -3248,16 +3248,16 @@ var LibraryOpenAL = { } switch (param) { - case {{{ cDefine('AL_DOPPLER_FACTOR') }}}: - case {{{ cDefine('AL_SPEED_OF_SOUND') }}}: - case {{{ cDefine('AL_DISTANCE_MODEL') }}}: + case {{{ cDefs.AL_DOPPLER_FACTOR }}}: + case {{{ cDefs.AL_SPEED_OF_SOUND }}}: + case {{{ cDefs.AL_DISTANCE_MODEL }}}: {{{ makeSetValue('pValues', '0', 'val', 'float') }}}; break; default: #if OPENAL_DEBUG dbg('alGetFloatv(): param ' + ptrToString(param) + ' has wrong signature'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_ENUM') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; } }, @@ -3271,15 +3271,15 @@ var LibraryOpenAL = { } switch (param) { - case {{{ cDefine('AL_DOPPLER_FACTOR') }}}: - case {{{ cDefine('AL_SPEED_OF_SOUND') }}}: - case {{{ cDefine('AL_DISTANCE_MODEL') }}}: + case {{{ cDefs.AL_DOPPLER_FACTOR }}}: + case {{{ cDefs.AL_SPEED_OF_SOUND }}}: + case {{{ cDefs.AL_DISTANCE_MODEL }}}: return val; default: #if OPENAL_DEBUG dbg('alGetInteger(): param ' + ptrToString(param) + ' has wrong signature'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_ENUM') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return 0; } }, @@ -3294,16 +3294,16 @@ var LibraryOpenAL = { } switch (param) { - case {{{ cDefine('AL_DOPPLER_FACTOR') }}}: - case {{{ cDefine('AL_SPEED_OF_SOUND') }}}: - case {{{ cDefine('AL_DISTANCE_MODEL') }}}: + case {{{ cDefs.AL_DOPPLER_FACTOR }}}: + case {{{ cDefs.AL_SPEED_OF_SOUND }}}: + case {{{ cDefs.AL_DISTANCE_MODEL }}}: {{{ makeSetValue('pValues', '0', 'val', 'i32') }}}; break; default: #if OPENAL_DEBUG dbg('alGetIntegerv(): param ' + ptrToString(param) + ' has wrong signature'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_ENUM') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; } }, @@ -3313,20 +3313,20 @@ var LibraryOpenAL = { alGetBoolean: function(param) { var val = AL.getGlobalParam('alGetBoolean', param); if (val === null) { - return {{{ cDefine('AL_FALSE') }}}; + return {{{ cDefs.AL_FALSE }}}; } switch (param) { - case {{{ cDefine('AL_DOPPLER_FACTOR') }}}: - case {{{ cDefine('AL_SPEED_OF_SOUND') }}}: - case {{{ cDefine('AL_DISTANCE_MODEL') }}}: - return val !== 0 ? {{{ cDefine('AL_TRUE') }}} : {{{ cDefine('AL_FALSE') }}}; + case {{{ cDefs.AL_DOPPLER_FACTOR }}}: + case {{{ cDefs.AL_SPEED_OF_SOUND }}}: + case {{{ cDefs.AL_DISTANCE_MODEL }}}: + return val !== 0 ? {{{ cDefs.AL_TRUE }}} : {{{ cDefs.AL_FALSE }}}; default: #if OPENAL_DEBUG dbg('alGetBoolean(): param ' + ptrToString(param) + ' has wrong signature'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_ENUM') }}}; - return {{{ cDefine('AL_FALSE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; + return {{{ cDefs.AL_FALSE }}}; } }, @@ -3340,16 +3340,16 @@ var LibraryOpenAL = { } switch (param) { - case {{{ cDefine('AL_DOPPLER_FACTOR') }}}: - case {{{ cDefine('AL_SPEED_OF_SOUND') }}}: - case {{{ cDefine('AL_DISTANCE_MODEL') }}}: + case {{{ cDefs.AL_DOPPLER_FACTOR }}}: + case {{{ cDefs.AL_SPEED_OF_SOUND }}}: + case {{{ cDefs.AL_DISTANCE_MODEL }}}: {{{ makeSetValue('pValues', '0', 'val', 'i8') }}}; break; default: #if OPENAL_DEBUG dbg('alGetBooleanv(): param ' + ptrToString(param) + ' has wrong signature'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_ENUM') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; } }, @@ -3357,19 +3357,19 @@ var LibraryOpenAL = { alDistanceModel__proxy: 'sync', alDistanceModel__sig: 'vi', alDistanceModel: function(model) { - AL.setGlobalParam('alDistanceModel', {{{ cDefine('AL_DISTANCE_MODEL') }}}, model); + AL.setGlobalParam('alDistanceModel', {{{ cDefs.AL_DISTANCE_MODEL }}}, model); }, alSpeedOfSound__proxy: 'sync', alSpeedOfSound__sig: 'vf', alSpeedOfSound: function(value) { - AL.setGlobalParam('alSpeedOfSound', {{{ cDefine('AL_SPEED_OF_SOUND') }}}, value); + AL.setGlobalParam('alSpeedOfSound', {{{ cDefs.AL_SPEED_OF_SOUND }}}, value); }, alDopplerFactor__proxy: 'sync', alDopplerFactor__sig: 'vf', alDopplerFactor: function(value) { - AL.setGlobalParam('alDopplerFactor', {{{ cDefine('AL_DOPPLER_FACTOR') }}}, value); + AL.setGlobalParam('alDopplerFactor', {{{ cDefs.AL_DOPPLER_FACTOR }}}, value); }, // http://openal.996291.n3.nabble.com/alSpeedOfSound-or-alDopperVelocity-tp1960.html @@ -3387,7 +3387,7 @@ var LibraryOpenAL = { return; } if (value <= 0) { // Negative or zero values are disallowed - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } }, @@ -3407,19 +3407,19 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alGetListenerf() called with a null pointer'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } switch (param) { - case {{{ cDefine('AL_GAIN') }}}: + case {{{ cDefs.AL_GAIN }}}: {{{ makeSetValue('pValue', '0', 'val', 'float') }}}; break; default: #if OPENAL_DEBUG dbg('alGetListenerf(): param ' + ptrToString(param) + ' has wrong signature'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_ENUM') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; } }, @@ -3435,13 +3435,13 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alGetListener3f() called with a null pointer'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } switch (param) { - case {{{ cDefine('AL_POSITION') }}}: - case {{{ cDefine('AL_VELOCITY') }}}: + case {{{ cDefs.AL_POSITION }}}: + case {{{ cDefs.AL_VELOCITY }}}: {{{ makeSetValue('pValue0', '0', 'val[0]', 'float') }}}; {{{ makeSetValue('pValue1', '0', 'val[1]', 'float') }}}; {{{ makeSetValue('pValue2', '0', 'val[2]', 'float') }}}; @@ -3450,7 +3450,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alGetListener3f(): param ' + ptrToString(param) + ' has wrong signature'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_ENUM') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; } }, @@ -3466,18 +3466,18 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alGetListenerfv() called with a null pointer'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } switch (param) { - case {{{ cDefine('AL_POSITION') }}}: - case {{{ cDefine('AL_VELOCITY') }}}: + case {{{ cDefs.AL_POSITION }}}: + case {{{ cDefs.AL_VELOCITY }}}: {{{ makeSetValue('pValues', '0', 'val[0]', 'float') }}}; {{{ makeSetValue('pValues', '4', 'val[1]', 'float') }}}; {{{ makeSetValue('pValues', '8', 'val[2]', 'float') }}}; break; - case {{{ cDefine('AL_ORIENTATION') }}}: + case {{{ cDefs.AL_ORIENTATION }}}: {{{ makeSetValue('pValues', '0', 'val[0]', 'float') }}}; {{{ makeSetValue('pValues', '4', 'val[1]', 'float') }}}; {{{ makeSetValue('pValues', '8', 'val[2]', 'float') }}}; @@ -3489,7 +3489,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alGetListenerfv(): param ' + ptrToString(param) + ' has wrong signature'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_ENUM') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; } }, @@ -3505,14 +3505,14 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alGetListeneri() called with a null pointer'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } #if OPENAL_DEBUG dbg('alGetListeneri(): param ' + ptrToString(param) + ' has wrong signature'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_ENUM') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; }, alGetListener3i__proxy: 'sync', @@ -3526,13 +3526,13 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alGetListener3i() called with a null pointer'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } switch (param) { - case {{{ cDefine('AL_POSITION') }}}: - case {{{ cDefine('AL_VELOCITY') }}}: + case {{{ cDefs.AL_POSITION }}}: + case {{{ cDefs.AL_VELOCITY }}}: {{{ makeSetValue('pValue0', '0', 'val[0]', 'i32') }}}; {{{ makeSetValue('pValue1', '0', 'val[1]', 'i32') }}}; {{{ makeSetValue('pValue2', '0', 'val[2]', 'i32') }}}; @@ -3541,7 +3541,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alGetListener3i(): param ' + ptrToString(param) + ' has wrong signature'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_ENUM') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; } }, @@ -3557,18 +3557,18 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alGetListeneriv() called with a null pointer'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } switch (param) { - case {{{ cDefine('AL_POSITION') }}}: - case {{{ cDefine('AL_VELOCITY') }}}: + case {{{ cDefs.AL_POSITION }}}: + case {{{ cDefs.AL_VELOCITY }}}: {{{ makeSetValue('pValues', '0', 'val[0]', 'i32') }}}; {{{ makeSetValue('pValues', '4', 'val[1]', 'i32') }}}; {{{ makeSetValue('pValues', '8', 'val[2]', 'i32') }}}; break; - case {{{ cDefine('AL_ORIENTATION') }}}: + case {{{ cDefs.AL_ORIENTATION }}}: {{{ makeSetValue('pValues', '0', 'val[0]', 'i32') }}}; {{{ makeSetValue('pValues', '4', 'val[1]', 'i32') }}}; {{{ makeSetValue('pValues', '8', 'val[2]', 'i32') }}}; @@ -3580,7 +3580,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alGetListeneriv(): param ' + ptrToString(param) + ' has wrong signature'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_ENUM') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; } }, @@ -3589,7 +3589,7 @@ var LibraryOpenAL = { alListenerf__sig: 'vif', alListenerf: function(param, value) { switch (param) { - case {{{ cDefine('AL_GAIN') }}}: + case {{{ cDefs.AL_GAIN }}}: AL.setListenerParam('alListenerf', param, value); break; default: @@ -3602,8 +3602,8 @@ var LibraryOpenAL = { alListener3f__sig: 'vifff', alListener3f: function(param, value0, value1, value2) { switch (param) { - case {{{ cDefine('AL_POSITION') }}}: - case {{{ cDefine('AL_VELOCITY') }}}: + case {{{ cDefs.AL_POSITION }}}: + case {{{ cDefs.AL_VELOCITY }}}: AL.paramArray[0] = value0; AL.paramArray[1] = value1; AL.paramArray[2] = value2; @@ -3628,19 +3628,19 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alListenerfv() called with a null pointer'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } switch (param) { - case {{{ cDefine('AL_POSITION') }}}: - case {{{ cDefine('AL_VELOCITY') }}}: + case {{{ cDefs.AL_POSITION }}}: + case {{{ cDefs.AL_VELOCITY }}}: AL.paramArray[0] = {{{ makeGetValue('pValues', '0', 'float') }}}; AL.paramArray[1] = {{{ makeGetValue('pValues', '4', 'float') }}}; AL.paramArray[2] = {{{ makeGetValue('pValues', '8', 'float') }}}; AL.setListenerParam('alListenerfv', param, AL.paramArray); break; - case {{{ cDefine('AL_ORIENTATION') }}}: + case {{{ cDefs.AL_ORIENTATION }}}: AL.paramArray[0] = {{{ makeGetValue('pValues', '0', 'float') }}}; AL.paramArray[1] = {{{ makeGetValue('pValues', '4', 'float') }}}; AL.paramArray[2] = {{{ makeGetValue('pValues', '8', 'float') }}}; @@ -3665,8 +3665,8 @@ var LibraryOpenAL = { alListener3i__sig: 'viiii', alListener3i: function(param, value0, value1, value2) { switch (param) { - case {{{ cDefine('AL_POSITION') }}}: - case {{{ cDefine('AL_VELOCITY') }}}: + case {{{ cDefs.AL_POSITION }}}: + case {{{ cDefs.AL_VELOCITY }}}: AL.paramArray[0] = value0; AL.paramArray[1] = value1; AL.paramArray[2] = value2; @@ -3691,19 +3691,19 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alListeneriv() called with a null pointer'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } switch (param) { - case {{{ cDefine('AL_POSITION') }}}: - case {{{ cDefine('AL_VELOCITY') }}}: + case {{{ cDefs.AL_POSITION }}}: + case {{{ cDefs.AL_VELOCITY }}}: AL.paramArray[0] = {{{ makeGetValue('pValues', '0', 'i32') }}}; AL.paramArray[1] = {{{ makeGetValue('pValues', '4', 'i32') }}}; AL.paramArray[2] = {{{ makeGetValue('pValues', '8', 'i32') }}}; AL.setListenerParam('alListeneriv', param, AL.paramArray); break; - case {{{ cDefine('AL_ORIENTATION') }}}: + case {{{ cDefs.AL_ORIENTATION }}}: AL.paramArray[0] = {{{ makeGetValue('pValues', '0', 'i32') }}}; AL.paramArray[1] = {{{ makeGetValue('pValues', '4', 'i32') }}}; AL.paramArray[2] = {{{ makeGetValue('pValues', '8', 'i32') }}}; @@ -3752,14 +3752,14 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alBufferData() called with an invalid buffer'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } if (freq <= 0) { #if OPENAL_DEBUG dbg('alBufferData() called with an invalid frequency'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } @@ -3852,7 +3852,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alBufferData() called with invalid format ' + format); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } buf.frequency = freq; @@ -3861,7 +3861,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alBufferData() upload failed with an exception ' + e); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } }, @@ -3877,14 +3877,14 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alGetBufferf() called with a null pointer'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } #if OPENAL_DEBUG dbg('alGetBufferf(): param ' + ptrToString(param) + ' has wrong signature'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_ENUM') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; }, alGetBuffer3f__proxy: 'sync', @@ -3898,14 +3898,14 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alGetBuffer3f() called with a null pointer'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } #if OPENAL_DEBUG dbg('alGetBuffer3f(): param ' + ptrToString(param) + ' has wrong signature'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_ENUM') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; }, alGetBufferfv__proxy: 'sync', @@ -3919,14 +3919,14 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alGetBufferfv() called with a null pointer'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } #if OPENAL_DEBUG dbg('alGetBufferfv(): param ' + ptrToString(param) + ' has wrong signature'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_ENUM') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; }, alGetBufferi__proxy: 'sync', @@ -3940,7 +3940,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alGetBufferi() called with a null pointer'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } @@ -3955,7 +3955,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alGetBufferi(): param ' + ptrToString(param) + ' has wrong signature'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_ENUM') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; } }, @@ -3971,14 +3971,14 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alGetBuffer3i() called with a null pointer'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } #if OPENAL_DEBUG dbg('alGetBuffer3i(): param ' + ptrToString(param) + ' has wrong signature'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_ENUM') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; }, alGetBufferiv__proxy: 'sync', @@ -3992,7 +3992,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alGetBufferiv() called with a null pointer'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } @@ -4011,7 +4011,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alGetBufferiv(): param ' + ptrToString(param) + ' has wrong signature'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_ENUM') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; } }, @@ -4045,7 +4045,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alBufferfv() called with a null pointer'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } @@ -4077,7 +4077,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alBufferiv() called with a null pointer'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } @@ -4124,14 +4124,14 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alSourceQueueBuffers() called with an invalid source'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_NAME') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_NAME }}}; return; } if (src.type === 0x1028 /* AL_STATIC */) { #if OPENAL_DEBUG dbg('alSourceQueueBuffers() called while a static buffer is bound'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_OPERATION') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_OPERATION }}}; return; } @@ -4155,7 +4155,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alSourceQueueBuffers() called with an invalid buffer'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_NAME') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_NAME }}}; return; } @@ -4168,7 +4168,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alSourceQueueBuffers() called with a buffer of different format'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_OPERATION') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_OPERATION }}}; } } @@ -4208,11 +4208,11 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alSourceUnqueueBuffers() called with an invalid source'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_NAME') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_NAME }}}; return; } if (count > (src.bufQueue.length === 1 && src.bufQueue[0].id === 0 ? 0 : src.bufsProcessed)) { - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } @@ -4251,7 +4251,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alSourcePlay() called with an invalid source'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_NAME') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_NAME }}}; return; } AL.setSourceState(src, 0x1012 /* AL_PLAYING */); @@ -4270,14 +4270,14 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alSourcePlayv() called with null pointer'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; } for (var i = 0; i < count; ++i) { if (!AL.currentCtx.sources[{{{ makeGetValue('pSourceIds', 'i*4', 'i32') }}}]) { #if OPENAL_DEBUG dbg('alSourcePlayv() called with an invalid source'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_NAME') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_NAME }}}; return; } } @@ -4302,7 +4302,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alSourceStop() called with an invalid source'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_NAME') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_NAME }}}; return; } AL.setSourceState(src, 0x1014 /* AL_STOPPED */); @@ -4321,14 +4321,14 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alSourceStopv() called with null pointer'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; } for (var i = 0; i < count; ++i) { if (!AL.currentCtx.sources[{{{ makeGetValue('pSourceIds', 'i*4', 'i32') }}}]) { #if OPENAL_DEBUG dbg('alSourceStopv() called with an invalid source'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_NAME') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_NAME }}}; return; } } @@ -4353,7 +4353,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alSourceRewind() called with an invalid source'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_NAME') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_NAME }}}; return; } // Stop the source first to clear the source queue @@ -4375,14 +4375,14 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alSourceRewindv() called with null pointer'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; } for (var i = 0; i < count; ++i) { if (!AL.currentCtx.sources[{{{ makeGetValue('pSourceIds', 'i*4', 'i32') }}}]) { #if OPENAL_DEBUG dbg('alSourceRewindv() called with an invalid source'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_NAME') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_NAME }}}; return; } } @@ -4407,7 +4407,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alSourcePause() called with an invalid source'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_NAME') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_NAME }}}; return; } AL.setSourceState(src, 0x1013 /* AL_PAUSED */); @@ -4426,14 +4426,14 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alSourcePausev() called with null pointer'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; } for (var i = 0; i < count; ++i) { if (!AL.currentCtx.sources[{{{ makeGetValue('pSourceIds', 'i*4', 'i32') }}}]) { #if OPENAL_DEBUG dbg('alSourcePausev() called with an invalid source'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_NAME') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_NAME }}}; return; } } @@ -4455,7 +4455,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alGetSourcef() called with a null pointer'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } @@ -4463,7 +4463,7 @@ var LibraryOpenAL = { case 0x1001 /* AL_CONE_INNER_ANGLE */: case 0x1002 /* AL_CONE_OUTER_ANGLE */: case 0x1003 /* AL_PITCH */: - case {{{ cDefine('AL_GAIN') }}}: + case {{{ cDefs.AL_GAIN }}}: case 0x100D /* AL_MIN_GAIN */: case 0x100E /* AL_MAX_GAIN */: case 0x1020 /* AL_REFERENCE_DISTANCE */: @@ -4480,7 +4480,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alGetSourcef(): param ' + ptrToString(param) + ' has wrong signature'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_ENUM') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; } }, @@ -4496,14 +4496,14 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alGetSource3f() called with a null pointer'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } switch (param) { - case {{{ cDefine('AL_POSITION') }}}: - case {{{ cDefine('AL_DIRECTION') }}}: - case {{{ cDefine('AL_VELOCITY') }}}: + case {{{ cDefs.AL_POSITION }}}: + case {{{ cDefs.AL_DIRECTION }}}: + case {{{ cDefs.AL_VELOCITY }}}: {{{ makeSetValue('pValue0', '0', 'val[0]', 'float') }}}; {{{ makeSetValue('pValue1', '0', 'val[1]', 'float') }}}; {{{ makeSetValue('pValue2', '0', 'val[2]', 'float') }}}; @@ -4512,7 +4512,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alGetSource3f(): param ' + ptrToString(param) + ' has wrong signature'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_ENUM') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; } }, @@ -4528,7 +4528,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alGetSourcefv() called with a null pointer'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } @@ -4536,7 +4536,7 @@ var LibraryOpenAL = { case 0x1001 /* AL_CONE_INNER_ANGLE */: case 0x1002 /* AL_CONE_OUTER_ANGLE */: case 0x1003 /* AL_PITCH */: - case {{{ cDefine('AL_GAIN') }}}: + case {{{ cDefs.AL_GAIN }}}: case 0x100D /* AL_MIN_GAIN */: case 0x100E /* AL_MAX_GAIN */: case 0x1020 /* AL_REFERENCE_DISTANCE */: @@ -4549,9 +4549,9 @@ var LibraryOpenAL = { case 0x200B /* AL_SEC_LENGTH_SOFT */: {{{ makeSetValue('pValues', '0', 'val[0]', 'float') }}}; break; - case {{{ cDefine('AL_POSITION') }}}: - case {{{ cDefine('AL_DIRECTION') }}}: - case {{{ cDefine('AL_VELOCITY') }}}: + case {{{ cDefs.AL_POSITION }}}: + case {{{ cDefs.AL_DIRECTION }}}: + case {{{ cDefs.AL_VELOCITY }}}: {{{ makeSetValue('pValues', '0', 'val[0]', 'float') }}}; {{{ makeSetValue('pValues', '4', 'val[1]', 'float') }}}; {{{ makeSetValue('pValues', '8', 'val[2]', 'float') }}}; @@ -4560,7 +4560,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alGetSourcefv(): param ' + ptrToString(param) + ' has wrong signature'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_ENUM') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; } }, @@ -4576,7 +4576,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alGetSourcei() called with a null pointer'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } @@ -4599,14 +4599,14 @@ var LibraryOpenAL = { case 0x1214 /* AL_SOURCE_SPATIALIZE_SOFT */: case 0x2009 /* AL_BYTE_LENGTH_SOFT */: case 0x200A /* AL_SAMPLE_LENGTH_SOFT */: - case {{{ cDefine('AL_DISTANCE_MODEL') }}}: + case {{{ cDefs.AL_DISTANCE_MODEL }}}: {{{ makeSetValue('pValue', '0', 'val', 'i32') }}}; break; default: #if OPENAL_DEBUG dbg('alGetSourcei(): param ' + ptrToString(param) + ' has wrong signature'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_ENUM') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; } }, @@ -4622,14 +4622,14 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alGetSource3i() called with a null pointer'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } switch (param) { - case {{{ cDefine('AL_POSITION') }}}: - case {{{ cDefine('AL_DIRECTION') }}}: - case {{{ cDefine('AL_VELOCITY') }}}: + case {{{ cDefs.AL_POSITION }}}: + case {{{ cDefs.AL_DIRECTION }}}: + case {{{ cDefs.AL_VELOCITY }}}: {{{ makeSetValue('pValue0', '0', 'val[0]', 'i32') }}}; {{{ makeSetValue('pValue1', '0', 'val[1]', 'i32') }}}; {{{ makeSetValue('pValue2', '0', 'val[2]', 'i32') }}}; @@ -4638,7 +4638,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alGetSource3i(): param ' + ptrToString(param) + ' has wrong signature'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_ENUM') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; } }, @@ -4654,7 +4654,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alGetSourceiv() called with a null pointer'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } @@ -4677,12 +4677,12 @@ var LibraryOpenAL = { case 0x1214 /* AL_SOURCE_SPATIALIZE_SOFT */: case 0x2009 /* AL_BYTE_LENGTH_SOFT */: case 0x200A /* AL_SAMPLE_LENGTH_SOFT */: - case {{{ cDefine('AL_DISTANCE_MODEL') }}}: + case {{{ cDefs.AL_DISTANCE_MODEL }}}: {{{ makeSetValue('pValues', '0', 'val', 'i32') }}}; break; - case {{{ cDefine('AL_POSITION') }}}: - case {{{ cDefine('AL_DIRECTION') }}}: - case {{{ cDefine('AL_VELOCITY') }}}: + case {{{ cDefs.AL_POSITION }}}: + case {{{ cDefs.AL_DIRECTION }}}: + case {{{ cDefs.AL_VELOCITY }}}: {{{ makeSetValue('pValues', '0', 'val[0]', 'i32') }}}; {{{ makeSetValue('pValues', '4', 'val[1]', 'i32') }}}; {{{ makeSetValue('pValues', '8', 'val[2]', 'i32') }}}; @@ -4691,7 +4691,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alGetSourceiv(): param ' + ptrToString(param) + ' has wrong signature'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_ENUM') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; } }, @@ -4703,7 +4703,7 @@ var LibraryOpenAL = { case 0x1001 /* AL_CONE_INNER_ANGLE */: case 0x1002 /* AL_CONE_OUTER_ANGLE */: case 0x1003 /* AL_PITCH */: - case {{{ cDefine('AL_GAIN') }}}: + case {{{ cDefs.AL_GAIN }}}: case 0x100D /* AL_MIN_GAIN */: case 0x100E /* AL_MAX_GAIN */: case 0x1020 /* AL_REFERENCE_DISTANCE */: @@ -4726,9 +4726,9 @@ var LibraryOpenAL = { alSource3f__sig: 'viifff', alSource3f: function(sourceId, param, value0, value1, value2) { switch (param) { - case {{{ cDefine('AL_POSITION') }}}: - case {{{ cDefine('AL_DIRECTION') }}}: - case {{{ cDefine('AL_VELOCITY') }}}: + case {{{ cDefs.AL_POSITION }}}: + case {{{ cDefs.AL_DIRECTION }}}: + case {{{ cDefs.AL_VELOCITY }}}: AL.paramArray[0] = value0; AL.paramArray[1] = value1; AL.paramArray[2] = value2; @@ -4753,7 +4753,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alSourcefv() called with a null pointer'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } @@ -4761,7 +4761,7 @@ var LibraryOpenAL = { case 0x1001 /* AL_CONE_INNER_ANGLE */: case 0x1002 /* AL_CONE_OUTER_ANGLE */: case 0x1003 /* AL_PITCH */: - case {{{ cDefine('AL_GAIN') }}}: + case {{{ cDefs.AL_GAIN }}}: case 0x100D /* AL_MIN_GAIN */: case 0x100E /* AL_MAX_GAIN */: case 0x1020 /* AL_REFERENCE_DISTANCE */: @@ -4775,9 +4775,9 @@ var LibraryOpenAL = { var val = {{{ makeGetValue('pValues', '0', 'float') }}}; AL.setSourceParam('alSourcefv', sourceId, param, val); break; - case {{{ cDefine('AL_POSITION') }}}: - case {{{ cDefine('AL_DIRECTION') }}}: - case {{{ cDefine('AL_VELOCITY') }}}: + case {{{ cDefs.AL_POSITION }}}: + case {{{ cDefs.AL_DIRECTION }}}: + case {{{ cDefs.AL_VELOCITY }}}: AL.paramArray[0] = {{{ makeGetValue('pValues', '0', 'float') }}}; AL.paramArray[1] = {{{ makeGetValue('pValues', '4', 'float') }}}; AL.paramArray[2] = {{{ makeGetValue('pValues', '8', 'float') }}}; @@ -4807,7 +4807,7 @@ var LibraryOpenAL = { case 0x1214 /* AL_SOURCE_SPATIALIZE_SOFT */: case 0x2009 /* AL_BYTE_LENGTH_SOFT */: case 0x200A /* AL_SAMPLE_LENGTH_SOFT */: - case {{{ cDefine('AL_DISTANCE_MODEL') }}}: + case {{{ cDefs.AL_DISTANCE_MODEL }}}: AL.setSourceParam('alSourcei', sourceId, param, value); break; default: @@ -4820,9 +4820,9 @@ var LibraryOpenAL = { alSource3i__sig: 'viiiii', alSource3i: function(sourceId, param, value0, value1, value2) { switch (param) { - case {{{ cDefine('AL_POSITION') }}}: - case {{{ cDefine('AL_DIRECTION') }}}: - case {{{ cDefine('AL_VELOCITY') }}}: + case {{{ cDefs.AL_POSITION }}}: + case {{{ cDefs.AL_DIRECTION }}}: + case {{{ cDefs.AL_VELOCITY }}}: AL.paramArray[0] = value0; AL.paramArray[1] = value1; AL.paramArray[2] = value2; @@ -4847,7 +4847,7 @@ var LibraryOpenAL = { #if OPENAL_DEBUG dbg('alSourceiv() called with a null pointer'); #endif - AL.currentCtx.err = {{{ cDefine('AL_INVALID_VALUE') }}}; + AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; } @@ -4866,13 +4866,13 @@ var LibraryOpenAL = { case 0x1214 /* AL_SOURCE_SPATIALIZE_SOFT */: case 0x2009 /* AL_BYTE_LENGTH_SOFT */: case 0x200A /* AL_SAMPLE_LENGTH_SOFT */: - case {{{ cDefine('AL_DISTANCE_MODEL') }}}: + case {{{ cDefs.AL_DISTANCE_MODEL }}}: var val = {{{ makeGetValue('pValues', '0', 'i32') }}}; AL.setSourceParam('alSourceiv', sourceId, param, val); break; - case {{{ cDefine('AL_POSITION') }}}: - case {{{ cDefine('AL_DIRECTION') }}}: - case {{{ cDefine('AL_VELOCITY') }}}: + case {{{ cDefs.AL_POSITION }}}: + case {{{ cDefs.AL_DIRECTION }}}: + case {{{ cDefs.AL_VELOCITY }}}: AL.paramArray[0] = {{{ makeGetValue('pValues', '0', 'i32') }}}; AL.paramArray[1] = {{{ makeGetValue('pValues', '4', 'i32') }}}; AL.paramArray[2] = {{{ makeGetValue('pValues', '8', 'i32') }}}; diff --git a/src/library_pipefs.js b/src/library_pipefs.js index d2f3cac46b4fb..e443c38ac2a03 100644 --- a/src/library_pipefs.js +++ b/src/library_pipefs.js @@ -14,7 +14,7 @@ mergeInto(LibraryManager.library, { mount: function (mount) { // Do not pollute the real root directory or its child nodes with pipes // Looks like it is OK to create another pseudo-root node not linked to the FS.root hierarchy this way - return FS.createNode(null, '/', {{{ cDefine('S_IFDIR') }}} | 511 /* 0777 */, 0); + return FS.createNode(null, '/', {{{ cDefs.S_IFDIR }}} | 511 /* 0777 */, 0); }, createPipe: function () { var pipe = { @@ -32,8 +32,8 @@ mergeInto(LibraryManager.library, { var rName = PIPEFS.nextname(); var wName = PIPEFS.nextname(); - var rNode = FS.createNode(PIPEFS.root, rName, {{{ cDefine('S_IFIFO') }}}, 0); - var wNode = FS.createNode(PIPEFS.root, wName, {{{ cDefine('S_IFIFO') }}}, 0); + var rNode = FS.createNode(PIPEFS.root, rName, {{{ cDefs.S_IFIFO }}}, 0); + var wNode = FS.createNode(PIPEFS.root, wName, {{{ cDefs.S_IFIFO }}}, 0); rNode.pipe = pipe; wNode.pipe = pipe; @@ -41,7 +41,7 @@ mergeInto(LibraryManager.library, { var readableStream = FS.createStream({ path: rName, node: rNode, - flags: {{{ cDefine('O_RDONLY') }}}, + flags: {{{ cDefs.O_RDONLY }}}, seekable: false, stream_ops: PIPEFS.stream_ops }); @@ -50,7 +50,7 @@ mergeInto(LibraryManager.library, { var writableStream = FS.createStream({ path: wName, node: wNode, - flags: {{{ cDefine('O_WRONLY') }}}, + flags: {{{ cDefs.O_WRONLY }}}, seekable: false, stream_ops: PIPEFS.stream_ops }); @@ -65,14 +65,14 @@ mergeInto(LibraryManager.library, { poll: function (stream) { var pipe = stream.node.pipe; - if ((stream.flags & {{{ cDefine('O_ACCMODE') }}}) === {{{ cDefine('O_WRONLY') }}}) { - return ({{{ cDefine('POLLWRNORM') }}} | {{{ cDefine('POLLOUT') }}}); + if ((stream.flags & {{{ cDefs.O_ACCMODE }}}) === {{{ cDefs.O_WRONLY }}}) { + return ({{{ cDefs.POLLWRNORM }}} | {{{ cDefs.POLLOUT }}}); } if (pipe.buckets.length > 0) { for (var i = 0; i < pipe.buckets.length; i++) { var bucket = pipe.buckets[i]; if (bucket.offset - bucket.roffset > 0) { - return ({{{ cDefine('POLLRDNORM') }}} | {{{ cDefine('POLLIN') }}}); + return ({{{ cDefs.POLLRDNORM }}} | {{{ cDefs.POLLIN }}}); } } } @@ -80,10 +80,10 @@ mergeInto(LibraryManager.library, { return 0; }, ioctl: function (stream, request, varargs) { - return {{{ cDefine('EINVAL') }}}; + return {{{ cDefs.EINVAL }}}; }, fsync: function (stream) { - return {{{ cDefine('EINVAL') }}}; + return {{{ cDefs.EINVAL }}}; }, read: function (stream, buffer, offset, length, position /* ignored */) { var pipe = stream.node.pipe; @@ -106,7 +106,7 @@ mergeInto(LibraryManager.library, { } if (currentLength == 0) { // Behave as if the read end is always non-blocking - throw new FS.ErrnoError({{{ cDefine('EAGAIN') }}}); + throw new FS.ErrnoError({{{ cDefs.EAGAIN }}}); } var toRead = Math.min(currentLength, length); diff --git a/src/library_promise.js b/src/library_promise.js index f00d6766bebeb..4ef9fed97d216 100644 --- a/src/library_promise.js +++ b/src/library_promise.js @@ -52,17 +52,17 @@ mergeInto(LibraryManager.library, { #endif var info = promiseMap.get(id); switch (result) { - case {{{ cDefine('EM_PROMISE_FULFILL') }}}: + case {{{ cDefs.EM_PROMISE_FULFILL }}}: info.resolve(value); return; - case {{{ cDefine('EM_PROMISE_MATCH') }}}: + case {{{ cDefs.EM_PROMISE_MATCH }}}: info.resolve(getPromise(value)); return; - case {{{ cDefine('EM_PROMISE_MATCH_RELEASE') }}}: + case {{{ cDefs.EM_PROMISE_MATCH_RELEASE }}}: info.resolve(getPromise(value)); _emscripten_promise_destroy(value); return; - case {{{ cDefine('EM_PROMISE_REJECT') }}}: + case {{{ cDefs.EM_PROMISE_REJECT }}}: info.reject(value); return; } @@ -110,15 +110,15 @@ mergeInto(LibraryManager.library, { stackRestore(stack); } switch (result) { - case {{{ cDefine('EM_PROMISE_FULFILL') }}}: + case {{{ cDefs.EM_PROMISE_FULFILL }}}: return resultVal; - case {{{ cDefine('EM_PROMISE_MATCH') }}}: + case {{{ cDefs.EM_PROMISE_MATCH }}}: return getPromise(resultVal); - case {{{ cDefine('EM_PROMISE_MATCH_RELEASE') }}}: + case {{{ cDefs.EM_PROMISE_MATCH_RELEASE }}}: var ret = getPromise(resultVal); _emscripten_promise_destroy(resultVal); return ret; - case {{{ cDefine('EM_PROMISE_REJECT') }}}: + case {{{ cDefs.EM_PROMISE_REJECT }}}: throw resultVal; } #if ASSERTIONS diff --git a/src/library_proxyfs.js b/src/library_proxyfs.js index 4ad2e9a1b4aff..d1bb858361b82 100644 --- a/src/library_proxyfs.js +++ b/src/library_proxyfs.js @@ -196,9 +196,9 @@ mergeInto(LibraryManager.library, { }, llseek: function (stream, offset, whence) { var position = offset; - if (whence === {{{ cDefine('SEEK_CUR') }}}) { + if (whence === {{{ cDefs.SEEK_CUR }}}) { position += stream.position; - } else if (whence === {{{ cDefine('SEEK_END') }}}) { + } else if (whence === {{{ cDefs.SEEK_END }}}) { if (FS.isFile(stream.node.mode)) { try { var stat = stream.node.node_ops.getattr(stream.node); diff --git a/src/library_pthread.js b/src/library_pthread.js index b3e5df5d8471f..e36fede406edd 100644 --- a/src/library_pthread.js +++ b/src/library_pthread.js @@ -655,7 +655,7 @@ var LibraryPThread = { var worker = PThread.getNewWorker(); if (!worker) { // No available workers in the PThread pool. - return {{{ cDefine('EAGAIN') }}}; + return {{{ cDefs.EAGAIN }}}; } #if ASSERTIONS assert(!worker.pthread_ptr, 'Internal error!'); @@ -744,7 +744,7 @@ var LibraryPThread = { __pthread_create_js: function(pthread_ptr, attr, startRoutine, arg) { if (typeof SharedArrayBuffer == 'undefined') { err('Current environment does not support SharedArrayBuffer, pthreads are not available!'); - return {{{ cDefine('EAGAIN') }}}; + return {{{ cDefs.EAGAIN }}}; } #if PTHREADS_DEBUG dbg("createThread: " + ptrToString(pthread_ptr)); @@ -782,7 +782,7 @@ var LibraryPThread = { if (name == '#canvas') { if (!Module['canvas']) { err('pthread_create: could not find canvas with ID "' + name + '" to transfer to thread!'); - error = {{{ cDefine('EINVAL') }}}; + error = {{{ cDefs.EINVAL }}}; break; } name = Module['canvas'].id; @@ -798,12 +798,12 @@ var LibraryPThread = { var canvas = (Module['canvas'] && Module['canvas'].id === name) ? Module['canvas'] : document.querySelector(name); if (!canvas) { err('pthread_create: could not find canvas with ID "' + name + '" to transfer to thread!'); - error = {{{ cDefine('EINVAL') }}}; + error = {{{ cDefs.EINVAL }}}; break; } if (canvas.controlTransferredOffscreen) { err('pthread_create: cannot transfer canvas with ID "' + name + '" to thread, since the current thread does not have control over it!'); - error = {{{ cDefine('EPERM') }}}; // Operation not permitted, some other thread is accessing the canvas. + error = {{{ cDefs.EPERM }}}; // Operation not permitted, some other thread is accessing the canvas. break; } if (canvas.transferControlToOffscreen) { @@ -837,7 +837,7 @@ var LibraryPThread = { // proxied from worker to main thread. #if !OFFSCREEN_FRAMEBUFFER err('pthread_create: Build with -sOFFSCREEN_FRAMEBUFFER to enable fallback proxying of GL commands from pthread to main thread.'); - return {{{ cDefine('ENOSYS') }}}; // Function not implemented, browser doesn't have support for this. + return {{{ cDefs.ENOSYS }}}; // Function not implemented, browser doesn't have support for this. #endif } } @@ -847,7 +847,7 @@ var LibraryPThread = { } } catch(e) { err('pthread_create: failed to transfer control of canvas "' + name + '" to OffscreenCanvas! Error: ' + e); - return {{{ cDefine('EINVAL') }}}; // Hitting this might indicate an implementation bug or some other internal error + return {{{ cDefs.EINVAL }}}; // Hitting this might indicate an implementation bug or some other internal error } } #endif // OFFSCREENCANVAS_SUPPORT @@ -917,7 +917,7 @@ var LibraryPThread = { }, __pthread_kill_js: function(thread, signal) { - if (signal === {{{ cDefine('SIGCANCEL') }}}) { // Used by pthread_cancel in musl + if (signal === {{{ cDefs.SIGCANCEL }}}) { // Used by pthread_cancel in musl if (!ENVIRONMENT_IS_PTHREAD) cancelThread(thread); else postMessage({ 'cmd': 'cancelThread', 'thread': thread }); } else { @@ -958,7 +958,7 @@ var LibraryPThread = { var numCallArgs = arguments.length - 2; var outerArgs = arguments; #if ASSERTIONS - var maxArgs = {{{ cDefine('EM_QUEUED_JS_CALL_MAX_ARGS') - 1 }}}; + var maxArgs = {{{ cDefs.EM_QUEUED_JS_CALL_MAX_ARGS - 1 }}}; if (numCallArgs > maxArgs) { throw 'emscripten_proxy_to_main_thread_js: Too many arguments ' + numCallArgs + ' to proxied function idx=' + index + ', maximum supported is ' + maxArgs; } diff --git a/src/library_sdl.js b/src/library_sdl.js index 17af30575818d..66a59e5d5e279 100644 --- a/src/library_sdl.js +++ b/src/library_sdl.js @@ -65,7 +65,7 @@ var LibrarySDL = { volume: 1.0 }, mixerFrequency: 22050, - mixerFormat: {{{ cDefine('AUDIO_S16LSB') }}}, + mixerFormat: {{{ cDefs.AUDIO_S16LSB }}}, mixerNumChannels: 2, mixerChunkSize: 1024, channelMinimumNumber: 0, @@ -317,7 +317,7 @@ var LibrarySDL = { #if ASSERTIONS // Canvas screens are always RGBA. var format = {{{ makeGetValue('fmt', C_STRUCTS.SDL_PixelFormat.format, 'i32') }}}; - if (format != {{{ cDefine('SDL_PIXELFORMAT_RGBA8888') }}}) { + if (format != {{{ cDefs.SDL_PIXELFORMAT_RGBA8888 }}}) { warnOnce('Unsupported pixel format!'); } #endif @@ -377,7 +377,7 @@ var LibrarySDL = { {{{ makeSetValue('surf', C_STRUCTS.SDL_Surface.refcount, '1', 'i32') }}}; - {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.format, cDefine('SDL_PIXELFORMAT_RGBA8888'), 'i32') }}}; + {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.format, cDefs.SDL_PIXELFORMAT_RGBA8888, 'i32') }}}; {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.palette, '0', 'i32') }}};// TODO {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.BitsPerPixel, 'bpp * 8', 'i8') }}}; {{{ makeSetValue('pixelFormat', C_STRUCTS.SDL_PixelFormat.BytesPerPixel, 'bpp', 'i8') }}}; @@ -655,7 +655,7 @@ var LibrarySDL = { type: 'touchmove', touch: { identifier: 0, - deviceID: {{{ cDefine('SDL_TOUCH_MOUSEID') }}}, + deviceID: {{{ cDefs.SDL_TOUCH_MOUSEID }}}, pageX: event.pageX, pageY: event.pageY } @@ -691,7 +691,7 @@ var LibrarySDL = { type: 'touchstart', touch: { identifier: 0, - deviceID: {{{ cDefine('SDL_TOUCH_MOUSEID') }}}, + deviceID: {{{ cDefs.SDL_TOUCH_MOUSEID }}}, pageX: event.pageX, pageY: event.pageY } @@ -707,7 +707,7 @@ var LibrarySDL = { type: 'touchend', touch: { identifier: 0, - deviceID: {{{ cDefine('SDL_TOUCH_MOUSEID') }}}, + deviceID: {{{ cDefs.SDL_TOUCH_MOUSEID }}}, pageX: event.pageX, pageY: event.pageY } @@ -1197,16 +1197,16 @@ var LibrarySDL = { if (channelData.length != sizeSamplesPerChannel) { throw 'Web Audio output buffer length mismatch! Destination size: ' + channelData.length + ' samples vs expected ' + sizeSamplesPerChannel + ' samples!'; } - if (audio.format == {{{ cDefine('AUDIO_S16LSB') }}}) { + if (audio.format == {{{ cDefs.AUDIO_S16LSB }}}) { for (var j = 0; j < sizeSamplesPerChannel; ++j) { channelData[j] = ({{{ makeGetValue('heapPtr', '(j*numChannels + c)*2', 'i16') }}}) / 0x8000; } - } else if (audio.format == {{{ cDefine('AUDIO_U8') }}}) { + } else if (audio.format == {{{ cDefs.AUDIO_U8 }}}) { for (var j = 0; j < sizeSamplesPerChannel; ++j) { var v = ({{{ makeGetValue('heapPtr', 'j*numChannels + c', 'i8') }}}); channelData[j] = ((v >= 0) ? v-128 : v+128) /128; } - } else if (audio.format == {{{ cDefine('AUDIO_F32') }}}) { + } else if (audio.format == {{{ cDefs.AUDIO_F32 }}}) { for (var j = 0; j < sizeSamplesPerChannel; ++j) { channelData[j] = ({{{ makeGetValue('heapPtr', '(j*numChannels + c)*4', 'float') }}}); } @@ -2409,11 +2409,11 @@ var LibrarySDL = { timer: null }; // The .silence field tells the constant sample value that corresponds to the safe un-skewed silence value for the wave data. - if (SDL.audio.format == {{{ cDefine('AUDIO_U8') }}}) { + if (SDL.audio.format == {{{ cDefs.AUDIO_U8 }}}) { SDL.audio.silence = 128; // Audio ranges in [0, 255], so silence is half-way in between. - } else if (SDL.audio.format == {{{ cDefine('AUDIO_S16LSB') }}}) { + } else if (SDL.audio.format == {{{ cDefs.AUDIO_S16LSB }}}) { SDL.audio.silence = 0; // Signed data in range [-32768, 32767], silence is 0. - } else if (SDL.audio.format == {{{ cDefine('AUDIO_F32') }}}) { + } else if (SDL.audio.format == {{{ cDefs.AUDIO_F32 }}}) { SDL.audio.silence = 0.0; // Float data in range [-1.0, 1.0], silence is 0.0 } else { throw 'Invalid SDL audio format ' + SDL.audio.format + '!'; @@ -2449,11 +2449,11 @@ var LibrarySDL = { } var totalSamples = SDL.audio.samples*SDL.audio.channels; - if (SDL.audio.format == {{{ cDefine('AUDIO_U8') }}}) { + if (SDL.audio.format == {{{ cDefs.AUDIO_U8 }}}) { SDL.audio.bytesPerSample = 1; - } else if (SDL.audio.format == {{{ cDefine('AUDIO_S16LSB') }}}) { + } else if (SDL.audio.format == {{{ cDefs.AUDIO_S16LSB }}}) { SDL.audio.bytesPerSample = 2; - } else if (SDL.audio.format == {{{ cDefine('AUDIO_F32') }}}) { + } else if (SDL.audio.format == {{{ cDefs.AUDIO_F32 }}}) { SDL.audio.bytesPerSample = 4; } else { throw 'Invalid SDL audio format ' + SDL.audio.format + '!'; diff --git a/src/library_sockfs.js b/src/library_sockfs.js index 44e653a6fa0a3..1704ee5bf2d2e 100644 --- a/src/library_sockfs.js +++ b/src/library_sockfs.js @@ -43,13 +43,13 @@ mergeInto(LibraryManager.library, { Module['websocket']['on']('close', (fd) => dbg('Socket close fd = ' + fd)); #endif - return FS.createNode(null, '/', {{{ cDefine('S_IFDIR') }}} | 511 /* 0777 */, 0); + return FS.createNode(null, '/', {{{ cDefs.S_IFDIR }}} | 511 /* 0777 */, 0); }, createSocket: function(family, type, protocol) { - type &= ~{{{ cDefine('SOCK_CLOEXEC') | cDefine('SOCK_NONBLOCK') }}}; // Some applications may pass it; it makes no sense for a single process. - var streaming = type == {{{ cDefine('SOCK_STREAM') }}}; - if (streaming && protocol && protocol != {{{ cDefine('IPPROTO_TCP') }}}) { - throw new FS.ErrnoError({{{ cDefine('EPROTONOSUPPORT') }}}); // if SOCK_STREAM, must be tcp or 0. + type &= ~{{{ cDefs.SOCK_CLOEXEC | cDefs.SOCK_NONBLOCK }}}; // Some applications may pass it; it makes no sense for a single process. + var streaming = type == {{{ cDefs.SOCK_STREAM }}}; + if (streaming && protocol && protocol != {{{ cDefs.IPPROTO_TCP }}}) { + throw new FS.ErrnoError({{{ cDefs.EPROTONOSUPPORT }}}); // if SOCK_STREAM, must be tcp or 0. } // create our internal socket structure @@ -70,7 +70,7 @@ mergeInto(LibraryManager.library, { // create the filesystem node to store the socket structure var name = SOCKFS.nextname(); - var node = FS.createNode(SOCKFS.root, name, {{{ cDefine('S_IFSOCK') }}}, 0); + var node = FS.createNode(SOCKFS.root, name, {{{ cDefs.S_IFSOCK }}}, 0); node.sock = sock; // and the wrapping stream that enables library functions such @@ -78,7 +78,7 @@ mergeInto(LibraryManager.library, { var stream = FS.createStream({ path: name, node: node, - flags: {{{ cDefine('O_RDWR') }}}, + flags: {{{ cDefs.O_RDWR }}}, seekable: false, stream_ops: SOCKFS.stream_ops }); @@ -229,7 +229,7 @@ mergeInto(LibraryManager.library, { ws = new WebSocketConstructor(url, opts); ws.binaryType = 'arraybuffer'; } catch (e) { - throw new FS.ErrnoError({{{ cDefine('EHOSTUNREACH') }}}); + throw new FS.ErrnoError({{{ cDefs.EHOSTUNREACH }}}); } } @@ -250,7 +250,7 @@ mergeInto(LibraryManager.library, { // if this is a bound dgram socket, send the port number first to allow // us to override the ephemeral port reported to us by remotePort on the // remote end. - if (sock.type === {{{ cDefine('SOCK_DGRAM') }}} && typeof sock.sport != 'undefined') { + if (sock.type === {{{ cDefs.SOCK_DGRAM }}} && typeof sock.sport != 'undefined') { #if SOCKET_DEBUG dbg('websocket queuing port message (port ' + sock.sport + ')'); #endif @@ -352,7 +352,7 @@ mergeInto(LibraryManager.library, { // ECONNREFUSED they are not necessarily the expected error code e.g. // ENOTFOUND on getaddrinfo seems to be node.js specific, so using ECONNREFUSED // is still probably the most useful thing to do. - sock.error = {{{ cDefine('ECONNREFUSED') }}}; // Used in getsockopt for SOL_SOCKET/SO_ERROR test. + sock.error = {{{ cDefs.ECONNREFUSED }}}; // Used in getsockopt for SOL_SOCKET/SO_ERROR test. Module['websocket'].emit('error', [sock.stream.fd, sock.error, 'ECONNREFUSED: Connection refused']); // don't throw }); @@ -367,7 +367,7 @@ mergeInto(LibraryManager.library, { peer.socket.onerror = function(error) { // The WebSocket spec only allows a 'simple event' to be thrown on error, // so we only really know as much as ECONNREFUSED. - sock.error = {{{ cDefine('ECONNREFUSED') }}}; // Used in getsockopt for SOL_SOCKET/SO_ERROR test. + sock.error = {{{ cDefs.ECONNREFUSED }}}; // Used in getsockopt for SOL_SOCKET/SO_ERROR test. Module['websocket'].emit('error', [sock.stream.fd, sock.error, 'ECONNREFUSED: Connection refused']); }; } @@ -377,14 +377,14 @@ mergeInto(LibraryManager.library, { // actual sock ops // poll: function(sock) { - if (sock.type === {{{ cDefine('SOCK_STREAM') }}} && sock.server) { + if (sock.type === {{{ cDefs.SOCK_STREAM }}} && sock.server) { // listen sockets should only say they're available for reading // if there are pending clients. - return sock.pending.length ? ({{{ cDefine('POLLRDNORM') }}} | {{{ cDefine('POLLIN') }}}) : 0; + return sock.pending.length ? ({{{ cDefs.POLLRDNORM }}} | {{{ cDefs.POLLIN }}}) : 0; } var mask = 0; - var dest = sock.type === {{{ cDefine('SOCK_STREAM') }}} ? // we only care about the socket state for connection-based sockets + var dest = sock.type === {{{ cDefs.SOCK_STREAM }}} ? // we only care about the socket state for connection-based sockets SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport) : null; @@ -392,24 +392,24 @@ mergeInto(LibraryManager.library, { !dest || // connection-less sockets are always ready to read (dest && dest.socket.readyState === dest.socket.CLOSING) || (dest && dest.socket.readyState === dest.socket.CLOSED)) { // let recv return 0 once closed - mask |= ({{{ cDefine('POLLRDNORM') }}} | {{{ cDefine('POLLIN') }}}); + mask |= ({{{ cDefs.POLLRDNORM }}} | {{{ cDefs.POLLIN }}}); } if (!dest || // connection-less sockets are always ready to write (dest && dest.socket.readyState === dest.socket.OPEN)) { - mask |= {{{ cDefine('POLLOUT') }}}; + mask |= {{{ cDefs.POLLOUT }}}; } if ((dest && dest.socket.readyState === dest.socket.CLOSING) || (dest && dest.socket.readyState === dest.socket.CLOSED)) { - mask |= {{{ cDefine('POLLHUP') }}}; + mask |= {{{ cDefs.POLLHUP }}}; } return mask; }, ioctl: function(sock, request, arg) { switch (request) { - case {{{ cDefine('FIONREAD') }}}: + case {{{ cDefs.FIONREAD }}}: var bytes = 0; if (sock.recv_queue.length) { bytes = sock.recv_queue[0].data.length; @@ -417,7 +417,7 @@ mergeInto(LibraryManager.library, { {{{ makeSetValue('arg', '0', 'bytes', 'i32') }}}; return 0; default: - return {{{ cDefine('EINVAL') }}}; + return {{{ cDefs.EINVAL }}}; } }, close: function(sock) { @@ -443,14 +443,14 @@ mergeInto(LibraryManager.library, { }, bind: function(sock, addr, port) { if (typeof sock.saddr != 'undefined' || typeof sock.sport != 'undefined') { - throw new FS.ErrnoError({{{ cDefine('EINVAL') }}}); // already bound + throw new FS.ErrnoError({{{ cDefs.EINVAL }}}); // already bound } sock.saddr = addr; sock.sport = port; // in order to emulate dgram sockets, we need to launch a listen server when // binding on a connection-less socket // note: this is only required on the server side - if (sock.type === {{{ cDefine('SOCK_DGRAM') }}}) { + if (sock.type === {{{ cDefs.SOCK_DGRAM }}}) { // close the existing server if it exists if (sock.server) { sock.server.close(); @@ -462,17 +462,17 @@ mergeInto(LibraryManager.library, { sock.sock_ops.listen(sock, 0); } catch (e) { if (!(e.name === 'ErrnoError')) throw e; - if (e.errno !== {{{ cDefine('EOPNOTSUPP') }}}) throw e; + if (e.errno !== {{{ cDefs.EOPNOTSUPP }}}) throw e; } } }, connect: function(sock, addr, port) { if (sock.server) { - throw new FS.ErrnoError({{{ cDefine('EOPNOTSUPP') }}}); + throw new FS.ErrnoError({{{ cDefs.EOPNOTSUPP }}}); } // TODO autobind - // if (!sock.addr && sock.type == {{{ cDefine('SOCK_DGRAM') }}}) { + // if (!sock.addr && sock.type == {{{ cDefs.SOCK_DGRAM }}}) { // } // early out if we're already connected / in the middle of connecting @@ -480,9 +480,9 @@ mergeInto(LibraryManager.library, { var dest = SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport); if (dest) { if (dest.socket.readyState === dest.socket.CONNECTING) { - throw new FS.ErrnoError({{{ cDefine('EALREADY') }}}); + throw new FS.ErrnoError({{{ cDefs.EALREADY }}}); } else { - throw new FS.ErrnoError({{{ cDefine('EISCONN') }}}); + throw new FS.ErrnoError({{{ cDefs.EISCONN }}}); } } } @@ -494,15 +494,15 @@ mergeInto(LibraryManager.library, { sock.dport = peer.port; // always "fail" in non-blocking mode - throw new FS.ErrnoError({{{ cDefine('EINPROGRESS') }}}); + throw new FS.ErrnoError({{{ cDefs.EINPROGRESS }}}); }, listen: function(sock, backlog) { if (!ENVIRONMENT_IS_NODE) { - throw new FS.ErrnoError({{{ cDefine('EOPNOTSUPP') }}}); + throw new FS.ErrnoError({{{ cDefs.EOPNOTSUPP }}}); } #if ENVIRONMENT_MAY_BE_NODE if (sock.server) { - throw new FS.ErrnoError({{{ cDefine('EINVAL') }}}); // already listening + throw new FS.ErrnoError({{{ cDefs.EINVAL }}}); // already listening } var WebSocketServer = require('ws').Server; var host = sock.saddr; @@ -520,7 +520,7 @@ mergeInto(LibraryManager.library, { #if SOCKET_DEBUG dbg('received connection from: ' + ws._socket.remoteAddress + ':' + ws._socket.remotePort); #endif - if (sock.type === {{{ cDefine('SOCK_STREAM') }}}) { + if (sock.type === {{{ cDefs.SOCK_STREAM }}}) { var newsock = SOCKFS.createSocket(sock.family, sock.type, sock.protocol); // create a peer on the new socket @@ -550,7 +550,7 @@ mergeInto(LibraryManager.library, { // is still probably the most useful thing to do. This error shouldn't // occur in a well written app as errors should get trapped in the compiled // app's own getaddrinfo call. - sock.error = {{{ cDefine('EHOSTUNREACH') }}}; // Used in getsockopt for SOL_SOCKET/SO_ERROR test. + sock.error = {{{ cDefs.EHOSTUNREACH }}}; // Used in getsockopt for SOL_SOCKET/SO_ERROR test. Module['websocket'].emit('error', [sock.stream.fd, sock.error, 'EHOSTUNREACH: Host is unreachable']); // don't throw }); @@ -558,7 +558,7 @@ mergeInto(LibraryManager.library, { }, accept: function(listensock) { if (!listensock.server || !listensock.pending.length) { - throw new FS.ErrnoError({{{ cDefine('EINVAL') }}}); + throw new FS.ErrnoError({{{ cDefs.EINVAL }}}); } var newsock = listensock.pending.shift(); newsock.stream.flags = listensock.stream.flags; @@ -568,7 +568,7 @@ mergeInto(LibraryManager.library, { var addr, port; if (peer) { if (sock.daddr === undefined || sock.dport === undefined) { - throw new FS.ErrnoError({{{ cDefine('ENOTCONN') }}}); + throw new FS.ErrnoError({{{ cDefs.ENOTCONN }}}); } addr = sock.daddr; port = sock.dport; @@ -581,7 +581,7 @@ mergeInto(LibraryManager.library, { return { addr: addr, port: port }; }, sendmsg: function(sock, buffer, offset, length, addr, port) { - if (sock.type === {{{ cDefine('SOCK_DGRAM') }}}) { + if (sock.type === {{{ cDefs.SOCK_DGRAM }}}) { // connection-less sockets will honor the message address, // and otherwise fall back to the bound destination address if (addr === undefined || port === undefined) { @@ -590,7 +590,7 @@ mergeInto(LibraryManager.library, { } // if there was no address to fall back to, error out if (addr === undefined || port === undefined) { - throw new FS.ErrnoError({{{ cDefine('EDESTADDRREQ') }}}); + throw new FS.ErrnoError({{{ cDefs.EDESTADDRREQ }}}); } } else { // connection-based sockets will only use the bound @@ -602,11 +602,11 @@ mergeInto(LibraryManager.library, { var dest = SOCKFS.websocket_sock_ops.getPeer(sock, addr, port); // early out if not connected with a connection-based socket - if (sock.type === {{{ cDefine('SOCK_STREAM') }}}) { + if (sock.type === {{{ cDefs.SOCK_STREAM }}}) { if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) { - throw new FS.ErrnoError({{{ cDefine('ENOTCONN') }}}); + throw new FS.ErrnoError({{{ cDefs.ENOTCONN }}}); } else if (dest.socket.readyState === dest.socket.CONNECTING) { - throw new FS.ErrnoError({{{ cDefine('EAGAIN') }}}); + throw new FS.ErrnoError({{{ cDefs.EAGAIN }}}); } } @@ -634,7 +634,7 @@ mergeInto(LibraryManager.library, { // if we're emulating a connection-less dgram socket and don't have // a cached connection, queue the buffer to send upon connect and // lie, saying the data was sent now. - if (sock.type === {{{ cDefine('SOCK_DGRAM') }}}) { + if (sock.type === {{{ cDefs.SOCK_DGRAM }}}) { if (!dest || dest.socket.readyState !== dest.socket.OPEN) { // if we're not connected, open a new connection if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) { @@ -656,33 +656,33 @@ mergeInto(LibraryManager.library, { dest.socket.send(data); return length; } catch (e) { - throw new FS.ErrnoError({{{ cDefine('EINVAL') }}}); + throw new FS.ErrnoError({{{ cDefs.EINVAL }}}); } }, recvmsg: function(sock, length) { // http://pubs.opengroup.org/onlinepubs/7908799/xns/recvmsg.html - if (sock.type === {{{ cDefine('SOCK_STREAM') }}} && sock.server) { + if (sock.type === {{{ cDefs.SOCK_STREAM }}} && sock.server) { // tcp servers should not be recv()'ing on the listen socket - throw new FS.ErrnoError({{{ cDefine('ENOTCONN') }}}); + throw new FS.ErrnoError({{{ cDefs.ENOTCONN }}}); } var queued = sock.recv_queue.shift(); if (!queued) { - if (sock.type === {{{ cDefine('SOCK_STREAM') }}}) { + if (sock.type === {{{ cDefs.SOCK_STREAM }}}) { var dest = SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport); if (!dest) { // if we have a destination address but are not connected, error out - throw new FS.ErrnoError({{{ cDefine('ENOTCONN') }}}); + throw new FS.ErrnoError({{{ cDefs.ENOTCONN }}}); } if (dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) { // return null if the socket has closed return null; } // else, our socket is in a valid state but truly has nothing available - throw new FS.ErrnoError({{{ cDefine('EAGAIN') }}}); + throw new FS.ErrnoError({{{ cDefs.EAGAIN }}}); } - throw new FS.ErrnoError({{{ cDefine('EAGAIN') }}}); + throw new FS.ErrnoError({{{ cDefs.EAGAIN }}}); } // queued.data will be an ArrayBuffer if it's unadulterated, but if it's @@ -702,7 +702,7 @@ mergeInto(LibraryManager.library, { #endif // push back any unread data for TCP connections - if (sock.type === {{{ cDefine('SOCK_STREAM') }}} && bytesRead < queuedLength) { + if (sock.type === {{{ cDefs.SOCK_STREAM }}} && bytesRead < queuedLength) { var bytesRemaining = queuedLength - bytesRead; #if SOCKET_DEBUG dbg('websocket read: put back ' + bytesRemaining + ' bytes'); diff --git a/src/library_syscall.js b/src/library_syscall.js index bd68e9bc4ac5b..109f554825b53 100644 --- a/src/library_syscall.js +++ b/src/library_syscall.js @@ -17,7 +17,7 @@ var SyscallsLibrary = { $SYSCALLS: { #if SYSCALLS_REQUIRE_FILESYSTEM // global constants - DEFAULT_POLLMASK: {{{ cDefine('POLLIN') }}} | {{{ cDefine('POLLOUT') }}}, + DEFAULT_POLLMASK: {{{ cDefs.POLLIN }}} | {{{ cDefs.POLLOUT }}}, // shared utilities calculateAt: function(dirfd, path, allowEmpty) { @@ -26,7 +26,7 @@ var SyscallsLibrary = { } // relative path var dir; - if (dirfd === {{{ cDefine('AT_FDCWD') }}}) { + if (dirfd === {{{ cDefs.AT_FDCWD }}}) { dir = FS.cwd(); } else { var dirstream = SYSCALLS.getStreamFromFD(dirfd); @@ -34,7 +34,7 @@ var SyscallsLibrary = { } if (path.length == 0) { if (!allowEmpty) { - throw new FS.ErrnoError({{{ cDefine('ENOENT') }}});; + throw new FS.ErrnoError({{{ cDefs.ENOENT }}});; } return dir; } @@ -47,7 +47,7 @@ var SyscallsLibrary = { } catch (e) { if (e && e.node && PATH.normalize(path) !== PATH.normalize(FS.getPath(e.node))) { // an error occurred while trying to look up the path; we should just report ENOTDIR - return -{{{ cDefine('ENOTDIR') }}}; + return -{{{ cDefs.ENOTDIR }}}; } throw e; } @@ -75,9 +75,9 @@ var SyscallsLibrary = { }, doMsync: function(addr, stream, len, flags, offset) { if (!FS.isFile(stream.node.mode)) { - throw new FS.ErrnoError({{{ cDefine('ENODEV') }}}); + throw new FS.ErrnoError({{{ cDefs.ENODEV }}}); } - if (flags & {{{ cDefine('MAP_PRIVATE') }}}) { + if (flags & {{{ cDefs.MAP_PRIVATE }}}) { // MAP_PRIVATE calls need not to be synced back to underlying fs return 0; } @@ -115,7 +115,7 @@ var SyscallsLibrary = { // Just like `FS.getStream` but will throw EBADF if stream is undefined. getStreamFromFD: function(fd) { var stream = FS.getStream(fd); - if (!stream) throw new FS.ErrnoError({{{ cDefine('EBADF') }}}); + if (!stream) throw new FS.ErrnoError({{{ cDefs.EBADF }}}); #if SYSCALL_DEBUG dbg(' (stream: "' + stream.path + '")'); #endif @@ -142,7 +142,7 @@ var SyscallsLibrary = { {{{ makeSetValue('addr', 0, 'ptr', '*') }}}; return 0; #else // no filesystem support; report lack of support - return -{{{ cDefine('ENOSYS') }}}; + return -{{{ cDefs.ENOSYS }}}; #endif }, @@ -155,7 +155,7 @@ var SyscallsLibrary = { _munmap_js: function(addr, len, prot, flags, fd, offset) { #if FILESYSTEM && SYSCALLS_REQUIRE_FILESYSTEM var stream = SYSCALLS.getStreamFromFD(fd); - if (prot & {{{ cDefine('PROT_WRITE') }}}) { + if (prot & {{{ cDefs.PROT_WRITE }}}) { SYSCALLS.doMsync(addr, stream, len, flags, offset); } FS.munmap(stream); @@ -190,7 +190,7 @@ var SyscallsLibrary = { __syscall_pipe__sig: 'ip', __syscall_pipe: function(fdPtr) { if (fdPtr == 0) { - throw new FS.ErrnoError({{{ cDefine('EFAULT') }}}); + throw new FS.ErrnoError({{{ cDefs.EFAULT }}}); } var res = PIPEFS.createPipe(); @@ -210,51 +210,51 @@ var SyscallsLibrary = { #else var stream = SYSCALLS.getStreamFromFD(fd); switch (op) { - case {{{ cDefine('TCGETA') }}}: - case {{{ cDefine('TCGETS') }}}: { - if (!stream.tty) return -{{{ cDefine('ENOTTY') }}}; + case {{{ cDefs.TCGETA }}}: + case {{{ cDefs.TCGETS }}}: { + if (!stream.tty) return -{{{ cDefs.ENOTTY }}}; #if SYSCALL_DEBUG dbg('warning: not filling tio struct'); #endif return 0; } - case {{{ cDefine('TCSETA') }}}: - case {{{ cDefine('TCSETAW') }}}: - case {{{ cDefine('TCSETAF') }}}: - case {{{ cDefine('TCSETS') }}}: - case {{{ cDefine('TCSETSW') }}}: - case {{{ cDefine('TCSETSF') }}}: { - if (!stream.tty) return -{{{ cDefine('ENOTTY') }}}; + case {{{ cDefs.TCSETA }}}: + case {{{ cDefs.TCSETAW }}}: + case {{{ cDefs.TCSETAF }}}: + case {{{ cDefs.TCSETS }}}: + case {{{ cDefs.TCSETSW }}}: + case {{{ cDefs.TCSETSF }}}: { + if (!stream.tty) return -{{{ cDefs.ENOTTY }}}; return 0; // no-op, not actually adjusting terminal settings } - case {{{ cDefine('TIOCGPGRP') }}}: { - if (!stream.tty) return -{{{ cDefine('ENOTTY') }}}; + case {{{ cDefs.TIOCGPGRP }}}: { + if (!stream.tty) return -{{{ cDefs.ENOTTY }}}; var argp = SYSCALLS.get(); {{{ makeSetValue('argp', 0, 0, 'i32') }}}; return 0; } - case {{{ cDefine('TIOCSPGRP') }}}: { - if (!stream.tty) return -{{{ cDefine('ENOTTY') }}}; - return -{{{ cDefine('EINVAL') }}}; // not supported + case {{{ cDefs.TIOCSPGRP }}}: { + if (!stream.tty) return -{{{ cDefs.ENOTTY }}}; + return -{{{ cDefs.EINVAL }}}; // not supported } - case {{{ cDefine('FIONREAD') }}}: { + case {{{ cDefs.FIONREAD }}}: { var argp = SYSCALLS.get(); return FS.ioctl(stream, op, argp); } - case {{{ cDefine('TIOCGWINSZ') }}}: { + case {{{ cDefs.TIOCGWINSZ }}}: { // TODO: in theory we should write to the winsize struct that gets // passed in, but for now musl doesn't read anything on it - if (!stream.tty) return -{{{ cDefine('ENOTTY') }}}; + if (!stream.tty) return -{{{ cDefs.ENOTTY }}}; return 0; } - case {{{ cDefine('TIOCSWINSZ') }}}: { + case {{{ cDefs.TIOCSWINSZ }}}: { // TODO: technically, this ioctl call should change the window size. // but, since emscripten doesn't have any concept of a terminal window // yet, we'll just silently throw it away as we do TIOCGWINSZ - if (!stream.tty) return -{{{ cDefine('ENOTTY') }}}; + if (!stream.tty) return -{{{ cDefs.ENOTTY }}}; return 0; } - default: return -{{{ cDefine('EINVAL') }}}; // not supported + default: return -{{{ cDefs.EINVAL }}}; // not supported } #endif // SYSCALLS_REQUIRE_FILESYSTEM }, @@ -277,7 +277,7 @@ var SyscallsLibrary = { $getSocketFromFD__deps: ['$SOCKFS', '$FS'], $getSocketFromFD: function(fd) { var socket = SOCKFS.getSocket(fd); - if (!socket) throw new FS.ErrnoError({{{ cDefine('EBADF') }}}); + if (!socket) throw new FS.ErrnoError({{{ cDefs.EBADF }}}); #if SYSCALL_DEBUG dbg(' (socket: "' + socket.path + '")'); #endif @@ -319,7 +319,7 @@ var SyscallsLibrary = { __syscall_getpeername: function(fd, addr, addrlen) { var sock = getSocketFromFD(fd); if (!sock.daddr) { - return -{{{ cDefine('ENOTCONN') }}}; // The socket is not connected. + return -{{{ cDefs.ENOTCONN }}}; // The socket is not connected. } var errno = writeSockaddr(addr, sock.family, DNS.lookup_name(sock.daddr), sock.dport, addrlen); #if ASSERTIONS @@ -338,7 +338,7 @@ var SyscallsLibrary = { __syscall_shutdown__deps: ['$getSocketFromFD'], __syscall_shutdown: function(fd, how) { getSocketFromFD(fd); - return -{{{ cDefine('ENOSYS') }}}; // unsupported feature + return -{{{ cDefs.ENOSYS }}}; // unsupported feature }, __syscall_accept4__deps: ['$getSocketFromFD', '$writeSockaddr', '$DNS'], __syscall_accept4: function(fd, addr, addrlen, flags) { @@ -397,15 +397,15 @@ var SyscallsLibrary = { var sock = getSocketFromFD(fd); // Minimal getsockopt aimed at resolving https://github.com/emscripten-core/emscripten/issues/2211 // so only supports SOL_SOCKET with SO_ERROR. - if (level === {{{ cDefine('SOL_SOCKET') }}}) { - if (optname === {{{ cDefine('SO_ERROR') }}}) { + if (level === {{{ cDefs.SOL_SOCKET }}}) { + if (optname === {{{ cDefs.SO_ERROR }}}) { {{{ makeSetValue('optval', 0, 'sock.error', 'i32') }}}; {{{ makeSetValue('optlen', 0, 4, 'i32') }}}; sock.error = null; // Clear the error (The SO_ERROR option obtains and then clears this field). return 0; } } - return -{{{ cDefine('ENOPROTOOPT') }}}; // The option is unknown at the level indicated. + return -{{{ cDefs.ENOPROTOOPT }}}; // The option is unknown at the level indicated. }, __syscall_sendmsg__deps: ['$getSocketFromFD', '$readSockaddr', '$DNS'], __syscall_sendmsg: function(fd, message, flags) { @@ -553,15 +553,15 @@ var SyscallsLibrary = { flags = stream.stream_ops.poll(stream); } - if ((flags & {{{ cDefine('POLLIN') }}}) && check(fd, srcReadLow, srcReadHigh, mask)) { + if ((flags & {{{ cDefs.POLLIN }}}) && check(fd, srcReadLow, srcReadHigh, mask)) { fd < 32 ? (dstReadLow = dstReadLow | mask) : (dstReadHigh = dstReadHigh | mask); total++; } - if ((flags & {{{ cDefine('POLLOUT') }}}) && check(fd, srcWriteLow, srcWriteHigh, mask)) { + if ((flags & {{{ cDefs.POLLOUT }}}) && check(fd, srcWriteLow, srcWriteHigh, mask)) { fd < 32 ? (dstWriteLow = dstWriteLow | mask) : (dstWriteHigh = dstWriteHigh | mask); total++; } - if ((flags & {{{ cDefine('POLLPRI') }}}) && check(fd, srcExceptLow, srcExceptHigh, mask)) { + if ((flags & {{{ cDefs.POLLPRI }}}) && check(fd, srcExceptLow, srcExceptHigh, mask)) { fd < 32 ? (dstExceptLow = dstExceptLow | mask) : (dstExceptHigh = dstExceptHigh | mask); total++; } @@ -598,7 +598,7 @@ var SyscallsLibrary = { var pollfd = fds + {{{ C_STRUCTS.pollfd.__size__ }}} * i; var fd = {{{ makeGetValue('pollfd', C_STRUCTS.pollfd.fd, 'i32') }}}; var events = {{{ makeGetValue('pollfd', C_STRUCTS.pollfd.events, 'i16') }}}; - var mask = {{{ cDefine('POLLNVAL') }}}; + var mask = {{{ cDefs.POLLNVAL }}}; var stream = FS.getStream(fd); if (stream) { mask = SYSCALLS.DEFAULT_POLLMASK; @@ -606,7 +606,7 @@ var SyscallsLibrary = { mask = stream.stream_ops.poll(stream); } } - mask &= events | {{{ cDefine('POLLERR') }}} | {{{ cDefine('POLLHUP') }}}; + mask &= events | {{{ cDefs.POLLERR }}} | {{{ cDefs.POLLHUP }}}; if (mask) nonzero++; {{{ makeSetValue('pollfd', C_STRUCTS.pollfd.revents, 'mask', 'i16') }}}; } @@ -614,17 +614,17 @@ var SyscallsLibrary = { }, __syscall_getcwd__sig: 'ipp', __syscall_getcwd: function(buf, size) { - if (size === 0) return -{{{ cDefine('EINVAL') }}}; + if (size === 0) return -{{{ cDefs.EINVAL }}}; var cwd = FS.cwd(); var cwdLengthInBytes = lengthBytesUTF8(cwd) + 1; - if (size < cwdLengthInBytes) return -{{{ cDefine('ERANGE') }}}; + if (size < cwdLengthInBytes) return -{{{ cDefs.ERANGE }}}; stringToUTF8(cwd, buf, size); return cwdLengthInBytes; }, __syscall_truncate64__sig: 'ipj', __syscall_truncate64__deps: i53ConversionDeps, __syscall_truncate64: function(path, {{{ defineI64Param('length') }}}) { - {{{ receiveI64ParamAsI53('length', -cDefine('EOVERFLOW')) }}} + {{{ receiveI64ParamAsI53('length', -cDefs.EOVERFLOW) }}} path = SYSCALLS.getStr(path); FS.truncate(path, length); return 0; @@ -632,7 +632,7 @@ var SyscallsLibrary = { __syscall_ftruncate64__sig: 'iij', __syscall_ftruncate64__deps: i53ConversionDeps, __syscall_ftruncate64: function(fd, {{{ defineI64Param('length') }}}) { - {{{ receiveI64ParamAsI53('length', -cDefine('EOVERFLOW')) }}} + {{{ receiveI64ParamAsI53('length', -cDefs.EOVERFLOW) }}} FS.ftruncate(fd, length); return 0; }, @@ -664,7 +664,7 @@ var SyscallsLibrary = { var struct_size = {{{ C_STRUCTS.dirent.__size__ }}}; var pos = 0; - var off = FS.llseek(stream, 0, {{{ cDefine('SEEK_CUR') }}}); + var off = FS.llseek(stream, 0, {{{ cDefs.SEEK_CUR }}}); var idx = Math.floor(off / struct_size); @@ -700,7 +700,7 @@ var SyscallsLibrary = { pos += struct_size; idx += 1; } - FS.llseek(stream, idx * struct_size, {{{ cDefine('SEEK_SET') }}}); + FS.llseek(stream, idx * struct_size, {{{ cDefs.SEEK_SET }}}); return pos; }, __syscall_fcntl64__deps: ['$setErrNo'], @@ -714,53 +714,53 @@ var SyscallsLibrary = { #else var stream = SYSCALLS.getStreamFromFD(fd); switch (cmd) { - case {{{ cDefine('F_DUPFD') }}}: { + case {{{ cDefs.F_DUPFD }}}: { var arg = SYSCALLS.get(); if (arg < 0) { - return -{{{ cDefine('EINVAL') }}}; + return -{{{ cDefs.EINVAL }}}; } var newStream; newStream = FS.createStream(stream, arg); return newStream.fd; } - case {{{ cDefine('F_GETFD') }}}: - case {{{ cDefine('F_SETFD') }}}: + case {{{ cDefs.F_GETFD }}}: + case {{{ cDefs.F_SETFD }}}: return 0; // FD_CLOEXEC makes no sense for a single process. - case {{{ cDefine('F_GETFL') }}}: + case {{{ cDefs.F_GETFL }}}: return stream.flags; - case {{{ cDefine('F_SETFL') }}}: { + case {{{ cDefs.F_SETFL }}}: { var arg = SYSCALLS.get(); stream.flags |= arg; return 0; } - case {{{ cDefine('F_GETLK') }}}: - /* case {{{ cDefine('F_GETLK64') }}}: Currently in musl F_GETLK64 has same value as F_GETLK, so omitted to avoid duplicate case blocks. If that changes, uncomment this */ { - {{{ assert(cDefine('F_GETLK') === cDefine('F_GETLK64')), '' }}} + case {{{ cDefs.F_GETLK }}}: + /* case {{{ cDefs.F_GETLK64 }}}: Currently in musl F_GETLK64 has same value as F_GETLK, so omitted to avoid duplicate case blocks. If that changes, uncomment this */ { + {{{ assert(cDefs.F_GETLK === cDefs.F_GETLK64), '' }}} var arg = SYSCALLS.get(); var offset = {{{ C_STRUCTS.flock.l_type }}}; // We're always unlocked. - {{{ makeSetValue('arg', 'offset', cDefine('F_UNLCK'), 'i16') }}}; + {{{ makeSetValue('arg', 'offset', cDefs.F_UNLCK, 'i16') }}}; return 0; } - case {{{ cDefine('F_SETLK') }}}: - case {{{ cDefine('F_SETLKW') }}}: - /* case {{{ cDefine('F_SETLK64') }}}: Currently in musl F_SETLK64 has same value as F_SETLK, so omitted to avoid duplicate case blocks. If that changes, uncomment this */ - /* case {{{ cDefine('F_SETLKW64') }}}: Currently in musl F_SETLKW64 has same value as F_SETLKW, so omitted to avoid duplicate case blocks. If that changes, uncomment this */ - {{{ assert(cDefine('F_SETLK64') === cDefine('F_SETLK')), '' }}} - {{{ assert(cDefine('F_SETLKW64') === cDefine('F_SETLKW')), '' }}} + case {{{ cDefs.F_SETLK }}}: + case {{{ cDefs.F_SETLKW }}}: + /* case {{{ cDefs.F_SETLK64 }}}: Currently in musl F_SETLK64 has same value as F_SETLK, so omitted to avoid duplicate case blocks. If that changes, uncomment this */ + /* case {{{ cDefs.F_SETLKW64 }}}: Currently in musl F_SETLKW64 has same value as F_SETLKW, so omitted to avoid duplicate case blocks. If that changes, uncomment this */ + {{{ assert(cDefs.F_SETLK64 === cDefs.F_SETLK), '' }}} + {{{ assert(cDefs.F_SETLKW64 === cDefs.F_SETLKW), '' }}} return 0; // Pretend that the locking is successful. - case {{{ cDefine('F_GETOWN_EX') }}}: - case {{{ cDefine('F_SETOWN') }}}: - return -{{{ cDefine('EINVAL') }}}; // These are for sockets. We don't have them fully implemented yet. - case {{{ cDefine('F_GETOWN') }}}: + case {{{ cDefs.F_GETOWN_EX }}}: + case {{{ cDefs.F_SETOWN }}}: + return -{{{ cDefs.EINVAL }}}; // These are for sockets. We don't have them fully implemented yet. + case {{{ cDefs.F_GETOWN }}}: // musl trusts getown return values, due to a bug where they must be, as they overlap with errors. just return -1 here, so fcntl() returns that, and we set errno ourselves. - setErrNo({{{ cDefine('EINVAL') }}}); + setErrNo({{{ cDefs.EINVAL }}}); return -1; default: { #if SYSCALL_DEBUG dbg('warning: fcntl unrecognized command ' + cmd); #endif - return -{{{ cDefine('EINVAL') }}}; + return -{{{ cDefs.EINVAL }}}; } } #endif // SYSCALLS_REQUIRE_FILESYSTEM @@ -825,14 +825,14 @@ var SyscallsLibrary = { path = SYSCALLS.getStr(path); path = SYSCALLS.calculateAt(dirfd, path); // we don't want this in the JS API as it uses mknod to create all nodes. - switch (mode & {{{ cDefine('S_IFMT') }}}) { - case {{{ cDefine('S_IFREG') }}}: - case {{{ cDefine('S_IFCHR') }}}: - case {{{ cDefine('S_IFBLK') }}}: - case {{{ cDefine('S_IFIFO') }}}: - case {{{ cDefine('S_IFSOCK') }}}: + switch (mode & {{{ cDefs.S_IFMT }}}) { + case {{{ cDefs.S_IFREG }}}: + case {{{ cDefs.S_IFCHR }}}: + case {{{ cDefs.S_IFBLK }}}: + case {{{ cDefs.S_IFIFO }}}: + case {{{ cDefs.S_IFSOCK }}}: break; - default: return -{{{ cDefine('EINVAL') }}}; + default: return -{{{ cDefs.EINVAL }}}; } FS.mknod(path, mode, dev); return 0; @@ -843,8 +843,8 @@ var SyscallsLibrary = { dbg('warning: untested syscall'); #endif path = SYSCALLS.getStr(path); - var nofollow = flags & {{{ cDefine('AT_SYMLINK_NOFOLLOW') }}}; - flags = flags & (~{{{ cDefine('AT_SYMLINK_NOFOLLOW') }}}); + var nofollow = flags & {{{ cDefs.AT_SYMLINK_NOFOLLOW }}}; + flags = flags & (~{{{ cDefs.AT_SYMLINK_NOFOLLOW }}}); #if ASSERTIONS assert(flags === 0); #endif @@ -855,9 +855,9 @@ var SyscallsLibrary = { __syscall_newfstatat__sig: 'iippi', __syscall_newfstatat: function(dirfd, path, buf, flags) { path = SYSCALLS.getStr(path); - var nofollow = flags & {{{ cDefine('AT_SYMLINK_NOFOLLOW') }}}; - var allowEmpty = flags & {{{ cDefine('AT_EMPTY_PATH') }}}; - flags = flags & (~{{{ cDefine('AT_SYMLINK_NOFOLLOW') | cDefine('AT_EMPTY_PATH') | cDefine('AT_NO_AUTOMOUNT') }}}); + var nofollow = flags & {{{ cDefs.AT_SYMLINK_NOFOLLOW }}}; + var allowEmpty = flags & {{{ cDefs.AT_EMPTY_PATH }}}; + flags = flags & (~{{{ cDefs.AT_SYMLINK_NOFOLLOW | cDefs.AT_EMPTY_PATH | cDefs.AT_NO_AUTOMOUNT }}}); #if ASSERTIONS assert(!flags, 'unknown flags in __syscall_newfstatat: ' + flags); #endif @@ -870,7 +870,7 @@ var SyscallsLibrary = { path = SYSCALLS.calculateAt(dirfd, path); if (flags === 0) { FS.unlink(path); - } else if (flags === {{{ cDefine('AT_REMOVEDIR') }}}) { + } else if (flags === {{{ cDefs.AT_REMOVEDIR }}}) { FS.rmdir(path); } else { abort('Invalid flags passed to unlinkat'); @@ -889,7 +889,7 @@ var SyscallsLibrary = { __syscall_linkat__nothrow: true, __syscall_linkat__proxy: false, __syscall_linkat: function(olddirfd, oldpath, newdirfd, newpath, flags) { - return -{{{ cDefine('EMLINK') }}}; // no hardlinks for us + return -{{{ cDefs.EMLINK }}}; // no hardlinks for us }, __syscall_symlinkat: function(target, newdirfd, linkpath) { #if SYSCALL_DEBUG @@ -903,7 +903,7 @@ var SyscallsLibrary = { __syscall_readlinkat: function(dirfd, path, buf, bufsize) { path = SYSCALLS.getStr(path); path = SYSCALLS.calculateAt(dirfd, path); - if (bufsize <= 0) return -{{{ cDefine('EINVAL') }}}; + if (bufsize <= 0) return -{{{ cDefs.EINVAL }}}; var ret = FS.readlink(path); var len = Math.min(bufsize, lengthBytesUTF8(ret)); @@ -934,21 +934,21 @@ var SyscallsLibrary = { assert(flags === 0); #endif path = SYSCALLS.calculateAt(dirfd, path); - if (amode & ~{{{ cDefine('S_IRWXO') }}}) { + if (amode & ~{{{ cDefs.S_IRWXO }}}) { // need a valid mode - return -{{{ cDefine('EINVAL') }}}; + return -{{{ cDefs.EINVAL }}}; } var lookup = FS.lookupPath(path, { follow: true }); var node = lookup.node; if (!node) { - return -{{{ cDefine('ENOENT') }}}; + return -{{{ cDefs.ENOENT }}}; } var perms = ''; - if (amode & {{{ cDefine('R_OK') }}}) perms += 'r'; - if (amode & {{{ cDefine('W_OK') }}}) perms += 'w'; - if (amode & {{{ cDefine('X_OK') }}}) perms += 'x'; + if (amode & {{{ cDefs.R_OK }}}) perms += 'r'; + if (amode & {{{ cDefs.W_OK }}}) perms += 'w'; + if (amode & {{{ cDefs.X_OK }}}) perms += 'x'; if (perms /* otherwise, they've just passed F_OK */ && FS.nodePermissions(node, perms)) { - return -{{{ cDefine('EACCES') }}}; + return -{{{ cDefs.EACCES }}}; } return 0; }, @@ -977,8 +977,8 @@ var SyscallsLibrary = { }, __syscall_fallocate__deps: i53ConversionDeps, __syscall_fallocate: function(fd, mode, {{{ defineI64Param('offset') }}}, {{{ defineI64Param('len') }}}) { - {{{ receiveI64ParamAsI53('offset', -cDefine('EOVERFLOW')) }}} - {{{ receiveI64ParamAsI53('len', -cDefine('EOVERFLOW')) }}} + {{{ receiveI64ParamAsI53('offset', -cDefs.EOVERFLOW) }}} + {{{ receiveI64ParamAsI53('len', -cDefs.EOVERFLOW) }}} var stream = SYSCALLS.getStreamFromFD(fd) #if ASSERTIONS assert(mode === 0); @@ -991,7 +991,7 @@ var SyscallsLibrary = { #if ASSERTIONS assert(!flags); #endif - if (old.fd === suggestFD) return -{{{ cDefine('EINVAL') }}}; + if (old.fd === suggestFD) return -{{{ cDefs.EINVAL }}}; var suggest = FS.getStream(suggestFD); if (suggest) FS.close(suggest); return FS.createStream(old, suggestFD, suggestFD + 1).fd; diff --git a/src/library_tty.js b/src/library_tty.js index 9e84170a7713a..8c78fbd3cd893 100644 --- a/src/library_tty.js +++ b/src/library_tty.js @@ -43,7 +43,7 @@ mergeInto(LibraryManager.library, { open: function(stream) { var tty = TTY.ttys[stream.node.rdev]; if (!tty) { - throw new FS.ErrnoError({{{ cDefine('ENODEV') }}}); + throw new FS.ErrnoError({{{ cDefs.ENODEV }}}); } stream.tty = tty; stream.seekable = false; @@ -57,7 +57,7 @@ mergeInto(LibraryManager.library, { }, read: function(stream, buffer, offset, length, pos /* ignored */) { if (!stream.tty || !stream.tty.ops.get_char) { - throw new FS.ErrnoError({{{ cDefine('ENXIO') }}}); + throw new FS.ErrnoError({{{ cDefs.ENXIO }}}); } var bytesRead = 0; for (var i = 0; i < length; i++) { @@ -65,10 +65,10 @@ mergeInto(LibraryManager.library, { try { result = stream.tty.ops.get_char(stream.tty); } catch (e) { - throw new FS.ErrnoError({{{ cDefine('EIO') }}}); + throw new FS.ErrnoError({{{ cDefs.EIO }}}); } if (result === undefined && bytesRead === 0) { - throw new FS.ErrnoError({{{ cDefine('EAGAIN') }}}); + throw new FS.ErrnoError({{{ cDefs.EAGAIN }}}); } if (result === null || result === undefined) break; bytesRead++; @@ -81,14 +81,14 @@ mergeInto(LibraryManager.library, { }, write: function(stream, buffer, offset, length, pos) { if (!stream.tty || !stream.tty.ops.put_char) { - throw new FS.ErrnoError({{{ cDefine('ENXIO') }}}); + throw new FS.ErrnoError({{{ cDefs.ENXIO }}}); } try { for (var i = 0; i < length; i++) { stream.tty.ops.put_char(stream.tty, buffer[offset+i]); } } catch (e) { - throw new FS.ErrnoError({{{ cDefine('EIO') }}}); + throw new FS.ErrnoError({{{ cDefs.EIO }}}); } if (length) { stream.node.timestamp = Date.now(); diff --git a/src/library_uuid.js b/src/library_uuid.js index 6a4bb4d9b8b65..f0f0e72219436 100644 --- a/src/library_uuid.js +++ b/src/library_uuid.js @@ -140,12 +140,12 @@ mergeInto(LibraryManager.library, { uuid_type: function(uu) { // int uuid_type(const uuid_t uu); - return {{{ cDefine('UUID_TYPE_DCE_RANDOM') }}}; + return {{{ cDefs.UUID_TYPE_DCE_RANDOM }}}; }, uuid_variant: function(uu) { // int uuid_variant(const uuid_t uu); - return {{{ cDefine('UUID_VARIANT_DCE') }}}; + return {{{ cDefs.UUID_VARIANT_DCE }}}; } }); diff --git a/src/library_wasi.js b/src/library_wasi.js index 3aff37ecfbb4c..a57b9326bc43b 100644 --- a/src/library_wasi.js +++ b/src/library_wasi.js @@ -140,10 +140,10 @@ var WasiLibrary = { #endif $checkWasiClock: function(clock_id) { - return clock_id == {{{ cDefine('__WASI_CLOCKID_REALTIME') }}} || - clock_id == {{{ cDefine('__WASI_CLOCKID_MONOTONIC') }}} || - clock_id == {{{ cDefine('__WASI_CLOCKID_PROCESS_CPUTIME_ID') }}} || - clock_id == {{{ cDefine('__WASI_CLOCKID_THREAD_CPUTIME_ID') }}}; + return clock_id == {{{ cDefs.__WASI_CLOCKID_REALTIME }}} || + clock_id == {{{ cDefs.__WASI_CLOCKID_MONOTONIC }}} || + clock_id == {{{ cDefs.__WASI_CLOCKID_PROCESS_CPUTIME_ID }}} || + clock_id == {{{ cDefs.__WASI_CLOCKID_THREAD_CPUTIME_ID }}}; }, // TODO: the i64 in the API here must be legalized for this JS code to run, @@ -155,16 +155,16 @@ var WasiLibrary = { clock_time_get__deps: ['emscripten_get_now', '$nowIsMonotonic', '$checkWasiClock'], clock_time_get: function(clk_id, {{{ defineI64Param('ignored_precision') }}}, ptime) { if (!checkWasiClock(clk_id)) { - return {{{ cDefine('EINVAL') }}}; + return {{{ cDefs.EINVAL }}}; } var now; // all wasi clocks but realtime are monotonic - if (clk_id === {{{ cDefine('__WASI_CLOCKID_REALTIME') }}}) { + if (clk_id === {{{ cDefs.__WASI_CLOCKID_REALTIME }}}) { now = Date.now(); } else if (nowIsMonotonic) { now = _emscripten_get_now(); } else { - return {{{ cDefine('ENOSYS') }}}; + return {{{ cDefs.ENOSYS }}}; } // "now" is in ms, and wasi times are in ns. var nsec = Math.round(now * 1000 * 1000); @@ -178,16 +178,16 @@ var WasiLibrary = { clock_res_get__deps: ['emscripten_get_now', 'emscripten_get_now_res', '$nowIsMonotonic', '$checkWasiClock'], clock_res_get: function(clk_id, pres) { if (!checkWasiClock(clk_id)) { - return {{{ cDefine('EINVAL') }}}; + return {{{ cDefs.EINVAL }}}; } var nsec; // all wasi clocks but realtime are monotonic - if (clk_id === {{{ cDefine('CLOCK_REALTIME') }}}) { + if (clk_id === {{{ cDefs.CLOCK_REALTIME }}}) { nsec = 1000 * 1000; // educated guess that it's milliseconds } else if (nowIsMonotonic) { nsec = _emscripten_get_now_res(); } else { - return {{{ cDefine('ENOSYS') }}}; + return {{{ cDefs.ENOSYS }}}; } {{{ makeSetValue('pres', 0, 'nsec >>> 0', 'i32') }}}; {{{ makeSetValue('pres', 4, '(nsec / Math.pow(2, 32)) >>> 0', 'i32') }}}; @@ -297,7 +297,7 @@ var WasiLibrary = { fd_pwrite__sig: 'iippjp', fd_pwrite: function(fd, iov, iovcnt, {{{ defineI64Param('offset') }}}, pnum) { #if SYSCALLS_REQUIRE_FILESYSTEM - {{{ receiveI64ParamAsI53('offset', cDefine('EOVERFLOW')) }}} + {{{ receiveI64ParamAsI53('offset', cDefs.EOVERFLOW) }}} var stream = SYSCALLS.getStreamFromFD(fd) var num = doWritev(stream, iov, iovcnt, offset); {{{ makeSetValue('pnum', 0, 'num', SIZE_TYPE) }}}; @@ -305,7 +305,7 @@ var WasiLibrary = { #elif ASSERTIONS abort('fd_pwrite called without SYSCALLS_REQUIRE_FILESYSTEM'); #else - return {{{ cDefine('ENOSYS') }}}; + return {{{ cDefs.ENOSYS }}}; #endif }, @@ -325,7 +325,7 @@ var WasiLibrary = { #elif ASSERTIONS abort('fd_close called without SYSCALLS_REQUIRE_FILESYSTEM'); #else - return {{{ cDefine('ENOSYS') }}}; + return {{{ cDefs.ENOSYS }}}; #endif // SYSCALLS_REQUIRE_FILESYSTEM }, @@ -342,7 +342,7 @@ var WasiLibrary = { #elif ASSERTIONS abort('fd_read called without SYSCALLS_REQUIRE_FILESYSTEM'); #else - return {{{ cDefine('ENOSYS') }}}; + return {{{ cDefs.ENOSYS }}}; #endif // SYSCALLS_REQUIRE_FILESYSTEM }, @@ -354,7 +354,7 @@ var WasiLibrary = { fd_pread__sig: 'iippjp', fd_pread: function(fd, iov, iovcnt, {{{ defineI64Param('offset') }}}, pnum) { #if SYSCALLS_REQUIRE_FILESYSTEM - {{{ receiveI64ParamAsI53('offset', cDefine('EOVERFLOW')) }}} + {{{ receiveI64ParamAsI53('offset', cDefs.EOVERFLOW) }}} var stream = SYSCALLS.getStreamFromFD(fd) var num = doReadv(stream, iov, iovcnt, offset); {{{ makeSetValue('pnum', 0, 'num', SIZE_TYPE) }}}; @@ -362,7 +362,7 @@ var WasiLibrary = { #elif ASSERTIONS abort('fd_pread called without SYSCALLS_REQUIRE_FILESYSTEM'); #else - return {{{ cDefine('ENOSYS') }}}; + return {{{ cDefs.ENOSYS }}}; #endif }, @@ -370,14 +370,14 @@ var WasiLibrary = { fd_seek__deps: i53ConversionDeps, fd_seek: function(fd, {{{ defineI64Param('offset') }}}, whence, newOffset) { #if SYSCALLS_REQUIRE_FILESYSTEM - {{{ receiveI64ParamAsI53('offset', cDefine('EOVERFLOW')) }}} + {{{ receiveI64ParamAsI53('offset', cDefs.EOVERFLOW) }}} var stream = SYSCALLS.getStreamFromFD(fd); FS.llseek(stream, offset, whence); {{{ makeSetValue('newOffset', '0', 'stream.position', 'i64') }}}; - if (stream.getdents && offset === 0 && whence === {{{ cDefine('SEEK_SET') }}}) stream.getdents = null; // reset readdir state + if (stream.getdents && offset === 0 && whence === {{{ cDefs.SEEK_SET }}}) stream.getdents = null; // reset readdir state return 0; #else - return {{{ cDefine('ESPIPE') }}}; + return {{{ cDefs.ESPIPE }}}; #endif }, @@ -387,13 +387,13 @@ var WasiLibrary = { var stream = SYSCALLS.getStreamFromFD(fd); // All character devices are terminals (other things a Linux system would // assume is a character device, like the mouse, we have special APIs for). - var type = stream.tty ? {{{ cDefine('__WASI_FILETYPE_CHARACTER_DEVICE') }}} : - FS.isDir(stream.mode) ? {{{ cDefine('__WASI_FILETYPE_DIRECTORY') }}} : - FS.isLink(stream.mode) ? {{{ cDefine('__WASI_FILETYPE_SYMBOLIC_LINK') }}} : - {{{ cDefine('__WASI_FILETYPE_REGULAR_FILE') }}}; + var type = stream.tty ? {{{ cDefs.__WASI_FILETYPE_CHARACTER_DEVICE }}} : + FS.isDir(stream.mode) ? {{{ cDefs.__WASI_FILETYPE_DIRECTORY }}} : + FS.isLink(stream.mode) ? {{{ cDefs.__WASI_FILETYPE_SYMBOLIC_LINK }}} : + {{{ cDefs.__WASI_FILETYPE_REGULAR_FILE }}}; #else // hack to support printf in SYSCALLS_REQUIRE_FILESYSTEM=0 - var type = fd == 1 || fd == 2 ? {{{ cDefine('__WASI_FILETYPE_CHARACTER_DEVICE') }}} : abort(); + var type = fd == 1 || fd == 2 ? {{{ cDefs.__WASI_FILETYPE_CHARACTER_DEVICE }}} : abort(); #endif {{{ makeSetValue('pbuf', C_STRUCTS.__wasi_fdstat_t.fs_filetype, 'type', 'i8') }}}; // TODO {{{ makeSetValue('pbuf', C_STRUCTS.__wasi_fdstat_t.fs_flags, '?', 'i16') }}}; @@ -416,7 +416,7 @@ var WasiLibrary = { } mount.type.syncfs(mount, false, function(err) { if (err) { - wakeUp(function() { return {{{ cDefine('EIO') }}} }); + wakeUp(function() { return {{{ cDefs.EIO }}} }); return; } wakeUp(0); @@ -431,7 +431,7 @@ var WasiLibrary = { #elif ASSERTIONS abort('fd_sync called without SYSCALLS_REQUIRE_FILESYSTEM'); #else - return {{{ cDefine('ENOSYS') }}}; + return {{{ cDefs.ENOSYS }}}; #endif // SYSCALLS_REQUIRE_FILESYSTEM }, }; diff --git a/src/library_wasmfs.js b/src/library_wasmfs.js index 42f50d08f4d99..f984b74290b09 100644 --- a/src/library_wasmfs.js +++ b/src/library_wasmfs.js @@ -57,8 +57,8 @@ mergeInto(LibraryManager.library, { }, getMode: (canRead, canWrite) => { var mode = 0; - if (canRead) mode |= {{{ cDefine('S_IRUGO') }}} | {{{ cDefine('S_IXUGO') }}}; - if (canWrite) mode |= {{{ cDefine('S_IWUGO') }}}; + if (canRead) mode |= {{{ cDefs.S_IRUGO }}} | {{{ cDefs.S_IXUGO }}}; + if (canWrite) mode |= {{{ cDefs.S_IWUGO }}}; return mode; }, modeStringToFlags: (str) => { @@ -73,12 +73,12 @@ mergeInto(LibraryManager.library, { // Extra quotes used here on the keys to this object otherwise jsifier will // erase them in the process of reading and then writing the JS library // code. - '"r"': {{{ cDefine('O_RDONLY') }}}, - '"r+"': {{{ cDefine('O_RDWR') }}}, - '"w"': {{{ cDefine('O_TRUNC') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_WRONLY') }}}, - '"w+"': {{{ cDefine('O_TRUNC') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_RDWR') }}}, - '"a"': {{{ cDefine('O_APPEND') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_WRONLY') }}}, - '"a+"': {{{ cDefine('O_APPEND') }}} | {{{ cDefine('O_CREAT') }}} | {{{ cDefine('O_RDWR') }}}, + '"r"': {{{ cDefs.O_RDONLY }}}, + '"r+"': {{{ cDefs.O_RDWR }}}, + '"w"': {{{ cDefs.O_TRUNC }}} | {{{ cDefs.O_CREAT }}} | {{{ cDefs.O_WRONLY }}}, + '"w+"': {{{ cDefs.O_TRUNC }}} | {{{ cDefs.O_CREAT }}} | {{{ cDefs.O_RDWR }}}, + '"a"': {{{ cDefs.O_APPEND }}} | {{{ cDefs.O_CREAT }}} | {{{ cDefs.O_WRONLY }}}, + '"a+"': {{{ cDefs.O_APPEND }}} | {{{ cDefs.O_CREAT }}} | {{{ cDefs.O_RDWR }}}, }, createDataFile: (parent, name, data, canRead, canWrite, canOwn) => { // Data files must be cached until the file system itself has been initialized. @@ -215,11 +215,11 @@ mergeInto(LibraryManager.library, { // TODO: utime findObject: (path) => { var result = __wasmfs_identify(path); - if (result == {{{ cDefine('ENOENT') }}}) { + if (result == {{{ cDefs.ENOENT }}}) { return null; } return { - isFolder: result == {{{ cDefine('EISDIR') }}}, + isFolder: result == {{{ cDefs.EISDIR }}}, isDevice: false, // TODO: wasmfs support for devices }; }, diff --git a/src/library_wasmfs_fetch.js b/src/library_wasmfs_fetch.js index 48bf2a6598833..9052c717d5712 100644 --- a/src/library_wasmfs_fetch.js +++ b/src/library_wasmfs_fetch.js @@ -74,7 +74,7 @@ mergeInto(LibraryManager.library, { try { await getFile(file); } catch (response) { - return response.status === 404 ? -{{{ cDefine('ENOENT') }}} : -{{{ cDefine('EBADF') }}}; + return response.status === 404 ? -{{{ cDefs.ENOENT }}} : -{{{ cDefs.EBADF }}}; } return jsFileOps.read(file, buffer, length, offset); }, diff --git a/src/library_wasmfs_js_file.js b/src/library_wasmfs_js_file.js index 3c8e334f91024..f4b07c428c075 100644 --- a/src/library_wasmfs_js_file.js +++ b/src/library_wasmfs_js_file.js @@ -32,7 +32,7 @@ mergeInto(LibraryManager.library, { wasmFS$JSMemoryFiles[file].set(HEAPU8.subarray(buffer, buffer + length), offset); return length; } catch (err) { - return -{{{ cDefine('EIO') }}}; + return -{{{ cDefs.EIO }}}; } }, read: (file, buffer, length, offset) => { diff --git a/src/library_wasmfs_opfs.js b/src/library_wasmfs_opfs.js index 7f556580137da..f048a381bf452 100644 --- a/src/library_wasmfs_opfs.js +++ b/src/library_wasmfs_opfs.js @@ -36,15 +36,15 @@ mergeInto(LibraryManager.library, { fileHandle = await parentHandle.getFileHandle(name, {create: create}); } catch (e) { if (e.name === "NotFoundError") { - return -{{{ cDefine('EEXIST') }}}; + return -{{{ cDefs.EEXIST }}}; } if (e.name === "TypeMismatchError") { - return -{{{ cDefine('EISDIR') }}}; + return -{{{ cDefs.EISDIR }}}; } #if ASSERTIONS err('unexpected error:', e, e.stack); #endif - return -{{{ cDefine('EIO') }}}; + return -{{{ cDefs.EIO }}}; } return wasmfsOPFSFileHandles.allocate(fileHandle); }, @@ -61,15 +61,15 @@ mergeInto(LibraryManager.library, { await parentHandle.getDirectoryHandle(name, {create: create}); } catch (e) { if (e.name === "NotFoundError") { - return -{{{ cDefine('EEXIST') }}}; + return -{{{ cDefs.EEXIST }}}; } if (e.name === "TypeMismatchError") { - return -{{{ cDefine('ENOTDIR') }}}; + return -{{{ cDefs.ENOTDIR }}}; } #if ASSERTIONS err('unexpected error:', e, e.stack); #endif - return -{{{ cDefine('EIO') }}}; + return -{{{ cDefs.EIO }}}; } return wasmfsOPFSDirectoryHandles.allocate(childHandle); }, @@ -81,7 +81,7 @@ mergeInto(LibraryManager.library, { let name = UTF8ToString(namePtr); let childType = 1; let childID = await wasmfsOPFSGetOrCreateFile(parent, name, false); - if (childID == -{{{ cDefine('EISDIR') }}}) { + if (childID == -{{{ cDefs.EISDIR }}}) { childType = 2; childID = await wasmfsOPFSGetOrCreateDir(parent, name, false); } @@ -108,7 +108,7 @@ mergeInto(LibraryManager.library, { }); } } catch { - let err = -{{{ cDefine('EIO') }}}; + let err = -{{{ cDefs.EIO }}}; {{{ makeSetValue('errPtr', 0, 'err', 'i32') }}}; } _emscripten_proxy_finish(ctx); @@ -140,7 +140,7 @@ mergeInto(LibraryManager.library, { try { await fileHandle.move(newDirHandle, name); } catch { - let err = -{{{ cDefine('EIO') }}}; + let err = -{{{ cDefs.EIO }}}; {{{ makeSetValue('errPtr', 0, 'err', 'i32') }}}; } _emscripten_proxy_finish(ctx); @@ -153,7 +153,7 @@ mergeInto(LibraryManager.library, { try { await dirHandle.removeEntry(name); } catch { - let err = -{{{ cDefine('EIO') }}}; + let err = -{{{ cDefs.EIO }}}; {{{ makeSetValue('errPtr', 0, 'err', 'i32') }}}; } _emscripten_proxy_finish(ctx); @@ -188,12 +188,12 @@ mergeInto(LibraryManager.library, { // TODO: Presumably only one of these will appear in the final API? if (e.name === "InvalidStateError" || e.name === "NoModificationAllowedError") { - accessID = -{{{ cDefine('EACCES') }}}; + accessID = -{{{ cDefs.EACCES }}}; } else { #if ASSERTIONS err('unexpected error:', e, e.stack); #endif - accessID = -{{{ cDefine('EIO') }}}; + accessID = -{{{ cDefs.EIO }}}; } } {{{ makeSetValue('accessIDPtr', 0, 'accessID', 'i32') }}}; @@ -210,12 +210,12 @@ mergeInto(LibraryManager.library, { blobID = wasmfsOPFSBlobs.allocate(blob); } catch (e) { if (e.name === "NotAllowedError") { - blobID = -{{{ cDefine('EACCES') }}}; + blobID = -{{{ cDefs.EACCES }}}; } else { #if ASSERTIONS err('unexpected error:', e, e.stack); #endif - blobID = -{{{ cDefine('EIO') }}}; + blobID = -{{{ cDefs.EIO }}}; } } {{{ makeSetValue('blobIDPtr', 0, 'blobID', 'i32') }}}; @@ -228,7 +228,7 @@ mergeInto(LibraryManager.library, { try { await accessHandle.close(); } catch { - let err = -{{{ cDefine('EIO') }}}; + let err = -{{{ cDefs.EIO }}}; {{{ makeSetValue('errPtr', 0, 'err', 'i32') }}}; } wasmfsOPFSAccessHandles.free(accessID); @@ -248,12 +248,12 @@ mergeInto(LibraryManager.library, { return accessHandle.read(data, {at: pos}); } catch (e) { if (e.name == "TypeError") { - return -{{{ cDefine('EINVAL') }}}; + return -{{{ cDefs.EINVAL }}}; } #if ASSERTIONS err('unexpected error:', e, e.stack); #endif - return -{{{ cDefine('EIO') }}}; + return -{{{ cDefs.EIO }}}; } }, @@ -273,12 +273,12 @@ mergeInto(LibraryManager.library, { nread += data.length; } catch (e) { if (e instanceof RangeError) { - nread = -{{{ cDefine('EFAULT') }}}; + nread = -{{{ cDefs.EFAULT }}}; } else { #if ASSERTIONS err('unexpected error:', e, e.stack); #endif - nread = -{{{ cDefine('EIO') }}}; + nread = -{{{ cDefs.EIO }}}; } } @@ -294,12 +294,12 @@ mergeInto(LibraryManager.library, { return accessHandle.write(data, {at: pos}); } catch (e) { if (e.name == "TypeError") { - return -{{{ cDefine('EINVAL') }}}; + return -{{{ cDefs.EINVAL }}}; } #if ASSERTIONS err('unexpected error:', e, e.stack); #endif - return -{{{ cDefine('EIO') }}}; + return -{{{ cDefs.EIO }}}; } }, @@ -310,7 +310,7 @@ mergeInto(LibraryManager.library, { try { size = await accessHandle.getSize(); } catch { - size = -{{{ cDefine('EIO') }}}; + size = -{{{ cDefs.EIO }}}; } {{{ makeSetValue('sizePtr', 0, 'size', 'i64') }}}; _emscripten_proxy_finish(ctx); @@ -329,7 +329,7 @@ mergeInto(LibraryManager.library, { try { size = (await fileHandle.getFile()).size; } catch { - size = -{{{ cDefine('EIO') }}}; + size = -{{{ cDefs.EIO }}}; } {{{ makeSetValue('sizePtr', 0, 'size', 'i64') }}}; _emscripten_proxy_finish(ctx); @@ -344,7 +344,7 @@ mergeInto(LibraryManager.library, { try { await accessHandle.truncate(size); } catch { - let err = -{{{ cDefine('EIO') }}}; + let err = -{{{ cDefs.EIO }}}; {{{ makeSetValue('errPtr', 0, 'err', 'i32') }}}; } _emscripten_proxy_finish(ctx); @@ -361,7 +361,7 @@ mergeInto(LibraryManager.library, { await writable.truncate(size); await writable.close(); } catch { - let err = -{{{ cDefine('EIO') }}}; + let err = -{{{ cDefs.EIO }}}; {{{ makeSetValue('errPtr', 0, 'err', 'i32') }}}; } _emscripten_proxy_finish(ctx); @@ -373,7 +373,7 @@ mergeInto(LibraryManager.library, { try { await accessHandle.flush(); } catch { - let err = -{{{ cDefine('EIO') }}}; + let err = -{{{ cDefs.EIO }}}; {{{ makeSetValue('errPtr', 0, 'err', 'i32') }}}; } _emscripten_proxy_finish(ctx); diff --git a/src/library_webgl.js b/src/library_webgl.js index 13d09d1e4e6e6..a63d287ef96db 100644 --- a/src/library_webgl.js +++ b/src/library_webgl.js @@ -1241,7 +1241,7 @@ var LibraryGL = { break; case 0x8DF8: // GL_SHADER_BINARY_FORMATS #if GL_TRACK_ERRORS - if (type != {{{ cDefine('EM_FUNC_SIG_PARAM_I') }}} && type != {{{ cDefine('EM_FUNC_SIG_PARAM_I64') }}}) { + if (type != {{{ cDefs.EM_FUNC_SIG_PARAM_I }}} && type != {{{ cDefs.EM_FUNC_SIG_PARAM_I64 }}}) { GL.recordError(0x500); // GL_INVALID_ENUM #if GL_ASSERTIONS err('GL_INVALID_ENUM in glGet' + type + 'v(GL_SHADER_BINARY_FORMATS): Invalid parameter type!'); @@ -1357,9 +1357,9 @@ var LibraryGL = { result instanceof Array) { for (var i = 0; i < result.length; ++i) { switch (type) { - case {{{ cDefine('EM_FUNC_SIG_PARAM_I') }}}: {{{ makeSetValue('p', 'i*4', 'result[i]', 'i32') }}}; break; - case {{{ cDefine('EM_FUNC_SIG_PARAM_F') }}}: {{{ makeSetValue('p', 'i*4', 'result[i]', 'float') }}}; break; - case {{{ cDefine('EM_FUNC_SIG_PARAM_B') }}}: {{{ makeSetValue('p', 'i', 'result[i] ? 1 : 0', 'i8') }}}; break; + case {{{ cDefs.EM_FUNC_SIG_PARAM_I }}}: {{{ makeSetValue('p', 'i*4', 'result[i]', 'i32') }}}; break; + case {{{ cDefs.EM_FUNC_SIG_PARAM_F }}}: {{{ makeSetValue('p', 'i*4', 'result[i]', 'float') }}}; break; + case {{{ cDefs.EM_FUNC_SIG_PARAM_B }}}: {{{ makeSetValue('p', 'i', 'result[i] ? 1 : 0', 'i8') }}}; break; #if GL_ASSERTIONS default: throw 'internal glGet error, bad type: ' + type; #endif @@ -1390,10 +1390,10 @@ var LibraryGL = { } switch (type) { - case {{{ cDefine('EM_FUNC_SIG_PARAM_I64') }}}: writeI53ToI64(p, ret); break; - case {{{ cDefine('EM_FUNC_SIG_PARAM_I') }}}: {{{ makeSetValue('p', '0', 'ret', 'i32') }}}; break; - case {{{ cDefine('EM_FUNC_SIG_PARAM_F') }}}: {{{ makeSetValue('p', '0', 'ret', 'float') }}}; break; - case {{{ cDefine('EM_FUNC_SIG_PARAM_B') }}}: {{{ makeSetValue('p', '0', 'ret ? 1 : 0', 'i8') }}}; break; + case {{{ cDefs.EM_FUNC_SIG_PARAM_I64 }}}: writeI53ToI64(p, ret); break; + case {{{ cDefs.EM_FUNC_SIG_PARAM_I }}}: {{{ makeSetValue('p', '0', 'ret', 'i32') }}}; break; + case {{{ cDefs.EM_FUNC_SIG_PARAM_F }}}: {{{ makeSetValue('p', '0', 'ret', 'float') }}}; break; + case {{{ cDefs.EM_FUNC_SIG_PARAM_B }}}: {{{ makeSetValue('p', '0', 'ret ? 1 : 0', 'i8') }}}; break; #if GL_ASSERTIONS default: throw 'internal glGet error, bad type: ' + type; #endif @@ -1403,19 +1403,19 @@ var LibraryGL = { glGetIntegerv__sig: 'vip', glGetIntegerv__deps: ['$emscriptenWebGLGet'], glGetIntegerv: function(name_, p) { - emscriptenWebGLGet(name_, p, {{{ cDefine('EM_FUNC_SIG_PARAM_I') }}}); + emscriptenWebGLGet(name_, p, {{{ cDefs.EM_FUNC_SIG_PARAM_I }}}); }, glGetFloatv__sig: 'vip', glGetFloatv__deps: ['$emscriptenWebGLGet'], glGetFloatv: function(name_, p) { - emscriptenWebGLGet(name_, p, {{{ cDefine('EM_FUNC_SIG_PARAM_F') }}}); + emscriptenWebGLGet(name_, p, {{{ cDefs.EM_FUNC_SIG_PARAM_F }}}); }, glGetBooleanv__sig: 'vip', glGetBooleanv__deps: ['$emscriptenWebGLGet'], glGetBooleanv: function(name_, p) { - emscriptenWebGLGet(name_, p, {{{ cDefine('EM_FUNC_SIG_PARAM_B') }}}); + emscriptenWebGLGet(name_, p, {{{ cDefs.EM_FUNC_SIG_PARAM_B }}}); }, glDeleteTextures__sig: 'vip', @@ -2034,8 +2034,8 @@ var LibraryGL = { var data = GLctx.getUniform(program, webglGetUniformLocation(location)); if (typeof data == 'number' || typeof data == 'boolean') { switch (type) { - case {{{ cDefine('EM_FUNC_SIG_PARAM_I') }}}: {{{ makeSetValue('params', '0', 'data', 'i32') }}}; break; - case {{{ cDefine('EM_FUNC_SIG_PARAM_F') }}}: {{{ makeSetValue('params', '0', 'data', 'float') }}}; break; + case {{{ cDefs.EM_FUNC_SIG_PARAM_I }}}: {{{ makeSetValue('params', '0', 'data', 'i32') }}}; break; + case {{{ cDefs.EM_FUNC_SIG_PARAM_F }}}: {{{ makeSetValue('params', '0', 'data', 'float') }}}; break; #if GL_ASSERTIONS default: throw 'internal emscriptenWebGLGetUniform() error, bad type: ' + type; #endif @@ -2043,8 +2043,8 @@ var LibraryGL = { } else { for (var i = 0; i < data.length; i++) { switch (type) { - case {{{ cDefine('EM_FUNC_SIG_PARAM_I') }}}: {{{ makeSetValue('params', 'i*4', 'data[i]', 'i32') }}}; break; - case {{{ cDefine('EM_FUNC_SIG_PARAM_F') }}}: {{{ makeSetValue('params', 'i*4', 'data[i]', 'float') }}}; break; + case {{{ cDefs.EM_FUNC_SIG_PARAM_I }}}: {{{ makeSetValue('params', 'i*4', 'data[i]', 'i32') }}}; break; + case {{{ cDefs.EM_FUNC_SIG_PARAM_F }}}: {{{ makeSetValue('params', 'i*4', 'data[i]', 'float') }}}; break; #if GL_ASSERTIONS default: throw 'internal emscriptenWebGLGetUniform() error, bad type: ' + type; #endif @@ -2056,13 +2056,13 @@ var LibraryGL = { glGetUniformfv__sig: 'viip', glGetUniformfv__deps: ['$emscriptenWebGLGetUniform'], glGetUniformfv: function(program, location, params) { - emscriptenWebGLGetUniform(program, location, params, {{{ cDefine('EM_FUNC_SIG_PARAM_F') }}}); + emscriptenWebGLGetUniform(program, location, params, {{{ cDefs.EM_FUNC_SIG_PARAM_F }}}); }, glGetUniformiv__sig: 'viip', glGetUniformiv__deps: ['$emscriptenWebGLGetUniform'], glGetUniformiv: function(program, location, params) { - emscriptenWebGLGetUniform(program, location, params, {{{ cDefine('EM_FUNC_SIG_PARAM_I') }}}); + emscriptenWebGLGetUniform(program, location, params, {{{ cDefs.EM_FUNC_SIG_PARAM_I }}}); }, // Returns the WebGLUniformLocation object corresponding to the location index integer on @@ -2229,9 +2229,9 @@ var LibraryGL = { {{{ makeSetValue('params', '0', 'data && data["name"]', 'i32') }}}; } else if (typeof data == 'number' || typeof data == 'boolean') { switch (type) { - case {{{ cDefine('EM_FUNC_SIG_PARAM_I') }}}: {{{ makeSetValue('params', '0', 'data', 'i32') }}}; break; - case {{{ cDefine('EM_FUNC_SIG_PARAM_F') }}}: {{{ makeSetValue('params', '0', 'data', 'float') }}}; break; - case {{{ cDefine('EM_FUNC_SIG_PARAM_F2I') }}}: {{{ makeSetValue('params', '0', 'Math.fround(data)', 'i32') }}}; break; + case {{{ cDefs.EM_FUNC_SIG_PARAM_I }}}: {{{ makeSetValue('params', '0', 'data', 'i32') }}}; break; + case {{{ cDefs.EM_FUNC_SIG_PARAM_F }}}: {{{ makeSetValue('params', '0', 'data', 'float') }}}; break; + case {{{ cDefs.EM_FUNC_SIG_PARAM_F2I }}}: {{{ makeSetValue('params', '0', 'Math.fround(data)', 'i32') }}}; break; #if GL_ASSERTIONS default: throw 'internal emscriptenWebGLGetVertexAttrib() error, bad type: ' + type; #endif @@ -2239,9 +2239,9 @@ var LibraryGL = { } else { for (var i = 0; i < data.length; i++) { switch (type) { - case {{{ cDefine('EM_FUNC_SIG_PARAM_I') }}}: {{{ makeSetValue('params', 'i*4', 'data[i]', 'i32') }}}; break; - case {{{ cDefine('EM_FUNC_SIG_PARAM_F') }}}: {{{ makeSetValue('params', 'i*4', 'data[i]', 'float') }}}; break; - case {{{ cDefine('EM_FUNC_SIG_PARAM_F2I') }}}: {{{ makeSetValue('params', 'i*4', 'Math.fround(data[i])', 'i32') }}}; break; + case {{{ cDefs.EM_FUNC_SIG_PARAM_I }}}: {{{ makeSetValue('params', 'i*4', 'data[i]', 'i32') }}}; break; + case {{{ cDefs.EM_FUNC_SIG_PARAM_F }}}: {{{ makeSetValue('params', 'i*4', 'data[i]', 'float') }}}; break; + case {{{ cDefs.EM_FUNC_SIG_PARAM_F2I }}}: {{{ makeSetValue('params', 'i*4', 'Math.fround(data[i])', 'i32') }}}; break; #if GL_ASSERTIONS default: throw 'internal emscriptenWebGLGetVertexAttrib() error, bad type: ' + type; #endif @@ -2255,7 +2255,7 @@ var LibraryGL = { glGetVertexAttribfv: function(index, pname, params) { // N.B. This function may only be called if the vertex attribute was specified using the function glVertexAttrib*f(), // otherwise the results are undefined. (GLES3 spec 6.1.12) - emscriptenWebGLGetVertexAttrib(index, pname, params, {{{ cDefine('EM_FUNC_SIG_PARAM_F') }}}); + emscriptenWebGLGetVertexAttrib(index, pname, params, {{{ cDefs.EM_FUNC_SIG_PARAM_F }}}); }, glGetVertexAttribiv__sig: 'viip', @@ -2263,7 +2263,7 @@ var LibraryGL = { glGetVertexAttribiv: function(index, pname, params) { // N.B. This function may only be called if the vertex attribute was specified using the function glVertexAttrib*f(), // otherwise the results are undefined. (GLES3 spec 6.1.12) - emscriptenWebGLGetVertexAttrib(index, pname, params, {{{ cDefine('EM_FUNC_SIG_PARAM_F2I') }}}); + emscriptenWebGLGetVertexAttrib(index, pname, params, {{{ cDefs.EM_FUNC_SIG_PARAM_F2I }}}); }, glGetVertexAttribPointerv__sig: 'viip', diff --git a/src/library_webgl2.js b/src/library_webgl2.js index 1b9ef5388e5c6..de44722ae3b8f 100644 --- a/src/library_webgl2.js +++ b/src/library_webgl2.js @@ -52,7 +52,7 @@ var LibraryWebGL2 = { glGetInteger64v__sig: 'vii', glGetInteger64v__deps: ['$emscriptenWebGLGet'], glGetInteger64v: function(name_, p) { - emscriptenWebGLGet(name_, p, {{{ cDefine('EM_FUNC_SIG_PARAM_I64') }}}); + emscriptenWebGLGet(name_, p, {{{ cDefs.EM_FUNC_SIG_PARAM_I64 }}}); }, glGetInternalformativ__sig: 'viiiii', @@ -495,10 +495,10 @@ var LibraryWebGL2 = { } switch (type) { - case {{{ cDefine('EM_FUNC_SIG_PARAM_I64') }}}: writeI53ToI64(data, ret); break; - case {{{ cDefine('EM_FUNC_SIG_PARAM_I') }}}: {{{ makeSetValue('data', '0', 'ret', 'i32') }}}; break; - case {{{ cDefine('EM_FUNC_SIG_PARAM_F') }}}: {{{ makeSetValue('data', '0', 'ret', 'float') }}}; break; - case {{{ cDefine('EM_FUNC_SIG_PARAM_B') }}}: {{{ makeSetValue('data', '0', 'ret ? 1 : 0', 'i8') }}}; break; + case {{{ cDefs.EM_FUNC_SIG_PARAM_I64 }}}: writeI53ToI64(data, ret); break; + case {{{ cDefs.EM_FUNC_SIG_PARAM_I }}}: {{{ makeSetValue('data', '0', 'ret', 'i32') }}}; break; + case {{{ cDefs.EM_FUNC_SIG_PARAM_F }}}: {{{ makeSetValue('data', '0', 'ret', 'float') }}}; break; + case {{{ cDefs.EM_FUNC_SIG_PARAM_B }}}: {{{ makeSetValue('data', '0', 'ret ? 1 : 0', 'i8') }}}; break; default: throw 'internal emscriptenWebGLGetIndexed() error, bad type: ' + type; } }, @@ -506,13 +506,13 @@ var LibraryWebGL2 = { glGetIntegeri_v__sig: 'viii', glGetIntegeri_v__deps: ['$emscriptenWebGLGetIndexed'], glGetIntegeri_v: function(target, index, data) { - emscriptenWebGLGetIndexed(target, index, data, {{{ cDefine('EM_FUNC_SIG_PARAM_I') }}}); + emscriptenWebGLGetIndexed(target, index, data, {{{ cDefs.EM_FUNC_SIG_PARAM_I }}}); }, glGetInteger64i_v__sig: 'viii', glGetInteger64i_v__deps: ['$emscriptenWebGLGetIndexed'], glGetInteger64i_v: function(target, index, data) { - emscriptenWebGLGetIndexed(target, index, data, {{{ cDefine('EM_FUNC_SIG_PARAM_I64') }}}); + emscriptenWebGLGetIndexed(target, index, data, {{{ cDefs.EM_FUNC_SIG_PARAM_I64 }}}); }, // Uniform Buffer objects @@ -783,7 +783,7 @@ var LibraryWebGL2 = { glGetUniformuiv__sig: 'viii', glGetUniformuiv__deps: ['$emscriptenWebGLGetUniform'], glGetUniformuiv: function(program, location, params) { - emscriptenWebGLGetUniform(program, location, params, {{{ cDefine('EM_FUNC_SIG_PARAM_I') }}}); + emscriptenWebGLGetUniform(program, location, params, {{{ cDefs.EM_FUNC_SIG_PARAM_I }}}); }, glGetFragDataLocation__sig: 'iii', @@ -799,7 +799,7 @@ var LibraryWebGL2 = { glGetVertexAttribIiv: function(index, pname, params) { // N.B. This function may only be called if the vertex attribute was specified using the function glVertexAttribI4iv(), // otherwise the results are undefined. (GLES3 spec 6.1.12) - emscriptenWebGLGetVertexAttrib(index, pname, params, {{{ cDefine('EM_FUNC_SIG_PARAM_I') }}}); + emscriptenWebGLGetVertexAttrib(index, pname, params, {{{ cDefs.EM_FUNC_SIG_PARAM_I }}}); }, // N.B. This function may only be called if the vertex attribute was specified using the function glVertexAttribI4uiv(), diff --git a/src/library_websocket.js b/src/library_websocket.js index ff6fbc55c9b4b..88f3f77839fff 100644 --- a/src/library_websocket.js +++ b/src/library_websocket.js @@ -19,11 +19,11 @@ var LibraryWebSocket = { #if WEBSOCKET_DEBUG dbg('emscripten_websocket_get_ready_state(): Invalid socket ID ' + socketId + ' specified!'); #endif - return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}}; } {{{ makeSetValue('readyState', '0', 'socket.readyState', 'i16') }}}; - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_websocket_get_buffered_amount__deps: ['$WS'], @@ -35,11 +35,11 @@ var LibraryWebSocket = { #if WEBSOCKET_DEBUG dbg('emscripten_websocket_get_buffered_amount(): Invalid socket ID ' + socketId + ' specified!'); #endif - return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}}; } {{{ makeSetValue('bufferedAmount', '0', 'socket.bufferedAmount', '*') }}}; - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_websocket_get_extensions__deps: ['$WS'], @@ -51,11 +51,11 @@ var LibraryWebSocket = { #if WEBSOCKET_DEBUG dbg('emscripten_websocket_get_extensions(): Invalid socket ID ' + socketId + ' specified!'); #endif - return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}}; } - if (!extensions) return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_PARAM') }}}; + if (!extensions) return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_PARAM }}}; stringToUTF8(socket.extensions, extensions, extensionsLength); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_websocket_get_extensions_length__deps: ['$WS'], @@ -67,11 +67,11 @@ var LibraryWebSocket = { #if WEBSOCKET_DEBUG dbg('emscripten_websocket_get_extensions_length(): Invalid socket ID ' + socketId + ' specified!'); #endif - return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}}; } - if (!extensionsLength) return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_PARAM') }}}; + if (!extensionsLength) return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_PARAM }}}; {{{ makeSetValue('extensionsLength', '0', 'lengthBytesUTF8(socket.extensions)+1', 'i32') }}}; - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_websocket_get_protocol__deps: ['$WS'], @@ -83,11 +83,11 @@ var LibraryWebSocket = { #if WEBSOCKET_DEBUG dbg('emscripten_websocket_get_protocol(): Invalid socket ID ' + socketId + ' specified!'); #endif - return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}}; } - if (!protocol) return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_PARAM') }}}; + if (!protocol) return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_PARAM }}}; stringToUTF8(socket.protocol, protocol, protocolLength); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_websocket_get_protocol_length__deps: ['$WS'], @@ -99,11 +99,11 @@ var LibraryWebSocket = { #if WEBSOCKET_DEBUG dbg('emscripten_websocket_get_protocol_length(): Invalid socket ID ' + socketId + ' specified!'); #endif - return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}}; } - if (!protocolLength) return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_PARAM') }}}; + if (!protocolLength) return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_PARAM }}}; {{{ makeSetValue('protocolLength', '0', 'lengthBytesUTF8(socket.protocol)+1', 'i32') }}}; - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_websocket_get_url__deps: ['$WS'], @@ -115,11 +115,11 @@ var LibraryWebSocket = { #if WEBSOCKET_DEBUG dbg('emscripten_websocket_get_url(): Invalid socket ID ' + socketId + ' specified!'); #endif - return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}}; } - if (!url) return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_PARAM') }}}; + if (!url) return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_PARAM }}}; stringToUTF8(socket.url, url, urlLength); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_websocket_get_url_length__deps: ['$WS'], @@ -131,11 +131,11 @@ var LibraryWebSocket = { #if WEBSOCKET_DEBUG dbg('emscripten_websocket_get_url_length(): Invalid socket ID ' + socketId + ' specified!'); #endif - return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}}; } - if (!urlLength) return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_PARAM') }}}; + if (!urlLength) return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_PARAM }}}; {{{ makeSetValue('urlLength', '0', 'lengthBytesUTF8(socket.url)+1', 'i32') }}}; - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_websocket_set_onopen_callback_on_thread__deps: ['$WS'], @@ -143,7 +143,7 @@ var LibraryWebSocket = { emscripten_websocket_set_onopen_callback_on_thread__sig: 'iippp', emscripten_websocket_set_onopen_callback_on_thread: function(socketId, userData, callbackFunc, thread) { // TODO: -// if (thread == {{{ cDefine('EM_CALLBACK_THREAD_CONTEXT_CALLING_THREAD') }}} || +// if (thread == {{{ cDefs.EM_CALLBACK_THREAD_CONTEXT_CALLING_THREAD }}} || // (thread == _pthread_self()) return emscripten_websocket_set_onopen_callback_on_calling_thread(socketId, userData, callbackFunc); if (!WS.socketEvent) WS.socketEvent = _malloc(1024); // TODO: sizeof(EmscriptenWebSocketCloseEvent), which is the largest event struct @@ -153,7 +153,7 @@ var LibraryWebSocket = { #if WEBSOCKET_DEBUG dbg('emscripten_websocket_set_onopen_callback(): Invalid socket ID ' + socketId + ' specified!'); #endif - return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}}; } #if WEBSOCKET_DEBUG @@ -166,7 +166,7 @@ var LibraryWebSocket = { HEAPU32[WS.socketEvent>>2] = socketId; {{{ makeDynCall('iiii', 'callbackFunc') }}}(0/*TODO*/, WS.socketEvent, userData); } - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_websocket_set_onerror_callback_on_thread__deps: ['$WS'], @@ -180,7 +180,7 @@ var LibraryWebSocket = { #if WEBSOCKET_DEBUG dbg('emscripten_websocket_set_onerror_callback(): Invalid socket ID ' + socketId + ' specified!'); #endif - return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}}; } #if WEBSOCKET_DEBUG @@ -193,7 +193,7 @@ var LibraryWebSocket = { HEAPU32[WS.socketEvent>>2] = socketId; {{{ makeDynCall('iiii', 'callbackFunc') }}}(0/*TODO*/, WS.socketEvent, userData); } - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_websocket_set_onclose_callback_on_thread__deps: ['$WS'], @@ -207,7 +207,7 @@ var LibraryWebSocket = { #if WEBSOCKET_DEBUG dbg('emscripten_websocket_set_onclose_callback(): Invalid socket ID ' + socketId + ' specified!'); #endif - return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}}; } #if WEBSOCKET_DEBUG @@ -223,7 +223,7 @@ var LibraryWebSocket = { stringToUTF8(e.reason, WS.socketEvent+10, 512); {{{ makeDynCall('iiii', 'callbackFunc') }}}(0/*TODO*/, WS.socketEvent, userData); } - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_websocket_set_onmessage_callback_on_thread__deps: ['$WS'], @@ -237,7 +237,7 @@ var LibraryWebSocket = { #if WEBSOCKET_DEBUG dbg('emscripten_websocket_set_onmessage_callback(): Invalid socket ID ' + socketId + ' specified!'); #endif - return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}}; } #if WEBSOCKET_DEBUG @@ -278,7 +278,7 @@ var LibraryWebSocket = { {{{ makeDynCall('iiii', 'callbackFunc') }}}(0/*TODO*/, WS.socketEvent, userData); _free(buf); } - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_websocket_new__deps: ['$WS'], @@ -289,13 +289,13 @@ var LibraryWebSocket = { #if WEBSOCKET_DEBUG dbg('emscripten_websocket_new(): WebSocket API is not supported by current browser)'); #endif - return {{{ cDefine('EMSCRIPTEN_RESULT_NOT_SUPPORTED') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; } if (!createAttributes) { #if WEBSOCKET_DEBUG dbg('emscripten_websocket_new(): Missing required "createAttributes" function parameter!'); #endif - return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_PARAM') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_PARAM }}}; } var createAttrs = createAttributes>>2; @@ -326,7 +326,7 @@ var LibraryWebSocket = { #if WEBSOCKET_DEBUG dbg('emscripten_websocket_send_utf8_text(): Invalid socket ID ' + socketId + ' specified!'); #endif - return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}}; } var str = UTF8ToString(textData); @@ -338,7 +338,7 @@ var LibraryWebSocket = { #endif #endif socket.send(str); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_websocket_send_binary__deps: ['$WS'], @@ -350,7 +350,7 @@ var LibraryWebSocket = { #if WEBSOCKET_DEBUG dbg('emscripten_websocket_send_binary(): Invalid socket ID ' + socketId + ' specified!'); #endif - return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}}; } #if WEBSOCKET_DEBUG @@ -370,7 +370,7 @@ var LibraryWebSocket = { #else socket.send({{{ makeHEAPView('U8', 'binaryData', 'binaryData+dataLength') }}}); #endif - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_websocket_close__deps: ['$WS'], @@ -382,7 +382,7 @@ var LibraryWebSocket = { #if WEBSOCKET_DEBUG dbg('emscripten_websocket_close(): Invalid socket ID ' + socketId + ' specified!'); #endif - return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}}; } var reasonStr = reason ? UTF8ToString(reason) : undefined; @@ -397,7 +397,7 @@ var LibraryWebSocket = { if (reason) socket.close(code || undefined, UTF8ToString(reason)); else if (code) socket.close(code); else socket.close(); - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_websocket_delete__deps: ['$WS'], @@ -409,7 +409,7 @@ var LibraryWebSocket = { #if WEBSOCKET_DEBUG dbg('emscripten_websocket_delete(): Invalid socket ID ' + socketId + ' specified!'); #endif - return {{{ cDefine('EMSCRIPTEN_RESULT_INVALID_TARGET') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}}; } #if WEBSOCKET_DEBUG @@ -417,7 +417,7 @@ var LibraryWebSocket = { #endif socket.onopen = socket.onerror = socket.onclose = socket.onmessage = null; delete WS.sockets[socketId]; - return {{{ cDefine('EMSCRIPTEN_RESULT_SUCCESS') }}}; + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, emscripten_websocket_is_supported__proxy: 'sync', diff --git a/src/library_workerfs.js b/src/library_workerfs.js index 09a4ba945fe34..d1ac1f54b05ab 100644 --- a/src/library_workerfs.js +++ b/src/library_workerfs.js @@ -7,8 +7,8 @@ mergeInto(LibraryManager.library, { $WORKERFS__deps: ['$FS'], $WORKERFS: { - DIR_MODE: {{{ cDefine('S_IFDIR') }}} | 511 /* 0777 */, - FILE_MODE: {{{ cDefine('S_IFREG') }}} | 511 /* 0777 */, + DIR_MODE: {{{ cDefs.S_IFDIR }}} | 511 /* 0777 */, + FILE_MODE: {{{ cDefs.S_IFREG }}} | 511 /* 0777 */, reader: null, mount: function (mount) { assert(ENVIRONMENT_IS_WORKER); @@ -100,19 +100,19 @@ mergeInto(LibraryManager.library, { } }, lookup: function(parent, name) { - throw new FS.ErrnoError({{{ cDefine('ENOENT') }}}); + throw new FS.ErrnoError({{{ cDefs.ENOENT }}}); }, mknod: function (parent, name, mode, dev) { - throw new FS.ErrnoError({{{ cDefine('EPERM') }}}); + throw new FS.ErrnoError({{{ cDefs.EPERM }}}); }, rename: function (oldNode, newDir, newName) { - throw new FS.ErrnoError({{{ cDefine('EPERM') }}}); + throw new FS.ErrnoError({{{ cDefs.EPERM }}}); }, unlink: function(parent, name) { - throw new FS.ErrnoError({{{ cDefine('EPERM') }}}); + throw new FS.ErrnoError({{{ cDefs.EPERM }}}); }, rmdir: function(parent, name) { - throw new FS.ErrnoError({{{ cDefine('EPERM') }}}); + throw new FS.ErrnoError({{{ cDefs.EPERM }}}); }, readdir: function(node) { var entries = ['.', '..']; @@ -125,7 +125,7 @@ mergeInto(LibraryManager.library, { return entries; }, symlink: function(parent, newName, oldPath) { - throw new FS.ErrnoError({{{ cDefine('EPERM') }}}); + throw new FS.ErrnoError({{{ cDefs.EPERM }}}); }, }, stream_ops: { @@ -137,19 +137,19 @@ mergeInto(LibraryManager.library, { return chunk.size; }, write: function (stream, buffer, offset, length, position) { - throw new FS.ErrnoError({{{ cDefine('EIO') }}}); + throw new FS.ErrnoError({{{ cDefs.EIO }}}); }, llseek: function (stream, offset, whence) { var position = offset; - if (whence === {{{ cDefine('SEEK_CUR') }}}) { + if (whence === {{{ cDefs.SEEK_CUR }}}) { position += stream.position; - } else if (whence === {{{ cDefine('SEEK_END') }}}) { + } else if (whence === {{{ cDefs.SEEK_END }}}) { if (FS.isFile(stream.node.mode)) { position += stream.node.size; } } if (position < 0) { - throw new FS.ErrnoError({{{ cDefine('EINVAL') }}}); + throw new FS.ErrnoError({{{ cDefs.EINVAL }}}); } return position; }, diff --git a/src/modules.js b/src/modules.js index 91ecbbb13f29b..cb8b22495d378 100644 --- a/src/modules.js +++ b/src/modules.js @@ -255,10 +255,30 @@ if (!BOOTSTRAPPING_STRUCT_INFO) { C_DEFINES = {}; } -// Safe way to access a C define. We check that we don't add library functions with missing defines. +// Use proxy objects for C_DEFINES and C_STRUCTS so that we can give useful +// error messages. +C_STRUCTS = new Proxy(C_STRUCTS, { + get(target, prop, receiver) { + if (!(prop in target)) { + throw new Error(`Missing C struct ${prop}! If you just added it to struct_info.json, you need to ./emcc --clear-cache`); + } + return target[prop] + } +}); + +cDefs = C_DEFINES = new Proxy(C_DEFINES, { + get(target, prop, receiver) { + if (!(prop in target)) { + throw new Error(`Missing C define ${prop}! If you just added it to struct_info.json, you need to ./emcc --clear-cache`); + } + return target[prop] + } +}); + +// Legacy function that existed solely to give error message. These are now +// provided by the cDefs proxy object above. function cDefine(key) { - if (key in C_DEFINES) return C_DEFINES[key]; - throw new Error(`Missing C define ${key}! If you just added it to struct_info.json, you need to ./emcc --clear-cache`); + return cDefs[key]; } function isFSPrefixed(name) { diff --git a/src/worker.js b/src/worker.js index ba539688cf0bd..12de2659763a6 100644 --- a/src/worker.js +++ b/src/worker.js @@ -255,7 +255,7 @@ function handleMessage(e) { } } else if (e.data.cmd === 'cancel') { // Main thread is asking for a pthread_cancel() on this thread. if (Module['_pthread_self']()) { - Module['__emscripten_thread_exit']({{{ cDefine('PTHREAD_CANCELED') }}}); + Module['__emscripten_thread_exit']({{{ cDefs.PTHREAD_CANCELED }}}); } } else if (e.data.target === 'setimmediate') { // no-op diff --git a/test/test_other.py b/test/test_other.py index a41b1cfa83e71..60d70f9717e81 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -13252,3 +13252,16 @@ def test_pthreads_flag(self): # See https://github.com/llvm/llvm-project/commit/c800391fb974cdaaa62bd74435f76408c2e5ceae err = self.expect_fail([EMCC, '-pthreads', '-c', test_file('hello_world.c')]) self.assertContained('emcc: error: unrecognized command-line option `-pthreads`; did you mean `-pthread`?', err) + + def test_missing_struct_info(self): + create_file('lib.js', ''' + {{{ C_STRUCTS.Foo }}} + ''') + err = self.expect_fail([EMCC, test_file('hello_world.c'), '--js-library=lib.js']) + self.assertContained('Error: Missing C struct Foo! If you just added it to struct_info.json, you need to ./emcc --clear-cache', err) + + create_file('lib.js', ''' + {{{ C_DEFINES.Foo }}} + ''') + err = self.expect_fail([EMCC, test_file('hello_world.c'), '--js-library=lib.js']) + self.assertContained('Error: Missing C define Foo! If you just added it to struct_info.json, you need to ./emcc --clear-cache', err) diff --git a/tools/maint/check_struct_info.py b/tools/maint/check_struct_info.py index 5b601404139a5..692c6f13572c4 100755 --- a/tools/maint/check_struct_info.py +++ b/tools/maint/check_struct_info.py @@ -34,7 +34,7 @@ def check_structs(info): def check_defines(info): for define in info['defines'].keys(): - key = 'cDefine(.' + define + '.)' + key = r'cDefs\.' + define + r'\>' # grep --quiet ruturns 0 when there is a match if subprocess.run(['git', 'grep', '--quiet', key], check=False).returncode != 0: print(define) From 3266e421a34e23a32db0b9152ce6a4488e55e848 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 20 Mar 2023 16:30:00 -0700 Subject: [PATCH 0033/1523] Update SDL_image port to 2.6.0 (#19014) This seems to be the latest release that exists on the SDL2 branch of the upstream repository. I verified that both of own downstream patches that we had in the emscripten-ports fork have since landed upstream: https://github.com/libsdl-org/SDL_image/commit/1d92df494 https://github.com/libsdl-org/SDL_image/commit/840782235 I also verified that both of these made it into the 2.6.0 release. This change is needed as part of #19004 but it also allows us to delete our fork which is nice. --- ChangeLog.md | 1 + tools/ports/sdl2_image.py | 11 ++++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 7eb007aa20c47..e8f00c48d1de9 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -20,6 +20,7 @@ See docs/process.md for more on how version tagging works. 3.1.35 (in development) ----------------------- +- `SDL_image` port was updated to version 2.6.0. - `-z` arguments are now passed directly to wasm-ld without the need for the `-Wl,` prefix. This matches the behaviour of both clang and gcc. (#18956) - Reverted #18525 which runs the JS pre-processor over files passed via diff --git a/tools/ports/sdl2_image.py b/tools/ports/sdl2_image.py index 9af62c32fab73..baa1c54d20cbc 100644 --- a/tools/ports/sdl2_image.py +++ b/tools/ports/sdl2_image.py @@ -5,8 +5,8 @@ import os -TAG = 'version_4' -HASH = '30a7b04652239bccff3cb1fa7cd8ae602791b5f502a96df39585c13ebc4bb2b64ba1598c0d1f5382028d94e04a5ca02185ea06bf7f4b3520f6df4cc253f9dd24' +TAG = 'release-2.6.0' +HASH = '2175d11a90211871f2289c8d57b31fe830e4b46af7361925c2c30cd521c1c677d2ee244feb682b6d3909cf085129255934751848fc81b480ea410952d990ffe0' deps = ['sdl2'] variants = { @@ -32,14 +32,15 @@ def get_lib_name(settings): def get(ports, settings, shared): sdl_build = os.path.join(ports.get_build_dir(), 'sdl2') assert os.path.exists(sdl_build), 'You must use SDL2 to use SDL2_image' - ports.fetch_project('sdl2_image', f'https://github.com/emscripten-ports/SDL2_image/archive/{TAG}.zip', sha512hash=HASH) + ports.fetch_project('sdl2_image', f'https://github.com/libsdl-org/SDL_image/archive/refs/tags/{TAG}.zip', sha512hash=HASH) libname = get_lib_name(settings) def create(final): - src_dir = os.path.join(ports.get_dir(), 'sdl2_image', 'SDL2_image-' + TAG) + src_dir = os.path.join(ports.get_dir(), 'sdl2_image', 'SDL_image-' + TAG) ports.install_headers(src_dir, target='SDL2') srcs = '''IMG.c IMG_bmp.c IMG_gif.c IMG_jpg.c IMG_lbm.c IMG_pcx.c IMG_png.c IMG_pnm.c IMG_tga.c - IMG_tif.c IMG_xcf.c IMG_xpm.c IMG_xv.c IMG_webp.c IMG_ImageIO.m'''.split() + IMG_tif.c IMG_xcf.c IMG_xpm.c IMG_xv.c IMG_webp.c IMG_ImageIO.m + IMG_avif.c IMG_jxl.c IMG_svg.c IMG_qoi.c'''.split() defs = ['-O2', '-sUSE_SDL=2', '-Wno-format-security'] From 7e5ab40c81ccc338404274c77f3a73ef7641e2bf Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 20 Mar 2023 17:51:01 -0700 Subject: [PATCH 0034/1523] Store generated struct info rather than auto-generating it in the sysroot. NFC (#19013) I noticed while working `gen_sig_info.py` in #18985 that is was simpler to just keep a copy of the generated file checked into source control. We can use a unit test check that its up-to-date on each commit. In fact we already had a unit test that was doing this and keeping a copy of the expected output in the test directory. This simplifies the emcc linker code since we can always assume the presence of the struct info file. Also allows us to remove the `varies=False` special case in cache logic. --- embuilder.py | 12 - emcc.py | 1 - emscripten.py | 23 - .../docs/contributing/developers_guide.rst | 13 +- .../generated_struct_info32.json | 0 src/generated_struct_info64.json | 1455 +++++++++++++++++ src/modules.js | 10 +- src/parseTools.js | 2 +- src/settings_internal.js | 3 - system/include/webgpu/README.md | 4 +- test/test_other.py | 18 +- tools/cache.py | 8 +- tools/gen_struct_info.py | 28 +- tools/maint/check_struct_info.py | 7 +- 14 files changed, 1508 insertions(+), 76 deletions(-) rename test/reference_struct_info.json => src/generated_struct_info32.json (100%) create mode 100644 src/generated_struct_info64.json diff --git a/embuilder.py b/embuilder.py index 993a30f272fca..ce514f94d8ad8 100755 --- a/embuilder.py +++ b/embuilder.py @@ -24,7 +24,6 @@ from tools import ports from tools.settings import settings from tools.system_libs import USE_NINJA -import emscripten # Minimal subset of targets used by CI systems to build enough to useful @@ -61,7 +60,6 @@ 'libsockets', 'libstubs', 'libstubs-debug', - 'struct_info', 'libstandalonewasm', 'crt1', 'crt1_proxy_main', @@ -150,11 +148,6 @@ def build_port(port_name): def get_system_tasks(): system_libraries = system_libs.Library.get_all_variations() system_tasks = list(system_libraries.keys()) - # This is needed to build the generated_struct_info.json file. - # It is not a system library, but it needs to be built before - # running with FROZEN_CACHE. - system_tasks += ['struct_info'] - return system_libraries, system_tasks @@ -257,11 +250,6 @@ def main(): cache.erase_file('sysroot_install.stamp') if do_build: system_libs.ensure_sysroot() - elif what == 'struct_info': - if do_clear: - emscripten.clear_struct_info() - if do_build: - emscripten.generate_struct_info() elif what in PORTS: if do_clear: clear_port(what) diff --git a/emcc.py b/emcc.py index d72412d4a05dd..61b0fffee9ea6 100755 --- a/emcc.py +++ b/emcc.py @@ -514,7 +514,6 @@ def generate_js_symbols(): # TODO(sbc): Find a way to optimize this. Potentially we could add a super-set # mode of the js compiler that would generate a list of all possible symbols # that could be checked in. - emscripten.generate_struct_info() _, forwarded_data = emscripten.compile_javascript(symbols_only=True) # When running in symbols_only mode compiler.js outputs a flat list of C symbols. return json.loads(forwarded_data) diff --git a/emscripten.py b/emscripten.py index 7bcf128704451..41d750aee4c19 100644 --- a/emscripten.py +++ b/emscripten.py @@ -20,12 +20,10 @@ import shutil from tools import building -from tools import cache from tools import diagnostics from tools import js_manipulation from tools import shared from tools import utils -from tools import gen_struct_info from tools import webassembly from tools import extract_metadata from tools.utils import exit_with_error, path_from_root @@ -920,26 +918,5 @@ def normalize_line_endings(text): return text -def clear_struct_info(): - output_name = cache.get_lib_name('struct_info.json', varies=False) - cache.erase_file(output_name) - - -def generate_struct_info(): - # If we are running in BOOTSTRAPPING_STRUCT_INFO we don't populate STRUCT_INFO - # otherwise that would lead to infinite recursion. - if settings.BOOTSTRAPPING_STRUCT_INFO: - return - - @ToolchainProfiler.profile() - def generate_struct_info(out): - gen_struct_info.main(['-q', '-o', out]) - - output_name = cache.get_lib_name('struct_info.json', varies=False) - settings.STRUCT_INFO = cache.get(output_name, generate_struct_info) - - def run(in_wasm, out_wasm, outfile_js, memfile): - generate_struct_info() - emscript(in_wasm, out_wasm, outfile_js, memfile) diff --git a/site/source/docs/contributing/developers_guide.rst b/site/source/docs/contributing/developers_guide.rst index ee733dd2a0242..ee0666ef35bc4 100644 --- a/site/source/docs/contributing/developers_guide.rst +++ b/site/source/docs/contributing/developers_guide.rst @@ -151,10 +151,19 @@ one of them, with the others kept fixed). Doing this will require rebuilding locally, which was not needed in the main bisection described in this section. +Working with C structs and defines +================================== + +If you change the layout of C structs or modify C defines that are used in +JavaScript library files you may need to modify ``tools/struct_info.json``. Any +time that file is modified or a struct layout is changed you will need to run +``./tools/gen_struct_info.py`` to re-generate the information used by +JavaScript. + +The ``test_gen_struct_info`` test will fail if you forget to do this. + See also ======== - :ref:`Debugging` - :ref:`Building-Projects` - - diff --git a/test/reference_struct_info.json b/src/generated_struct_info32.json similarity index 100% rename from test/reference_struct_info.json rename to src/generated_struct_info32.json diff --git a/src/generated_struct_info64.json b/src/generated_struct_info64.json new file mode 100644 index 0000000000000..d2265582696af --- /dev/null +++ b/src/generated_struct_info64.json @@ -0,0 +1,1455 @@ +{ + "defines": { + "AF_INET": 2, + "AF_INET6": 10, + "AF_UNSPEC": 0, + "AI_ADDRCONFIG": 32, + "AI_ALL": 16, + "AI_CANONNAME": 2, + "AI_NUMERICHOST": 4, + "AI_NUMERICSERV": 1024, + "AI_PASSIVE": 1, + "AI_V4MAPPED": 8, + "ALC_FALSE": 0, + "ALC_INVALID_DEVICE": 40961, + "ALC_INVALID_ENUM": 40963, + "ALC_INVALID_VALUE": 40964, + "ALC_NO_ERROR": 0, + "ALC_TRUE": 1, + "AL_DIRECTION": 4101, + "AL_DISTANCE_MODEL": 53248, + "AL_DOPPLER_FACTOR": 49152, + "AL_FALSE": 0, + "AL_GAIN": 4106, + "AL_INVALID_ENUM": 40962, + "AL_INVALID_NAME": 40961, + "AL_INVALID_OPERATION": 40964, + "AL_INVALID_VALUE": 40963, + "AL_NONE": 0, + "AL_NO_ERROR": 0, + "AL_ORIENTATION": 4111, + "AL_POSITION": 4100, + "AL_SPEED_OF_SOUND": 49155, + "AL_TRUE": 1, + "AL_VELOCITY": 4102, + "AT_EMPTY_PATH": 4096, + "AT_FDCWD": -100, + "AT_NO_AUTOMOUNT": 2048, + "AT_REMOVEDIR": 512, + "AT_SYMLINK_NOFOLLOW": 256, + "AUDIO_F32": 33056, + "AUDIO_S16LSB": 32784, + "AUDIO_U8": 8, + "CLOCK_REALTIME": 0, + "E2BIG": 1, + "EACCES": 2, + "EADDRINUSE": 3, + "EADDRNOTAVAIL": 4, + "EADV": 122, + "EAFNOSUPPORT": 5, + "EAGAIN": 6, + "EAI_AGAIN": -3, + "EAI_BADFLAGS": -1, + "EAI_FAIL": -4, + "EAI_FAMILY": -6, + "EAI_MEMORY": -10, + "EAI_NONAME": -2, + "EAI_OVERFLOW": -12, + "EAI_SERVICE": -8, + "EAI_SOCKTYPE": -7, + "EAI_SYSTEM": -11, + "EALREADY": 7, + "EBADE": 113, + "EBADF": 8, + "EBADFD": 127, + "EBADMSG": 9, + "EBADR": 114, + "EBADRQC": 103, + "EBADSLT": 102, + "EBFONT": 101, + "EBUSY": 10, + "ECANCELED": 11, + "ECHILD": 12, + "ECHRNG": 106, + "ECOMM": 124, + "ECONNABORTED": 13, + "ECONNREFUSED": 14, + "ECONNRESET": 15, + "EDEADLK": 16, + "EDEADLOCK": 16, + "EDESTADDRREQ": 17, + "EDOM": 18, + "EDOTDOT": 125, + "EDQUOT": 19, + "EEXIST": 20, + "EFAULT": 21, + "EFBIG": 22, + "EHOSTDOWN": 142, + "EHOSTUNREACH": 23, + "EIDRM": 24, + "EILSEQ": 25, + "EINPROGRESS": 26, + "EINTR": 27, + "EINVAL": 28, + "EIO": 29, + "EISCONN": 30, + "EISDIR": 31, + "EL2HLT": 112, + "EL2NSYNC": 156, + "EL3HLT": 107, + "EL3RST": 108, + "ELIBACC": 129, + "ELIBBAD": 130, + "ELIBEXEC": 133, + "ELIBMAX": 132, + "ELIBSCN": 131, + "ELNRNG": 109, + "ELOOP": 32, + "EMFILE": 33, + "EMLINK": 34, + "EMSCRIPTEN_DEVICE_MOTION_EVENT_SUPPORTS_ACCELERATION": 1, + "EMSCRIPTEN_DEVICE_MOTION_EVENT_SUPPORTS_ACCELERATION_INCLUDING_GRAVITY": 2, + "EMSCRIPTEN_DEVICE_MOTION_EVENT_SUPPORTS_ROTATION_RATE": 4, + "EMSCRIPTEN_EVENT_BATTERYCHARGINGCHANGE": 29, + "EMSCRIPTEN_EVENT_BATTERYLEVELCHANGE": 30, + "EMSCRIPTEN_EVENT_BEFOREUNLOAD": 28, + "EMSCRIPTEN_EVENT_BLUR": 12, + "EMSCRIPTEN_EVENT_CANVASRESIZED": 37, + "EMSCRIPTEN_EVENT_CLICK": 4, + "EMSCRIPTEN_EVENT_DBLCLICK": 7, + "EMSCRIPTEN_EVENT_DEVICEMOTION": 17, + "EMSCRIPTEN_EVENT_DEVICEORIENTATION": 16, + "EMSCRIPTEN_EVENT_FOCUS": 13, + "EMSCRIPTEN_EVENT_FOCUSIN": 14, + "EMSCRIPTEN_EVENT_FOCUSOUT": 15, + "EMSCRIPTEN_EVENT_FULLSCREENCHANGE": 19, + "EMSCRIPTEN_EVENT_GAMEPADCONNECTED": 26, + "EMSCRIPTEN_EVENT_GAMEPADDISCONNECTED": 27, + "EMSCRIPTEN_EVENT_KEYDOWN": 2, + "EMSCRIPTEN_EVENT_KEYPRESS": 1, + "EMSCRIPTEN_EVENT_KEYUP": 3, + "EMSCRIPTEN_EVENT_MOUSEDOWN": 5, + "EMSCRIPTEN_EVENT_MOUSEENTER": 33, + "EMSCRIPTEN_EVENT_MOUSELEAVE": 34, + "EMSCRIPTEN_EVENT_MOUSEMOVE": 8, + "EMSCRIPTEN_EVENT_MOUSEOUT": 36, + "EMSCRIPTEN_EVENT_MOUSEOVER": 35, + "EMSCRIPTEN_EVENT_MOUSEUP": 6, + "EMSCRIPTEN_EVENT_ORIENTATIONCHANGE": 18, + "EMSCRIPTEN_EVENT_POINTERLOCKCHANGE": 20, + "EMSCRIPTEN_EVENT_POINTERLOCKERROR": 38, + "EMSCRIPTEN_EVENT_RESIZE": 10, + "EMSCRIPTEN_EVENT_SCROLL": 11, + "EMSCRIPTEN_EVENT_TARGET_DOCUMENT": 1, + "EMSCRIPTEN_EVENT_TARGET_INVALID": 0, + "EMSCRIPTEN_EVENT_TARGET_SCREEN": 3, + "EMSCRIPTEN_EVENT_TARGET_WINDOW": 2, + "EMSCRIPTEN_EVENT_TOUCHCANCEL": 25, + "EMSCRIPTEN_EVENT_TOUCHEND": 23, + "EMSCRIPTEN_EVENT_TOUCHMOVE": 24, + "EMSCRIPTEN_EVENT_TOUCHSTART": 22, + "EMSCRIPTEN_EVENT_VISIBILITYCHANGE": 21, + "EMSCRIPTEN_EVENT_WEBGLCONTEXTLOST": 31, + "EMSCRIPTEN_EVENT_WEBGLCONTEXTRESTORED": 32, + "EMSCRIPTEN_EVENT_WHEEL": 9, + "EMSCRIPTEN_FETCH_APPEND": 8, + "EMSCRIPTEN_FETCH_LOAD_TO_MEMORY": 1, + "EMSCRIPTEN_FETCH_NO_DOWNLOAD": 32, + "EMSCRIPTEN_FETCH_PERSIST_FILE": 4, + "EMSCRIPTEN_FETCH_REPLACE": 16, + "EMSCRIPTEN_FETCH_STREAM_DATA": 2, + "EMSCRIPTEN_FETCH_SYNCHRONOUS": 64, + "EMSCRIPTEN_FETCH_WAITABLE": 128, + "EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_HIDEF": 2, + "EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_NONE": 0, + "EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_STDDEF": 1, + "EMSCRIPTEN_FULLSCREEN_FILTERING_BILINEAR": 2, + "EMSCRIPTEN_FULLSCREEN_FILTERING_DEFAULT": 0, + "EMSCRIPTEN_FULLSCREEN_FILTERING_NEAREST": 1, + "EMSCRIPTEN_FULLSCREEN_SCALE_ASPECT": 2, + "EMSCRIPTEN_FULLSCREEN_SCALE_CENTER": 3, + "EMSCRIPTEN_FULLSCREEN_SCALE_DEFAULT": 0, + "EMSCRIPTEN_FULLSCREEN_SCALE_STRETCH": 1, + "EMSCRIPTEN_RESULT_DEFERRED": 1, + "EMSCRIPTEN_RESULT_FAILED": -6, + "EMSCRIPTEN_RESULT_FAILED_NOT_DEFERRED": -2, + "EMSCRIPTEN_RESULT_INVALID_PARAM": -5, + "EMSCRIPTEN_RESULT_INVALID_TARGET": -3, + "EMSCRIPTEN_RESULT_NOT_SUPPORTED": -1, + "EMSCRIPTEN_RESULT_NO_DATA": -7, + "EMSCRIPTEN_RESULT_SUCCESS": 0, + "EMSCRIPTEN_RESULT_TIMED_OUT": -8, + "EMSCRIPTEN_RESULT_UNKNOWN_TARGET": -4, + "EMSCRIPTEN_WEBGL_CONTEXT_PROXY_ALWAYS": 2, + "EMSCRIPTEN_WEBGL_CONTEXT_PROXY_DISALLOW": 0, + "EMSCRIPTEN_WEBGL_CONTEXT_PROXY_FALLBACK": 1, + "EMSGSIZE": 35, + "EMULTIHOP": 36, + "EM_CALLBACK_THREAD_CONTEXT_CALLING_THREAD": 2, + "EM_CALLBACK_THREAD_CONTEXT_MAIN_RUNTIME_THREAD": 1, + "EM_FUNC_SIG_I": 536870912, + "EM_FUNC_SIG_II": 570425344, + "EM_FUNC_SIG_III": 603979776, + "EM_FUNC_SIG_IIII": 637534208, + "EM_FUNC_SIG_PARAM_B": 4, + "EM_FUNC_SIG_PARAM_D": 3, + "EM_FUNC_SIG_PARAM_F": 2, + "EM_FUNC_SIG_PARAM_F2I": 5, + "EM_FUNC_SIG_PARAM_I": 0, + "EM_FUNC_SIG_PARAM_I64": 1, + "EM_FUNC_SIG_V": 0, + "EM_FUNC_SIG_VI": 33554432, + "EM_FUNC_SIG_VII": 67108864, + "EM_FUNC_SIG_VIII": 100663296, + "EM_HTML5_LONG_STRING_LEN_BYTES": 128, + "EM_HTML5_MEDIUM_STRING_LEN_BYTES": 64, + "EM_HTML5_SHORT_STRING_LEN_BYTES": 32, + "EM_LOG_CONSOLE": 1, + "EM_LOG_C_STACK": 8, + "EM_LOG_DEBUG": 256, + "EM_LOG_DEMANGLE": 32, + "EM_LOG_ERROR": 4, + "EM_LOG_FUNC_PARAMS": 128, + "EM_LOG_INFO": 512, + "EM_LOG_JS_STACK": 16, + "EM_LOG_NO_PATHS": 64, + "EM_LOG_WARN": 2, + "EM_PROMISE_FULFILL": 0, + "EM_PROMISE_MATCH": 1, + "EM_PROMISE_MATCH_RELEASE": 2, + "EM_PROMISE_REJECT": 3, + "EM_PROXIED_RESIZE_OFFSCREENCANVAS": 654311424, + "EM_QUEUED_JS_CALL_MAX_ARGS": 20, + "ENAMETOOLONG": 37, + "ENETDOWN": 38, + "ENETRESET": 39, + "ENETUNREACH": 40, + "ENFILE": 41, + "ENOANO": 104, + "ENOBUFS": 42, + "ENOCSI": 111, + "ENODATA": 116, + "ENODEV": 43, + "ENOENT": 44, + "ENOEXEC": 45, + "ENOLCK": 46, + "ENOLINK": 47, + "ENOMEDIUM": 148, + "ENOMEM": 48, + "ENOMSG": 49, + "ENONET": 119, + "ENOPKG": 120, + "ENOPROTOOPT": 50, + "ENOSPC": 51, + "ENOSR": 118, + "ENOSTR": 100, + "ENOSYS": 52, + "ENOTBLK": 105, + "ENOTCONN": 53, + "ENOTDIR": 54, + "ENOTEMPTY": 55, + "ENOTRECOVERABLE": 56, + "ENOTSOCK": 57, + "ENOTSUP": 138, + "ENOTTY": 59, + "ENOTUNIQ": 126, + "ENXIO": 60, + "EOPNOTSUPP": 138, + "EOVERFLOW": 61, + "EOWNERDEAD": 62, + "EPERM": 63, + "EPFNOSUPPORT": 139, + "EPIPE": 64, + "EPROTO": 65, + "EPROTONOSUPPORT": 66, + "EPROTOTYPE": 67, + "ERANGE": 68, + "EREMCHG": 128, + "EREMOTE": 121, + "EROFS": 69, + "ESHUTDOWN": 140, + "ESOCKTNOSUPPORT": 137, + "ESPIPE": 70, + "ESRCH": 71, + "ESRMNT": 123, + "ESTALE": 72, + "ESTRPIPE": 135, + "ETIME": 117, + "ETIMEDOUT": 73, + "ETOOMANYREFS": 141, + "ETXTBSY": 74, + "EUNATCH": 110, + "EUSERS": 136, + "EWOULDBLOCK": 6, + "EXDEV": 75, + "EXFULL": 115, + "FIONREAD": 21531, + "F_DUPFD": 0, + "F_GETFD": 1, + "F_GETFL": 3, + "F_GETLK": 5, + "F_GETLK64": 5, + "F_GETOWN": 9, + "F_GETOWN_EX": 16, + "F_SETFD": 2, + "F_SETFL": 4, + "F_SETLK": 6, + "F_SETLK64": 6, + "F_SETLKW": 7, + "F_SETLKW64": 7, + "F_SETOWN": 8, + "F_UNLCK": 2, + "File::DataFileKind": 1, + "File::DirectoryKind": 2, + "File::SymlinkKind": 3, + "File::UnknownKind": 0, + "INADDR_LOOPBACK": 2130706433, + "IPPROTO_TCP": 6, + "IPPROTO_UDP": 17, + "MAP_ANONYMOUS": 32, + "MAP_FIXED": 16, + "MAP_PRIVATE": 2, + "NI_NAMEREQD": 8, + "NI_NUMERICHOST": 1, + "NOTIFICATION_NONE": 0, + "NOTIFICATION_PENDING": 2, + "NOTIFICATION_RECEIVED": 1, + "O_ACCMODE": 2097155, + "O_APPEND": 1024, + "O_CLOEXEC": 524288, + "O_CREAT": 64, + "O_DIRECTORY": 65536, + "O_DSYNC": 4096, + "O_EXCL": 128, + "O_LARGEFILE": 32768, + "O_NOCTTY": 256, + "O_NOFOLLOW": 131072, + "O_NONBLOCK": 2048, + "O_PATH": 2097152, + "O_RDONLY": 0, + "O_RDWR": 2, + "O_TRUNC": 512, + "O_WRONLY": 1, + "POLLERR": 8, + "POLLHUP": 16, + "POLLIN": 1, + "POLLNVAL": 32, + "POLLOUT": 4, + "POLLPRI": 2, + "POLLRDNORM": 64, + "POLLWRNORM": 256, + "PROT_WRITE": 2, + "PTHREAD_CANCELED": -1, + "RTLD_DEFAULT": 0, + "RTLD_GLOBAL": 256, + "RTLD_LAZY": 1, + "RTLD_NODELETE": 4096, + "RTLD_NOW": 2, + "R_OK": 4, + "SDL_PIXELFORMAT_RGBA8888": -2042224636, + "SDL_TOUCH_MOUSEID": -1, + "SEEK_CUR": 1, + "SEEK_END": 2, + "SEEK_SET": 0, + "SIGALRM": 14, + "SIGCANCEL": 33, + "SOCK_CLOEXEC": 524288, + "SOCK_DGRAM": 2, + "SOCK_NONBLOCK": 2048, + "SOCK_STREAM": 1, + "SOL_SOCKET": 1, + "SO_ERROR": 4, + "S_IALLUGO": 4095, + "S_IFBLK": 24576, + "S_IFCHR": 8192, + "S_IFDIR": 16384, + "S_IFIFO": 4096, + "S_IFLNK": 40960, + "S_IFMT": 61440, + "S_IFREG": 32768, + "S_IFSOCK": 49152, + "S_IRUGO": 292, + "S_IRWXO": 7, + "S_IRWXUGO": 511, + "S_ISVTX": 512, + "S_IWUGO": 146, + "S_IXUGO": 73, + "TCGETA": 21509, + "TCGETS": 21505, + "TCSETA": 21510, + "TCSETAF": 21512, + "TCSETAW": 21511, + "TCSETS": 21506, + "TCSETSF": 21508, + "TCSETSW": 21507, + "TIOCGPGRP": 21519, + "TIOCGWINSZ": 21523, + "TIOCSPGRP": 21520, + "TIOCSWINSZ": 21524, + "UUID_TYPE_DCE_RANDOM": 4, + "UUID_VARIANT_DCE": 1, + "W_OK": 2, + "X_OK": 1, + "__WASI_CLOCKID_MONOTONIC": 1, + "__WASI_CLOCKID_PROCESS_CPUTIME_ID": 2, + "__WASI_CLOCKID_REALTIME": 0, + "__WASI_CLOCKID_THREAD_CPUTIME_ID": 3, + "__WASI_FILETYPE_CHARACTER_DEVICE": 2, + "__WASI_FILETYPE_DIRECTORY": 3, + "__WASI_FILETYPE_REGULAR_FILE": 4, + "__WASI_FILETYPE_SYMBOLIC_LINK": 7 + }, + "structs": { + "EmscriptenBatteryEvent": { + "__size__": 32, + "charging": 24, + "chargingTime": 0, + "dischargingTime": 8, + "level": 16 + }, + "EmscriptenDeviceMotionEvent": { + "__size__": 80, + "accelerationIncludingGravityX": 24, + "accelerationIncludingGravityY": 32, + "accelerationIncludingGravityZ": 40, + "accelerationX": 0, + "accelerationY": 8, + "accelerationZ": 16, + "rotationRateAlpha": 48, + "rotationRateBeta": 56, + "rotationRateGamma": 64 + }, + "EmscriptenDeviceOrientationEvent": { + "__size__": 32, + "absolute": 24, + "alpha": 0, + "beta": 8, + "gamma": 16 + }, + "EmscriptenFocusEvent": { + "__size__": 256, + "id": 128, + "nodeName": 0 + }, + "EmscriptenFullscreenChangeEvent": { + "__size__": 280, + "elementHeight": 268, + "elementWidth": 264, + "fullscreenEnabled": 4, + "id": 136, + "isFullscreen": 0, + "nodeName": 8, + "screenHeight": 276, + "screenWidth": 272 + }, + "EmscriptenFullscreenStrategy": { + "__size__": 40, + "canvasResizedCallback": 16, + "canvasResizedCallbackTargetThread": 32, + "canvasResizedCallbackUserData": 24, + "canvasResolutionScaleMode": 4, + "filteringMode": 8, + "scaleMode": 0 + }, + "EmscriptenGamepadEvent": { + "__size__": 1440, + "analogButton": 528, + "axis": 16, + "connected": 1296, + "digitalButton": 1040, + "id": 1312, + "index": 1304, + "mapping": 1376, + "numAxes": 8, + "numButtons": 12, + "timestamp": 0 + }, + "EmscriptenKeyboardEvent": { + "__size__": 192, + "altKey": 24, + "charCode": 40, + "charValue": 128, + "code": 96, + "ctrlKey": 16, + "key": 64, + "keyCode": 48, + "locale": 160, + "location": 8, + "metaKey": 28, + "repeat": 32, + "shiftKey": 20, + "timestamp": 0, + "which": 56 + }, + "EmscriptenMouseEvent": { + "__size__": 120, + "altKey": 48, + "button": 56, + "buttons": 58, + "canvasX": 96, + "canvasY": 104, + "clientX": 24, + "clientY": 32, + "ctrlKey": 40, + "metaKey": 52, + "movementX": 64, + "movementY": 72, + "screenX": 8, + "screenY": 16, + "shiftKey": 44, + "targetX": 80, + "targetY": 88, + "timestamp": 0 + }, + "EmscriptenOrientationChangeEvent": { + "__size__": 8, + "orientationAngle": 4, + "orientationIndex": 0 + }, + "EmscriptenPointerlockChangeEvent": { + "__size__": 260, + "id": 132, + "isActive": 0, + "nodeName": 4 + }, + "EmscriptenTouchEvent": { + "__size__": 3104, + "altKey": 20, + "ctrlKey": 12, + "metaKey": 24, + "numTouches": 8, + "shiftKey": 16, + "timestamp": 0, + "touches": 32 + }, + "EmscriptenTouchPoint": { + "__size__": 96, + "canvasX": 80, + "canvasY": 88, + "clientX": 24, + "clientY": 32, + "identifier": 0, + "isChanged": 56, + "onTarget": 60, + "pageX": 40, + "pageY": 48, + "screenX": 8, + "screenY": 16, + "targetX": 64, + "targetY": 72 + }, + "EmscriptenUiEvent": { + "__size__": 40, + "detail": 0, + "documentBodyClientHeight": 12, + "documentBodyClientWidth": 8, + "scrollLeft": 36, + "scrollTop": 32, + "windowInnerHeight": 20, + "windowInnerWidth": 16, + "windowOuterHeight": 28, + "windowOuterWidth": 24 + }, + "EmscriptenVisibilityChangeEvent": { + "__size__": 8, + "hidden": 0, + "visibilityState": 4 + }, + "EmscriptenWebGLContextAttributes": { + "__size__": 56, + "alpha": 0, + "antialias": 12, + "depth": 4, + "enableExtensionsByDefault": 40, + "explicitSwapControl": 44, + "failIfMajorPerformanceCaveat": 28, + "majorVersion": 32, + "minorVersion": 36, + "powerPreference": 24, + "premultipliedAlpha": 16, + "preserveDrawingBuffer": 20, + "proxyContextToMainThread": 48, + "renderViaOffscreenBackBuffer": 52, + "stencil": 8 + }, + "EmscriptenWheelEvent": { + "__size__": 152, + "deltaMode": 144, + "deltaX": 120, + "deltaY": 128, + "deltaZ": 136, + "mouse": 0 + }, + "SDL_AudioSpec": { + "__size__": 32, + "callback": 16, + "channels": 6, + "format": 4, + "freq": 0, + "samples": 8, + "silence": 7, + "userdata": 24 + }, + "SDL_JoyAxisEvent": { + "__size__": 12, + "axis": 5, + "type": 0, + "value": 8, + "which": 4 + }, + "SDL_JoyButtonEvent": { + "__size__": 8, + "button": 5, + "state": 6, + "type": 0, + "which": 4 + }, + "SDL_KeyboardEvent": { + "__size__": 28, + "keysym": 12, + "repeat": 9, + "state": 8, + "type": 0 + }, + "SDL_Keysym": { + "__size__": 16, + "mod": 8, + "scancode": 0, + "sym": 4, + "unicode": 12 + }, + "SDL_MouseButtonEvent": { + "__size__": 28, + "button": 16, + "state": 17, + "timestamp": 4, + "type": 0, + "which": 12, + "windowID": 8, + "x": 20, + "y": 24 + }, + "SDL_MouseMotionEvent": { + "__size__": 36, + "state": 16, + "timestamp": 4, + "type": 0, + "which": 12, + "windowID": 8, + "x": 20, + "xrel": 28, + "y": 24, + "yrel": 32 + }, + "SDL_MouseWheelEvent": { + "__size__": 24, + "type": 0, + "x": 16, + "y": 20 + }, + "SDL_PixelFormat": { + "Amask": 32, + "BitsPerPixel": 16, + "Bmask": 28, + "BytesPerPixel": 17, + "Gmask": 24, + "Rmask": 20, + "__size__": 56, + "format": 0, + "palette": 8 + }, + "SDL_Rect": { + "__size__": 16, + "h": 12, + "w": 8, + "x": 0, + "y": 4 + }, + "SDL_ResizeEvent": { + "__size__": 12, + "h": 8, + "w": 4 + }, + "SDL_Surface": { + "__size__": 96, + "clip_rect": 64, + "flags": 0, + "format": 8, + "h": 20, + "pitch": 24, + "pixels": 32, + "refcount": 88, + "w": 16 + }, + "SDL_TextInputEvent": { + "__size__": 40, + "text": 8, + "type": 0 + }, + "SDL_TouchFingerEvent": { + "__size__": 48, + "dx": 32, + "dy": 36, + "fingerId": 16, + "pressure": 40, + "timestamp": 4, + "touchId": 8, + "type": 0, + "x": 24, + "y": 28 + }, + "SDL_VideoInfo": { + "__size__": 24, + "current_h": 20, + "current_w": 16 + }, + "SDL_WindowEvent": { + "__size__": 20, + "event": 8, + "type": 0, + "windowID": 4 + }, + "SDL_version": { + "__size__": 3, + "major": 0, + "minor": 1, + "patch": 2 + }, + "WGPUAdapterProperties": { + "__size__": 64, + "adapterType": 56, + "architecture": 24, + "backendType": 60, + "deviceID": 32, + "driverDescription": 48, + "name": 40, + "nextInChain": 0, + "vendorID": 8, + "vendorName": 16 + }, + "WGPUBindGroupDescriptor": { + "__size__": 40, + "entries": 32, + "entryCount": 24, + "label": 8, + "layout": 16, + "nextInChain": 0 + }, + "WGPUBindGroupEntry": { + "__size__": 56, + "binding": 8, + "buffer": 16, + "nextInChain": 0, + "offset": 24, + "sampler": 40, + "size": 32, + "textureView": 48 + }, + "WGPUBindGroupLayoutDescriptor": { + "__size__": 32, + "entries": 24, + "entryCount": 16, + "label": 8, + "nextInChain": 0 + }, + "WGPUBindGroupLayoutEntry": { + "__size__": 104, + "binding": 8, + "buffer": 16, + "nextInChain": 0, + "sampler": 40, + "storageTexture": 80, + "texture": 56, + "visibility": 12 + }, + "WGPUBlendComponent": { + "__size__": 12, + "dstFactor": 8, + "operation": 0, + "srcFactor": 4 + }, + "WGPUBlendState": { + "__size__": 24, + "alpha": 12, + "color": 0 + }, + "WGPUBufferBindingLayout": { + "__size__": 24, + "hasDynamicOffset": 12, + "minBindingSize": 16, + "nextInChain": 0, + "type": 8 + }, + "WGPUBufferDescriptor": { + "__size__": 40, + "label": 8, + "mappedAtCreation": 32, + "nextInChain": 0, + "size": 24, + "usage": 16 + }, + "WGPUChainedStruct": { + "__size__": 16, + "next": 0, + "sType": 8 + }, + "WGPUColor": { + "__size__": 32, + "a": 24, + "b": 16, + "g": 8, + "r": 0 + }, + "WGPUColorTargetState": { + "__size__": 32, + "blend": 16, + "format": 8, + "nextInChain": 0, + "writeMask": 24 + }, + "WGPUCommandBufferDescriptor": { + "__size__": 16, + "label": 8, + "nextInChain": 0 + }, + "WGPUCommandEncoderDescriptor": { + "__size__": 16, + "label": 8, + "nextInChain": 0 + }, + "WGPUCompilationInfo": { + "__size__": 24, + "messageCount": 8, + "messages": 16, + "nextInChain": 0 + }, + "WGPUCompilationMessage": { + "__size__": 56, + "length": 48, + "lineNum": 24, + "linePos": 32, + "message": 8, + "nextInChain": 0, + "offset": 40, + "type": 16 + }, + "WGPUComputePassDescriptor": { + "__size__": 32, + "label": 8, + "nextInChain": 0, + "timestampWriteCount": 16, + "timestampWrites": 24 + }, + "WGPUComputePassTimestampWrite": { + "__size__": 16, + "location": 12, + "queryIndex": 8, + "querySet": 0 + }, + "WGPUComputePipelineDescriptor": { + "__size__": 64, + "compute": 24, + "label": 8, + "layout": 16, + "nextInChain": 0 + }, + "WGPUConstantEntry": { + "__size__": 24, + "key": 8, + "nextInChain": 0, + "value": 16 + }, + "WGPUDepthStencilState": { + "__size__": 72, + "depthBias": 60, + "depthBiasClamp": 68, + "depthBiasSlopeScale": 64, + "depthCompare": 16, + "depthWriteEnabled": 12, + "format": 8, + "nextInChain": 0, + "stencilBack": 36, + "stencilFront": 20, + "stencilReadMask": 52, + "stencilWriteMask": 56 + }, + "WGPUDeviceDescriptor": { + "__size__": 56, + "defaultQueue": 40, + "label": 8, + "nextInChain": 0, + "requiredFeatures": 24, + "requiredFeaturesCount": 16, + "requiredLimits": 32 + }, + "WGPUExtent3D": { + "__size__": 12, + "depthOrArrayLayers": 8, + "height": 4, + "width": 0 + }, + "WGPUFragmentState": { + "__size__": 56, + "constantCount": 24, + "constants": 32, + "entryPoint": 16, + "module": 8, + "nextInChain": 0, + "targetCount": 40, + "targets": 48 + }, + "WGPUImageCopyBuffer": { + "__size__": 40, + "buffer": 32, + "layout": 8, + "nextInChain": 0 + }, + "WGPUImageCopyTexture": { + "__size__": 40, + "aspect": 32, + "mipLevel": 16, + "nextInChain": 0, + "origin": 20, + "texture": 8 + }, + "WGPUInstanceDescriptor": { + "__size__": 8, + "nextInChain": 0 + }, + "WGPULimits": { + "__size__": 120, + "maxBindGroups": 16, + "maxColorAttachments": 92, + "maxComputeInvocationsPerWorkgroup": 100, + "maxComputeWorkgroupSizeX": 104, + "maxComputeWorkgroupSizeY": 108, + "maxComputeWorkgroupSizeZ": 112, + "maxComputeWorkgroupStorageSize": 96, + "maxComputeWorkgroupsPerDimension": 116, + "maxDynamicStorageBuffersPerPipelineLayout": 24, + "maxDynamicUniformBuffersPerPipelineLayout": 20, + "maxInterStageShaderComponents": 84, + "maxInterStageShaderVariables": 88, + "maxSampledTexturesPerShaderStage": 28, + "maxSamplersPerShaderStage": 32, + "maxStorageBufferBindingSize": 56, + "maxStorageBuffersPerShaderStage": 36, + "maxStorageTexturesPerShaderStage": 40, + "maxTextureArrayLayers": 12, + "maxTextureDimension1D": 0, + "maxTextureDimension2D": 4, + "maxTextureDimension3D": 8, + "maxUniformBufferBindingSize": 48, + "maxUniformBuffersPerShaderStage": 44, + "maxVertexAttributes": 76, + "maxVertexBufferArrayStride": 80, + "maxVertexBuffers": 72, + "minStorageBufferOffsetAlignment": 68, + "minUniformBufferOffsetAlignment": 64 + }, + "WGPUMultisampleState": { + "__size__": 24, + "alphaToCoverageEnabled": 16, + "count": 8, + "mask": 12, + "nextInChain": 0 + }, + "WGPUOrigin3D": { + "__size__": 12, + "x": 0, + "y": 4, + "z": 8 + }, + "WGPUPipelineLayoutDescriptor": { + "__size__": 32, + "bindGroupLayoutCount": 16, + "bindGroupLayouts": 24, + "label": 8, + "nextInChain": 0 + }, + "WGPUPrimitiveDepthClipControl": { + "__size__": 24, + "chain": 0, + "unclippedDepth": 16 + }, + "WGPUPrimitiveState": { + "__size__": 24, + "cullMode": 20, + "frontFace": 16, + "nextInChain": 0, + "stripIndexFormat": 12, + "topology": 8 + }, + "WGPUProgrammableStageDescriptor": { + "__size__": 40, + "constantCount": 24, + "constants": 32, + "entryPoint": 16, + "module": 8, + "nextInChain": 0 + }, + "WGPUQuerySetDescriptor": { + "__size__": 40, + "count": 20, + "label": 8, + "nextInChain": 0, + "pipelineStatistics": 24, + "pipelineStatisticsCount": 32, + "type": 16 + }, + "WGPUQueueDescriptor": { + "__size__": 16, + "label": 8, + "nextInChain": 0 + }, + "WGPURenderBundleDescriptor": { + "__size__": 16, + "label": 8, + "nextInChain": 0 + }, + "WGPURenderBundleEncoderDescriptor": { + "__size__": 48, + "colorFormats": 24, + "colorFormatsCount": 16, + "depthReadOnly": 40, + "depthStencilFormat": 32, + "label": 8, + "nextInChain": 0, + "sampleCount": 36, + "stencilReadOnly": 41 + }, + "WGPURenderPassColorAttachment": { + "__size__": 56, + "clearValue": 24, + "loadOp": 16, + "resolveTarget": 8, + "storeOp": 20, + "view": 0 + }, + "WGPURenderPassDepthStencilAttachment": { + "__size__": 40, + "depthClearValue": 16, + "depthLoadOp": 8, + "depthReadOnly": 20, + "depthStoreOp": 12, + "stencilClearValue": 32, + "stencilLoadOp": 24, + "stencilReadOnly": 36, + "stencilStoreOp": 28, + "view": 0 + }, + "WGPURenderPassDescriptor": { + "__size__": 64, + "colorAttachmentCount": 16, + "colorAttachments": 24, + "depthStencilAttachment": 32, + "label": 8, + "nextInChain": 0, + "occlusionQuerySet": 40, + "timestampWriteCount": 48, + "timestampWrites": 56 + }, + "WGPURenderPassDescriptorMaxDrawCount": { + "__size__": 24, + "chain": 0, + "maxDrawCount": 16 + }, + "WGPURenderPassTimestampWrite": { + "__size__": 16, + "location": 12, + "queryIndex": 8, + "querySet": 0 + }, + "WGPURenderPipelineDescriptor": { + "__size__": 144, + "depthStencil": 104, + "fragment": 136, + "label": 8, + "layout": 16, + "multisample": 112, + "nextInChain": 0, + "primitive": 80, + "vertex": 24 + }, + "WGPURequestAdapterOptions": { + "__size__": 24, + "compatibleSurface": 8, + "forceFallbackAdapter": 20, + "nextInChain": 0, + "powerPreference": 16 + }, + "WGPURequiredLimits": { + "__size__": 128, + "limits": 8, + "nextInChain": 0 + }, + "WGPUSamplerBindingLayout": { + "__size__": 16, + "nextInChain": 0, + "type": 8 + }, + "WGPUSamplerDescriptor": { + "__size__": 56, + "addressModeU": 16, + "addressModeV": 20, + "addressModeW": 24, + "compare": 48, + "label": 8, + "lodMaxClamp": 44, + "lodMinClamp": 40, + "magFilter": 28, + "maxAnisotropy": 52, + "minFilter": 32, + "mipmapFilter": 36, + "nextInChain": 0 + }, + "WGPUShaderModuleDescriptor": { + "__size__": 16, + "label": 8, + "nextInChain": 0 + }, + "WGPUShaderModuleSPIRVDescriptor": { + "__size__": 32, + "chain": 0, + "code": 24, + "codeSize": 16 + }, + "WGPUShaderModuleWGSLDescriptor": { + "__size__": 24, + "chain": 0, + "source": 16 + }, + "WGPUStencilFaceState": { + "__size__": 16, + "compare": 0, + "depthFailOp": 8, + "failOp": 4, + "passOp": 12 + }, + "WGPUStorageTextureBindingLayout": { + "__size__": 24, + "access": 8, + "format": 12, + "nextInChain": 0, + "viewDimension": 16 + }, + "WGPUSupportedLimits": { + "__size__": 128, + "limits": 8, + "nextInChain": 0 + }, + "WGPUSurfaceDescriptor": { + "__size__": 16, + "label": 8, + "nextInChain": 0 + }, + "WGPUSurfaceDescriptorFromCanvasHTMLSelector": { + "__size__": 24, + "chain": 0, + "selector": 16 + }, + "WGPUSwapChainDescriptor": { + "__size__": 40, + "format": 20, + "height": 28, + "label": 8, + "nextInChain": 0, + "presentMode": 32, + "usage": 16, + "width": 24 + }, + "WGPUTextureBindingLayout": { + "__size__": 24, + "multisampled": 16, + "nextInChain": 0, + "sampleType": 8, + "viewDimension": 12 + }, + "WGPUTextureDataLayout": { + "__size__": 24, + "bytesPerRow": 16, + "nextInChain": 0, + "offset": 8, + "rowsPerImage": 20 + }, + "WGPUTextureDescriptor": { + "__size__": 64, + "dimension": 20, + "format": 36, + "label": 8, + "mipLevelCount": 40, + "nextInChain": 0, + "sampleCount": 44, + "size": 24, + "usage": 16, + "viewFormatCount": 48, + "viewFormats": 56 + }, + "WGPUTextureViewDescriptor": { + "__size__": 48, + "arrayLayerCount": 36, + "aspect": 40, + "baseArrayLayer": 32, + "baseMipLevel": 24, + "dimension": 20, + "format": 16, + "label": 8, + "mipLevelCount": 28, + "nextInChain": 0 + }, + "WGPUVertexAttribute": { + "__size__": 24, + "format": 0, + "offset": 8, + "shaderLocation": 16 + }, + "WGPUVertexBufferLayout": { + "__size__": 24, + "arrayStride": 0, + "attributeCount": 12, + "attributes": 16, + "stepMode": 8 + }, + "WGPUVertexState": { + "__size__": 56, + "bufferCount": 40, + "buffers": 48, + "constantCount": 24, + "constants": 32, + "entryPoint": 16, + "module": 8, + "nextInChain": 0 + }, + "__cxa_exception": { + "__size__": 48, + "adjustedPtr": 32, + "caught": 24, + "exceptionDestructor": 16, + "exceptionType": 8, + "referenceCount": 0, + "rethrown": 25 + }, + "__wasi_fdstat_t": { + "__size__": 24, + "fs_filetype": 0, + "fs_flags": 2, + "fs_rights_base": 8, + "fs_rights_inheriting": 16 + }, + "addrinfo": { + "__size__": 48, + "ai_addr": 24, + "ai_addrlen": 16, + "ai_canonname": 32, + "ai_family": 4, + "ai_flags": 0, + "ai_next": 40, + "ai_protocol": 12, + "ai_socktype": 8 + }, + "asyncify_data_s": { + "__size__": 24, + "rewind_id": 16, + "stack_limit": 8, + "stack_ptr": 0 + }, + "dirent": { + "__size__": 280, + "d_ino": 0, + "d_name": 19, + "d_off": 8, + "d_reclen": 16, + "d_type": 18 + }, + "dso": { + "__size__": 48, + "flags": 8, + "mem_addr": 16, + "mem_allocated": 12, + "mem_size": 24, + "name": 48, + "table_addr": 32, + "table_size": 40 + }, + "emscripten_fetch_attr_t": { + "__size__": 152, + "attributes": 72, + "destinationPath": 96, + "onerror": 48, + "onprogress": 56, + "onreadystatechange": 64, + "onsuccess": 40, + "overriddenMimeType": 128, + "password": 112, + "requestData": 136, + "requestDataSize": 144, + "requestHeaders": 120, + "requestMethod": 0, + "timeoutMSecs": 80, + "userData": 32, + "userName": 104, + "withCredentials": 88 + }, + "emscripten_fetch_t": { + "__attributes": 128, + "__proxyState": 124, + "__size__": 280, + "data": 24, + "dataOffset": 40, + "id": 0, + "numBytes": 32, + "readyState": 56, + "status": 58, + "statusText": 60, + "totalBytes": 48, + "url": 16, + "userData": 8 + }, + "emscripten_fiber_s": { + "__size__": 64, + "asyncify_data": 40, + "entry": 24, + "stack_base": 0, + "stack_limit": 8, + "stack_ptr": 16, + "user_data": 32 + }, + "flock": { + "__size__": 32, + "l_type": 0 + }, + "hostent": { + "__size__": 32, + "h_addr_list": 24, + "h_addrtype": 16, + "h_aliases": 8, + "h_length": 20, + "h_name": 0 + }, + "iovec": { + "__size__": 16, + "iov_base": 0, + "iov_len": 8 + }, + "msghdr": { + "__size__": 48, + "msg_iov": 16, + "msg_iovlen": 24, + "msg_name": 0, + "msg_namelen": 8 + }, + "pollfd": { + "__size__": 8, + "events": 4, + "fd": 0, + "revents": 6 + }, + "protoent": { + "__size__": 24, + "p_aliases": 8, + "p_name": 0, + "p_proto": 16 + }, + "pthread": { + "__size__": 232, + "profilerBlock": 200, + "stack": 88, + "stack_size": 96, + "waiting_async": 228 + }, + "pthread_attr_t": { + "__size__": 88, + "_a_transferredcanvases": 80 + }, + "sockaddr_in": { + "__size__": 16, + "sin_addr": { + "__size__": 4, + "s_addr": 4 + }, + "sin_family": 0, + "sin_port": 2 + }, + "sockaddr_in6": { + "__size__": 28, + "sin6_addr": { + "__in6_union": { + "__s6_addr": 8, + "__s6_addr16": 8, + "__s6_addr32": 8, + "__size__": 16 + }, + "__size__": 16 + }, + "sin6_family": 0, + "sin6_port": 2 + }, + "stat": { + "__size__": 120, + "__st_ino_truncated": 8, + "st_atim": { + "__size__": 16, + "tv_nsec": 72, + "tv_sec": 64 + }, + "st_blksize": 56, + "st_blocks": 60, + "st_ctim": { + "__size__": 16, + "tv_nsec": 104, + "tv_sec": 96 + }, + "st_dev": 0, + "st_gid": 36, + "st_ino": 112, + "st_mode": 16, + "st_mtim": { + "__size__": 16, + "tv_nsec": 88, + "tv_sec": 80 + }, + "st_nlink": 24, + "st_rdev": 40, + "st_size": 48, + "st_uid": 32 + }, + "statfs": { + "__size__": 104, + "f_bavail": 24, + "f_bfree": 20, + "f_blocks": 16, + "f_bsize": 8, + "f_ffree": 32, + "f_files": 28, + "f_flags": 64, + "f_frsize": 56, + "f_fsid": 36, + "f_namelen": 48 + }, + "thread_profiler_block": { + "__size__": 104, + "name": 72, + "threadStatus": 0, + "timeSpentInStatus": 16 + }, + "timespec": { + "__size__": 16, + "tv_nsec": 8, + "tv_sec": 0 + }, + "tm": { + "__size__": 56, + "tm_gmtoff": 40, + "tm_hour": 8, + "tm_isdst": 32, + "tm_mday": 12, + "tm_min": 4, + "tm_mon": 16, + "tm_sec": 0, + "tm_wday": 24, + "tm_yday": 28, + "tm_year": 20, + "tm_zone": 48 + } + } +} diff --git a/src/modules.js b/src/modules.js index cb8b22495d378..f1085c8f05012 100644 --- a/src/modules.js +++ b/src/modules.js @@ -246,8 +246,12 @@ global.LibraryManager = { }; if (!BOOTSTRAPPING_STRUCT_INFO) { + let structInfoFile = 'generated_struct_info32.json'; + if (MEMORY64) { + structInfoFile = 'generated_struct_info64.json' + } // Load struct and define information. - const temp = JSON.parse(read(STRUCT_INFO)); + const temp = JSON.parse(read(structInfoFile)); C_STRUCTS = temp.structs; C_DEFINES = temp.defines; } else { @@ -260,7 +264,7 @@ if (!BOOTSTRAPPING_STRUCT_INFO) { C_STRUCTS = new Proxy(C_STRUCTS, { get(target, prop, receiver) { if (!(prop in target)) { - throw new Error(`Missing C struct ${prop}! If you just added it to struct_info.json, you need to ./emcc --clear-cache`); + throw new Error(`Missing C struct ${prop}! If you just added it to struct_info.json, you need to run ./tools/gen_struct_info.py`); } return target[prop] } @@ -269,7 +273,7 @@ C_STRUCTS = new Proxy(C_STRUCTS, { cDefs = C_DEFINES = new Proxy(C_DEFINES, { get(target, prop, receiver) { if (!(prop in target)) { - throw new Error(`Missing C define ${prop}! If you just added it to struct_info.json, you need to ./emcc --clear-cache`); + throw new Error(`Missing C define ${prop}! If you just added it to struct_info.json, you need to run ./tools/gen_struct_info.py`); } return target[prop] } diff --git a/src/parseTools.js b/src/parseTools.js index be894884d048f..7a60029c41e51 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -650,7 +650,7 @@ function addAtExit(code) { } function makeRetainedCompilerSettings() { - const ignore = new Set(['STRUCT_INFO']); + const ignore = new Set(); if (STRICT) { for (const setting of LEGACY_SETTINGS) { ignore.add(setting); diff --git a/src/settings_internal.js b/src/settings_internal.js index fb0271691c580..040cb40d8e7c1 100644 --- a/src/settings_internal.js +++ b/src/settings_internal.js @@ -207,9 +207,6 @@ var EXPECT_MAIN = true; // MODULARIZE, and returned from the factory function. var EXPORT_READY_PROMISE = true; -// struct_info that is either generated or cached -var STRUCT_INFO = ''; - // If true, building against Emscripten's wasm heap memory profiler. var MEMORYPROFILER = false; diff --git a/system/include/webgpu/README.md b/system/include/webgpu/README.md index 536492c7108c2..6b4e07ec0d506 100644 --- a/system/include/webgpu/README.md +++ b/system/include/webgpu/README.md @@ -16,5 +16,5 @@ Dawn additionally autogenerates two "snippets" that are used in Emscripten: - `library_webgpu_enum_tables.js`, which is pasted into [`library_webgpu.js`](../../../src/library_webgpu.js) - `webgpu_struct_info.json`, which is pasted into [`struct_info.json`](../../../src/struct_info.json). -Once that's done, the following file also needs to be rebaselined: -- [`reference_struct_info.json`](../../../test/reference_struct_info.json): can be updated by running `test/runner other.test_gen_struct_info --rebaseline` +Once that's done, you need to run `./tools/gen_struct_info.py` to update +the auto-generated files. diff --git a/test/test_other.py b/test/test_other.py index 60d70f9717e81..59db4ace7ee19 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -11803,12 +11803,16 @@ def test_split_main_module(self): self.assertIn('Hello from lib!', result) def test_gen_struct_info(self): - # This tests is fragile and will need updating any time any of the referenced - # structs or defines change. However its easy to rebaseline with - # --rebaseline and it prevents regressions or unintended changes - # to the output json. + # This test will start failing whenever the struct info changes (e.g. offset or defines + # change). However it's easy to rebaseline with --rebaseline. self.run_process([PYTHON, path_from_root('tools/gen_struct_info.py'), '-o', 'out.json']) - self.assertFileContents(test_file('reference_struct_info.json'), read_file('out.json')) + self.assertFileContents(path_from_root('src/generated_struct_info32.json'), read_file('out.json')) + + # Same again for wasm64 + node_version = shared.check_node_version() + if node_version and node_version >= (14, 0, 0): + self.run_process([PYTHON, path_from_root('tools/gen_struct_info.py'), '--wasm64', '-o', 'out.json']) + self.assertFileContents(path_from_root('src/generated_struct_info64.json'), read_file('out.json')) def test_gen_struct_info_env(self): # gen_struct_info.py builds C code in a very specific and low level way. We don't want @@ -13258,10 +13262,10 @@ def test_missing_struct_info(self): {{{ C_STRUCTS.Foo }}} ''') err = self.expect_fail([EMCC, test_file('hello_world.c'), '--js-library=lib.js']) - self.assertContained('Error: Missing C struct Foo! If you just added it to struct_info.json, you need to ./emcc --clear-cache', err) + self.assertContained('Error: Missing C struct Foo! If you just added it to struct_info.json, you need to run ./tools/gen_struct_info.py', err) create_file('lib.js', ''' {{{ C_DEFINES.Foo }}} ''') err = self.expect_fail([EMCC, test_file('hello_world.c'), '--js-library=lib.js']) - self.assertContained('Error: Missing C define Foo! If you just added it to struct_info.json, you need to ./emcc --clear-cache', err) + self.assertContained('Error: Missing C define Foo! If you just added it to struct_info.json, you need to run ./tools/gen_struct_info.py', err) diff --git a/tools/cache.py b/tools/cache.py index b9ccb93c4a262..1d3d433aa0f52 100644 --- a/tools/cache.py +++ b/tools/cache.py @@ -93,14 +93,12 @@ def get_sysroot_dir(*parts): return str(Path(get_sysroot(absolute=True), *parts)) -def get_lib_dir(absolute, varies=True): +def get_lib_dir(absolute): path = Path(get_sysroot(absolute=absolute), 'lib') if settings.MEMORY64: path = Path(path, 'wasm64-emscripten') else: path = Path(path, 'wasm32-emscripten') - if not varies: - return path # if relevant, use a subdir of the cache subdir = [] if settings.LTO: @@ -115,8 +113,8 @@ def get_lib_dir(absolute, varies=True): return path -def get_lib_name(name, varies=True, absolute=False): - return str(get_lib_dir(absolute=absolute, varies=varies).joinpath(name)) +def get_lib_name(name, absolute=False): + return str(get_lib_dir(absolute=absolute).joinpath(name)) def erase_lib(name): diff --git a/tools/gen_struct_info.py b/tools/gen_struct_info.py index 5aadf842b268f..ec746aee87d74 100755 --- a/tools/gen_struct_info.py +++ b/tools/gen_struct_info.py @@ -248,10 +248,7 @@ def inspect_headers(headers, cflags): compiler_rt, '-sBOOTSTRAPPING_STRUCT_INFO', '-sSTRICT', - '-sASSERTIONS=0', - # Use SINGLE_FILE so there is only a single - # file to cleanup. - '-sSINGLE_FILE'] + '-sASSERTIONS=0'] # Default behavior for emcc is to warn for binaryen version check mismatches # so we should try to match that behavior. @@ -288,6 +285,8 @@ def inspect_headers(headers, cflags): if os.path.exists(js_file[1]): os.unlink(js_file[1]) + wasm_file = shared.replace_suffix(js_file[1], '.wasm') + os.unlink(wasm_file) # Parse the output of the program into a dict. return parse_c_output(info) @@ -352,14 +351,8 @@ def parse_json(path): return header_files -def output_json(obj, stream=None): - if stream is None: - stream = sys.stdout - elif isinstance(stream, str): - stream = open(stream, 'w') - +def output_json(obj, stream): json.dump(obj, stream, indent=4, sort_keys=True) - stream.write('\n') stream.close() @@ -379,7 +372,7 @@ def main(args): parser.add_argument('-q', dest='quiet', action='store_true', default=False, help='Don\'t output anything besides error messages.') parser.add_argument('-o', dest='output', metavar='path', default=None, - help='Path to the JSON file that will be written. If omitted, the generated data will be printed to stdout.') + help='Path to the JSON file that will be written. If omitted, the default location under `src` will be used.') parser.add_argument('-I', dest='includes', metavar='dir', action='append', default=[], help='Add directory to include search path') parser.add_argument('-D', dest='defines', metavar='define', action='append', default=[], @@ -437,7 +430,16 @@ def main(args): info_fragment = inspect_code(header_files, use_cflags) merge_info(info, info_fragment) - output_json(info, args.output) + if args.output: + output_file = args.output + elif args.wasm64: + output_file = utils.path_from_root('src/generated_struct_info64.json') + else: + output_file = utils.path_from_root('src/generated_struct_info32.json') + + with open(output_file, 'w') as f: + output_json(info, f) + return 0 diff --git a/tools/maint/check_struct_info.py b/tools/maint/check_struct_info.py index 692c6f13572c4..776e56a86f79d 100755 --- a/tools/maint/check_struct_info.py +++ b/tools/maint/check_struct_info.py @@ -13,8 +13,7 @@ sys.path.append(root_dir) -import emscripten -from tools.settings import settings +from tools import utils def check_structs(info): @@ -41,8 +40,8 @@ def check_defines(info): def main(): - emscripten.generate_struct_info() - info = json.loads(open(settings.STRUCT_INFO).read()) + json_file = utils.path_from_root('src/generated_struct_info32.json') + info = json.loads(utils.read_file(json_file)) check_structs(info) check_defines(info) return 0 From 6f793af69d332b44bcd48e978a9c24c448da525e Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 20 Mar 2023 18:40:52 -0700 Subject: [PATCH 0035/1523] Use JS names for functions that are JS-only. NFC (#18958) As JS_only functions there can never appear in native code so also have no effect it deps_info.py. --- src/library_html5.js | 35 ++++++++++++++++------------------- tools/deps_info.py | 4 ---- 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/src/library_html5.js b/src/library_html5.js index 36853a1b06fc3..3f75f317f25bc 100644 --- a/src/library_html5.js +++ b/src/library_html5.js @@ -2385,13 +2385,13 @@ var LibraryHTML5 = { }, #if PTHREADS - emscripten_set_canvas_element_size_calling_thread__deps: [ + $setCanvasElementSizeCallingThread__deps: [ '$JSEvents', #if OFFSCREENCANVAS_SUPPORT - 'emscripten_set_offscreencanvas_size_on_target_thread', + '$setOffscreenCanvasSizeOnTargetThread', #endif '$findCanvasEventTarget'], - emscripten_set_canvas_element_size_calling_thread: function(target, width, height) { + $setCanvasElementSizeCallingThread: function(target, width, height) { var canvas = findCanvasEventTarget(target); if (!canvas) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}}; @@ -2434,7 +2434,7 @@ var LibraryHTML5 = { #if OFFSCREENCANVAS_SUPPORT } else if (canvas.canvasSharedPtr) { var targetThread = {{{ makeGetValue('canvas.canvasSharedPtr', 8, 'i32') }}}; - _emscripten_set_offscreencanvas_size_on_target_thread(targetThread, target, width, height); + setOffscreenCanvasSizeOnTargetThread(targetThread, target, width, height); return {{{ cDefs.EMSCRIPTEN_RESULT_DEFERRED }}}; // This will have to be done asynchronously #endif } else { @@ -2453,8 +2453,9 @@ var LibraryHTML5 = { #if OFFSCREENCANVAS_SUPPORT _emscripten_set_offscreencanvas_size: 'emscripten_set_canvas_element_size', - emscripten_set_offscreencanvas_size_on_target_thread_js__deps: ['$stringToNewUTF8', 'emscripten_dispatch_to_thread_', '$withStackSave'], - emscripten_set_offscreencanvas_size_on_target_thread_js: function(targetThread, targetCanvas, width, height) { + $setOffscreenCanvasSizeOnTargetThread__deps: ['$stringToNewUTF8', 'emscripten_dispatch_to_thread_', '$withStackSave'], + $setOffscreenCanvasSizeOnTargetThread: function(targetThread, targetCanvas, width, height) { + targetCanvas = targetCanvas ? UTF8ToString(targetCanvas) : ''; withStackSave(function() { var varargs = stackAlloc(12); var targetCanvasPtr = 0; @@ -2471,12 +2472,6 @@ var LibraryHTML5 = { _emscripten_dispatch_to_thread_(targetThread, {{{ cDefs.EM_PROXIED_RESIZE_OFFSCREENCANVAS }}}, 0, targetCanvasPtr /* satellite data */, varargs); }); }, - - emscripten_set_offscreencanvas_size_on_target_thread__deps: ['emscripten_set_offscreencanvas_size_on_target_thread_js'], - emscripten_set_offscreencanvas_size_on_target_thread: function(targetThread, targetCanvas, width, height) { - targetCanvas = targetCanvas ? UTF8ToString(targetCanvas) : ''; - _emscripten_set_offscreencanvas_size_on_target_thread_js(targetThread, targetCanvas, width, height); - }, #else _emscripten_set_offscreencanvas_size: function(target, width, height) { #if ASSERTIONS @@ -2486,12 +2481,14 @@ var LibraryHTML5 = { }, #endif - emscripten_set_canvas_element_size_main_thread__proxy: 'sync', - emscripten_set_canvas_element_size_main_thread__sig: 'iiii', - emscripten_set_canvas_element_size_main_thread__deps: ['emscripten_set_canvas_element_size_calling_thread'], - emscripten_set_canvas_element_size_main_thread: function(target, width, height) { return _emscripten_set_canvas_element_size_calling_thread(target, width, height); }, + $setCanvasElementSizeMainThread__proxy: 'sync', + $setCanvasElementSizeMainThread__sig: 'iiii', + $setCanvasElementSizeMainThread__deps: ['$setCanvasElementSizeCallingThread'], + $setCanvasElementSizeMainThread: function(target, width, height) { + return setCanvasElementSizeCallingThread(target, width, height); + }, - emscripten_set_canvas_element_size__deps: ['$JSEvents', 'emscripten_set_canvas_element_size_calling_thread', 'emscripten_set_canvas_element_size_main_thread', '$findCanvasEventTarget'], + emscripten_set_canvas_element_size__deps: ['$JSEvents', '$setCanvasElementSizeCallingThread', '$setCanvasElementSizeMainThread', '$findCanvasEventTarget'], emscripten_set_canvas_element_size__sig: 'ipii', emscripten_set_canvas_element_size: function(target, width, height) { #if GL_DEBUG @@ -2499,9 +2496,9 @@ var LibraryHTML5 = { #endif var canvas = findCanvasEventTarget(target); if (canvas) { - return _emscripten_set_canvas_element_size_calling_thread(target, width, height); + return setCanvasElementSizeCallingThread(target, width, height); } - return _emscripten_set_canvas_element_size_main_thread(target, width, height); + return setCanvasElementSizeMainThread(target, width, height); }, #else emscripten_set_canvas_element_size__deps: ['$JSEvents', '$findCanvasEventTarget'], diff --git a/tools/deps_info.py b/tools/deps_info.py index 34619fa6683d0..4d5f9a557019b 100644 --- a/tools/deps_info.py +++ b/tools/deps_info.py @@ -205,13 +205,9 @@ def get_deps_info(): _deps_info['glutCreateWindow'] = ['malloc'] _deps_info['emscripten_webgl_create_context'] = ['malloc'] _deps_info['emscripten_webgl_destroy_context'] = ['free'] - _deps_info['emscripten_set_canvas_element_size_calling_thread'] = ['emscripten_dispatch_to_thread_'] if settings.OFFSCREEN_FRAMEBUFFER: # When OFFSCREEN_FRAMEBUFFER is defined these functions are defined in native code, # otherwise they are defined in src/library_html5_webgl.js. _deps_info['emscripten_webgl_destroy_context'] += ['emscripten_webgl_make_context_current', 'emscripten_webgl_get_current_context'] - if settings.OFFSCREENCANVAS_SUPPORT: - _deps_info['emscripten_set_offscreencanvas_size_on_target_thread'] = ['emscripten_dispatch_to_thread_', 'malloc', 'free'] - _deps_info['emscripten_set_offscreencanvas_size_on_target_thread_js'] = ['malloc'] return _deps_info From 1db2a1ec3447b929e524e8b47f85a7ac690fe5f8 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 21 Mar 2023 09:21:22 -0700 Subject: [PATCH 0036/1523] Fix name of dummy `emscripten_dlopen` symbol. NFC (#19016) This symbol doesn't start with an underscore, but this code is only used to aid in debugging when developer try to call these functions but without linking with `-sMAIN_MODULE`. --- src/library_dylink.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/library_dylink.js b/src/library_dylink.js index d48a31a01d737..4053ac83c0751 100644 --- a/src/library_dylink.js +++ b/src/library_dylink.js @@ -246,7 +246,7 @@ var LibraryDylink = { _dlsym_js__deps: [function() { error(dlopenMissingError); }], _dlsym_catchup_js__deps: [function() { error(dlopenMissingError); }], dlopen__deps: [function() { error(dlopenMissingError); }], - _emscripten_dlopen__deps: [function() { error(dlopenMissingError); }], + emscripten_dlopen__deps: [function() { error(dlopenMissingError); }], __dlsym__deps: [function() { error(dlopenMissingError); }], dladdr__deps: [function() { error(dlopenMissingError); }], #else @@ -256,7 +256,7 @@ var LibraryDylink = { _dlsym_js__deps: ['$dlopenMissingError'], _dlsym_catchup_js__deps: ['$dlopenMissingError'], dlopen__deps: ['$dlopenMissingError'], - _emscripten_dlopen__deps: ['$dlopenMissingError'], + emscripten_dlopen__deps: ['$dlopenMissingError'], __dlsym__deps: ['$dlopenMissingError'], dladdr__deps: ['$dlopenMissingError'], #endif @@ -275,7 +275,7 @@ var LibraryDylink = { dlopen: function(handle) { abort(dlopenMissingError); }, - _emscripten_dlopen: function(handle, onsuccess, onerror, user_data) { + emscripten_dlopen: function(handle, onsuccess, onerror, user_data) { abort(dlopenMissingError); }, __dlsym: function(handle, symbol) { From 058fa51dc62595b2e1f72c51d4415b51c3ac1f52 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 21 Mar 2023 12:32:35 -0700 Subject: [PATCH 0037/1523] Fix libpng and libfreetype port with wasm exceptions are enabled (#19004) Sadly, even though libpng can be compiled with setjmp/longjmp support some libraries such as openjpeg assume that setjmp support is included. Fixes: #19001 --- test/common.py | 24 ++++++++++++++++++++++++ test/test_core.py | 26 +------------------------- test/test_other.py | 3 ++- tools/ports/freetype.py | 16 ++++++++++++++-- tools/ports/libpng.py | 15 +++++++++++++-- 5 files changed, 54 insertions(+), 30 deletions(-) diff --git a/test/common.py b/test/common.py index c5b258e0298f9..676738a8e0e55 100644 --- a/test/common.py +++ b/test/common.py @@ -294,6 +294,30 @@ def metafunc(self, with_bigint): return metafunc +# This works just like `with_both_eh_sjlj` above but doesn't enable exceptions. +# Use this for tests that use setjmp/longjmp but not exceptions handling. +def with_both_sjlj(f): + assert callable(f) + + def metafunc(self, is_native): + if is_native: + if not self.is_wasm(): + self.skipTest('wasm2js does not support wasm SjLj') + self.require_wasm_eh() + # FIXME Temporarily disabled. Enable this later when the bug is fixed. + if '-fsanitize=address' in self.emcc_args: + self.skipTest('Wasm EH does not work with asan yet') + self.set_setting('SUPPORT_LONGJMP', 'wasm') + f(self) + else: + self.set_setting('SUPPORT_LONGJMP', 'emscripten') + f(self) + + metafunc._parameterize = {'': (False,), + 'wasm_sjlj': (True,)} + return metafunc + + def ensure_dir(dirname): dirname = Path(dirname) dirname.mkdir(parents=True, exist_ok=True) diff --git a/test/test_core.py b/test/test_core.py index 35d2019740868..e51021e5619d3 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -28,6 +28,7 @@ from common import skip_if, needs_dylink, no_windows, no_mac, is_slow_test, parameterized from common import env_modify, with_env_modify, disabled, node_pthreads, also_with_wasm_bigint from common import read_file, read_binary, requires_v8, requires_node, compiler_for, crossplatform +from common import with_both_sjlj from common import NON_ZERO, WEBIDL_BINDER, EMBUILDER, PYTHON import clang_native @@ -124,31 +125,6 @@ def metafunc(self, is_native): return metafunc -# This works just like `with_both_eh_sjlj` above but doesn't enable exceptions. -# Use this for tests that use setjmp/longjmp but not exceptions handling. -def with_both_sjlj(f): - assert callable(f) - - def metafunc(self, is_native): - if is_native: - # Wasm SjLj is currently supported only in wasm backend and V8 - if not self.is_wasm(): - self.skipTest('wasm2js does not support wasm SjLj') - self.require_wasm_eh() - # FIXME Temporarily disabled. Enable this later when the bug is fixed. - if '-fsanitize=address' in self.emcc_args: - self.skipTest('Wasm EH does not work with asan yet') - self.set_setting('SUPPORT_LONGJMP', 'wasm') - f(self) - else: - self.set_setting('SUPPORT_LONGJMP', 'emscripten') - f(self) - - metafunc._parameterize = {'': (False,), - 'wasm': (True,)} - return metafunc - - def no_wasm2js(note=''): assert not callable(note) diff --git a/test/test_other.py b/test/test_other.py index 59db4ace7ee19..0f9d748aff5a1 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -33,7 +33,7 @@ from common import env_modify, no_mac, no_windows, requires_native_clang, with_env_modify from common import create_file, parameterized, NON_ZERO, node_pthreads, TEST_ROOT, test_file from common import compiler_for, EMBUILDER, requires_v8, requires_node, requires_wasm64 -from common import requires_wasm_eh, crossplatform +from common import requires_wasm_eh, crossplatform, with_both_sjlj from common import also_with_minimal_runtime, also_with_wasm_bigint, EMTEST_BUILD_VERBOSE, PYTHON from tools import shared, building, utils, deps_info, response_file, cache from tools.utils import read_file, write_file, delete_file, read_binary @@ -2205,6 +2205,7 @@ def test_bzip2(self): self.do_runf(test_file('bzip2_test.c'), 'usage: unzcrash filename', emcc_args=['-sUSE_BZIP2', '-Wno-pointer-sign']) + @with_both_sjlj def test_freetype(self): # copy the Liberation Sans Bold truetype file located in the # /test/freetype to the compilation folder diff --git a/tools/ports/freetype.py b/tools/ports/freetype.py index c7fe77e92b598..83ef166a91cd7 100644 --- a/tools/ports/freetype.py +++ b/tools/ports/freetype.py @@ -8,11 +8,20 @@ TAG = 'version_1' HASH = '0d0b1280ba0501ad0a23cf1daa1f86821c722218b59432734d3087a89acd22aabd5c3e5e1269700dcd41e87073046e906060f167c032eb91a3ac8c5808a02783' +variants = {'freetype-wasm-sjlj': {'SUPPORT_LONGJMP': 'wasm'}} + def needed(settings): return settings.USE_FREETYPE +def get_lib_name(settings): + if settings.SUPPORT_LONGJMP == 'wasm': + return 'libfreetype-wasm-sjlj.a' + else: + return 'libfreetype.a' + + def get(ports, settings, shared): ports.fetch_project('freetype', f'https://github.com/emscripten-ports/FreeType/archive/{TAG}.zip', sha512hash=HASH) @@ -90,13 +99,16 @@ def create(final): '-pthread' ] + if settings.SUPPORT_LONGJMP == 'wasm': + flags.append('-sSUPPORT_LONGJMP=wasm') + ports.build_port(source_path, final, 'freetype', flags=flags, srcs=srcs) - return [shared.cache.get_lib('libfreetype.a', create, what='port')] + return [shared.cache.get_lib(get_lib_name(settings), create, what='port')] def clear(ports, settings, shared): - shared.cache.erase_lib('libfreetype.a') + shared.cache.erase_lib(get_lib_name(settings)) def process_args(ports): diff --git a/tools/ports/libpng.py b/tools/ports/libpng.py index 1e9c91b3670a6..19d30d1805666 100644 --- a/tools/ports/libpng.py +++ b/tools/ports/libpng.py @@ -10,7 +10,11 @@ HASH = '2ce2b855af307ca92a6e053f521f5d262c36eb836b4810cb53c809aa3ea2dcc08f834aee0ffd66137768a54397e28e92804534a74abb6fc9f6f3127f14c9c338' deps = ['zlib'] -variants = {'libpng-mt': {'PTHREADS': 1}} +variants = { + 'libpng-mt': {'PTHREADS': 1}, + 'libpng-wasm-sjlj': {'SUPPORT_LONGJMP': 'wasm'}, + 'libpng-mt-wasm-sjlj': {'PTHREADS': 1, 'SUPPORT_LONGJMP': 'wasm'}, +} def needed(settings): @@ -18,7 +22,12 @@ def needed(settings): def get_lib_name(settings): - return 'libpng' + ('-mt' if settings.PTHREADS else '') + '.a' + suffix = '' + if settings.PTHREADS: + suffix += '-mt' + if settings.SUPPORT_LONGJMP == 'wasm': + suffix += '-wasm-sjlj' + return f'libpng{suffix}.a' def get(ports, settings, shared): @@ -35,6 +44,8 @@ def create(final): flags = ['-sUSE_ZLIB'] if settings.PTHREADS: flags += ['-pthread'] + if settings.SUPPORT_LONGJMP == 'wasm': + flags.append('-sSUPPORT_LONGJMP=wasm') ports.build_port(source_path, final, 'libpng', flags=flags, exclude_files=['pngtest'], exclude_dirs=['scripts', 'contrib']) From c3f9ac2ac2db8656c4ebd04f3d1aed43051fd4e5 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 21 Mar 2023 16:03:49 -0700 Subject: [PATCH 0038/1523] Minor cleanups to GL passthrough function handling. NFC (#19023) --- src/library_webgl.js | 33 ++++++++++++++++----------------- src/library_webgl2.js | 32 ++++++++++++++++---------------- 2 files changed, 32 insertions(+), 33 deletions(-) diff --git a/src/library_webgl.js b/src/library_webgl.js index a63d287ef96db..a10a44cfab989 100644 --- a/src/library_webgl.js +++ b/src/library_webgl.js @@ -4172,18 +4172,18 @@ var LibraryGL = { glFrontFace__sig: 'vi', }; -// Simple pass-through functions. Starred ones have return values. [X] ones have X in the C name but not in the JS name -var glFuncs = [[0, 'finish flush'], - [1, 'clearDepth clearDepth[f] depthFunc enable disable frontFace cullFace clear lineWidth clearStencil stencilMask checkFramebufferStatus* generateMipmap activeTexture blendEquation isEnabled*'], - [2, 'blendFunc blendEquationSeparate depthRange depthRange[f] stencilMaskSeparate hint polygonOffset vertexAttrib1f'], - [3, 'texParameteri texParameterf vertexAttrib2f stencilFunc stencilOp'], - [4, 'viewport clearColor scissor vertexAttrib3f renderbufferStorage blendFuncSeparate blendColor stencilFuncSeparate stencilOpSeparate'], - [5, 'vertexAttrib4f'], - [6, ''], - [7, ''], - [8, 'copyTexImage2D copyTexSubImage2D'], - [9, ''], - [10, '']]; +// Simple pass-through functions. +// - Starred ones have return values. +// - [X] ones have X in the C name but not in the JS name +var glPassthroughFuncs = [ + [0, 'finish flush'], + [1, 'clearDepth clearDepth[f] depthFunc enable disable frontFace cullFace clear lineWidth clearStencil stencilMask checkFramebufferStatus* generateMipmap activeTexture blendEquation isEnabled*'], + [2, 'blendFunc blendEquationSeparate depthRange depthRange[f] stencilMaskSeparate hint polygonOffset vertexAttrib1f'], + [3, 'texParameteri texParameterf vertexAttrib2f stencilFunc stencilOp'], + [4, 'viewport clearColor scissor vertexAttrib3f renderbufferStorage blendFuncSeparate blendColor stencilFuncSeparate stencilOpSeparate'], + [5, 'vertexAttrib4f'], + [8, 'copyTexImage2D copyTexSubImage2D'], +]; function createGLPassthroughFunctions(lib, funcs) { funcs.forEach((data) => { @@ -4194,11 +4194,10 @@ function createGLPassthroughFunctions(lib, funcs) { const returnStub = '(function(' + args + ') { return GLctx[\'NAME\'](' + args + ') })'; const sigEnd = range(num).map(() => 'i').join(''); names.split(' ').forEach((name) => { - if (name.length == 0) return; let stub = plainStub; let sig; - if (name[name.length-1] == '*') { - name = name.substr(0, name.length-1); + if (name.endsWith('*')) { + name = name.slice(0, -1); stub = returnStub; sig = 'i' + sigEnd; } else { @@ -4207,7 +4206,7 @@ function createGLPassthroughFunctions(lib, funcs) { let cName = name; if (name.includes('[')) { cName = name.replace('[', '').replace(']', ''); - name = cName.substr(0, cName.length-1); + name = cName.slice(0, -1); } cName = 'gl' + cName[0].toUpperCase() + cName.substr(1); assert(!(cName in lib), "Cannot reimplement the existing function " + cName); @@ -4217,7 +4216,7 @@ function createGLPassthroughFunctions(lib, funcs) { }); } -createGLPassthroughFunctions(LibraryGL, glFuncs); +createGLPassthroughFunctions(LibraryGL, glPassthroughFuncs); autoAddDeps(LibraryGL, '$GL'); diff --git a/src/library_webgl2.js b/src/library_webgl2.js index de44722ae3b8f..b70f33b89c87c 100644 --- a/src/library_webgl2.js +++ b/src/library_webgl2.js @@ -1116,28 +1116,28 @@ var LibraryWebGL2 = { glClearBufferfi__sig: 'viifi', }; -// Simple pass-through functions. Starred ones have return values. [X] ones have X in the C name but not in the JS name -var webgl2Funcs = [[0, 'endTransformFeedback pauseTransformFeedback resumeTransformFeedback'], - [1, 'beginTransformFeedback readBuffer endQuery'], - [2, ''], - [3, ''], - [4, 'clearBufferfi'], - [5, 'vertexAttribI4i vertexAttribI4ui copyBufferSubData texStorage2D renderbufferStorageMultisample'], - [6, 'texStorage3D'], - [7, ''], - [8, ''], - [9, 'copyTexSubImage3D'], - [10, 'blitFramebuffer']]; - #if MAX_WEBGL_VERSION >= 2 -// If user passes -sMAX_WEBGL_VERSION >= 2 -sSTRICT but not -lGL (to link in WebGL 1), then WebGL2 library should not -// be linked in as well. +// Simple pass-through functions. +// - Starred ones have return values. +// - [X] ones have X in the C name but not in the JS name +var webgl2PassthroughFuncs = [ + [0, 'endTransformFeedback pauseTransformFeedback resumeTransformFeedback'], + [1, 'beginTransformFeedback readBuffer endQuery'], + [4, 'clearBufferfi'], + [5, 'vertexAttribI4i vertexAttribI4ui copyBufferSubData texStorage2D renderbufferStorageMultisample'], + [6, 'texStorage3D'], + [9, 'copyTexSubImage3D'], + [10, 'blitFramebuffer'] +]; + +// If user passes -sMAX_WEBGL_VERSION >= 2 -sSTRICT but not -lGL (to link in +// WebGL 1), then WebGL2 library should not be linked in as well. if (typeof createGLPassthroughFunctions == 'undefined') { throw 'In order to use WebGL 2 in strict mode with -sMAX_WEBGL_VERSION=2, you need to link in WebGL support with -lGL!'; } -createGLPassthroughFunctions(LibraryWebGL2, webgl2Funcs); +createGLPassthroughFunctions(LibraryWebGL2, webgl2PassthroughFuncs); recordGLProcAddressGet(LibraryWebGL2); From c4ea5681334696a732bdf51074cc1231fb0e39fd Mon Sep 17 00:00:00 2001 From: ShrekShao <5031596+shrekshao@users.noreply.github.com> Date: Tue, 21 Mar 2023 16:45:47 -0700 Subject: [PATCH 0039/1523] [WebGPU] Fix texture GetFormat to return enum int (#19027) * [WebGPU] Fix texture GetFormat to return enum int * [WebGPU] remove deprecated dispatch path --- src/library_webgpu.js | 17 ++++------------- test/webgpu_basic_rendering.cpp | 10 ++++++++-- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/src/library_webgpu.js b/src/library_webgpu.js index f0a3b5237e505..09e3911035748 100644 --- a/src/library_webgpu.js +++ b/src/library_webgpu.js @@ -2008,7 +2008,8 @@ var LibraryWebGPU = { wgpuTextureGetFormat: function(textureId) { var texture = WebGPU.mgrTexture.get(textureId); - return texture.format; + // Should return the enum integer instead of string. + return WebGPU.TextureFormat.indexOf(texture.format); }, wgpuTextureGetHeight: function(textureId) { @@ -2101,24 +2102,14 @@ var LibraryWebGPU = { wgpuComputePassEncoderDispatchWorkgroups: function(passId, x, y, z) { var pass = WebGPU.mgrComputePassEncoder.get(passId); - // TODO(shrekshao): Remove deprecated dispatch path - if (pass["dispatchWorkgroups"]) { - pass["dispatchWorkgroups"](x, y, z); - } else { - pass["dispatch"](x, y, z); - } + pass["dispatchWorkgroups"](x, y, z); }, wgpuComputePassEncoderDispatchWorkgroupsIndirect: function(passId, indirectBufferId, {{{ defineI64Param('indirectOffset') }}}) { {{{ receiveI64ParamAsI32s('indirectOffset') }}} var indirectBuffer = WebGPU.mgrBuffer.get(indirectBufferId); var indirectOffset = {{{ gpu.makeI32I32ToU53('indirectOffset_low', 'indirectOffset_high') }}}; var pass = WebGPU.mgrComputePassEncoder.get(passId); - // TODO(shrekshao): Remove deprecated dispatchIndirect path - if (pass["dispatchWorkgroupsIndirect"]) { - pass["dispatchWorkgroupsIndirect"](indirectBuffer, indirectOffset); - } else { - pass["dispatchIndirect"](indirectBuffer, indirectOffset); - } + pass["dispatchWorkgroupsIndirect"](indirectBuffer, indirectOffset); }, wgpuComputePassEncoderBeginPipelineStatisticsQuery: function(passId, querySetId, queryIndex) { diff --git a/test/webgpu_basic_rendering.cpp b/test/webgpu_basic_rendering.cpp index bfb40e8b79774..7db32b61e8e35 100644 --- a/test/webgpu_basic_rendering.cpp +++ b/test/webgpu_basic_rendering.cpp @@ -45,14 +45,14 @@ void GetDevice(void (*callback)(wgpu::Device)) { } static const char shaderCode[] = R"( - @stage(vertex) + @vertex fn main_v(@builtin(vertex_index) idx: u32) -> @builtin(position) vec4 { var pos = array, 3>( vec2(0.0, 0.5), vec2(-0.5, -0.5), vec2(0.5, -0.5)); return vec4(pos[idx], 0.0, 1.0); } - @stage(fragment) + @fragment fn main_f() -> @location(0) vec4 { return vec4(0.0, 0.502, 1.0, 1.0); // 0x80/0xff ~= 0.502 } @@ -309,6 +309,12 @@ void doRenderTest() { } render(readbackTexture.CreateView(), depthTexture.CreateView()); + { + // A little texture.GetFormat test + assert(wgpu::TextureFormat::BGRA8Unorm == readbackTexture.GetFormat()); + assert(wgpu::TextureFormat::Depth32Float == depthTexture.GetFormat()); + } + { wgpu::BufferDescriptor descriptor{}; descriptor.size = 4; From 468e2ab09cf866b403f85e3458587e6dfbc5aec7 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 21 Mar 2023 17:36:44 -0700 Subject: [PATCH 0040/1523] Avoid calling resetPrototype on missing object (#18076) `wasmSourceMapData` and `wasmOffestData` are used to communicate data to new pthreads and cannot/should not be used in general just because `instantatiateWasm` is overridden. Folks who want to override `instantatiateWasm` and still want asan (and the offset converter in general) to work would need to create the `WasmOffsetConverter` as part of `instantatiateWasm`. Fixes: #17472 --- src/preamble.js | 37 ++++++++++++++++++------------- test/manual_wasm_instantiate.html | 5 +++++ 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/src/preamble.js b/src/preamble.js index 527df8e762826..042e591ac2067 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -808,10 +808,12 @@ function instantiateSync(file, info) { } #endif -#if expectToReceiveOnModule('instantiateWasm') && (LOAD_SOURCE_MAP || USE_OFFSET_CONVERTER) -// When using postMessage to send an object, it is processed by the structured clone algorithm. -// The prototype, and hence methods, on that object is then lost. This function adds back the lost prototype. -// This does not work with nested objects that has prototypes, but it suffices for WasmSourceMap and WasmOffsetConverter. +#if PTHREADS && (LOAD_SOURCE_MAP || USE_OFFSET_CONVERTER) +// When using postMessage to send an object, it is processed by the structured +// clone algorithm. The prototype, and hence methods, on that object is then +// lost. This function adds back the lost prototype. This does not work with +// nested objects that has prototypes, but it suffices for WasmSourceMap and +// WasmOffsetConverter. function resetPrototype(constructor, attrs) { var object = Object.create(constructor.prototype); return Object.assign(object, attrs); @@ -1093,26 +1095,31 @@ function createWasm() { #if expectToReceiveOnModule('instantiateWasm') // User shell pages can write their own Module.instantiateWasm = function(imports, successCallback) callback - // to manually instantiate the Wasm module themselves. This allows pages to run the instantiation parallel - // to any other async startup actions they are performing. - // Also pthreads and wasm workers initialize the wasm instance through this path. + // to manually instantiate the Wasm module themselves. This allows pages to + // run the instantiation parallel to any other async startup actions they are + // performing. + // Also pthreads and wasm workers initialize the wasm instance through this + // path. if (Module['instantiateWasm']) { -#if USE_OFFSET_CONVERTER -#if ASSERTIONS && PTHREADS + +#if USE_OFFSET_CONVERTER && PTHREADS if (ENVIRONMENT_IS_PTHREAD) { +#if ASSERTIONS assert(Module['wasmOffsetData'], 'wasmOffsetData not found on Module object'); - } #endif - wasmOffsetConverter = resetPrototype(WasmOffsetConverter, Module['wasmOffsetData']); + wasmOffsetConverter = resetPrototype(WasmOffsetConverter, Module['wasmOffsetData']); + } #endif -#if LOAD_SOURCE_MAP -#if ASSERTIONS && PTHREADS + +#if LOAD_SOURCE_MAP && PTHREADS if (ENVIRONMENT_IS_PTHREAD) { +#if ASSERTIONS assert(Module['wasmSourceMapData'], 'wasmSourceMapData not found on Module object'); - } #endif - wasmSourceMap = resetPrototype(WasmSourceMap, Module['wasmSourceMapData']); + wasmSourceMap = resetPrototype(WasmSourceMap, Module['wasmSourceMapData']); + } #endif + try { return Module['instantiateWasm'](info, receiveInstance); } catch(e) { diff --git a/test/manual_wasm_instantiate.html b/test/manual_wasm_instantiate.html index 2d125e401f5fe..efb34c84c9cf2 100644 --- a/test/manual_wasm_instantiate.html +++ b/test/manual_wasm_instantiate.html @@ -172,6 +172,11 @@ wasm.then(function(wasmBinary) { console.log('wasm download finished, begin instantiating'); var wasmInstantiate = WebAssembly.instantiate(new Uint8Array(wasmBinary), imports).then(function(output) { + // When overriding instantiateWasm, in asan builds, we also need + // to take care of creating the WasmOffsetConverter + if (typeof WasmOffsetConverter != "undefined") { + wasmOffsetConverter = new WasmOffsetConverter(wasmBinary, output.module); + } console.log('wasm instantiation succeeded'); Module.testWasmInstantiationSucceeded = 1; successCallback(output.instance); From 592aeca6a44b20ddeea6948fd9b5793bb8fc36de Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 21 Mar 2023 18:34:11 -0700 Subject: [PATCH 0041/1523] Automatically generate `__sig` properties for JS library symbols (#18985) This primary change here is the creation of `emscripten_internal.h` which is an internal-only header that contains that declaration of internal JS function that are not already declared in other files. The reason for this is to ensure that all JS library functions that are callable form native code have a valid declaration, at least internally, so that gen_sig_info.py can extract that signature from a compiled wasm file. This change add the scripte for generating `library_sigs.js` but doesn't actually start using it, or erase the correpsonding hand-created `__sig` entries. That is will be part of a followup --- src/compiler.js | 11 +- src/jsifier.js | 2 +- src/library.js | 5 - src/library_sigs.js | 911 ++++++++++++++++++ src/modules.js | 7 +- src/utility.js | 12 + system/include/SDL/SDL_cpuinfo.h | 4 + system/lib/compiler-rt/emscripten_setjmp.c | 2 +- .../sanitizer_common/sanitizer_emscripten.cpp | 9 +- .../sanitizer_stacktrace_emscripten.cpp | 7 +- .../sanitizer_symbolizer_emscripten.cpp | 8 +- system/lib/gl/webgl1.c | 7 - system/lib/gl/webgl_internal.h | 7 + system/lib/libc/dynlink.c | 14 +- system/lib/libc/emscripten_internal.h | 112 +++ system/lib/libc/emscripten_memcpy.c | 7 +- system/lib/libc/emscripten_mmap.c | 13 +- system/lib/libc/emscripten_time.c | 5 +- system/lib/libc/mktime.c | 9 +- system/lib/libc/musl/src/internal/progname.c | 5 +- system/lib/libc/musl/src/signal/setitimer.c | 4 +- system/lib/libc/raise.c | 4 +- system/lib/libc/tzset.c | 2 +- system/lib/standalone/standalone.c | 3 +- test/test_other.py | 9 + tools/gen_sig_info.py | 301 ++++++ tools/system_libs.py | 5 +- 27 files changed, 1397 insertions(+), 88 deletions(-) create mode 100644 src/library_sigs.js create mode 100644 system/lib/libc/emscripten_internal.h create mode 100755 tools/gen_sig_info.py diff --git a/src/compiler.js b/src/compiler.js index 301381c3d660a..ba7bebc6acfe4 100755 --- a/src/compiler.js +++ b/src/compiler.js @@ -21,6 +21,7 @@ global.printErr = (x) => { }; function find(filename) { + assert(filename); const prefixes = [__dirname, process.cwd()]; for (let i = 0; i < prefixes.length; ++i) { const combined = nodePath.join(prefixes[i], filename); @@ -32,6 +33,7 @@ function find(filename) { } global.read = (filename) => { + assert(filename); const absolute = find(filename); return fs.readFileSync(absolute).toString(); }; @@ -43,6 +45,9 @@ function load(f) { // Basic utilities load('utility.js'); +// Load default settings +load('./settings.js'); +load('./settings_internal.js'); const argv = process.argv.slice(2); const symbolsOnlyArg = argv.indexOf('--symbols-only'); @@ -50,8 +55,6 @@ if (symbolsOnlyArg != -1) { argv.splice(symbolsOnlyArg, 1); } -const symbolsOnly = symbolsOnlyArg != -1; - // Load settings from JSON passed on the command line const settingsFile = argv[0]; assert(settingsFile); @@ -59,6 +62,8 @@ assert(settingsFile); const settings = JSON.parse(read(settingsFile)); Object.assign(global, settings); +global.symbolsOnly = symbolsOnlyArg != -1; + EXPORTED_FUNCTIONS = new Set(EXPORTED_FUNCTIONS); WASM_EXPORTS = new Set(WASM_EXPORTS); SIDE_MODULE_EXPORTS = new Set(SIDE_MODULE_EXPORTS); @@ -94,7 +99,7 @@ if (!STRICT) { B = new Benchmarker(); try { - runJSify(symbolsOnly); + runJSify(); B.print('glue'); } catch (err) { diff --git a/src/jsifier.js b/src/jsifier.js index 804355b3e8ec3..2503ae9f9e550 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -66,7 +66,7 @@ function isDefined(symName) { return false; } -function runJSify(symbolsOnly = false) { +function runJSify() { const libraryItems = []; const symbolDeps = {}; let postSets = []; diff --git a/src/library.js b/src/library.js index 94f9d5c72720e..ad5a6f953a4e2 100644 --- a/src/library.js +++ b/src/library.js @@ -3029,16 +3029,11 @@ mergeInto(LibraryManager.library, { return runEmAsmFunction(code, sigPtr, argbuf); }, -#if MEMORY64 - // We can't use the alias in wasm64 mode becuase the function signature differs emscripten_asm_const_ptr__sig: 'pppp', emscripten_asm_const_ptr__deps: ['$runEmAsmFunction'], emscripten_asm_const_ptr: function(code, sigPtr, argbuf) { return runEmAsmFunction(code, sigPtr, argbuf); }, -#else - emscripten_asm_const_ptr: 'emscripten_asm_const_int', -#endif $runMainThreadEmAsm__deps: ['$readEmAsmArgs'], $runMainThreadEmAsm__sig: 'iippi', diff --git a/src/library_sigs.js b/src/library_sigs.js new file mode 100644 index 0000000000000..dc424111eba65 --- /dev/null +++ b/src/library_sigs.js @@ -0,0 +1,911 @@ +/* Auto-generated by tools/gen_sig_info.py. DO NOT EDIT. */ + +sigs = { + IMG_Init__sig: 'ii', + IMG_Load__sig: 'pp', + IMG_Load_RW__sig: 'ppi', + IMG_Quit__sig: 'v', + Mix_AllocateChannels__sig: 'ii', + Mix_ChannelFinished__sig: 'vp', + Mix_CloseAudio__sig: 'v', + Mix_FadeInChannelTimed__sig: 'iipiii', + Mix_FadeInMusicPos__sig: 'ipiid', + Mix_FadeOutChannel__sig: 'iii', + Mix_FadeOutMusic__sig: 'ii', + Mix_FadingChannel__sig: 'ii', + Mix_FreeChunk__sig: 'vp', + Mix_FreeMusic__sig: 'vp', + Mix_HaltChannel__sig: 'ii', + Mix_HaltMusic__sig: 'i', + Mix_HookMusicFinished__sig: 'vp', + Mix_Init__sig: 'ii', + Mix_Linked_Version__sig: 'p', + Mix_LoadMUS__sig: 'pp', + Mix_LoadMUS_RW__sig: 'pp', + Mix_LoadWAV__sig: 'pp', + Mix_LoadWAV_RW__sig: 'ppi', + Mix_OpenAudio__sig: 'iiiii', + Mix_Pause__sig: 'vi', + Mix_PauseMusic__sig: 'v', + Mix_Paused__sig: 'ii', + Mix_PausedMusic__sig: 'i', + Mix_PlayChannelTimed__sig: 'iipii', + Mix_PlayMusic__sig: 'ipi', + Mix_Playing__sig: 'ii', + Mix_PlayingMusic__sig: 'i', + Mix_QuerySpec__sig: 'ippp', + Mix_QuickLoad_RAW__sig: 'ppi', + Mix_Quit__sig: 'v', + Mix_ReserveChannels__sig: 'ii', + Mix_Resume__sig: 'vi', + Mix_ResumeMusic__sig: 'v', + Mix_SetPanning__sig: 'iiii', + Mix_SetPosition__sig: 'iiii', + Mix_SetPostMix__sig: 'vpp', + Mix_Volume__sig: 'iii', + Mix_VolumeChunk__sig: 'ipi', + Mix_VolumeMusic__sig: 'ii', + SDL_AddTimer__sig: 'iipp', + SDL_AllocRW__sig: 'p', + SDL_AudioDriverName__sig: 'ppi', + SDL_AudioQuit__sig: 'v', + SDL_ClearError__sig: 'v', + SDL_CloseAudio__sig: 'v', + SDL_CondBroadcast__sig: 'ip', + SDL_CondSignal__sig: 'ip', + SDL_CondWait__sig: 'ipp', + SDL_CondWaitTimeout__sig: 'ippi', + SDL_ConvertSurface__sig: 'pppi', + SDL_CreateCond__sig: 'p', + SDL_CreateMutex__sig: 'p', + SDL_CreateRGBSurface__sig: 'piiiiiiii', + SDL_CreateRGBSurfaceFrom__sig: 'ppiiiiiiii', + SDL_CreateThread__sig: 'ppp', + SDL_Delay__sig: 'vi', + SDL_DestroyCond__sig: 'vp', + SDL_DestroyMutex__sig: 'vp', + SDL_DestroyRenderer__sig: 'vp', + SDL_DestroyWindow__sig: 'vp', + SDL_DisplayFormatAlpha__sig: 'pp', + SDL_EnableKeyRepeat__sig: 'iii', + SDL_EnableUNICODE__sig: 'ii', + SDL_FillRect__sig: 'ippi', + SDL_Flip__sig: 'ip', + SDL_FreeRW__sig: 'vp', + SDL_FreeSurface__sig: 'vp', + SDL_GL_DeleteContext__sig: 'vp', + SDL_GL_ExtensionSupported__sig: 'ip', + SDL_GL_GetAttribute__sig: 'iip', + SDL_GL_GetSwapInterval__sig: 'i', + SDL_GL_MakeCurrent__sig: 'ipp', + SDL_GL_SetAttribute__sig: 'iii', + SDL_GL_SetSwapInterval__sig: 'ii', + SDL_GL_SwapBuffers__sig: 'v', + SDL_GL_SwapWindow__sig: 'vp', + SDL_GetAppState__sig: 'i', + SDL_GetAudioDriver__sig: 'pi', + SDL_GetClipRect__sig: 'vpp', + SDL_GetCurrentAudioDriver__sig: 'p', + SDL_GetError__sig: 'p', + SDL_GetKeyName__sig: 'pi', + SDL_GetKeyboardState__sig: 'pp', + SDL_GetModState__sig: 'i', + SDL_GetMouseState__sig: 'ipp', + SDL_GetNumAudioDrivers__sig: 'i', + SDL_GetRGB__sig: 'vipppp', + SDL_GetRGBA__sig: 'vippppp', + SDL_GetScancodeFromKey__sig: 'ii', + SDL_GetThreadID__sig: 'pp', + SDL_GetTicks__sig: 'i', + SDL_GetVideoInfo__sig: 'p', + SDL_GetVideoSurface__sig: 'p', + SDL_GetWindowFlags__sig: 'ip', + SDL_GetWindowSize__sig: 'vppp', + SDL_Has3DNow__sig: 'i', + SDL_Has3DNowExt__sig: 'i', + SDL_HasAltiVec__sig: 'i', + SDL_HasMMX__sig: 'i', + SDL_HasMMXExt__sig: 'i', + SDL_HasRDTSC__sig: 'i', + SDL_HasSSE__sig: 'i', + SDL_HasSSE2__sig: 'i', + SDL_Init__sig: 'ii', + SDL_InitSubSystem__sig: 'ii', + SDL_JoystickClose__sig: 'vp', + SDL_JoystickEventState__sig: 'ii', + SDL_JoystickGetAxis__sig: 'ipi', + SDL_JoystickGetBall__sig: 'ipipp', + SDL_JoystickGetButton__sig: 'ipi', + SDL_JoystickGetHat__sig: 'ipi', + SDL_JoystickIndex__sig: 'ip', + SDL_JoystickName__sig: 'pi', + SDL_JoystickNumAxes__sig: 'ip', + SDL_JoystickNumBalls__sig: 'ip', + SDL_JoystickNumButtons__sig: 'ip', + SDL_JoystickNumHats__sig: 'ip', + SDL_JoystickOpen__sig: 'pi', + SDL_JoystickOpened__sig: 'ii', + SDL_JoystickUpdate__sig: 'v', + SDL_Linked_Version__sig: 'p', + SDL_ListModes__sig: 'ppi', + SDL_LoadBMP_RW__sig: 'ppi', + SDL_LockAudio__sig: 'v', + SDL_LockSurface__sig: 'ip', + SDL_LogSetOutputFunction__sig: 'vpp', + SDL_LowerBlit__sig: 'ipppp', + SDL_LowerBlitScaled__sig: 'ipppp', + SDL_MapRGB__sig: 'ipiii', + SDL_MapRGBA__sig: 'ipiiii', + SDL_NumJoysticks__sig: 'i', + SDL_OpenAudio__sig: 'ipp', + SDL_PauseAudio__sig: 'vi', + SDL_PeepEvents__sig: 'ipiiii', + SDL_PollEvent__sig: 'ip', + SDL_PumpEvents__sig: 'v', + SDL_PushEvent__sig: 'ip', + SDL_Quit__sig: 'v', + SDL_QuitSubSystem__sig: 'vi', + SDL_RWFromConstMem__sig: 'ppi', + SDL_RWFromFile__sig: 'ppp', + SDL_RWFromMem__sig: 'ppi', + SDL_RemoveTimer__sig: 'ii', + SDL_SaveBMP_RW__sig: 'ippi', + SDL_SetAlpha__sig: 'ipii', + SDL_SetClipRect__sig: 'ipp', + SDL_SetColorKey__sig: 'ipii', + SDL_SetColors__sig: 'ippii', + SDL_SetError__sig: 'vpp', + SDL_SetGamma__sig: 'ifff', + SDL_SetGammaRamp__sig: 'ippp', + SDL_SetPalette__sig: 'ipipii', + SDL_SetVideoMode__sig: 'piiii', + SDL_SetWindowFullscreen__sig: 'ipi', + SDL_SetWindowTitle__sig: 'vpp', + SDL_ShowCursor__sig: 'ii', + SDL_StartTextInput__sig: 'v', + SDL_StopTextInput__sig: 'v', + SDL_ThreadID__sig: 'p', + SDL_UnlockAudio__sig: 'v', + SDL_UnlockSurface__sig: 'vp', + SDL_UpdateRect__sig: 'vpiiii', + SDL_UpdateRects__sig: 'vpip', + SDL_UpperBlit__sig: 'ipppp', + SDL_UpperBlitScaled__sig: 'ipppp', + SDL_VideoDriverName__sig: 'ppi', + SDL_VideoModeOK__sig: 'iiiii', + SDL_VideoQuit__sig: 'v', + SDL_WM_GrabInput__sig: 'ii', + SDL_WM_IconifyWindow__sig: 'i', + SDL_WM_SetCaption__sig: 'vpp', + SDL_WM_SetIcon__sig: 'vpp', + SDL_WM_ToggleFullScreen__sig: 'ip', + SDL_WaitThread__sig: 'vpp', + SDL_WarpMouse__sig: 'vii', + SDL_WasInit__sig: 'ii', + SDL_mutexP__sig: 'ip', + SDL_mutexV__sig: 'ip', + TTF_CloseFont__sig: 'vp', + TTF_FontAscent__sig: 'ip', + TTF_FontDescent__sig: 'ip', + TTF_FontHeight__sig: 'ip', + TTF_FontLineSkip__sig: 'ip', + TTF_GlyphMetrics__sig: 'ipippppp', + TTF_Init__sig: 'i', + TTF_OpenFont__sig: 'ppi', + TTF_Quit__sig: 'v', + TTF_RenderText_Blended__sig: 'pppp', + TTF_RenderText_Shaded__sig: 'ppppp', + TTF_RenderText_Solid__sig: 'pppp', + TTF_RenderUTF8_Solid__sig: 'pppp', + TTF_SizeText__sig: 'ipppp', + TTF_SizeUTF8__sig: 'ipppp', + XChangeWindowAttributes__sig: 'ipppp', + XCreateWindow__sig: 'pppiiiiiiippp', + XInternAtom__sig: 'pppi', + XMapWindow__sig: 'ipp', + XOpenDisplay__sig: 'pp', + XPending__sig: 'ip', + XSendEvent__sig: 'ippipp', + XSetWMHints__sig: 'ippp', + XStoreName__sig: 'ippp', + __asctime_r__sig: 'ppp', + __assert_fail__sig: 'vppip', + __call_sighandler__sig: 'vpi', + __dlsym__sig: 'pppp', + __handle_stack_overflow__sig: 'vp', + __syscall__newselect__sig: 'iipppp', + __syscall_accept4__sig: 'iippiii', + __syscall_bind__sig: 'iippiii', + __syscall_chdir__sig: 'ip', + __syscall_chmod__sig: 'ipi', + __syscall_connect__sig: 'iippiii', + __syscall_dup__sig: 'ii', + __syscall_dup3__sig: 'iiii', + __syscall_faccessat__sig: 'iipii', + __syscall_fadvise64__sig: 'iijji', + __syscall_fallocate__sig: 'iiijj', + __syscall_fchdir__sig: 'ii', + __syscall_fchmod__sig: 'iii', + __syscall_fchmodat__sig: 'iipip', + __syscall_fchown32__sig: 'iiii', + __syscall_fchownat__sig: 'iipiii', + __syscall_fcntl64__sig: 'iiip', + __syscall_fdatasync__sig: 'ii', + __syscall_fstat64__sig: 'iip', + __syscall_fstatfs64__sig: 'iipp', + __syscall_ftruncate64__sig: 'iij', + __syscall_getcwd__sig: 'ipp', + __syscall_getdents64__sig: 'iipp', + __syscall_getpeername__sig: 'iippiii', + __syscall_getsockname__sig: 'iippiii', + __syscall_getsockopt__sig: 'iiiippi', + __syscall_ioctl__sig: 'iiip', + __syscall_linkat__sig: 'iipipi', + __syscall_listen__sig: 'iiiiiii', + __syscall_lstat64__sig: 'ipp', + __syscall_mkdirat__sig: 'iipi', + __syscall_mknodat__sig: 'iipii', + __syscall_newfstatat__sig: 'iippi', + __syscall_openat__sig: 'iipip', + __syscall_pipe__sig: 'ip', + __syscall_poll__sig: 'ipii', + __syscall_readlinkat__sig: 'iippp', + __syscall_recvfrom__sig: 'iippipp', + __syscall_recvmsg__sig: 'iipiiii', + __syscall_renameat__sig: 'iipip', + __syscall_rmdir__sig: 'ip', + __syscall_sendmsg__sig: 'iipippi', + __syscall_sendto__sig: 'iippipp', + __syscall_shutdown__sig: 'iiiiiii', + __syscall_socket__sig: 'iiiiiii', + __syscall_stat64__sig: 'ipp', + __syscall_statfs64__sig: 'ippp', + __syscall_symlink__sig: 'ipp', + __syscall_symlinkat__sig: 'ipip', + __syscall_truncate64__sig: 'ipj', + __syscall_unlinkat__sig: 'iipi', + __syscall_utimensat__sig: 'iippi', + _dlopen_js__sig: 'pp', + _dlsym_catchup_js__sig: 'ppi', + _dlsym_js__sig: 'pppp', + _emscripten_dbg__sig: 'vp', + _emscripten_dlopen_js__sig: 'vpppp', + _emscripten_err__sig: 'vp', + _emscripten_fs_load_embedded_files__sig: 'vp', + _emscripten_get_now_is_monotonic__sig: 'i', + _emscripten_get_progname__sig: 'vpi', + _emscripten_out__sig: 'vp', + _emscripten_push_main_loop_blocker__sig: 'vppp', + _emscripten_push_uncounted_main_loop_blocker__sig: 'vppp', + _emscripten_throw_longjmp__sig: 'v', + _gmtime_js__sig: 'vpp', + _localtime_js__sig: 'vpp', + _mktime_js__sig: 'ip', + _mmap_js__sig: 'ipiiippp', + _msync_js__sig: 'ippiiip', + _munmap_js__sig: 'ippiiip', + _setitimer_js__sig: 'iid', + _timegm_js__sig: 'ip', + _tzset_js__sig: 'vppp', + abort__sig: 'v', + alBuffer3f__sig: 'viifff', + alBuffer3i__sig: 'viiiii', + alBufferData__sig: 'viipii', + alBufferf__sig: 'viif', + alBufferfv__sig: 'viip', + alBufferi__sig: 'viii', + alBufferiv__sig: 'viip', + alDeleteBuffers__sig: 'vip', + alDeleteSources__sig: 'vip', + alDisable__sig: 'vi', + alDistanceModel__sig: 'vi', + alDopplerFactor__sig: 'vf', + alDopplerVelocity__sig: 'vf', + alEnable__sig: 'vi', + alGenBuffers__sig: 'vip', + alGenSources__sig: 'vip', + alGetBoolean__sig: 'ii', + alGetBooleanv__sig: 'vip', + alGetBuffer3f__sig: 'viippp', + alGetBuffer3i__sig: 'viippp', + alGetBufferf__sig: 'viip', + alGetBufferfv__sig: 'viip', + alGetBufferi__sig: 'viip', + alGetBufferiv__sig: 'viip', + alGetDouble__sig: 'di', + alGetDoublev__sig: 'vip', + alGetEnumValue__sig: 'ip', + alGetError__sig: 'i', + alGetFloat__sig: 'fi', + alGetFloatv__sig: 'vip', + alGetInteger__sig: 'ii', + alGetIntegerv__sig: 'vip', + alGetListener3f__sig: 'vippp', + alGetListener3i__sig: 'vippp', + alGetListenerf__sig: 'vip', + alGetListenerfv__sig: 'vip', + alGetListeneri__sig: 'vip', + alGetListeneriv__sig: 'vip', + alGetSource3f__sig: 'viippp', + alGetSource3i__sig: 'viippp', + alGetSourcef__sig: 'viip', + alGetSourcefv__sig: 'viip', + alGetSourcei__sig: 'viip', + alGetSourceiv__sig: 'viip', + alGetString__sig: 'pi', + alIsBuffer__sig: 'ii', + alIsEnabled__sig: 'ii', + alIsExtensionPresent__sig: 'ip', + alIsSource__sig: 'ii', + alListener3f__sig: 'vifff', + alListener3i__sig: 'viiii', + alListenerf__sig: 'vif', + alListenerfv__sig: 'vip', + alListeneri__sig: 'vii', + alListeneriv__sig: 'vip', + alSource3f__sig: 'viifff', + alSource3i__sig: 'viiiii', + alSourcePause__sig: 'vi', + alSourcePausev__sig: 'vip', + alSourcePlay__sig: 'vi', + alSourcePlayv__sig: 'vip', + alSourceQueueBuffers__sig: 'viip', + alSourceRewind__sig: 'vi', + alSourceRewindv__sig: 'vip', + alSourceStop__sig: 'vi', + alSourceStopv__sig: 'vip', + alSourceUnqueueBuffers__sig: 'viip', + alSourcef__sig: 'viif', + alSourcefv__sig: 'viip', + alSourcei__sig: 'viii', + alSourceiv__sig: 'viip', + alSpeedOfSound__sig: 'vf', + alcCaptureCloseDevice__sig: 'ip', + alcCaptureOpenDevice__sig: 'ppiii', + alcCaptureSamples__sig: 'vppi', + alcCaptureStart__sig: 'vp', + alcCaptureStop__sig: 'vp', + alcCloseDevice__sig: 'ip', + alcCreateContext__sig: 'ppp', + alcDestroyContext__sig: 'vp', + alcGetContextsDevice__sig: 'pp', + alcGetCurrentContext__sig: 'p', + alcGetEnumValue__sig: 'ipp', + alcGetError__sig: 'ip', + alcGetIntegerv__sig: 'vpiip', + alcGetString__sig: 'ppi', + alcIsExtensionPresent__sig: 'ipp', + alcMakeContextCurrent__sig: 'ip', + alcOpenDevice__sig: 'pp', + alcProcessContext__sig: 'vp', + alcSuspendContext__sig: 'vp', + args_get__sig: 'ipp', + args_sizes_get__sig: 'ipp', + boxColor__sig: 'ipiiiii', + boxRGBA__sig: 'ipiiiiiiii', + clock_res_get__sig: 'iip', + clock_time_get__sig: 'iijp', + dladdr__sig: 'ipp', + dlopen__sig: 'ppi', + ellipseColor__sig: 'ipiiiii', + ellipseRGBA__sig: 'ipiiiiiiii', + emscripten_SDL_SetEventHandler__sig: 'vpp', + emscripten_asm_const_async_on_main_thread__sig: 'vppp', + emscripten_asm_const_double__sig: 'dppp', + emscripten_asm_const_double_sync_on_main_thread__sig: 'dppp', + emscripten_asm_const_int__sig: 'ippp', + emscripten_asm_const_int_sync_on_main_thread__sig: 'ippp', + emscripten_asm_const_ptr__sig: 'pppp', + emscripten_async_call__sig: 'vppi', + emscripten_async_load_script__sig: 'vppp', + emscripten_async_run_script__sig: 'vpi', + emscripten_async_wget__sig: 'vpppp', + emscripten_async_wget2__sig: 'ipppppppp', + emscripten_async_wget2_abort__sig: 'vi', + emscripten_async_wget2_data__sig: 'ippppippp', + emscripten_async_wget_data__sig: 'vpppp', + emscripten_audio_context_state__sig: 'ii', + emscripten_audio_worklet_post_function_sig__sig: 'vippp', + emscripten_audio_worklet_post_function_v__sig: 'vip', + emscripten_audio_worklet_post_function_vd__sig: 'vipd', + emscripten_audio_worklet_post_function_vdd__sig: 'vipdd', + emscripten_audio_worklet_post_function_vddd__sig: 'vipddd', + emscripten_audio_worklet_post_function_vi__sig: 'vipi', + emscripten_audio_worklet_post_function_vii__sig: 'vipii', + emscripten_audio_worklet_post_function_viii__sig: 'vipiii', + emscripten_call_worker__sig: 'vippipp', + emscripten_cancel_animation_frame__sig: 'vi', + emscripten_cancel_main_loop__sig: 'v', + emscripten_clear_immediate__sig: 'vi', + emscripten_clear_interval__sig: 'vi', + emscripten_clear_timeout__sig: 'vi', + emscripten_console_error__sig: 'vp', + emscripten_console_log__sig: 'vp', + emscripten_console_warn__sig: 'vp', + emscripten_create_audio_context__sig: 'ip', + emscripten_create_worker__sig: 'ip', + emscripten_current_thread_is_audio_worklet__sig: 'i', + emscripten_date_now__sig: 'd', + emscripten_debugger__sig: 'v', + emscripten_destroy_audio_context__sig: 'vi', + emscripten_destroy_web_audio_node__sig: 'vi', + emscripten_destroy_worker__sig: 'vi', + emscripten_dlopen__sig: 'vpippp', + emscripten_enter_soft_fullscreen__sig: 'ipp', + emscripten_exit_fullscreen__sig: 'i', + emscripten_exit_pointerlock__sig: 'i', + emscripten_exit_soft_fullscreen__sig: 'i', + emscripten_exit_with_live_runtime__sig: 'v', + emscripten_fiber_init__sig: 'vppppppp', + emscripten_fiber_init_from_current_context__sig: 'vppp', + emscripten_fiber_swap__sig: 'vpp', + emscripten_force_exit__sig: 'vi', + emscripten_get_battery_status__sig: 'ip', + emscripten_get_callstack__sig: 'iipi', + emscripten_get_canvas_element_size__sig: 'ippp', + emscripten_get_canvas_size__sig: 'vppp', + emscripten_get_compiler_setting__sig: 'pp', + emscripten_get_device_pixel_ratio__sig: 'd', + emscripten_get_devicemotion_status__sig: 'ip', + emscripten_get_deviceorientation_status__sig: 'ip', + emscripten_get_element_css_size__sig: 'ippp', + emscripten_get_fullscreen_status__sig: 'ip', + emscripten_get_gamepad_status__sig: 'iip', + emscripten_get_heap_max__sig: 'p', + emscripten_get_main_loop_timing__sig: 'vpp', + emscripten_get_module_name__sig: 'ppp', + emscripten_get_mouse_status__sig: 'ip', + emscripten_get_now__sig: 'd', + emscripten_get_now_res__sig: 'd', + emscripten_get_num_gamepads__sig: 'i', + emscripten_get_orientation_status__sig: 'ip', + emscripten_get_pointerlock_status__sig: 'ip', + emscripten_get_preloaded_image_data__sig: 'pppp', + emscripten_get_preloaded_image_data_from_FILE__sig: 'pppp', + emscripten_get_screen_size__sig: 'vpp', + emscripten_get_visibility_status__sig: 'ip', + emscripten_get_window_title__sig: 'p', + emscripten_get_worker_queue_size__sig: 'ii', + emscripten_has_asyncify__sig: 'i', + emscripten_hide_mouse__sig: 'v', + emscripten_html5_remove_all_event_listeners__sig: 'v', + emscripten_idb_async_delete__sig: 'vppppp', + emscripten_idb_async_exists__sig: 'vppppp', + emscripten_idb_async_load__sig: 'vppppp', + emscripten_idb_async_store__sig: 'vpppippp', + emscripten_idb_delete__sig: 'vppp', + emscripten_idb_exists__sig: 'vpppp', + emscripten_idb_load__sig: 'vppppp', + emscripten_idb_store__sig: 'vpppip', + emscripten_is_webgl_context_lost__sig: 'ii', + emscripten_lock_orientation__sig: 'ii', + emscripten_log__sig: 'vipp', + emscripten_math_acos__sig: 'dd', + emscripten_math_acosh__sig: 'dd', + emscripten_math_asin__sig: 'dd', + emscripten_math_asinh__sig: 'dd', + emscripten_math_atan__sig: 'dd', + emscripten_math_atan2__sig: 'ddd', + emscripten_math_atanh__sig: 'dd', + emscripten_math_cbrt__sig: 'dd', + emscripten_math_cos__sig: 'dd', + emscripten_math_cosh__sig: 'dd', + emscripten_math_exp__sig: 'dd', + emscripten_math_expm1__sig: 'dd', + emscripten_math_fmod__sig: 'ddd', + emscripten_math_hypot__sig: 'dip', + emscripten_math_log__sig: 'dd', + emscripten_math_log10__sig: 'dd', + emscripten_math_log1p__sig: 'dd', + emscripten_math_log2__sig: 'dd', + emscripten_math_pow__sig: 'ddd', + emscripten_math_random__sig: 'd', + emscripten_math_round__sig: 'dd', + emscripten_math_sign__sig: 'dd', + emscripten_math_sin__sig: 'dd', + emscripten_math_sinh__sig: 'dd', + emscripten_math_sqrt__sig: 'dd', + emscripten_math_tan__sig: 'dd', + emscripten_math_tanh__sig: 'dd', + emscripten_memcpy_big__sig: 'vppp', + emscripten_notify_memory_growth__sig: 'vp', + emscripten_pause_main_loop__sig: 'v', + emscripten_pc_get_column__sig: 'ip', + emscripten_pc_get_file__sig: 'pp', + emscripten_pc_get_function__sig: 'pp', + emscripten_pc_get_line__sig: 'ip', + emscripten_performance_now__sig: 'd', + emscripten_print_double__sig: 'idpi', + emscripten_promise_all__sig: 'pppp', + emscripten_promise_create__sig: 'p', + emscripten_promise_destroy__sig: 'vp', + emscripten_promise_resolve__sig: 'vpip', + emscripten_promise_then__sig: 'ppppp', + emscripten_random__sig: 'f', + emscripten_request_animation_frame__sig: 'ipp', + emscripten_request_animation_frame_loop__sig: 'vpp', + emscripten_request_fullscreen__sig: 'ipi', + emscripten_request_fullscreen_strategy__sig: 'ipip', + emscripten_request_pointerlock__sig: 'ipi', + emscripten_resize_heap__sig: 'ip', + emscripten_resume_audio_context_async__sig: 'vipp', + emscripten_resume_audio_context_sync__sig: 'vi', + emscripten_resume_main_loop__sig: 'v', + emscripten_return_address__sig: 'pi', + emscripten_run_preload_plugins__sig: 'ippp', + emscripten_run_preload_plugins_data__sig: 'vpipppp', + emscripten_run_script__sig: 'vp', + emscripten_run_script_int__sig: 'ip', + emscripten_run_script_string__sig: 'pp', + emscripten_runtime_keepalive_check__sig: 'i', + emscripten_runtime_keepalive_pop__sig: 'v', + emscripten_runtime_keepalive_push__sig: 'v', + emscripten_sample_gamepad_data__sig: 'i', + emscripten_scan_registers__sig: 'vp', + emscripten_set_batterychargingchange_callback_on_thread__sig: 'ippp', + emscripten_set_batterylevelchange_callback_on_thread__sig: 'ippp', + emscripten_set_beforeunload_callback_on_thread__sig: 'ippp', + emscripten_set_blur_callback_on_thread__sig: 'ippipp', + emscripten_set_canvas_element_size__sig: 'ipii', + emscripten_set_canvas_size__sig: 'vii', + emscripten_set_click_callback_on_thread__sig: 'ippipp', + emscripten_set_dblclick_callback_on_thread__sig: 'ippipp', + emscripten_set_devicemotion_callback_on_thread__sig: 'ipipp', + emscripten_set_deviceorientation_callback_on_thread__sig: 'ipipp', + emscripten_set_element_css_size__sig: 'ipdd', + emscripten_set_focus_callback_on_thread__sig: 'ippipp', + emscripten_set_focusin_callback_on_thread__sig: 'ippipp', + emscripten_set_focusout_callback_on_thread__sig: 'ippipp', + emscripten_set_fullscreenchange_callback_on_thread__sig: 'ippipp', + emscripten_set_gamepadconnected_callback_on_thread__sig: 'ipipp', + emscripten_set_gamepaddisconnected_callback_on_thread__sig: 'ipipp', + emscripten_set_immediate__sig: 'ipp', + emscripten_set_immediate_loop__sig: 'vpp', + emscripten_set_interval__sig: 'ipdp', + emscripten_set_keydown_callback_on_thread__sig: 'ippipp', + emscripten_set_keypress_callback_on_thread__sig: 'ippipp', + emscripten_set_keyup_callback_on_thread__sig: 'ippipp', + emscripten_set_main_loop__sig: 'vpii', + emscripten_set_main_loop_arg__sig: 'vppii', + emscripten_set_main_loop_expected_blockers__sig: 'vi', + emscripten_set_main_loop_timing__sig: 'iii', + emscripten_set_mousedown_callback_on_thread__sig: 'ippipp', + emscripten_set_mouseenter_callback_on_thread__sig: 'ippipp', + emscripten_set_mouseleave_callback_on_thread__sig: 'ippipp', + emscripten_set_mousemove_callback_on_thread__sig: 'ippipp', + emscripten_set_mouseout_callback_on_thread__sig: 'ippipp', + emscripten_set_mouseover_callback_on_thread__sig: 'ippipp', + emscripten_set_mouseup_callback_on_thread__sig: 'ippipp', + emscripten_set_orientationchange_callback_on_thread__sig: 'ipipp', + emscripten_set_pointerlockchange_callback_on_thread__sig: 'ippipp', + emscripten_set_pointerlockerror_callback_on_thread__sig: 'ippipp', + emscripten_set_resize_callback_on_thread__sig: 'ippipp', + emscripten_set_scroll_callback_on_thread__sig: 'ippipp', + emscripten_set_socket_close_callback__sig: 'vpp', + emscripten_set_socket_connection_callback__sig: 'vpp', + emscripten_set_socket_error_callback__sig: 'vpp', + emscripten_set_socket_listen_callback__sig: 'vpp', + emscripten_set_socket_message_callback__sig: 'vpp', + emscripten_set_socket_open_callback__sig: 'vpp', + emscripten_set_timeout__sig: 'ipdp', + emscripten_set_timeout_loop__sig: 'vpdp', + emscripten_set_touchcancel_callback_on_thread__sig: 'ippipp', + emscripten_set_touchend_callback_on_thread__sig: 'ippipp', + emscripten_set_touchmove_callback_on_thread__sig: 'ippipp', + emscripten_set_touchstart_callback_on_thread__sig: 'ippipp', + emscripten_set_visibilitychange_callback_on_thread__sig: 'ipipp', + emscripten_set_webglcontextlost_callback_on_thread__sig: 'ippipp', + emscripten_set_webglcontextrestored_callback_on_thread__sig: 'ippipp', + emscripten_set_wheel_callback_on_thread__sig: 'ippipp', + emscripten_set_window_title__sig: 'vp', + emscripten_sleep__sig: 'vi', + emscripten_stack_snapshot__sig: 'p', + emscripten_stack_unwind_buffer__sig: 'ippi', + emscripten_supports_offscreencanvas__sig: 'i', + emscripten_throw_number__sig: 'vd', + emscripten_throw_string__sig: 'vp', + emscripten_unlock_orientation__sig: 'i', + emscripten_unwind_to_js_event_loop__sig: 'v', + emscripten_vibrate__sig: 'ii', + emscripten_vibrate_pattern__sig: 'ipi', + emscripten_webgl_commit_frame__sig: 'i', + emscripten_webgl_create_context__sig: 'ipp', + emscripten_webgl_destroy_context__sig: 'ii', + emscripten_webgl_do_commit_frame__sig: 'i', + emscripten_webgl_do_create_context__sig: 'ipp', + emscripten_webgl_do_get_current_context__sig: 'i', + emscripten_webgl_enable_ANGLE_instanced_arrays__sig: 'ii', + emscripten_webgl_enable_OES_vertex_array_object__sig: 'ii', + emscripten_webgl_enable_WEBGL_draw_buffers__sig: 'ii', + emscripten_webgl_enable_WEBGL_multi_draw__sig: 'ii', + emscripten_webgl_enable_extension__sig: 'iip', + emscripten_webgl_get_context_attributes__sig: 'iip', + emscripten_webgl_get_current_context__sig: 'i', + emscripten_webgl_get_drawing_buffer_size__sig: 'iipp', + emscripten_webgl_get_parameter_d__sig: 'di', + emscripten_webgl_get_parameter_i64v__sig: 'vip', + emscripten_webgl_get_parameter_o__sig: 'ii', + emscripten_webgl_get_parameter_utf8__sig: 'pi', + emscripten_webgl_get_parameter_v__sig: 'iipii', + emscripten_webgl_get_program_info_log_utf8__sig: 'pi', + emscripten_webgl_get_program_parameter_d__sig: 'dii', + emscripten_webgl_get_shader_info_log_utf8__sig: 'pi', + emscripten_webgl_get_shader_parameter_d__sig: 'dii', + emscripten_webgl_get_shader_source_utf8__sig: 'pi', + emscripten_webgl_get_supported_extensions__sig: 'p', + emscripten_webgl_get_uniform_d__sig: 'dii', + emscripten_webgl_get_uniform_v__sig: 'iiipii', + emscripten_webgl_get_vertex_attrib_d__sig: 'dii', + emscripten_webgl_get_vertex_attrib_o__sig: 'iii', + emscripten_webgl_get_vertex_attrib_v__sig: 'iiipii', + emscripten_webgl_init_context_attributes__sig: 'vp', + emscripten_webgl_make_context_current__sig: 'ii', + emscripten_websocket_close__sig: 'iiip', + emscripten_websocket_deinitialize__sig: 'v', + emscripten_websocket_delete__sig: 'ii', + emscripten_websocket_get_buffered_amount__sig: 'iip', + emscripten_websocket_get_extensions__sig: 'iipi', + emscripten_websocket_get_extensions_length__sig: 'iip', + emscripten_websocket_get_protocol__sig: 'iipi', + emscripten_websocket_get_protocol_length__sig: 'iip', + emscripten_websocket_get_ready_state__sig: 'iip', + emscripten_websocket_get_url__sig: 'iipi', + emscripten_websocket_get_url_length__sig: 'iip', + emscripten_websocket_is_supported__sig: 'i', + emscripten_websocket_new__sig: 'ip', + emscripten_websocket_send_binary__sig: 'iipi', + emscripten_websocket_send_utf8_text__sig: 'iip', + emscripten_websocket_set_onclose_callback_on_thread__sig: 'iippp', + emscripten_websocket_set_onerror_callback_on_thread__sig: 'iippp', + emscripten_websocket_set_onmessage_callback_on_thread__sig: 'iippp', + emscripten_websocket_set_onopen_callback_on_thread__sig: 'iippp', + emscripten_wget__sig: 'vpp', + emscripten_wget_data__sig: 'vpppp', + endprotoent__sig: 'v', + environ_get__sig: 'ipp', + environ_sizes_get__sig: 'ipp', + exit__sig: 'vi', + fd_close__sig: 'ii', + fd_fdstat_get__sig: 'iip', + fd_pread__sig: 'iippjp', + fd_pwrite__sig: 'iippjp', + fd_read__sig: 'iippp', + fd_seek__sig: 'iijip', + fd_sync__sig: 'ii', + fd_write__sig: 'iippp', + filledEllipseColor__sig: 'ipiiiii', + filledEllipseRGBA__sig: 'ipiiiiiiii', + getaddrinfo__sig: 'ipppp', + getentropy__sig: 'ipp', + gethostbyaddr__sig: 'ppii', + gethostbyname__sig: 'pp', + gethostbyname_r__sig: 'ipppppp', + getloadavg__sig: 'ipi', + getnameinfo__sig: 'ipipipii', + getprotobyname__sig: 'pp', + getprotobynumber__sig: 'pi', + getprotoent__sig: 'p', + glActiveTexture__sig: 'vi', + glAttachShader__sig: 'vii', + glBegin__sig: 'vi', + glBindAttribLocation__sig: 'viip', + glBindBuffer__sig: 'vii', + glBindFramebuffer__sig: 'vii', + glBindRenderbuffer__sig: 'vii', + glBindTexture__sig: 'vii', + glBindVertexArray__sig: 'vi', + glBindVertexArrayOES__sig: 'vi', + glBlendColor__sig: 'vffff', + glBlendEquation__sig: 'vi', + glBlendEquationSeparate__sig: 'vii', + glBlendFunc__sig: 'vii', + glBlendFuncSeparate__sig: 'viiii', + glBufferData__sig: 'vippi', + glBufferSubData__sig: 'vippp', + glCheckFramebufferStatus__sig: 'ii', + glClear__sig: 'vi', + glClearColor__sig: 'vffff', + glClearDepth__sig: 'vd', + glClearDepthf__sig: 'vf', + glClearStencil__sig: 'vi', + glColorMask__sig: 'viiii', + glCompileShader__sig: 'vi', + glCompressedTexImage2D__sig: 'viiiiiiip', + glCompressedTexSubImage2D__sig: 'viiiiiiiip', + glCopyTexImage2D__sig: 'viiiiiiii', + glCopyTexSubImage2D__sig: 'viiiiiiii', + glCreateProgram__sig: 'i', + glCreateShader__sig: 'ii', + glCullFace__sig: 'vi', + glDeleteBuffers__sig: 'vip', + glDeleteFramebuffers__sig: 'vip', + glDeleteProgram__sig: 'vi', + glDeleteRenderbuffers__sig: 'vip', + glDeleteShader__sig: 'vi', + glDeleteTextures__sig: 'vip', + glDeleteVertexArrays__sig: 'vip', + glDeleteVertexArraysOES__sig: 'vip', + glDepthFunc__sig: 'vi', + glDepthMask__sig: 'vi', + glDepthRange__sig: 'vdd', + glDepthRangef__sig: 'vff', + glDetachShader__sig: 'vii', + glDisable__sig: 'vi', + glDisableVertexAttribArray__sig: 'vi', + glDrawArrays__sig: 'viii', + glDrawArraysInstanced__sig: 'viiii', + glDrawBuffers__sig: 'vip', + glDrawElements__sig: 'viiip', + glDrawElementsInstanced__sig: 'viiipi', + glEnable__sig: 'vi', + glEnableVertexAttribArray__sig: 'vi', + glFinish__sig: 'v', + glFlush__sig: 'v', + glFlushMappedBufferRange__sig: 'vipp', + glFramebufferRenderbuffer__sig: 'viiii', + glFramebufferTexture2D__sig: 'viiiii', + glFrontFace__sig: 'vi', + glGenBuffers__sig: 'vip', + glGenFramebuffers__sig: 'vip', + glGenRenderbuffers__sig: 'vip', + glGenTextures__sig: 'vip', + glGenVertexArrays__sig: 'vip', + glGenVertexArraysOES__sig: 'vip', + glGenerateMipmap__sig: 'vi', + glGetActiveAttrib__sig: 'viiipppp', + glGetActiveUniform__sig: 'viiipppp', + glGetAttachedShaders__sig: 'viipp', + glGetAttribLocation__sig: 'iip', + glGetBooleanv__sig: 'vip', + glGetBufferParameteriv__sig: 'viip', + glGetBufferPointerv__sig: 'viip', + glGetError__sig: 'i', + glGetFloatv__sig: 'vip', + glGetFramebufferAttachmentParameteriv__sig: 'viiip', + glGetIntegerv__sig: 'vip', + glGetProgramInfoLog__sig: 'viipp', + glGetProgramiv__sig: 'viip', + glGetRenderbufferParameteriv__sig: 'viip', + glGetShaderInfoLog__sig: 'viipp', + glGetShaderPrecisionFormat__sig: 'viipp', + glGetShaderSource__sig: 'viipp', + glGetShaderiv__sig: 'viip', + glGetString__sig: 'pi', + glGetTexParameterfv__sig: 'viip', + glGetTexParameteriv__sig: 'viip', + glGetUniformLocation__sig: 'iip', + glGetUniformfv__sig: 'viip', + glGetUniformiv__sig: 'viip', + glGetVertexAttribPointerv__sig: 'viip', + glGetVertexAttribfv__sig: 'viip', + glGetVertexAttribiv__sig: 'viip', + glHint__sig: 'vii', + glIsBuffer__sig: 'ii', + glIsEnabled__sig: 'ii', + glIsFramebuffer__sig: 'ii', + glIsProgram__sig: 'ii', + glIsRenderbuffer__sig: 'ii', + glIsShader__sig: 'ii', + glIsTexture__sig: 'ii', + glIsVertexArray__sig: 'ii', + glIsVertexArrayOES__sig: 'ii', + glLineWidth__sig: 'vf', + glLinkProgram__sig: 'vi', + glLoadIdentity__sig: 'v', + glMapBufferRange__sig: 'pippi', + glMatrixMode__sig: 'vi', + glMultiDrawArrays__sig: 'vippi', + glMultiDrawElements__sig: 'vipipi', + glPixelStorei__sig: 'vii', + glPolygonOffset__sig: 'vff', + glReadPixels__sig: 'viiiiiip', + glReleaseShaderCompiler__sig: 'v', + glRenderbufferStorage__sig: 'viiii', + glSampleCoverage__sig: 'vfi', + glScissor__sig: 'viiii', + glShaderBinary__sig: 'vipipi', + glShaderSource__sig: 'viipp', + glStencilFunc__sig: 'viii', + glStencilFuncSeparate__sig: 'viiii', + glStencilMask__sig: 'vi', + glStencilMaskSeparate__sig: 'vii', + glStencilOp__sig: 'viii', + glStencilOpSeparate__sig: 'viiii', + glTexImage2D__sig: 'viiiiiiiip', + glTexParameterf__sig: 'viif', + glTexParameterfv__sig: 'viip', + glTexParameteri__sig: 'viii', + glTexParameteriv__sig: 'viip', + glTexSubImage2D__sig: 'viiiiiiiip', + glUniform1f__sig: 'vif', + glUniform1fv__sig: 'viip', + glUniform1i__sig: 'vii', + glUniform1iv__sig: 'viip', + glUniform2f__sig: 'viff', + glUniform2fv__sig: 'viip', + glUniform2i__sig: 'viii', + glUniform2iv__sig: 'viip', + glUniform3f__sig: 'vifff', + glUniform3fv__sig: 'viip', + glUniform3i__sig: 'viiii', + glUniform3iv__sig: 'viip', + glUniform4f__sig: 'viffff', + glUniform4fv__sig: 'viip', + glUniform4i__sig: 'viiiii', + glUniform4iv__sig: 'viip', + glUniformMatrix2fv__sig: 'viiip', + glUniformMatrix3fv__sig: 'viiip', + glUniformMatrix4fv__sig: 'viiip', + glUnmapBuffer__sig: 'ii', + glUseProgram__sig: 'vi', + glValidateProgram__sig: 'vi', + glVertexAttrib1f__sig: 'vif', + glVertexAttrib1fv__sig: 'vip', + glVertexAttrib2f__sig: 'viff', + glVertexAttrib2fv__sig: 'vip', + glVertexAttrib3f__sig: 'vifff', + glVertexAttrib3fv__sig: 'vip', + glVertexAttrib4f__sig: 'viffff', + glVertexAttrib4fv__sig: 'vip', + glVertexAttribDivisor__sig: 'vii', + glVertexAttribPointer__sig: 'viiiiip', + glVertexPointer__sig: 'viiip', + glViewport__sig: 'viiii', + glewGetErrorString__sig: 'pi', + glewGetExtension__sig: 'ip', + glewGetString__sig: 'pi', + glewInit__sig: 'i', + glewIsSupported__sig: 'ip', + glutCreateWindow__sig: 'ip', + glutDestroyWindow__sig: 'vi', + glutDisplayFunc__sig: 'vp', + glutFullScreen__sig: 'v', + glutGet__sig: 'ii', + glutGetModifiers__sig: 'i', + glutIdleFunc__sig: 'vp', + glutInit__sig: 'vpp', + glutInitDisplayMode__sig: 'vi', + glutInitWindowPosition__sig: 'vii', + glutInitWindowSize__sig: 'vii', + glutKeyboardFunc__sig: 'vp', + glutKeyboardUpFunc__sig: 'vp', + glutMainLoop__sig: 'v', + glutMotionFunc__sig: 'vp', + glutMouseFunc__sig: 'vp', + glutPassiveMotionFunc__sig: 'vp', + glutPositionWindow__sig: 'vii', + glutPostRedisplay__sig: 'v', + glutReshapeFunc__sig: 'vp', + glutReshapeWindow__sig: 'vii', + glutSetCursor__sig: 'vi', + glutSpecialFunc__sig: 'vp', + glutSpecialUpFunc__sig: 'vp', + glutSwapBuffers__sig: 'v', + glutTimerFunc__sig: 'vipi', + lineColor__sig: 'ipiiiii', + lineRGBA__sig: 'ipiiiiiiii', + pixelRGBA__sig: 'ipiiiiii', + proc_exit__sig: 'vi', + rectangleColor__sig: 'ipiiiii', + rectangleRGBA__sig: 'ipiiiiiiii', + rotozoomSurface__sig: 'ppddi', + setprotoent__sig: 'vi', + strftime__sig: 'ppppp', + strftime_l__sig: 'pppppp', + strptime__sig: 'pppp', + strptime_l__sig: 'ppppp', + system__sig: 'ip', + uuid_clear__sig: 'vp', + uuid_compare__sig: 'ipp', + uuid_copy__sig: 'vpp', + uuid_generate__sig: 'vp', + uuid_is_null__sig: 'ip', + uuid_parse__sig: 'ipp', + uuid_type__sig: 'ip', + uuid_unparse__sig: 'vpp', + uuid_unparse_lower__sig: 'vpp', + uuid_unparse_upper__sig: 'vpp', + uuid_variant__sig: 'ip', + zoomSurface__sig: 'ppddi', +} +mergeInto(LibraryManager.library, sigs); diff --git a/src/modules.js b/src/modules.js index f1085c8f05012..82555691d29a9 100644 --- a/src/modules.js +++ b/src/modules.js @@ -37,6 +37,9 @@ global.LibraryManager = { // Core system libraries (always linked against) let libraries = [ 'library.js', + // TODO(sbc): Start using this auto-generated file instead of the hand + // written signatures in the indivudual libraries. + //'library_sigs.js', 'library_int53.js', 'library_ccall.js', 'library_addfunction.js', @@ -114,12 +117,14 @@ global.LibraryManager = { 'library_glut.js', 'library_xlib.js', 'library_egl.js', - 'library_glfw.js', 'library_uuid.js', 'library_glew.js', 'library_idbstore.js', 'library_async.js', ]); + if (USE_GLFW) { + libraries.push('library_glfw.js'); + } } else { if (ASYNCIFY) { libraries.push('library_async.js'); diff --git a/src/utility.js b/src/utility.js index 944b815fe6cec..d0f4ac8b32b1a 100644 --- a/src/utility.js +++ b/src/utility.js @@ -119,6 +119,18 @@ function mergeInto(obj, other, options = null) { } } + for (const key of Object.keys(other)) { + if (key.endsWith('__sig')) { + if (obj.hasOwnProperty(key)) { + const oldsig = obj[key]; + const newsig = other[key]; + if (oldsig != newsig) { + console.warn(`Signature redefinition mismatch for : ${key}. (old=${oldsig} vs new=${newsig})`); + } + } + } + } + return Object.assign(obj, other); } diff --git a/system/include/SDL/SDL_cpuinfo.h b/system/include/SDL/SDL_cpuinfo.h index 7fb39edb4288b..7c9a28c635d1f 100644 --- a/system/include/SDL/SDL_cpuinfo.h +++ b/system/include/SDL/SDL_cpuinfo.h @@ -105,21 +105,25 @@ extern DECLSPEC SDL_bool SDLCALL SDL_HasAltiVec(void); * This function returns true if the CPU has MMX features. */ extern DECLSPEC SDL_bool SDLCALL SDL_HasMMX(void); +extern DECLSPEC SDL_bool SDLCALL SDL_HasMMXExt(void); /** * This function returns true if the CPU has 3DNow! features. */ extern DECLSPEC SDL_bool SDLCALL SDL_Has3DNow(void); +extern DECLSPEC SDL_bool SDLCALL SDL_Has3DNowExt(void); /** * This function returns true if the CPU has SSE features. */ extern DECLSPEC SDL_bool SDLCALL SDL_HasSSE(void); +extern DECLSPEC SDL_bool SDLCALL SDL_HasSSEExt(void); /** * This function returns true if the CPU has SSE2 features. */ extern DECLSPEC SDL_bool SDLCALL SDL_HasSSE2(void); +extern DECLSPEC SDL_bool SDLCALL SDL_HasSSE2Ext(void); /** * This function returns true if the CPU has SSE3 features. diff --git a/system/lib/compiler-rt/emscripten_setjmp.c b/system/lib/compiler-rt/emscripten_setjmp.c index b53a95e1c0c03..9c4afc3620d81 100644 --- a/system/lib/compiler-rt/emscripten_setjmp.c +++ b/system/lib/compiler-rt/emscripten_setjmp.c @@ -64,7 +64,7 @@ uint32_t testSetjmp(uintptr_t id, TableEntry* table, uint32_t size) { #if !defined(__USING_WASM_SJLJ__) -void _emscripten_throw_longjmp(); // defined in src/library.js +#include "emscripten_internal.h" void emscripten_longjmp(uintptr_t env, int val) { setThrew(env, val); diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_emscripten.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_emscripten.cpp index d619759c73f62..babc6793663a7 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_emscripten.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_emscripten.cpp @@ -26,14 +26,9 @@ #include #include -namespace __sanitizer { +#include "emscripten_internal.h" -extern "C" { -char* emscripten_get_module_name(char *buf, size_t length); -void* emscripten_builtin_mmap(void *addr, size_t length, int prot, int flags, - int fd, off_t offset); -int emscripten_builtin_munmap(void *addr, size_t length); -} +namespace __sanitizer { void ListOfModules::init() { modules_.Initialize(2); diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_emscripten.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_emscripten.cpp index a37e2de7f9f6e..9e25ef311aa60 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_emscripten.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_emscripten.cpp @@ -18,12 +18,9 @@ #include "sanitizer_common.h" #include "sanitizer_stacktrace.h" -namespace __sanitizer { +#include "emscripten_internal.h" -extern "C" { - uptr emscripten_stack_snapshot(); - u32 emscripten_stack_unwind_buffer(uptr pc, uptr *buffer, u32 depth); -} +namespace __sanitizer { bool StackTrace::snapshot_stack = true; diff --git a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_emscripten.cpp b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_emscripten.cpp index 14f3d05fcce31..45d8d5c1403df 100644 --- a/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_emscripten.cpp +++ b/system/lib/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_emscripten.cpp @@ -17,16 +17,10 @@ #if SANITIZER_EMSCRIPTEN #include "sanitizer_symbolizer_internal.h" +#include "emscripten_internal.h" namespace __sanitizer { -extern "C" { - const char *emscripten_pc_get_function(uptr pc); - const char *emscripten_pc_get_file(uptr pc); - int emscripten_pc_get_line(uptr pc); - int emscripten_pc_get_column(uptr pc); -} - class EmscriptenSymbolizerTool : public SymbolizerTool { public: bool SymbolizePC(uptr addr, SymbolizedStack *stack) override; diff --git a/system/lib/gl/webgl1.c b/system/lib/gl/webgl1.c index fffa9b8dbaf27..1fa41d267d78e 100644 --- a/system/lib/gl/webgl1.c +++ b/system/lib/gl/webgl1.c @@ -12,13 +12,6 @@ #if defined(__EMSCRIPTEN_PTHREADS__) && defined(__EMSCRIPTEN_OFFSCREEN_FRAMEBUFFER__) -extern EMSCRIPTEN_WEBGL_CONTEXT_HANDLE emscripten_webgl_do_create_context(const char *target, const EmscriptenWebGLContextAttributes *attributes); -extern EMSCRIPTEN_RESULT emscripten_webgl_make_context_current_calling_thread(EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context); -extern EMSCRIPTEN_RESULT emscripten_webgl_do_commit_frame(void); -extern EM_BOOL emscripten_supports_offscreencanvas(void); -extern EMSCRIPTEN_WEBGL_CONTEXT_HANDLE emscripten_webgl_do_get_current_context(void); -extern void _emscripten_proxied_gl_context_activated_from_main_browser_thread(EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context); - pthread_key_t currentActiveWebGLContext; pthread_key_t currentThreadOwnsItsWebGLContext; static pthread_once_t tlsInit = PTHREAD_ONCE_INIT; diff --git a/system/lib/gl/webgl_internal.h b/system/lib/gl/webgl_internal.h index 61474d1f60a08..01b84f2f20cf8 100644 --- a/system/lib/gl/webgl_internal.h +++ b/system/lib/gl/webgl_internal.h @@ -1,5 +1,12 @@ #pragma once +EMSCRIPTEN_WEBGL_CONTEXT_HANDLE emscripten_webgl_do_get_current_context(void); +EMSCRIPTEN_WEBGL_CONTEXT_HANDLE emscripten_webgl_do_create_context(const char *target, const EmscriptenWebGLContextAttributes *attributes); +EMSCRIPTEN_RESULT emscripten_webgl_make_context_current_calling_thread(EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context); +EMSCRIPTEN_RESULT emscripten_webgl_do_commit_frame(void); +EM_BOOL emscripten_supports_offscreencanvas(void); +void _emscripten_proxied_gl_context_activated_from_main_browser_thread(EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context); + #ifdef EMSCRIPTEN_WEBGL_TRACE #define GL_FUNCTION_TRACE(func) printf(#func "\n") #else diff --git a/system/lib/libc/dynlink.c b/system/lib/libc/dynlink.c index 639c481780687..939aa8707942f 100644 --- a/system/lib/libc/dynlink.c +++ b/system/lib/libc/dynlink.c @@ -18,14 +18,15 @@ #include #include #include -#include #include #include #include #include +#include "dynlink.h" #include "pthread_impl.h" +#include "emscripten_internal.h" //#define DYLINK_DEBUG @@ -40,14 +41,7 @@ struct async_data { em_arg_callback_func onerror; void* user_data; }; -typedef void (*dlopen_callback_func)(struct dso*, void* user_data); - -void* _dlopen_js(struct dso* handle); -void* _dlsym_js(struct dso* handle, const char* symbol, int* sym_index); -void _emscripten_dlopen_js(struct dso* handle, - dlopen_callback_func onsuccess, - dlopen_callback_func onerror, - void* user_data); + void __dl_vseterr(const char*, va_list); // We maintain a list of all dlopen and dlsym events linked list. @@ -82,8 +76,6 @@ static struct dlevent* _Atomic head = &main_event; static struct dlevent* _Atomic tail = &main_event; #ifdef _REENTRANT -void* _dlsym_catchup_js(struct dso* handle, int sym_index); - static thread_local struct dlevent* thread_local_tail = &main_event; static pthread_mutex_t write_lock = PTHREAD_MUTEX_INITIALIZER; static thread_local bool skip_dlsync = false; diff --git a/system/lib/libc/emscripten_internal.h b/system/lib/libc/emscripten_internal.h new file mode 100644 index 0000000000000..819755001da8f --- /dev/null +++ b/system/lib/libc/emscripten_internal.h @@ -0,0 +1,112 @@ +/* + * Copyright 2023 The Emscripten Authors. All rights reserved. + * Emscripten is available under two separate licenses, the MIT license and the + * University of Illinois/NCSA Open Source License. Both these licenses can be + * found in the LICENSE file. + * + * Declarations for internal-only JS library functions. + * + * All JS library functions must be declares in one header or anther in order + * for `tools/gen_sig_info.py` to work. This file contains declarations for + * functions that are not declared in any other public or private header. + */ + +#include + +#include // for `sighandler_t` +#include // for `bool` +#include // for `intptr_t` +#include // for `off_t` +#include // for `struct tm` + +#ifdef __cplusplus +extern "C" { +#endif + +// An external JS implementation that is efficient for very large copies, using +// HEAPU8.set() +void emscripten_memcpy_big(void* __restrict__ dest, + const void* __restrict__ src, + size_t n) EM_IMPORT(emscripten_memcpy_big); + +void emscripten_notify_memory_growth(size_t memory_index); + +// Declare these functions `int` rather than time_t to avoid int64 at the wasm +// boundary (avoids 64-bit complexity at the boundary when WASM_BIGINT is +// missing). +// TODO(sbc): Covert back to `time_t` before 2038 ... +int _timegm_js(struct tm* tm); +int _mktime_js(struct tm* tm); +void _localtime_js(const time_t* __restrict__ t, struct tm* __restrict__ tm); +void _gmtime_js(const time_t* __restrict__ t, struct tm* __restrict__ tm); + +void _tzset_js(long* timezone, int* daylight, char** tzname); + +const char* emscripten_pc_get_function(uintptr_t pc); +const char* emscripten_pc_get_file(uintptr_t pc); +int emscripten_pc_get_line(uintptr_t pc); +int emscripten_pc_get_column(uintptr_t pc); + +char* emscripten_get_module_name(char* buf, size_t length); +void* emscripten_builtin_mmap( + void* addr, size_t length, int prot, int flags, int fd, off_t offset); +int emscripten_builtin_munmap(void* addr, size_t length); + +uintptr_t emscripten_stack_snapshot(void); +uint32_t +emscripten_stack_unwind_buffer(uintptr_t pc, uintptr_t* buffer, uint32_t depth); + +bool _emscripten_get_now_is_monotonic(void); + +void _emscripten_get_progname(char*, int); + +// Not defined in musl, but defined in library.js. Included here to for +// the benefit of gen_sig_info.py +char* strptime_l(const char* __restrict __s, + const char* __restrict __fmt, + struct tm* __tp, + locale_t __loc); + +int _mmap_js(size_t length, + int prot, + int flags, + int fd, + size_t offset, + int* allocated, + void** addr); +int _munmap_js( + intptr_t addr, size_t length, int prot, int flags, int fd, size_t offset); +int _msync_js( + intptr_t addr, size_t length, int prot, int flags, int fd, size_t offset); + +struct dso; + +typedef void (*dlopen_callback_func)(struct dso*, void* user_data); + +void* _dlopen_js(struct dso* handle); +void* _dlsym_js(struct dso* handle, const char* symbol, int* sym_index); +void _emscripten_dlopen_js(struct dso* handle, + dlopen_callback_func onsuccess, + dlopen_callback_func onerror, + void* user_data); +void* _dlsym_catchup_js(struct dso* handle, int sym_index); + +int _setitimer_js(int which, double timeout); + +#ifdef _GNU_SOURCE +void __call_sighandler(sighandler_t handler, int sig); +#endif + +double emscripten_get_now_res(void); + +void* emscripten_return_address(int level); + +void _emscripten_fs_load_embedded_files(void* ptr); + +void _emscripten_throw_longjmp(void); + +void __handle_stack_overflow(void* addr); + +#ifdef __cplusplus +} +#endif diff --git a/system/lib/libc/emscripten_memcpy.c b/system/lib/libc/emscripten_memcpy.c index a11db5881e665..3a3f091a5def6 100644 --- a/system/lib/libc/emscripten_memcpy.c +++ b/system/lib/libc/emscripten_memcpy.c @@ -6,6 +6,7 @@ #include #include #include "libc.h" +#include "emscripten_internal.h" // Use the simple/naive version of memcpy when building with asan #if defined(EMSCRIPTEN_OPTIMIZE_FOR_OZ) || __has_feature(address_sanitizer) @@ -20,12 +21,6 @@ static void *__memcpy(void *dest, const void *src, size_t n) { #else -#ifndef EMSCRIPTEN_STANDALONE_WASM -// An external JS implementation that is efficient for very large copies, using -// HEAPU8.set() -void emscripten_memcpy_big(void *restrict dest, const void *restrict src, size_t n) EM_IMPORT(emscripten_memcpy_big); -#endif - static void *__memcpy(void *restrict dest, const void *restrict src, size_t n) { unsigned char *d = dest; const unsigned char *s = src; diff --git a/system/lib/libc/emscripten_mmap.c b/system/lib/libc/emscripten_mmap.c index e8f08f9e2c02b..01ee6530c378e 100644 --- a/system/lib/libc/emscripten_mmap.c +++ b/system/lib/libc/emscripten_mmap.c @@ -14,6 +14,7 @@ #include +#include "emscripten_internal.h" #include "lock.h" #include "syscall.h" @@ -34,18 +35,6 @@ struct map { static volatile int lock[1]; static struct map* mappings; -// JS library functions. Used only when mapping files (not MAP_ANONYMOUS) -int _mmap_js(size_t length, - int prot, - int flags, - int fd, - size_t offset, - int* allocated, - void** addr); -int _munmap_js(intptr_t addr, size_t length, int prot, int flags, int fd, size_t offset); -int _msync_js( - intptr_t addr, size_t length, int prot, int flags, int fd, size_t offset); - static struct map* find_mapping(intptr_t addr, struct map** prev) { struct map* map = mappings; while (map) { diff --git a/system/lib/libc/emscripten_time.c b/system/lib/libc/emscripten_time.c index cee7811e67f0f..c3db253219923 100644 --- a/system/lib/libc/emscripten_time.c +++ b/system/lib/libc/emscripten_time.c @@ -13,14 +13,14 @@ #include #include "libc.h" +#include "emscripten_internal.h" + // Replaces musl's __tz.c weak long timezone = 0; weak int daylight = 0; weak char *tzname[2] = { 0, 0 }; -double emscripten_get_now_res(); - weak clock_t __clock() { static thread_local double start = 0; if (!start) { @@ -37,7 +37,6 @@ weak time_t __time(time_t *t) { return ret; } -extern bool _emscripten_get_now_is_monotonic(); static thread_local bool checked_monotonic = false; static thread_local bool is_monotonic = 0; diff --git a/system/lib/libc/mktime.c b/system/lib/libc/mktime.c index 9f3f9fddc96a9..603f8fde0aa7d 100644 --- a/system/lib/libc/mktime.c +++ b/system/lib/libc/mktime.c @@ -6,14 +6,7 @@ */ #include -// Declare these functions `int` rather than time_t to avoid int64 at the wasm -// boundary (avoids 64-bit complexity at the boundary when WASM_BIGINT is -// missing). -// TODO(sbc): Covert back to `time_t` before 2038 ... -int _timegm_js(struct tm *tm); -int _mktime_js(struct tm *tm); -void _localtime_js(const time_t *restrict t, struct tm *restrict tm); -void _gmtime_js(const time_t *restrict t, struct tm *restrict tm); +#include "emscripten_internal.h" weak time_t timegm(struct tm *tm) { tzset(); diff --git a/system/lib/libc/musl/src/internal/progname.c b/system/lib/libc/musl/src/internal/progname.c index 3bfaa036aabc7..ffefb792e6989 100644 --- a/system/lib/libc/musl/src/internal/progname.c +++ b/system/lib/libc/musl/src/internal/progname.c @@ -9,14 +9,13 @@ #include #include +#include "emscripten_internal.h" + char *__progname=0, *__progname_full=0; weak_alias(__progname, program_invocation_short_name); weak_alias(__progname_full, program_invocation_name); -/* See src/library.js for the implementation. */ -extern void _emscripten_get_progname(char*, int); - __attribute__((constructor)) static void __progname_ctor(void) { diff --git a/system/lib/libc/musl/src/signal/setitimer.c b/system/lib/libc/musl/src/signal/setitimer.c index ec90635b3bd66..5e7468bf35dcb 100644 --- a/system/lib/libc/musl/src/signal/setitimer.c +++ b/system/lib/libc/musl/src/signal/setitimer.c @@ -9,6 +9,8 @@ #include #include +#include "emscripten_internal.h" + // Timeouts can either fire directly from the JS event loop (which calls // `_emscripten_timeout`), or from `_emscripten_check_timers` (which is called // from `_emscripten_yield`). In order to be able to check the timers here we @@ -19,8 +21,6 @@ static double current_intervals_ms[3]; #define MAX(a,b) ((a)>(b)?(a):(b)) -int _setitimer_js(int which, double timeout); - void __getitimer(int which, struct itimerval *old, double now) { double remaining_ms = MAX(current_timeout_ms[which] - now, 0); diff --git a/system/lib/libc/raise.c b/system/lib/libc/raise.c index dbd9f1cde0289..4aded6784ab61 100644 --- a/system/lib/libc/raise.c +++ b/system/lib/libc/raise.c @@ -10,13 +10,13 @@ #include #include +#include "emscripten_internal.h" + extern struct sigaction __sig_actions[_NSIG]; extern sigset_t __sig_pending; bool __sig_is_blocked(int sig); -extern void __call_sighandler(sighandler_t handler, int sig); - int raise(int sig) { if (__sig_is_blocked(sig)) { sigaddset(&__sig_pending, sig); diff --git a/system/lib/libc/tzset.c b/system/lib/libc/tzset.c index a584de4c9d211..bdc580fcd0291 100644 --- a/system/lib/libc/tzset.c +++ b/system/lib/libc/tzset.c @@ -8,7 +8,7 @@ #include #include -void _tzset_js(long* timezone, int* daylight, char** tzname); +#include "emscripten_internal.h" weak void tzset() { static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; diff --git a/system/lib/standalone/standalone.c b/system/lib/standalone/standalone.c index 690106cce8cf9..200002dce1e1b 100644 --- a/system/lib/standalone/standalone.c +++ b/system/lib/standalone/standalone.c @@ -24,6 +24,7 @@ #include #include "lock.h" +#include "emscripten_internal.h" /* * WASI support code. These are compiled with the program, and call out @@ -123,8 +124,6 @@ int getentropy(void* buffer, size_t length) { // Emscripten additions -extern void emscripten_notify_memory_growth(size_t memory_index); - // Should never be called in standalone mode void emscripten_memcpy_big(void *restrict dest, const void *restrict src, size_t n) { __builtin_unreachable(); diff --git a/test/test_other.py b/test/test_other.py index 0f9d748aff5a1..3eb3aa53e5da7 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -11803,6 +11803,7 @@ def test_split_main_module(self): self.assertIn('Hello from main!', result) self.assertIn('Hello from lib!', result) + @crossplatform def test_gen_struct_info(self): # This test will start failing whenever the struct info changes (e.g. offset or defines # change). However it's easy to rebaseline with --rebaseline. @@ -11815,6 +11816,14 @@ def test_gen_struct_info(self): self.run_process([PYTHON, path_from_root('tools/gen_struct_info.py'), '--wasm64', '-o', 'out.json']) self.assertFileContents(path_from_root('src/generated_struct_info64.json'), read_file('out.json')) + @crossplatform + def test_gen_sig_info(self): + # This tests is fragile and will need updating any time a JS library + # function is added or its signature changed. However it's easy to + # rebaseline with --rebaseline. + self.run_process([PYTHON, path_from_root('tools/gen_sig_info.py'), '-o', 'out.js']) + self.assertFileContents(path_from_root('src/library_sigs.js'), read_file('out.js')) + def test_gen_struct_info_env(self): # gen_struct_info.py builds C code in a very specific and low level way. We don't want # EMCC_CFLAGS (or any of the other environment variables that might effect compilation or diff --git a/tools/gen_sig_info.py b/tools/gen_sig_info.py new file mode 100755 index 0000000000000..0d3da8c75c775 --- /dev/null +++ b/tools/gen_sig_info.py @@ -0,0 +1,301 @@ +#!/usr/bin/env python3 +# Copyright 2023 The Emscripten Authors. All rights reserved. +# Emscripten is available under two separate licenses, the MIT license and the +# University of Illinois/NCSA Open Source License. Both these licenses can be +# found in the LICENSE file. + +"""This tool extracts native/C signature information for JS library functions + +It generates a file called `src/library_sigs.js` which contains `__sig` declarations +for the majority of JS library functions. +""" + +import argparse +import json +import os +import sys +import subprocess +import re +import glob + + +__scriptdir__ = os.path.dirname(os.path.abspath(__file__)) +__rootdir__ = os.path.dirname(__scriptdir__) +sys.path.append(__rootdir__) + +from tools import shared, utils, webassembly + +header = '''/* Auto-generated by %s */ + +#define _GNU_SOURCE + +// Public emscripen headers +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Internal emscripten headers +#include "emscripten_internal.h" +#include "webgl_internal.h" + +// Internal musl headers +#include "musl/include/assert.h" +#include "musl/arch/emscripten/syscall_arch.h" +#include "dynlink.h" + +// Public musl/libc headers +#include +#include +#include +#include +#include +#include +#include +#include + +// Public library headers +#define GL_GLEXT_PROTOTYPES +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +''' % os.path.basename(__file__) + +footer = '''\ +}; + +int main(int argc, char* argv[]) { + return argc + (intptr_t)symbol_list; +} +''' + +wasi_symbols = { + 'proc_exit', + 'environ_sizes_get', + 'environ_get', + 'clock_time_get', + 'clock_res_get', + 'fd_write', + 'fd_pwrite', + 'fd_read', + 'fd_pread', + 'fd_close', + 'fd_seek', + 'fd_sync', + 'fd_fdstat_get', + 'args_get', + 'args_sizes_get', +} + + +def ignore_symbol(s): + if s in {'SDL_GetKeyState'}: + return True + if s.startswith('emscripten_gl') or s.startswith('emscripten_alc'): + return True + if s.startswith('egl'): + return True + if s.startswith('gl') and any(s.endswith(x) for x in ('NV', 'EXT', 'WEBGL', 'ARB', 'ANGLE')): + return True + return False + + +def create_c_file(filename, symbol_list): + source_lines = [header] + source_lines.append('\nvoid* symbol_list[] = {') + for s in symbol_list: + if s in wasi_symbols: + source_lines.append(f' &__wasi_{s},') + else: + source_lines.append(f' &{s},') + source_lines.append(footer) + utils.write_file(filename, '\n'.join(source_lines) + '\n') + + +def valuetype_to_chr(t, t64): + if t == webassembly.Type.I32 and t64 == webassembly.Type.I64: + return 'p' + assert t == t64 + return { + webassembly.Type.I32: 'i', + webassembly.Type.I64: 'j', + webassembly.Type.F32: 'f', + webassembly.Type.F64: 'd', + }[t] + + +def functype_to_str(t, t64): + assert len(t.returns) == len(t64.returns) + assert len(t.params) == len(t64.params) + if t.returns: + assert len(t.returns) == 1 + rtn = valuetype_to_chr(t.returns[0], t64.returns[0]) + else: + rtn = 'v' + for p, p64 in zip(t.params, t64.params): + rtn += valuetype_to_chr(p, p64) + return rtn + + +def write_sig_library(filename, sig_info): + lines = [ + '/* Auto-generated by tools/gen_sig_info.py. DO NOT EDIT. */', + '', + 'sigs = {'] + for s, sig in sorted(sig_info.items()): + lines.append(f" {s}__sig: '{sig}',") + lines.append('}') + lines.append('mergeInto(LibraryManager.library, sigs);') + utils.write_file(filename, '\n'.join(lines) + '\n') + + +def update_sigs(sig_info): + print("updating __sig attributes ...") + + def update_line(l): + if '__sig' not in l: + return l + stripped = l.strip() + for sym, sig in sig_info.items(): + if stripped.startswith(f'{sym}__sig:'): + return re.sub(rf"\b{sym}__sig: '.*'", f"{sym}__sig: '{sig}'", l) + return l + + files = glob.glob('src/*.js') + glob.glob('src/**/*.js') + for file in files: + lines = utils.read_file(file).splitlines() + lines = [update_line(l) for l in lines] + utils.write_file(file, '\n'.join(lines) + '\n') + + +def remove_sigs(sig_info): + print("removing __sig attributes ...") + + to_remove = [f'{sym}__sig:' for sym in sig_info.keys()] + + def strip_line(l): + l = l.strip() + return any(l.startswith(r) for r in to_remove) + + files = glob.glob('src/*.js') + glob.glob('src/**/*.js') + for file in files: + lines = utils.read_file(file).splitlines() + lines = [l for l in lines if not strip_line(l)] + utils.write_file(file, '\n'.join(lines) + '\n') + + +def extract_sigs(symbols, obj_file): + sig_info = {} + with webassembly.Module(obj_file) as mod: + imports = mod.get_imports() + types = mod.get_types() + import_map = {i.field: i for i in imports} + for s in symbols: + sig_info[s] = types[import_map[s].type] + return sig_info + + +def extract_sig_info(sig_info, extra_settings=None, extra_cflags=None): + tempfiles = shared.get_temp_files() + settings = { + 'USE_PTHREADS': 1, + 'STACK_OVERFLOW_CHECK': 1, + 'FULL_ES3': 1, + # Currently GLFW symbols have different sigs for the same symbol because the + # signatures changed between v2 and v3, so for now we continue to maintain + # them by hand. + 'USE_GLFW': 0, + 'JS_LIBRARIES': ['src/library_websocket.js', + 'src/library_webaudio.js'], + 'SUPPORT_LONGJMP': 'emscripten' + } + if extra_settings: + settings.update(extra_settings) + with tempfiles.get_file('.json') as settings_json: + utils.write_file(settings_json, json.dumps(settings)) + output = shared.run_js_tool(utils.path_from_root('src/compiler.js'), + ['--symbols-only', settings_json], + stdout=subprocess.PIPE, cwd=utils.path_from_root()) + symbols = json.loads(output).keys() + symbols = [s for s in symbols if not ignore_symbol(s)] + with tempfiles.get_file('.c') as c_file: + create_c_file(c_file, symbols) + + # We build the `.c` file twice, once with wasm32 and wasm64. + # The first build gives is that base signature of each function. + # The second build build allows us to determine which args/returns are pointers + # or `size_t` types. These get marked as `p` in the `__sig`. + obj_file = 'out.o' + cmd = [shared.EMCC, c_file, '-c', '-pthread', + '-Wno-deprecated-declarations', + '-o', obj_file, + '-I' + utils.path_from_root('system/lib/libc'), + '-I' + utils.path_from_root('system/lib/libc/musl/src/include'), + '-I' + utils.path_from_root('system/lib/libc/musl/src/internal'), + '-I' + utils.path_from_root('system/lib/gl'), + '-I' + utils.path_from_root('system/lib/libcxxabi/include'), + '-isysroot', 'c++/v1'] + if extra_cflags: + cmd += extra_cflags + shared.check_call(cmd) + sig_info32 = extract_sigs(symbols, obj_file) + + # Run the same command again with memory64. + shared.check_call(cmd + ['-sMEMORY64', '-Wno-experimental']) + sig_info64 = extract_sigs(symbols, obj_file) + + for sym, sig32 in sig_info32.items(): + assert sym in sig_info64 + sig64 = sig_info64[sym] + sig_string = functype_to_str(sig32, sig64) + if sym in sig_info: + if sig_info[sym] != sig_string: + print(sym) + print(sig_string) + print(sig_info[sym]) + assert sig_info[sym] == sig_string + sig_info[sym] = sig_string + + +def main(args): + parser = argparse.ArgumentParser() + parser.add_argument('-o', '--output', default='src/library_sigs.js') + parser.add_argument('-r', '--remove', action='store_true', help='remove from JS library files any `__sig` entires that are part of the auto-generated file') + parser.add_argument('-u', '--update', action='store_true', help='update with JS library files any `__sig` entires that are part of the auto-generated file') + args = parser.parse_args() + + print('generating signatures ...') + sig_info = {} + extract_sig_info(sig_info) + extract_sig_info(sig_info, {'STANDALONE_WASM': 1}) + extract_sig_info(sig_info, {'MAIN_MODULE': 2}) + + write_sig_library(args.output, sig_info) + if args.update: + update_sigs(sig_info) + if args.remove: + remove_sigs(sig_info) + + +if __name__ == '__main__': + sys.exit(main(sys.argv[1:])) diff --git a/tools/system_libs.py b/tools/system_libs.py index 877364cb1dd45..9287295df327f 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -808,6 +808,7 @@ class MuslInternalLibrary(Library): includes = [ 'system/lib/libc/musl/src/internal', 'system/lib/libc/musl/src/include', + 'system/lib/libc', 'system/lib/pthread', ] @@ -853,6 +854,7 @@ class libcompiler_rt(MTLibrary, SjLjLibrary): cflags = ['-fno-builtin'] src_dir = 'system/lib/compiler-rt/lib/builtins' + includes = ['system/lib/libc'] # gcc_personality_v0.c depends on libunwind, which don't include by default. src_files = glob_in_path(src_dir, '*.c', excludes=['gcc_personality_v0.c', 'truncdfbf2.c', 'truncsfbf2.c']) src_files += files_in_path( @@ -1838,7 +1840,8 @@ class libsanitizer_common_rt(CompilerRTLibrary, MTLibrary): name = 'libsanitizer_common_rt' # TODO(sbc): We should not need musl-internal headers here. includes = ['system/lib/libc/musl/src/internal', - 'system/lib/compiler-rt/lib'] + 'system/lib/compiler-rt/lib', + 'system/lib/libc'] never_force = True src_dir = 'system/lib/compiler-rt/lib/sanitizer_common' From 13b1f81e1ef6089321fc4ac1a3a2aa273d436b89 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 21 Mar 2023 22:41:51 -0700 Subject: [PATCH 0042/1523] Rebaseline codesize expectations. NFC --- test/other/test_unoptimized_code_size.js.size | 2 +- test/other/test_unoptimized_code_size_no_asserts.js.size | 2 +- test/other/test_unoptimized_code_size_strict.js.size | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/other/test_unoptimized_code_size.js.size b/test/other/test_unoptimized_code_size.js.size index 7734a8d01e994..eae45d4b94fb2 100644 --- a/test/other/test_unoptimized_code_size.js.size +++ b/test/other/test_unoptimized_code_size.js.size @@ -1 +1 @@ -64423 +64434 diff --git a/test/other/test_unoptimized_code_size_no_asserts.js.size b/test/other/test_unoptimized_code_size_no_asserts.js.size index 7054030185832..5c9209553b59f 100644 --- a/test/other/test_unoptimized_code_size_no_asserts.js.size +++ b/test/other/test_unoptimized_code_size_no_asserts.js.size @@ -1 +1 @@ -37780 +37791 diff --git a/test/other/test_unoptimized_code_size_strict.js.size b/test/other/test_unoptimized_code_size_strict.js.size index e834ee820806e..9dcf0080cce43 100644 --- a/test/other/test_unoptimized_code_size_strict.js.size +++ b/test/other/test_unoptimized_code_size_strict.js.size @@ -1 +1 @@ -63430 +63441 From fda8dd1d51e6e1a1336654c5f4decadae89123a8 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 22 Mar 2023 10:31:32 -0700 Subject: [PATCH 0043/1523] Use normal JS library aliases for GL symbols. NFC (#19033) The `recordGLProcAddressGet` helper was attempt to resolve and create aliases using `copyLibEntry`, but this function doesn't work when the target of the alias exists in a different library file. This was resulting `undefined` being set for these aliases and the resulting JS code would contains, for example: ``` var glGenFramebuffersOES = undefined; ``` Completely removing the aliasing resolution and the symbol copying from `recordGLProcAddressGet` seems to do the right thing, and should save on code size too: ``` var _glGenFramebuffersOES = _glGenFramebuffers; ``` --- src/library_glemu.js | 20 ++++++++++---------- src/library_webgl.js | 36 +++++------------------------------- 2 files changed, 15 insertions(+), 41 deletions(-) diff --git a/src/library_glemu.js b/src/library_glemu.js index c70ec55bb3652..d9914cd0882bd 100644 --- a/src/library_glemu.js +++ b/src/library_glemu.js @@ -3881,16 +3881,16 @@ var LibraryGLEmulation = { // Open GLES1.1 compatibility - glGenFramebuffersOES : 'glGenFramebuffers', - glGenRenderbuffersOES : 'glGenRenderbuffers', - glBindFramebufferOES : 'glBindFramebuffer', - glBindRenderbufferOES : 'glBindRenderbuffer', - glGetRenderbufferParameterivOES : 'glGetRenderbufferParameteriv', - glFramebufferRenderbufferOES : 'glFramebufferRenderbuffer', - glRenderbufferStorageOES : 'glRenderbufferStorage', - glCheckFramebufferStatusOES : 'glCheckFramebufferStatus', - glDeleteFramebuffersOES : 'glDeleteFramebuffers', - glDeleteRenderbuffersOES : 'glDeleteRenderbuffers', + glGenFramebuffersOES: 'glGenFramebuffers', + glGenRenderbuffersOES: 'glGenRenderbuffers', + glBindFramebufferOES: 'glBindFramebuffer', + glBindRenderbufferOES: 'glBindRenderbuffer', + glGetRenderbufferParameterivOES: 'glGetRenderbufferParameteriv', + glFramebufferRenderbufferOES: 'glFramebufferRenderbuffer', + glRenderbufferStorageOES: 'glRenderbufferStorage', + glCheckFramebufferStatusOES: 'glCheckFramebufferStatus', + glDeleteFramebuffersOES: 'glDeleteFramebuffers', + glDeleteRenderbuffersOES: 'glDeleteRenderbuffers', glFramebufferTexture2DOES: 'glFramebufferTexture2D', // GLU diff --git a/src/library_webgl.js b/src/library_webgl.js index a10a44cfab989..1f7ec630abd43 100644 --- a/src/library_webgl.js +++ b/src/library_webgl.js @@ -4220,40 +4220,14 @@ createGLPassthroughFunctions(LibraryGL, glPassthroughFuncs); autoAddDeps(LibraryGL, '$GL'); -function copyLibEntry(lib, a, b) { - lib[a] = lib[b]; - lib[a + '__postset'] = lib[b + '__postset']; - lib[a + '__proxy'] = lib[b + '__proxy']; - lib[a + '__sig'] = lib[b + '__sig']; - lib[a + '__deps'] = (lib[b + '__deps'] || []).slice(0); -} - function recordGLProcAddressGet(lib) { - // GL proc address retrieval - allow access through glX and emscripten_glX, to allow name collisions with user-implemented things having the same name (see gl.c) + // GL proc address retrieval - allow access through glX and emscripten_glX, to + // allow name collisions with user-implemented things having the same name + // (see gl.c) Object.keys(lib).forEach((x) => { - if (isJsLibraryConfigIdentifier(x)) return; - if (x.substr(0, 2) != 'gl') return; - while (typeof lib[x] == 'string') { - // resolve aliases right here, simpler for fastcomp - copyLibEntry(lib, x, lib[x]); + if (x.startsWith('gl') && !isJsLibraryConfigIdentifier(x)) { + lib['emscripten_' + x] = x; } - const y = 'emscripten_' + x; - lib[x + '__deps'] = (lib[x + '__deps'] || []).map((dep) => { - // prefix dependencies as well - if (typeof dep == 'string' && dep[0] == 'g' && dep[1] == 'l' && lib[dep]) { - const orig = dep; - dep = 'emscripten_' + dep; - let fixed = lib[x].toString().replace(new RegExp('_' + orig + '\\(', 'g'), '_' + dep + '('); - // `function` is 8 characters, add space and an explicit name after if there isn't one already - if (fixed.startsWith('function(') || fixed.startsWith('function (')) { - fixed = fixed.substr(0, 8) + ' _' + y + fixed.substr(8); - } - lib[x] = eval('(function() { return ' + fixed + ' })()'); - } - return dep; - }); - // copy it - copyLibEntry(lib, y, x); }); } From 6071f7814c18c9ffc0f4cce73a77ac51e9fce717 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 22 Mar 2023 10:38:37 -0700 Subject: [PATCH 0044/1523] Improve error/warning reporting during JS library processing (#19029) Keep track of which file is bring processed not just during pre-processing but during the entire processing of a given library file. --- src/modules.js | 2 ++ src/parseTools.js | 9 ++++----- src/utility.js | 13 +++++++++++-- test/test_other.py | 6 +++--- 4 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/modules.js b/src/modules.js index 82555691d29a9..3ccdaa481f7b8 100644 --- a/src/modules.js +++ b/src/modules.js @@ -215,6 +215,7 @@ global.LibraryManager = { }, }); } + currentFile = filename; try { processed = processMacros(preprocess(filename)); vm.runInThisContext(processed, { filename: filename.replace(/\.\w+$/, '.preprocessed$&') }); @@ -232,6 +233,7 @@ global.LibraryManager = { } throw e; } finally { + currentFile = null; if (origLibrary) { this.library = origLibrary; } diff --git a/src/parseTools.js b/src/parseTools.js index 7a60029c41e51..9b7432349a292 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -11,8 +11,6 @@ global.FOUR_GB = 4 * 1024 * 1024 * 1024; const FLOAT_TYPES = new Set(['float', 'double']); -let currentlyParsedFilename = ''; - // Does simple 'macro' substitution, using Django-like syntax, // {{{ code }}} will be replaced with |eval(code)|. // NOTE: Be careful with that ret check. If ret is |0|, |ret ? ret.toString() : ''| would result in ''! @@ -57,7 +55,8 @@ function preprocess(filename) { const showStack = []; const showCurrentLine = () => showStack.every((x) => x == SHOW); - currentlyParsedFilename = filename; + const oldFilename = currentFile; + currentFile = filename; const fileExt = filename.split('.').pop().toLowerCase(); const isHtml = (fileExt === 'html' || fileExt === 'htm') ? true : false; let inStyle = false; @@ -155,7 +154,7 @@ function preprocess(filename) { no matching #endif found (${showStack.length$}' unmatched preprocessing directives on stack)`); return ret; } finally { - currentlyParsedFilename = null; + currentFile = oldFilename; } } @@ -565,7 +564,7 @@ function makeDynCall(sig, funcPtr) { if (funcPtr === undefined) { - warn(`${currentlyParsedFilename}: \ + warn(` Legacy use of {{{ makeDynCall("${sig}") }}}(funcPtr, arg1, arg2, ...). \ Starting from Emscripten 2.0.2 (Aug 31st 2020), syntax for makeDynCall has changed. \ New syntax is {{{ makeDynCall("${sig}", "funcPtr") }}}(arg1, arg2, ...). \ diff --git a/src/utility.js b/src/utility.js index d0f4ac8b32b1a..2157461fc4c6f 100644 --- a/src/utility.js +++ b/src/utility.js @@ -40,6 +40,15 @@ function dump(item) { } global.warnings = false; +global.currentFile = null; + +function errorPrefix() { + if (currentFile) { + return currentFile + ': ' + } else { + return ''; + } +} function warn(a, msg) { global.warnings = true; @@ -48,7 +57,7 @@ function warn(a, msg) { a = false; } if (!a) { - printErr('warning: ' + msg); + printErr(`warning: ${errorPrefix()}${msg}`); } } @@ -69,7 +78,7 @@ global.abortExecution = false; function error(msg) { abortExecution = true; - printErr('error: ' + msg); + printErr(`error: ${errorPrefix()}${msg}`); } function range(size) { diff --git a/test/test_other.py b/test/test_other.py index 3eb3aa53e5da7..ccb054beda70f 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -3740,7 +3740,7 @@ def test_js_lib_no_override(self): self.emcc_args += ['--js-library', 'duplicated_func_1.js', '--js-library', 'duplicated_func_2.js'] err = self.expect_fail([EMCC, 'duplicated_func.c'] + self.get_emcc_args()) - self.assertContained('error: Symbol re-definition in JavaScript library: duplicatedFunc. Do not use noOverride if this is intended', err) + self.assertContained('duplicated_func_2.js: Symbol re-definition in JavaScript library: duplicatedFunc. Do not use noOverride if this is intended', err) def test_override_stub(self): self.do_run_from_file(test_file('other/test_override_stub.c'), test_file('other/test_override_stub.out')) @@ -3767,7 +3767,7 @@ def test_js_lib_missing_sig(self): self.emcc_args += ['--js-library', 'some_func.js'] err = self.expect_fail([EMCC, 'some_func.c'] + self.get_emcc_args()) - self.assertContained('error: __sig is missing for function: someFunc. Do not use checkSig if this is intended', err) + self.assertContained('some_func.js: __sig is missing for function: someFunc. Do not use checkSig if this is intended', err) def test_js_lib_quoted_key(self): create_file('lib.js', r''' @@ -11592,7 +11592,7 @@ def test_jslib_ifdef(self): #endif ''') proc = self.run_process([EMCC, test_file('hello_world.c'), '--js-library=lib.js'], stderr=PIPE) - self.assertContained('warning: use of #ifdef in js library. Use #if instead.', proc.stderr) + self.assertContained('lib.js: use of #ifdef in js library. Use #if instead.', proc.stderr) def test_jslib_mangling(self): create_file('lib.js', ''' From 676ef728cd57e1ec158116d5b065efcf5dfc4cba Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 22 Mar 2023 10:56:35 -0700 Subject: [PATCH 0045/1523] Remove `__sig` attributes from JS-only functions (#19030) IIUC these serve no purpose. --- src/library.js | 3 +-- src/library_webgl.js | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/library.js b/src/library.js index ad5a6f953a4e2..e4de910da4b5e 100644 --- a/src/library.js +++ b/src/library.js @@ -3008,7 +3008,6 @@ mergeInto(LibraryManager.library, { }, #if HAVE_EM_ASM - $runEmAsmFunction__sig: 'ippp', $runEmAsmFunction__deps: ['$readEmAsmArgs'], $runEmAsmFunction: function(code, sigPtr, argbuf) { var args = readEmAsmArgs(sigPtr, argbuf); @@ -3036,7 +3035,6 @@ mergeInto(LibraryManager.library, { }, $runMainThreadEmAsm__deps: ['$readEmAsmArgs'], - $runMainThreadEmAsm__sig: 'iippi', $runMainThreadEmAsm: function(code, sigPtr, argbuf, sync) { var args = readEmAsmArgs(sigPtr, argbuf); #if PTHREADS @@ -3067,6 +3065,7 @@ mergeInto(LibraryManager.library, { }, emscripten_asm_const_double_sync_on_main_thread: 'emscripten_asm_const_int_sync_on_main_thread', emscripten_asm_const_async_on_main_thread__deps: ['$runMainThreadEmAsm'], + emscripten_asm_const_async_on_main_thread__sig: 'vppp', emscripten_asm_const_async_on_main_thread: function(code, sigPtr, argbuf) { return runMainThreadEmAsm(code, sigPtr, argbuf, 0); }, diff --git a/src/library_webgl.js b/src/library_webgl.js index 1f7ec630abd43..17ec5a5eb7527 100644 --- a/src/library_webgl.js +++ b/src/library_webgl.js @@ -1684,7 +1684,6 @@ var LibraryGL = { // merge the functions together to only have one generated copy of this. 'createFunction' refers to the WebGL context function name to do // the actual creation, 'objectTable' points to the GL object table where to populate the created objects, and 'functionName' carries // the name of the caller for debug information. - $__glGenObject__sig: 'vii', $__glGenObject: function(n, buffers, createFunction, objectTable #if GL_ASSERTIONS , functionName From ac75bb0b3efba45c4d820d082f9d24d63020f1bb Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 22 Mar 2023 12:32:59 -0700 Subject: [PATCH 0046/1523] [Wasm64] Check argument names in convertPointerParams. NFC (#19039) Without this `convertPointerParams` will silently generate invalid output. --- src/jsifier.js | 8 ++++++-- src/library_async.js | 8 ++++---- src/library_idbstore.js | 8 ++++---- src/library_sdl.js | 34 +++++++++++++++++----------------- src/library_syscall.js | 12 ++++++------ src/library_webgl.js | 16 ++++++++++++---- src/library_xlib.js | 12 ++++++------ 7 files changed, 55 insertions(+), 43 deletions(-) diff --git a/src/jsifier.js b/src/jsifier.js index 2503ae9f9e550..889b326eb1108 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -87,7 +87,7 @@ function runJSify() { } } - function convertPointerParams(snippet, sig) { + function convertPointerParams(symbol, snippet, sig) { // Automatically convert any incoming pointer arguments from BigInt // to double (this limits the range to int53). // And convert the return value if the function returns a pointer. @@ -99,6 +99,10 @@ function runJSify() { let argConvertions = ''; for (let i = 1; i < sig.length; i++) { const name = argNames[i - 1]; + if (!name) { + error(`convertPointerParams: missing name for argument ${i} in ${symbol}`); + return snippet; + } if (sig[i] == 'p') { argConvertions += ` ${name} = Number(${name});\n`; newArgs.push(`Number(${name})`); @@ -182,7 +186,7 @@ function ${name}(${args}) { if (MEMORY64) { const sig = LibraryManager.library[symbol + '__sig']; if (sig && sig.includes('p')) { - snippet = convertPointerParams(snippet, sig); + snippet = convertPointerParams(symbol, snippet, sig); } } diff --git a/src/library_async.js b/src/library_async.js index bb713e4222636..82c57b741f8a8 100644 --- a/src/library_async.js +++ b/src/library_async.js @@ -647,13 +647,13 @@ mergeInto(LibraryManager.library, { emscripten_sleep: function() { throw 'Please compile your program with async support in order to use asynchronous operations like emscripten_sleep'; }, - emscripten_wget: function() { + emscripten_wget: function(url, file) { throw 'Please compile your program with async support in order to use asynchronous operations like emscripten_wget'; }, - emscripten_wget_data: function() { + emscripten_wget_data: function(url, pbuffer, pnum, perror) { throw 'Please compile your program with async support in order to use asynchronous operations like emscripten_wget_data'; }, - emscripten_scan_registers: function() { + emscripten_scan_registers: function(func) { throw 'Please compile your program with async support in order to use asynchronous operations like emscripten_scan_registers'; }, emscripten_fiber_init: function() { @@ -662,7 +662,7 @@ mergeInto(LibraryManager.library, { emscripten_fiber_init_from_current_context: function() { throw 'Please compile your program with async support in order to use asynchronous operations like emscripten_fiber_init_from_current_context'; }, - emscripten_fiber_swap: function() { + emscripten_fiber_swap: function(oldFiber, newFiber) { throw 'Please compile your program with async support in order to use asynchronous operations like emscripten_fiber_swap'; }, #endif // ASYNCIFY diff --git a/src/library_idbstore.js b/src/library_idbstore.js index 872787c6d7f96..c28da22e7f7a1 100644 --- a/src/library_idbstore.js +++ b/src/library_idbstore.js @@ -157,16 +157,16 @@ var LibraryIDBStore = { IDBStore.blobs[blobId] = null; }, #else - emscripten_idb_load: function() { + emscripten_idb_load: function(db, id, pbuffer, pnum, perror) { throw 'Please compile your program with async support in order to use synchronous operations like emscripten_idb_load, etc.'; }, - emscripten_idb_store: function() { + emscripten_idb_store: function(db, id, ptr, num, perror) { throw 'Please compile your program with async support in order to use synchronous operations like emscripten_idb_store, etc.'; }, - emscripten_idb_delete: function() { + emscripten_idb_delete: function(db, id, perror) { throw 'Please compile your program with async support in order to use synchronous operations like emscripten_idb_delete, etc.'; }, - emscripten_idb_exists: function() { + emscripten_idb_exists: function(db, id, pexists, perror) { throw 'Please compile your program with async support in order to use synchronous operations like emscripten_idb_exists, etc.'; }, #endif // ASYNCIFY diff --git a/src/library_sdl.js b/src/library_sdl.js index 66a59e5d5e279..0d97cab60935d 100644 --- a/src/library_sdl.js +++ b/src/library_sdl.js @@ -1843,7 +1843,7 @@ var LibrarySDL = { return SDL.errorMessage; }, - SDL_SetError: function() {}, + SDL_SetError: function(fmt, varargs) {}, SDL_CreateRGBSurface__deps: ['malloc', 'free'], SDL_CreateRGBSurface__proxy: 'sync', @@ -2657,14 +2657,14 @@ var LibrarySDL = { SDL_UnlockAudio: function() {}, SDL_CreateMutex: function() { return 0 }, - SDL_mutexP: function() { return 0 }, - SDL_mutexV: function() { return 0 }, - SDL_DestroyMutex: function() {}, + SDL_mutexP: function(mutex) { return 0 }, + SDL_mutexV: function(mutex) { return 0 }, + SDL_DestroyMutex: function(mutex) {}, SDL_CreateCond: function() { return 0 }, - SDL_CondSignal: function() {}, - SDL_CondWait: function() {}, - SDL_DestroyCond: function() {}, + SDL_CondSignal: function(cond) {}, + SDL_CondWait: function(cond, mutex) {}, + SDL_DestroyCond: function(cond) {}, SDL_StartTextInput__proxy: 'sync', SDL_StartTextInput__sig: 'v', @@ -3716,30 +3716,30 @@ var LibrarySDL = { }, // TODO: - SDL_CreateThread: function() { + SDL_CreateThread: function(fs, data, pfnBeginThread, pfnEndThread) { throw 'SDL threads cannot be supported in the web platform because they assume shared state. See emscripten_create_worker etc. for a message-passing concurrency model that does let you run code in another thread.' }, - SDL_WaitThread: function() { throw 'SDL_WaitThread' }, - SDL_GetThreadID: function() { throw 'SDL_GetThreadID' }, + SDL_WaitThread: function(thread, status) { throw 'SDL_WaitThread' }, + SDL_GetThreadID: function(thread) { throw 'SDL_GetThreadID' }, SDL_ThreadID: function() { return 0; }, SDL_AllocRW: function() { throw 'SDL_AllocRW: TODO' }, - SDL_CondBroadcast: function() { throw 'SDL_CondBroadcast: TODO' }, - SDL_CondWaitTimeout: function() { throw 'SDL_CondWaitTimeout: TODO' }, + SDL_CondBroadcast: function(cond) { throw 'SDL_CondBroadcast: TODO' }, + SDL_CondWaitTimeout: function(cond, mutex, ms) { throw 'SDL_CondWaitTimeout: TODO' }, SDL_WM_IconifyWindow: function() { throw 'SDL_WM_IconifyWindow TODO' }, - Mix_SetPostMix: function() { warnOnce('Mix_SetPostMix: TODO') }, + Mix_SetPostMix: function(func, arg) { warnOnce('Mix_SetPostMix: TODO') }, Mix_VolumeChunk: function(chunk, volume) { throw 'Mix_VolumeChunk: TODO' }, Mix_SetPosition: function(channel, angle, distance) { throw 'Mix_SetPosition: TODO' }, - Mix_QuerySpec: function() { throw 'Mix_QuerySpec: TODO' }, - Mix_FadeInChannelTimed: function() { throw 'Mix_FadeInChannelTimed' }, + Mix_QuerySpec: function(frequency, format, channels) { throw 'Mix_QuerySpec: TODO' }, + Mix_FadeInChannelTimed: function(channel, chunk, loop, ms, ticks) { throw 'Mix_FadeInChannelTimed' }, Mix_FadeOutChannel: function() { throw 'Mix_FadeOutChannel' }, Mix_Linked_Version: function() { throw 'Mix_Linked_Version: TODO' }, - SDL_SaveBMP_RW: function() { throw 'SDL_SaveBMP_RW: TODO' }, + SDL_SaveBMP_RW: function(surface, dst, freedst) { throw 'SDL_SaveBMP_RW: TODO' }, - SDL_WM_SetIcon: function() { /* This function would set the application window icon surface, which doesn't apply for web canvases, so a no-op. */ }, + SDL_WM_SetIcon: function(icon, mask) { /* This function would set the application window icon surface, which doesn't apply for web canvases, so a no-op. */ }, SDL_HasRDTSC: function() { return 0; }, SDL_HasMMX: function() { return 0; }, SDL_HasMMXExt: function() { return 0; }, diff --git a/src/library_syscall.js b/src/library_syscall.js index 109f554825b53..e9b69cbd06b99 100644 --- a/src/library_syscall.js +++ b/src/library_syscall.js @@ -305,7 +305,7 @@ var SyscallsLibrary = { return sock.stream.fd; }, __syscall_getsockname__deps: ['$getSocketFromFD', '$writeSockaddr', '$DNS'], - __syscall_getsockname: function(fd, addr, addrlen) { + __syscall_getsockname: function(fd, addr, addrlen, d1, d2, d3) { err("__syscall_getsockname " + fd); var sock = getSocketFromFD(fd); // TODO: sock.saddr should never be undefined, see TODO in websocket_sock_ops.getname @@ -316,7 +316,7 @@ var SyscallsLibrary = { return 0; }, __syscall_getpeername__deps: ['$getSocketFromFD', '$writeSockaddr', '$DNS'], - __syscall_getpeername: function(fd, addr, addrlen) { + __syscall_getpeername: function(fd, addr, addrlen, d1, d2, d3) { var sock = getSocketFromFD(fd); if (!sock.daddr) { return -{{{ cDefs.ENOTCONN }}}; // The socket is not connected. @@ -341,7 +341,7 @@ var SyscallsLibrary = { return -{{{ cDefs.ENOSYS }}}; // unsupported feature }, __syscall_accept4__deps: ['$getSocketFromFD', '$writeSockaddr', '$DNS'], - __syscall_accept4: function(fd, addr, addrlen, flags) { + __syscall_accept4: function(fd, addr, addrlen, flags, d1, d2) { var sock = getSocketFromFD(fd); var newsock = sock.sock_ops.accept(sock); if (addr) { @@ -393,7 +393,7 @@ var SyscallsLibrary = { return sock.sock_ops.sendmsg(sock, {{{ heapAndOffset('HEAP8', 'message') }}}, length, dest.addr, dest.port); }, __syscall_getsockopt__deps: ['$getSocketFromFD'], - __syscall_getsockopt: function(fd, level, optname, optval, optlen) { + __syscall_getsockopt: function(fd, level, optname, optval, optlen, d1) { var sock = getSocketFromFD(fd); // Minimal getsockopt aimed at resolving https://github.com/emscripten-core/emscripten/issues/2211 // so only supports SOL_SOCKET with SO_ERROR. @@ -408,7 +408,7 @@ var SyscallsLibrary = { return -{{{ cDefs.ENOPROTOOPT }}}; // The option is unknown at the level indicated. }, __syscall_sendmsg__deps: ['$getSocketFromFD', '$readSockaddr', '$DNS'], - __syscall_sendmsg: function(fd, message, flags) { + __syscall_sendmsg: function(fd, message, flags, d1, d2, d3) { var sock = getSocketFromFD(fd); var iov = {{{ makeGetValue('message', C_STRUCTS.msghdr.msg_iov, '*') }}}; var num = {{{ makeGetValue('message', C_STRUCTS.msghdr.msg_iovlen, 'i32') }}}; @@ -440,7 +440,7 @@ var SyscallsLibrary = { return sock.sock_ops.sendmsg(sock, view, 0, total, addr, port); }, __syscall_recvmsg__deps: ['$getSocketFromFD', '$writeSockaddr', '$DNS'], - __syscall_recvmsg: function(fd, message, flags) { + __syscall_recvmsg: function(fd, message, flags, d1, d2, d3) { var sock = getSocketFromFD(fd); var iov = {{{ makeGetValue('message', C_STRUCTS.msghdr.msg_iov, POINTER_TYPE) }}}; var num = {{{ makeGetValue('message', C_STRUCTS.msghdr.msg_iovlen, 'i32') }}}; diff --git a/src/library_webgl.js b/src/library_webgl.js index 17ec5a5eb7527..7e7012379fbfc 100644 --- a/src/library_webgl.js +++ b/src/library_webgl.js @@ -3710,10 +3710,18 @@ var LibraryGL = { #if !LEGACY_GL_EMULATION - glVertexPointer: function(){ throw 'Legacy GL function (glVertexPointer) called. If you want legacy GL emulation, you need to compile with -sLEGACY_GL_EMULATION to enable legacy GL emulation.'; }, - glMatrixMode: function(){ throw 'Legacy GL function (glMatrixMode) called. If you want legacy GL emulation, you need to compile with -sLEGACY_GL_EMULATION to enable legacy GL emulation.'; }, - glBegin: function(){ throw 'Legacy GL function (glBegin) called. If you want legacy GL emulation, you need to compile with -sLEGACY_GL_EMULATION to enable legacy GL emulation.'; }, - glLoadIdentity: function(){ throw 'Legacy GL function (glLoadIdentity) called. If you want legacy GL emulation, you need to compile with -sLEGACY_GL_EMULATION to enable legacy GL emulation.'; }, + glVertexPointer: function(size, type, stride, ptr) { + throw 'Legacy GL function (glVertexPointer) called. If you want legacy GL emulation, you need to compile with -sLEGACY_GL_EMULATION to enable legacy GL emulation.'; + }, + glMatrixMode: function() { + throw 'Legacy GL function (glMatrixMode) called. If you want legacy GL emulation, you need to compile with -sLEGACY_GL_EMULATION to enable legacy GL emulation.'; + }, + glBegin: function() { + throw 'Legacy GL function (glBegin) called. If you want legacy GL emulation, you need to compile with -sLEGACY_GL_EMULATION to enable legacy GL emulation.'; + }, + glLoadIdentity: function() { + throw 'Legacy GL function (glLoadIdentity) called. If you want legacy GL emulation, you need to compile with -sLEGACY_GL_EMULATION to enable legacy GL emulation.'; + }, #endif // LEGACY_GL_EMULATION diff --git a/src/library_xlib.js b/src/library_xlib.js index 8afc763f8e3a3..60c477e420feb 100644 --- a/src/library_xlib.js +++ b/src/library_xlib.js @@ -5,7 +5,7 @@ */ var LibraryXlib = { - XOpenDisplay: function() { + XOpenDisplay: function(name) { return 1; // We support 1 display, the canvas }, @@ -16,12 +16,12 @@ var LibraryXlib = { return 2; }, - XChangeWindowAttributes: function(){}, - XSetWMHints: function(){}, - XMapWindow: function(){}, - XStoreName: function(){}, + XChangeWindowAttributes: function(display, window, valuemask, attributes){}, + XSetWMHints: function(display, win, hints){}, + XMapWindow: function(display, win){}, + XStoreName: function(display, win, name){}, XInternAtom: function(display, name_, hmm) { return 0 }, - XSendEvent: function(){}, + XSendEvent: function(display, win, propagate, event_mask, even_send){}, XPending: function(display) { return 0 }, }; From 0f74a7db63ca9556d45cb0ad4067e288c60dd206 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 22 Mar 2023 17:37:35 -0700 Subject: [PATCH 0047/1523] Fix closure warnings in SDL + pthreads (#19044) These were caused by the injected emscripten_proxy_to_main_thread_js calls expected all args to be either numbers of boolean (and never `undefined`). --- embuilder.py | 1 + src/library_sdl.js | 28 ++++++++++++++-------------- test/test_other.py | 1 + 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/embuilder.py b/embuilder.py index ce514f94d8ad8..c65921283164c 100755 --- a/embuilder.py +++ b/embuilder.py @@ -94,6 +94,7 @@ 'libwasm_workers_stub-debug', 'libwebgpu_cpp', 'libfetch', + 'libfetch-mt', 'libwasmfs', 'giflib', ] diff --git a/src/library_sdl.js b/src/library_sdl.js index 0d97cab60935d..59271962490e5 100644 --- a/src/library_sdl.js +++ b/src/library_sdl.js @@ -1351,7 +1351,7 @@ var LibrarySDL = { SDL_Init__deps: ['$zeroMemory', 'malloc', 'free', 'memcpy'], SDL_Init__proxy: 'sync', SDL_Init__sig: 'ii', - SDL_Init__docs: '/** @param{number=} initFlags */', + SDL_Init__docs: '/** @param{number} initFlags */', SDL_Init: function(initFlags) { SDL.startTime = Date.now(); SDL.initFlags = initFlags; @@ -1401,7 +1401,7 @@ var LibrarySDL = { SDL_WasInit__sig: 'ii', SDL_WasInit: function(flags) { if (SDL.startTime === null) { - _SDL_Init(); + _SDL_Init(0); } return 1; }, @@ -1760,7 +1760,7 @@ var LibrarySDL = { SDL_GetKeyboardState__proxy: 'sync', SDL_GetKeyboardState__sig: 'pp', - SDL_GetKeyboardState__docs: '/** @param {number=} numKeys */', + SDL_GetKeyboardState__docs: '/** @param {number} numKeys */', SDL_GetKeyboardState: function(numKeys) { if (numKeys) { {{{ makeSetValue('numKeys', 0, 0x10000, 'i32') }}}; @@ -1770,7 +1770,7 @@ var LibrarySDL = { SDL_GetKeyState__deps: ['SDL_GetKeyboardState'], SDL_GetKeyState: function() { - return _SDL_GetKeyboardState(); + return _SDL_GetKeyboardState(0); }, SDL_GetKeyName__proxy: 'sync', @@ -1884,7 +1884,7 @@ var LibrarySDL = { SDL_ConvertSurface__proxy: 'sync', SDL_ConvertSurface__sig: 'pppi', - SDL_ConvertSurface__docs: '/** @param {number=} format @param {number=} flags */', + SDL_ConvertSurface__docs: '/** @param {number} format @param {number} flags */', SDL_ConvertSurface: function(surf, format, flags) { if (format) { SDL.checkPixelFormat(format); @@ -1902,7 +1902,7 @@ var LibrarySDL = { SDL_DisplayFormatAlpha__deps: ['SDL_ConvertSurface'], SDL_DisplayFormatAlpha: function(surf) { - return _SDL_ConvertSurface(surf); + return _SDL_ConvertSurface(surf, 0, 0); }, SDL_FreeSurface__proxy: 'sync', @@ -2382,7 +2382,7 @@ var LibrarySDL = { IMG_Load__proxy: 'sync', IMG_Load__sig: 'pp', IMG_Load: function(filename){ - var rwops = _SDL_RWFromFile(filename); + var rwops = _SDL_RWFromFile(filename, 0); var result = _IMG_Load_RW(rwops, 1); return result; }, @@ -2746,7 +2746,7 @@ var LibrarySDL = { Mix_LoadWAV_RW__deps: ['$PATH_FS', 'fileno'], Mix_LoadWAV_RW__proxy: 'sync', Mix_LoadWAV_RW__sig: 'ppi', - Mix_LoadWAV_RW__docs: '/** @param {number|boolean=} freesrc */', + Mix_LoadWAV_RW__docs: '/** @param {number} freesrc */', Mix_LoadWAV_RW: function(rwopsID, freesrc) { var rwops = SDL.rwops[rwopsID]; @@ -2854,8 +2854,8 @@ var LibrarySDL = { Mix_LoadWAV__proxy: 'sync', Mix_LoadWAV__sig: 'pp', Mix_LoadWAV: function(filename) { - var rwops = _SDL_RWFromFile(filename); - var result = _Mix_LoadWAV_RW(rwops); + var rwops = _SDL_RWFromFile(filename, 0); + var result = _Mix_LoadWAV_RW(rwops, 0); _SDL_FreeRW(rwops); return result; }, @@ -3000,15 +3000,15 @@ var LibrarySDL = { return SDL.setGetVolume(SDL.music, volume); }, - Mix_LoadMUS_RW__docs: '/** @param {number|boolean=} a1 */', + Mix_LoadMUS_RW__docs: '/** @param {number} a1 */', Mix_LoadMUS_RW: 'Mix_LoadWAV_RW', Mix_LoadMUS__deps: ['Mix_LoadMUS_RW', 'SDL_RWFromFile', 'SDL_FreeRW'], Mix_LoadMUS__proxy: 'sync', Mix_LoadMUS__sig: 'pp', Mix_LoadMUS: function(filename) { - var rwops = _SDL_RWFromFile(filename); - var result = _Mix_LoadMUS_RW(rwops); + var rwops = _SDL_RWFromFile(filename, 0); + var result = _Mix_LoadMUS_RW(rwops, 0); _SDL_FreeRW(rwops); return result; }, @@ -3664,7 +3664,7 @@ var LibrarySDL = { SDL_RWFromFile__proxy: 'sync', SDL_RWFromFile__sig: 'ppp', - SDL_RWFromFile__docs: '/** @param {number=} mode */', + SDL_RWFromFile__docs: '/** @param {number} mode */', SDL_RWFromFile: function(_name, mode) { var id = SDL.rwops.length; // TODO: recycle ids when they are null var name = UTF8ToString(_name); diff --git a/test/test_other.py b/test/test_other.py index ccb054beda70f..e4850735141ff 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -8643,6 +8643,7 @@ def test_full_js_library_minimal_runtime(self): # bigint support is interesting to test here because it changes which # binaryen tools get run, which can affect how debug info is kept around 'bigint': [['-sWASM_BIGINT']], + 'pthread': [['-pthread', '-Wno-experimental']], }) def test_closure_full_js_library(self, args): # Test for closure errors and warnings in the entire JS library. From 7320016d7f4414289ee810821ff2272fc18e5b7e Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 22 Mar 2023 22:23:50 -0700 Subject: [PATCH 0048/1523] Fix failing test_closure_full_js_library. NFC (#19050) This should really have been part of #19044 but I landed it without waiting for all tests to pass. --- embuilder.py | 1 + test/test_other.py | 1 + 2 files changed, 2 insertions(+) diff --git a/embuilder.py b/embuilder.py index c65921283164c..1fc59af5c17ed 100755 --- a/embuilder.py +++ b/embuilder.py @@ -86,6 +86,7 @@ 'libdlmalloc-mt', 'libGL-emu', 'libGL-mt', + 'libGL-mt-emu', 'libsockets_proxy', 'libsockets-mt', 'crtbegin', diff --git a/test/test_other.py b/test/test_other.py index e4850735141ff..db2b8f39326ec 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -8638,6 +8638,7 @@ def test_full_js_library_no_exception_throwing(self): def test_full_js_library_minimal_runtime(self): self.run_process([EMCC, test_file('hello_world.c'), '-sSTRICT_JS', '-sINCLUDE_FULL_LIBRARY', '-sMINIMAL_RUNTIME']) + @crossplatform @parameterized({ '': [[]], # bigint support is interesting to test here because it changes which From a4e750e4e21762e46eb952c4b6f7bc3cceb52759 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 22 Mar 2023 22:25:48 -0700 Subject: [PATCH 0049/1523] Downgrade error message when threads exit with live runtime (#19048) Fixes: #19036 --- src/worker.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/worker.js b/src/worker.js index 12de2659763a6..4c8fe3cebc4f7 100644 --- a/src/worker.js +++ b/src/worker.js @@ -249,8 +249,8 @@ function handleMessage(e) { // and let the top level handler propagate it back to the main thread. throw ex; } -#if ASSERTIONS - err('Pthread 0x' + Module['_pthread_self']().toString(16) + ' completed its main entry point with an `unwind`, keeping the worker alive for asynchronous operation.'); +#if RUNTIME_DEBUG + dbg('Pthread 0x' + Module['_pthread_self']().toString(16) + ' completed its main entry point with an `unwind`, keeping the worker alive for asynchronous operation.'); #endif } } else if (e.data.cmd === 'cancel') { // Main thread is asking for a pthread_cancel() on this thread. From 9d46f349f427254552f2eb989ae24fe1181b208c Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 23 Mar 2023 00:09:39 -0700 Subject: [PATCH 0050/1523] Move __deps type checking into mergeInto. NFC (#19045) Doing the checks here gives better error message that include the filename. --- src/jsifier.js | 4 ---- src/utility.js | 9 ++++++++- test/test_other.py | 46 +++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 51 insertions(+), 8 deletions(-) diff --git a/src/jsifier.js b/src/jsifier.js index 889b326eb1108..530db452a3c82 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -251,10 +251,6 @@ function ${name}(${args}) { } const deps = LibraryManager.library[symbol + '__deps'] || []; - if (!Array.isArray(deps)) { - error(`JS library directive ${symbol}__deps=${deps.toString()} is of type ${typeof deps}, but it should be an array!`); - return; - } if (symbolsOnly) { if (!isJsOnlySymbol(symbol) && LibraryManager.library.hasOwnProperty(symbol)) { diff --git a/src/utility.js b/src/utility.js index 2157461fc4c6f..abd503c43373c 100644 --- a/src/utility.js +++ b/src/utility.js @@ -134,10 +134,17 @@ function mergeInto(obj, other, options = null) { const oldsig = obj[key]; const newsig = other[key]; if (oldsig != newsig) { - console.warn(`Signature redefinition mismatch for : ${key}. (old=${oldsig} vs new=${newsig})`); + error(`Signature redefinition for: ${key}. (old=${oldsig} vs new=${newsig})`); } } } + + if (key.endsWith('__deps')) { + const deps = other[key]; + if (!Array.isArray(deps)) { + error(`JS library directive ${key}=${deps.toString()} is of type ${typeof deps}, but it should be an array`); + } + } } return Object.assign(obj, other); diff --git a/test/test_other.py b/test/test_other.py index db2b8f39326ec..429e344794a11 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -3839,16 +3839,56 @@ def test_js_internal_deps(self): }, }); ''') - create_file('src.cpp', r''' + create_file('src.c', r''' #include -extern "C" int jslibfunc(); +int jslibfunc(); int main() { printf("c calling: %d\n", jslibfunc()); } ''') - err = self.run_process([EMXX, 'src.cpp', '--js-library', 'lib.js'], stderr=PIPE).stderr + err = self.run_process([EMCC, 'src.c', '--js-library', 'lib.js'], stderr=PIPE).stderr self.assertContained("warning: user library symbol 'jslibfunc' depends on internal symbol '$callRuntimeCallbacks'", err) + def test_js_lib_sig_mismatch(self): + create_file('lib.js', r''' +mergeInto(LibraryManager.library, { + jslibfunc__sig: 'ii', + jslibfunc: function(x) {}, +}); + +mergeInto(LibraryManager.library, { + jslibfunc__sig: 'dd', + jslibfunc: function(x) {}, +}); + +''') + create_file('src.c', r''' +#include +int jslibfunc(); +int main() { + printf("c calling: %d\n", jslibfunc()); +} +''') + err = self.expect_fail([EMCC, 'src.c', '--js-library', 'lib.js']) + self.assertContained('lib.js: Signature redefinition for: jslibfunc__sig. (old=ii vs new=dd)', err) + + def test_js_lib_invalid_deps(self): + create_file('lib.js', r''' +mergeInto(LibraryManager.library, { + jslibfunc__deps: 'hello', + jslibfunc: function(x) {}, +}); +''') + create_file('src.c', r''' +#include +int jslibfunc(); +int main() { + printf("c calling: %d\n", jslibfunc()); +} +''') + err = self.expect_fail([EMCC, 'src.c', '--js-library', 'lib.js']) + self.assertContained('lib.js: JS library directive jslibfunc__deps=hello is of type string, but it should be an array', err) + def test_EMCC_BUILD_DIR(self): # EMCC_BUILD_DIR env var contains the dir we were building in, when running the js compiler (e.g. when # running a js library). We force the cwd to be src/ for technical reasons, so this lets you find out From 07af96af4a1fbfe293aa2fb6c64236f00afc201f Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 23 Mar 2023 01:18:48 -0700 Subject: [PATCH 0051/1523] jsifier: Simplify runJSify. NFC (#19047) Rather than processing JS objects, just process symbols and geneate JS strings. I think there was perhaps more complex needed in the past but no longer. --- src/jsifier.js | 37 +++++++++++++------------------------ 1 file changed, 13 insertions(+), 24 deletions(-) diff --git a/src/jsifier.js b/src/jsifier.js index 530db452a3c82..0357104dc8431 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -211,34 +211,29 @@ function ${name}(${args}) { } } - function itemHandler(item) { + function symbolHandler(symbol) { // In LLVM, exceptions generate a set of functions of form // __cxa_find_matching_catch_1(), __cxa_find_matching_catch_2(), etc. where // the number specifies the number of arguments. In Emscripten, route all // these to a single function '__cxa_find_matching_catch' that variadically // processes all of these functions using JS 'arguments' object. - if (item.mangled.startsWith('___cxa_find_matching_catch_')) { + if (symbol.startsWith('__cxa_find_matching_catch_')) { if (DISABLE_EXCEPTION_THROWING) { error('DISABLE_EXCEPTION_THROWING was set (likely due to -fno-exceptions), which means no C++ exception throwing support code is linked in, but exception catching code appears. Either do not set DISABLE_EXCEPTION_THROWING (if you do want exception throwing) or compile all source files with -fno-except (so that no exceptions support code is required); also make sure DISABLE_EXCEPTION_CATCHING is set to the right value - if you want exceptions, it should be off, and vice versa.'); return; } - const num = +item.mangled.split('_').slice(-1)[0]; + const num = +symbol.split('_').slice(-1)[0]; addCxaCatch(num); // Continue, with the code below emitting the proper JavaScript based on // what we just added to the library. } - const TOP_LEVEL = 'top-level compiled C/C++ code'; - - function addFromLibrary(item, dependent) { + function addFromLibrary(symbol, dependent) { // dependencies can be JS functions, which we just run - if (typeof item == 'function') { - return item(); + if (typeof symbol == 'function') { + return symbol(); } - const symbol = item.symbol; - const mangled = item.mangled; - if (symbol in addedLibraryItems) { return; } @@ -271,6 +266,8 @@ function ${name}(${args}) { // will resolve the correct symbol at runtime, or assert if its missing. let isStub = false; + const mangled = mangleCSymbolName(symbol); + if (!LibraryManager.library.hasOwnProperty(symbol)) { const isWeakImport = WEAK_IMPORTS.has(symbol); if (!isDefined(symbol) && !isWeakImport) { @@ -369,9 +366,7 @@ function ${name}(${args}) { } if (postset && !addedLibraryItems[postsetId]) { addedLibraryItems[postsetId] = true; - postSets.push({ - JS: postset + ';', - }); + postSets.push(postset + ';'); } } @@ -381,9 +376,6 @@ function ${name}(${args}) { const deps_list = deps.join("','"); const identDependents = symbol + `__deps: ['${deps_list}']`; function addDependency(dep) { - if (typeof dep != 'function') { - dep = {symbol: dep, mangled: mangleCSymbolName(dep)}; - } return addFromLibrary(dep, `${identDependents}, referenced by ${dependent}`); } let contentText; @@ -447,8 +439,8 @@ function ${name}(${args}) { return depsText + commentText + contentText; } - libraryItems.push(item); - item.JS = addFromLibrary(item, TOP_LEVEL); + const JS = addFromLibrary(symbol, 'top-level compiled C/C++ code'); + libraryItems.push(JS); } function includeFile(fileName) { @@ -492,7 +484,7 @@ function ${name}(${args}) { includeFile(preFile); for (const item of libraryItems.concat(postSets)) { - print(indentify(item.JS || '', 2)); + print(indentify(item || '', 2)); } if (PTHREADS) { @@ -544,10 +536,7 @@ function ${name}(${args}) { } for (const sym of symbolsNeeded) { - itemHandler({ - symbol: sym, - mangled: mangleCSymbolName(sym), - }); + symbolHandler(sym); } if (symbolsOnly) { From b116323214e11982d611fe9cd8d27c47d41783d7 Mon Sep 17 00:00:00 2001 From: Brendan Dahl Date: Thu, 23 Mar 2023 09:16:30 -0700 Subject: [PATCH 0052/1523] Test that JSPI works in chrome browser tests. (#19026) --- .circleci/config.yml | 2 +- test/test_browser.py | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 1b6723cb42759..83147d30b8bd5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -329,7 +329,7 @@ commands: # this flag for now: https://crbug.com/638180 CHROME_FLAGS_BASE: "--no-first-run -start-maximized --no-sandbox --use-gl=swiftshader --user-data-dir=/tmp/chrome-emscripten-profile --enable-experimental-web-platform-features" CHROME_FLAGS_HEADLESS: "--headless --remote-debugging-port=1234" - CHROME_FLAGS_WASM: "--enable-experimental-webassembly-features --js-flags=\"--experimental-wasm-memory64\"" + CHROME_FLAGS_WASM: "--enable-experimental-webassembly-features --js-flags=\"--experimental-wasm-memory64 --experimental-wasm-stack-switching --experimental-wasm-type-reflection\"" CHROME_FLAGS_NOCACHE: "--disk-cache-dir=/dev/null --disk-cache-size=1 --media-cache-size=1 --disable-application-cache --incognito" command: | export EMTEST_BROWSER="/usr/bin/google-chrome $CHROME_FLAGS_BASE $CHROME_FLAGS_HEADLESS $CHROME_FLAGS_WASM $CHROME_FLAGS_NOCACHE" diff --git a/test/test_browser.py b/test/test_browser.py index f3dc06fad07e5..d0d2026155df6 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -149,6 +149,10 @@ def no_firefox(note='firefox is not supported'): return lambda f: f +def is_jspi(args): + return '-sASYNCIFY=2' in args + + def no_swiftshader(f): assert callable(f) @@ -3320,10 +3324,17 @@ def test_cocos2d_hello(self): '-Wno-inconsistent-missing-override', '-Wno-deprecated-declarations']) - def test_async(self): + @parameterized({ + 'asyncify': (['-sASYNCIFY=1'],), + 'jspi': (['-sASYNCIFY=2', '-Wno-experimental'],), + }) + def test_async(self, args): + if is_jspi(args) and not is_chrome(): + self.skipTest('only chrome supports jspi') + for opts in [0, 1, 2, 3]: print(opts) - self.btest_exit('browser/async.cpp', args=['-O' + str(opts), '-g2', '-sASYNCIFY']) + self.btest_exit('browser/async.cpp', args=['-O' + str(opts), '-g2'] + args) def test_asyncify_tricky_function_sig(self): self.btest('browser/test_asyncify_tricky_function_sig.cpp', '85', args=['-sASYNCIFY_ONLY=[foo(char.const*?.int#),foo2(),main,__original_main]', '-sASYNCIFY']) From 3cf83fdc4711e9bf3b01cf9821e717311a13c1b5 Mon Sep 17 00:00:00 2001 From: Ingvar Stepanyan Date: Fri, 24 Mar 2023 12:32:01 +0000 Subject: [PATCH 0053/1523] Optimise getentropy (#19056) --- src/library.js | 50 ++++++++++++++++++++++++++++++++--------------- src/library_fs.js | 15 ++++++++++---- 2 files changed, 45 insertions(+), 20 deletions(-) diff --git a/src/library.js b/src/library.js index e4de910da4b5e..e66d2df490085 100644 --- a/src/library.js +++ b/src/library.js @@ -2223,21 +2223,38 @@ mergeInto(LibraryManager.library, { // random.h - // TODO: consider allowing the API to get a parameter for the number of - // bytes. - $getRandomDevice: function() { + $initRandomFill: function() { if (typeof crypto == 'object' && typeof crypto['getRandomValues'] == 'function') { // for modern web browsers - var randomBuffer = new Uint8Array(1); - return () => { crypto.getRandomValues(randomBuffer); return randomBuffer[0]; }; +#if SHARED_MEMORY + // like with most Web APIs, we can't use Web Crypto API directly on shared memory, + // so we need to create an intermediate buffer and copy it to the destination + return (view) => ( + view.set(crypto.getRandomValues(new Uint8Array(view.byteLength))), + // Return the original view to match modern native implementations. + view + ); +#else + return (view) => crypto.getRandomValues(view); +#endif } else #if ENVIRONMENT_MAY_BE_NODE if (ENVIRONMENT_IS_NODE) { // for nodejs with or without crypto support included try { var crypto_module = require('crypto'); - // nodejs has crypto support - return () => crypto_module['randomBytes'](1)[0]; + var randomFillSync = crypto_module['randomFillSync']; + if (randomFillSync) { + // nodejs with LTS crypto support + return (view) => crypto_module['randomFillSync'](view); + } + // very old nodejs with the original crypto API + var randomBytes = crypto_module['randomBytes']; + return (view) => ( + view.set(randomBytes(view.byteLength)), + // Return the original view to match modern native implementations. + view + ); } catch (e) { // nodejs doesn't have crypto support } @@ -2245,21 +2262,22 @@ mergeInto(LibraryManager.library, { #endif // ENVIRONMENT_MAY_BE_NODE // we couldn't find a proper implementation, as Math.random() is not suitable for /dev/random, see emscripten-core/emscripten/pull/7096 #if ASSERTIONS - return () => abort("no cryptographic support found for randomDevice. consider polyfilling it if you want to use something insecure like Math.random(), e.g. put this in a --pre-js: var crypto = { getRandomValues: function(array) { for (var i = 0; i < array.length; i++) array[i] = (Math.random()*256)|0 } };"); + abort("no cryptographic support found for randomDevice. consider polyfilling it if you want to use something insecure like Math.random(), e.g. put this in a --pre-js: var crypto = { getRandomValues: function(array) { for (var i = 0; i < array.length; i++) array[i] = (Math.random()*256)|0 } };"); #else - return () => abort("randomDevice"); + abort("initRandomDevice"); #endif }, - getentropy__deps: ['$getRandomDevice'], + $randomFill__deps: ['$initRandomFill'], + $randomFill: function(view) { + // Lazily init on the first invocation. + return (randomFill = initRandomFill())(view); + }, + + getentropy__deps: ['$randomFill'], getentropy__sig: 'ipp', getentropy: function(buffer, size) { - if (!_getentropy.randomDevice) { - _getentropy.randomDevice = getRandomDevice(); - } - for (var i = 0; i < size; i++) { - {{{ makeSetValue('buffer', 'i', '_getentropy.randomDevice()', 'i8') }}}; - } + randomFill(HEAPU8.subarray(buffer, buffer + size)); return 0; }, diff --git a/src/library_fs.js b/src/library_fs.js index 517c10c417cba..b051144958551 100644 --- a/src/library_fs.js +++ b/src/library_fs.js @@ -5,7 +5,7 @@ */ mergeInto(LibraryManager.library, { - $FS__deps: ['$getRandomDevice', '$PATH', '$PATH_FS', '$TTY', '$MEMFS', '$asyncLoad', '$intArrayFromString', + $FS__deps: ['$randomFill', '$PATH', '$PATH_FS', '$TTY', '$MEMFS', '$asyncLoad', '$intArrayFromString', #if LibraryManager.has('library_idbfs.js') '$IDBFS', #endif @@ -1348,9 +1348,16 @@ FS.staticInit();` + FS.mkdev('/dev/tty', FS.makedev(5, 0)); FS.mkdev('/dev/tty1', FS.makedev(6, 0)); // setup /dev/[u]random - var random_device = getRandomDevice(); - FS.createDevice('/dev', 'random', random_device); - FS.createDevice('/dev', 'urandom', random_device); + // use a buffer to avoid overhead of individual crypto calls per byte + var randomBuffer = new Uint8Array(1024), randomLeft = 0; + var randomByte = () => { + if (randomLeft === 0) { + randomLeft = randomFill(randomBuffer).byteLength; + } + return randomBuffer[--randomLeft]; + }; + FS.createDevice('/dev', 'random', randomByte); + FS.createDevice('/dev', 'urandom', randomByte); // we're not going to emulate the actual shm device, // just create the tmp dirs that reside in it commonly FS.mkdir('/dev/shm'); From 978e102f23c7fa304d9a5e25a60104789bc47001 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 24 Mar 2023 09:50:21 -0700 Subject: [PATCH 0054/1523] Always include library_sdl.js and library_glfw.js conditionally (#19057) Split out from #19028. --- emcc.py | 1 + src/modules.js | 9 ++++++--- src/settings.js | 1 + src/shell.js | 1 + tools/gen_sig_info.py | 1 + 5 files changed, 10 insertions(+), 3 deletions(-) diff --git a/emcc.py b/emcc.py index 61b0fffee9ea6..1b3171b6d4c7d 100755 --- a/emcc.py +++ b/emcc.py @@ -1993,6 +1993,7 @@ def phase_linker_setup(options, state, newargs): default_setting('AUTO_JS_LIBRARIES', 0) # When using MINIMAL_RUNTIME, symbols should only be exported if requested. default_setting('EXPORT_KEEPALIVE', 0) + default_setting('USE_GLFW', 0) if settings.STRICT_JS and (settings.MODULARIZE or settings.EXPORT_ES6): exit_with_error("STRICT_JS doesn't work with MODULARIZE or EXPORT_ES6") diff --git a/src/modules.js b/src/modules.js index 3ccdaa481f7b8..d41779ce5bbbf 100644 --- a/src/modules.js +++ b/src/modules.js @@ -113,7 +113,6 @@ global.LibraryManager = { 'library_webgl.js', 'library_html5_webgl.js', 'library_openal.js', - 'library_sdl.js', 'library_glut.js', 'library_xlib.js', 'library_egl.js', @@ -122,8 +121,8 @@ global.LibraryManager = { 'library_idbstore.js', 'library_async.js', ]); - if (USE_GLFW) { - libraries.push('library_glfw.js'); + if (USE_SDL != 2) { + libraries.push('library_sdl.js'); } } else { if (ASYNCIFY) { @@ -137,6 +136,10 @@ global.LibraryManager = { } } + if (USE_GLFW) { + libraries.push('library_glfw.js'); + } + if (LZ4) { libraries.push('library_lz4.js'); } diff --git a/src/settings.js b/src/settings.js index 1a9c436f0a3f9..e839bf2a78fd0 100644 --- a/src/settings.js +++ b/src/settings.js @@ -1292,6 +1292,7 @@ var EMSCRIPTEN_TRACING = false; // Specify the GLFW version that is being linked against. Only relevant, if you // are linking against the GLFW library. Valid options are 2 for GLFW2 and 3 // for GLFW3. +// In MINIMAL_RUNTIME builds, this option defaults to 0. // [link] var USE_GLFW = 2; diff --git a/src/shell.js b/src/shell.js index 5375e1daa5799..a5cfbc2ce1a8e 100644 --- a/src/shell.js +++ b/src/shell.js @@ -27,6 +27,7 @@ var /** @type {{ noAudioDecoding: boolean, noWasmDecoding: boolean, canvas: HTMLCanvasElement, + ctx: Object, dataFileDownloads: Object, preloadResults: Object, useWebGL: boolean, diff --git a/tools/gen_sig_info.py b/tools/gen_sig_info.py index 0d3da8c75c775..b35ad23706987 100755 --- a/tools/gen_sig_info.py +++ b/tools/gen_sig_info.py @@ -221,6 +221,7 @@ def extract_sig_info(sig_info, extra_settings=None, extra_cflags=None): 'USE_PTHREADS': 1, 'STACK_OVERFLOW_CHECK': 1, 'FULL_ES3': 1, + 'USE_SDL': 1, # Currently GLFW symbols have different sigs for the same symbol because the # signatures changed between v2 and v3, so for now we continue to maintain # them by hand. From b79bf7b62eb0588a2292266c4322988085ff7c78 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 24 Mar 2023 12:29:11 -0700 Subject: [PATCH 0055/1523] Rebaseline codesize expectations. NFC --- test/other/metadce/test_metadce_cxx_ctors1.jssize | 2 +- test/other/metadce/test_metadce_cxx_ctors2.jssize | 2 +- test/other/metadce/test_metadce_cxx_except.jssize | 2 +- test/other/metadce/test_metadce_cxx_except_wasm.jssize | 2 +- test/other/metadce/test_metadce_cxx_mangle.jssize | 2 +- test/other/metadce/test_metadce_cxx_noexcept.jssize | 2 +- test/other/metadce/test_metadce_hello_O0.jssize | 2 +- test/other/metadce/test_metadce_hello_dylink.jssize | 2 +- test/other/metadce/test_metadce_minimal_O0.jssize | 2 +- test/other/test_unoptimized_code_size.js.size | 2 +- test/other/test_unoptimized_code_size_strict.js.size | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/test/other/metadce/test_metadce_cxx_ctors1.jssize b/test/other/metadce/test_metadce_cxx_ctors1.jssize index 258a27db4d100..11aaae0dc022f 100644 --- a/test/other/metadce/test_metadce_cxx_ctors1.jssize +++ b/test/other/metadce/test_metadce_cxx_ctors1.jssize @@ -1 +1 @@ -26046 +26183 diff --git a/test/other/metadce/test_metadce_cxx_ctors2.jssize b/test/other/metadce/test_metadce_cxx_ctors2.jssize index df6676401a863..c87d967550f6a 100644 --- a/test/other/metadce/test_metadce_cxx_ctors2.jssize +++ b/test/other/metadce/test_metadce_cxx_ctors2.jssize @@ -1 +1 @@ -26010 +26147 diff --git a/test/other/metadce/test_metadce_cxx_except.jssize b/test/other/metadce/test_metadce_cxx_except.jssize index 843c780975de7..f11164ae1afba 100644 --- a/test/other/metadce/test_metadce_cxx_except.jssize +++ b/test/other/metadce/test_metadce_cxx_except.jssize @@ -1 +1 @@ -30583 +30720 diff --git a/test/other/metadce/test_metadce_cxx_except_wasm.jssize b/test/other/metadce/test_metadce_cxx_except_wasm.jssize index c1668a6c1f6f0..79ad1614ad48f 100644 --- a/test/other/metadce/test_metadce_cxx_except_wasm.jssize +++ b/test/other/metadce/test_metadce_cxx_except_wasm.jssize @@ -1 +1 @@ -25725 +25862 diff --git a/test/other/metadce/test_metadce_cxx_mangle.jssize b/test/other/metadce/test_metadce_cxx_mangle.jssize index 843c780975de7..f11164ae1afba 100644 --- a/test/other/metadce/test_metadce_cxx_mangle.jssize +++ b/test/other/metadce/test_metadce_cxx_mangle.jssize @@ -1 +1 @@ -30583 +30720 diff --git a/test/other/metadce/test_metadce_cxx_noexcept.jssize b/test/other/metadce/test_metadce_cxx_noexcept.jssize index 258a27db4d100..11aaae0dc022f 100644 --- a/test/other/metadce/test_metadce_cxx_noexcept.jssize +++ b/test/other/metadce/test_metadce_cxx_noexcept.jssize @@ -1 +1 @@ -26046 +26183 diff --git a/test/other/metadce/test_metadce_hello_O0.jssize b/test/other/metadce/test_metadce_hello_O0.jssize index 7451e1e04eef3..45129635426fa 100644 --- a/test/other/metadce/test_metadce_hello_O0.jssize +++ b/test/other/metadce/test_metadce_hello_O0.jssize @@ -1 +1 @@ -23946 +23956 diff --git a/test/other/metadce/test_metadce_hello_dylink.jssize b/test/other/metadce/test_metadce_hello_dylink.jssize index b961f935d763b..e8f92ab1737aa 100644 --- a/test/other/metadce/test_metadce_hello_dylink.jssize +++ b/test/other/metadce/test_metadce_hello_dylink.jssize @@ -1 +1 @@ -27785 +27921 diff --git a/test/other/metadce/test_metadce_minimal_O0.jssize b/test/other/metadce/test_metadce_minimal_O0.jssize index 570a495f908e8..6ddb211dca615 100644 --- a/test/other/metadce/test_metadce_minimal_O0.jssize +++ b/test/other/metadce/test_metadce_minimal_O0.jssize @@ -1 +1 @@ -20254 +20264 diff --git a/test/other/test_unoptimized_code_size.js.size b/test/other/test_unoptimized_code_size.js.size index eae45d4b94fb2..5b97533eb699e 100644 --- a/test/other/test_unoptimized_code_size.js.size +++ b/test/other/test_unoptimized_code_size.js.size @@ -1 +1 @@ -64434 +64449 diff --git a/test/other/test_unoptimized_code_size_strict.js.size b/test/other/test_unoptimized_code_size_strict.js.size index 9dcf0080cce43..119b34a173cdd 100644 --- a/test/other/test_unoptimized_code_size_strict.js.size +++ b/test/other/test_unoptimized_code_size_strict.js.size @@ -1 +1 @@ -63441 +63483 From 1320828147d8e0a0dc2301093843acc773da8264 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 24 Mar 2023 13:45:21 -0700 Subject: [PATCH 0056/1523] Start using auto-generated sigs from library_sigs.js. NFC (#19028) The sigs here were removed by running `tools/gen_sig_info.py --remove` Currently the auto-generated signature cover 906 of the 1279 total signatures we have in the JS library. Hopefully we can figure out a way to remove the rest too, but that work can happen in followups. --- src/library.js | 59 --------------- src/library_async.js | 5 -- src/library_browser.js | 23 ------ src/library_dylink.js | 4 - src/library_eventloop.js | 8 -- src/library_glew.js | 1 - src/library_glut.js | 25 ------- src/library_html5.js | 66 ---------------- src/library_html5_webgl.js | 35 +-------- src/library_idbstore.js | 4 - src/library_math.js | 1 - src/library_openal.js | 91 ---------------------- src/library_promise.js | 5 -- src/library_sdl.js | 108 --------------------------- src/library_sigs.js | 5 +- src/library_syscall.js | 34 --------- src/library_wasi.js | 15 ---- src/library_webaudio.js | 9 --- src/library_webgl.js | 149 +------------------------------------ src/library_websocket.js | 19 ----- src/library_wget.js | 5 -- src/modules.js | 14 +--- src/utility.js | 12 +++ test/test_other.py | 2 +- tools/gen_sig_info.py | 12 ++- 25 files changed, 32 insertions(+), 679 deletions(-) diff --git a/src/library.js b/src/library.js index e66d2df490085..983d3f7a966a6 100644 --- a/src/library.js +++ b/src/library.js @@ -112,7 +112,6 @@ mergeInto(LibraryManager.library, { }, #endif - exit__sig: 'vi', #if MINIMAL_RUNTIME // minimal runtime doesn't do any exit cleanup handling so just // map exit directly to the lower-level proc_exit syscall. @@ -124,7 +123,6 @@ mergeInto(LibraryManager.library, { // Returns a pointer ('p'), which means an i32 on wasm32 and an i64 wasm64 // We have a separate JS version `getHeapMax()` which can be called directly // avoiding any wrapper added for wasm64. - emscripten_get_heap_max__sig: 'p', emscripten_get_heap_max__deps: ['$getHeapMax'], emscripten_get_heap_max: function() { return getHeapMax(); @@ -189,7 +187,6 @@ mergeInto(LibraryManager.library, { }, #endif // ~TEST_MEMORY_GROWTH_FAILS - emscripten_resize_heap__sig: 'ip', emscripten_resize_heap__deps: [ '$getHeapMax', #if ASSERTIONS == 2 @@ -322,7 +319,6 @@ mergeInto(LibraryManager.library, { }, system__deps: ['$setErrNo'], - system__sig: 'ip', system: function(command) { #if ENVIRONMENT_MAY_BE_NODE if (ENVIRONMENT_IS_NODE) { @@ -374,7 +370,6 @@ mergeInto(LibraryManager.library, { // module scope: the built-in runtime function abort(), and this library // function _abort(). Remove one of these, importing two functions for the // same purpose is wasteful. - abort__sig: 'v', abort: function() { #if ASSERTIONS abort('native code called abort()'); @@ -387,7 +382,6 @@ mergeInto(LibraryManager.library, { // the initial values of the environment accessible by getenv. $ENV: {}, - getloadavg__sig: 'ipi', getloadavg: function(loadavg, nelem) { // int getloadavg(double loadavg[], int nelem); // http://linux.die.net/man/3/getloadavg @@ -407,7 +401,6 @@ mergeInto(LibraryManager.library, { // so we cannot override parts of it, and therefore cannot use libc_optz. #if (SHRINK_LEVEL < 2 || LINKABLE || process.env.EMCC_FORCE_STDLIBS) && !STANDALONE_WASM - emscripten_memcpy_big__sig: 'vppp', #if MIN_CHROME_VERSION < 45 || MIN_EDGE_VERSION < 14 || MIN_FIREFOX_VERSION < 34 || MIN_IE_VERSION != TARGET_NOT_SUPPORTED || MIN_SAFARI_VERSION < 100101 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/copyWithin lists browsers that support TypedArray.prototype.copyWithin, but it // has outdated information for Safari, saying it would not support it. @@ -436,7 +429,6 @@ mergeInto(LibraryManager.library, { // assert.h // ========================================================================== - __assert_fail__sig: 'vppip', __assert_fail: function(condition, filename, line, func) { abort('Assertion failed: ' + UTF8ToString(condition) + ', at: ' + [filename ? UTF8ToString(filename) : 'unknown filename', line, func ? UTF8ToString(func) : 'unknown function']); }, @@ -446,7 +438,6 @@ mergeInto(LibraryManager.library, { // ========================================================================== _mktime_js__deps: ['$ydayFromDate'], - _mktime_js__sig: 'ip', _mktime_js: function(tmPtr) { var date = new Date({{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_year, 'i32') }}} + 1900, {{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_mon, 'i32') }}}, @@ -490,7 +481,6 @@ mergeInto(LibraryManager.library, { }, _gmtime_js__deps: ['$readI53FromI64'], - _gmtime_js__sig: 'vpp', _gmtime_js: function(time, tmPtr) { var date = new Date({{{ makeGetValue('time', 0, 'i53') }}}*1000); {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_sec, 'date.getUTCSeconds()', 'i32') }}}; @@ -505,7 +495,6 @@ mergeInto(LibraryManager.library, { {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_yday, 'yday', 'i32') }}}; }, - _timegm_js__sig: 'ip', _timegm_js: function(tmPtr) { var time = Date.UTC({{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_year, 'i32') }}} + 1900, {{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_mon, 'i32') }}}, @@ -525,7 +514,6 @@ mergeInto(LibraryManager.library, { }, _localtime_js__deps: ['$readI53FromI64', '$ydayFromDate'], - _localtime_js__sig: 'vpp', _localtime_js: function(time, tmPtr) { var date = new Date({{{ makeGetValue('time', 0, 'i53') }}}*1000); {{{ makeSetValue('tmPtr', C_STRUCTS.tm.tm_sec, 'date.getSeconds()', 'i32') }}}; @@ -549,7 +537,6 @@ mergeInto(LibraryManager.library, { }, // musl-internal function used to implement both `asctime` and `asctime_r` - __asctime_r__sig: 'ppp', __asctime_r: function(tmPtr, buf) { var date = { tm_sec: {{{ makeGetValue('tmPtr', C_STRUCTS.tm.tm_sec, 'i32') }}}, @@ -590,7 +577,6 @@ mergeInto(LibraryManager.library, { // Note: glibc has one fewer underscore for all of these. Also used in other related functions (timegm) _tzset_js__deps: ['$allocateUTF8'], _tzset_js__internal: true, - _tzset_js__sig: 'vppp', _tzset_js: function(timezone, daylight, tzname) { // TODO: Use (malleable) environment variables instead of system settings. var currentYear = new Date().getFullYear(); @@ -690,7 +676,6 @@ mergeInto(LibraryManager.library, { strftime__deps: ['$isLeapYear', '$arraySum', '$addDays', '$MONTH_DAYS_REGULAR', '$MONTH_DAYS_LEAP', '$intArrayFromString', '$writeArrayToMemory' ], - strftime__sig: 'ppppp', strftime: function(s, maxsize, format, tm) { // size_t strftime(char *restrict s, size_t maxsize, const char *restrict format, const struct tm *restrict timeptr); // http://pubs.opengroup.org/onlinepubs/009695399/functions/strftime.html @@ -977,14 +962,12 @@ mergeInto(LibraryManager.library, { return bytes.length-1; }, strftime_l__deps: ['strftime'], - strftime_l__sig: 'pppppp', strftime_l: function(s, maxsize, format, tm, loc) { return _strftime(s, maxsize, format, tm); // no locale support yet }, strptime__deps: ['$isLeapYear', '$arraySum', '$addDays', '$MONTH_DAYS_REGULAR', '$MONTH_DAYS_LEAP', '$jstoi_q', '$intArrayFromString' ], - strptime__sig: 'pppp', strptime: function(buf, format, tm) { // char *strptime(const char *restrict buf, const char *restrict format, struct tm *restrict tm); // http://pubs.opengroup.org/onlinepubs/009695399/functions/strptime.html @@ -1225,7 +1208,6 @@ mergeInto(LibraryManager.library, { return 0; }, - strptime_l__sig: 'ppppp', strptime_l__deps: ['strptime'], strptime_l: function(buf, format, tm, locale) { return _strptime(buf, format, tm); // no locale support yet @@ -1236,7 +1218,6 @@ mergeInto(LibraryManager.library, { // ========================================================================== #if SUPPORT_LONGJMP == 'emscripten' - _emscripten_throw_longjmp__sig: 'v', _emscripten_throw_longjmp: function() { #if EXCEPTION_STACK_TRACES throw new EmscriptenSjLj; @@ -1831,7 +1812,6 @@ mergeInto(LibraryManager.library, { // note: lots of leaking here! gethostbyaddr__deps: ['$DNS', '$getHostByName', '$inetNtop4', '$setErrNo'], gethostbyaddr__proxy: 'sync', - gethostbyaddr__sig: 'ppii', gethostbyaddr: function (addr, addrlen, type) { if (type !== {{{ cDefs.AF_INET }}}) { setErrNo({{{ cDefs.EAFNOSUPPORT }}}); @@ -1849,7 +1829,6 @@ mergeInto(LibraryManager.library, { gethostbyname__deps: ['$getHostByName'], gethostbyname__proxy: 'sync', - gethostbyname__sig: 'pp', gethostbyname: function(name) { return getHostByName(UTF8ToString(name)); }, @@ -1877,7 +1856,6 @@ mergeInto(LibraryManager.library, { gethostbyname_r__deps: ['gethostbyname', 'memcpy', 'free'], gethostbyname_r__proxy: 'sync', - gethostbyname_r__sig: 'ipppppp', gethostbyname_r: function(name, ret, buf, buflen, out, err) { var data = _gethostbyname(name); _memcpy(ret, data, {{{ C_STRUCTS.hostent.__size__ }}}); @@ -1889,7 +1867,6 @@ mergeInto(LibraryManager.library, { getaddrinfo__deps: ['$Sockets', '$DNS', '$inetPton4', '$inetNtop4', '$inetPton6', '$inetNtop6', '$writeSockaddr'], getaddrinfo__proxy: 'sync', - getaddrinfo__sig: 'ipppp', getaddrinfo: function(node, service, hint, out) { // Note getaddrinfo currently only returns a single addrinfo with ai_next defaulting to NULL. When NULL // hints are specified or ai_family set to AF_UNSPEC or ai_socktype or ai_protocol set to 0 then we @@ -2060,7 +2037,6 @@ mergeInto(LibraryManager.library, { }, getnameinfo__deps: ['$Sockets', '$DNS', '$readSockaddr'], - getnameinfo__sig: 'ipipipii', getnameinfo: function (sa, salen, node, nodelen, serv, servlen, flags) { var info = readSockaddr(sa, salen); if (info.errno) { @@ -2275,7 +2251,6 @@ mergeInto(LibraryManager.library, { }, getentropy__deps: ['$randomFill'], - getentropy__sig: 'ipp', getentropy: function(buffer, size) { randomFill(HEAPU8.subarray(buffer, buffer + size)); return 0; @@ -2286,7 +2261,6 @@ mergeInto(LibraryManager.library, { // Helper function for setitimer that registers timers with the eventloop. // Timers always fire on the main thread, either directly from JS (here) or // or when the main thread is busy waiting calling _emscripten_yield. - _setitimer_js__sig: 'iid', _setitimer_js__proxy: 'sync', _setitimer_js__deps: ['$timers', '$callUserCallback', '_emscripten_timeout', 'emscripten_get_now'], @@ -2320,7 +2294,6 @@ mergeInto(LibraryManager.library, { // Helper for raise() to avoid signature mismatch failures: // https://github.com/emscripten-core/posixtestsuite/issues/6 - __call_sighandler__sig: 'vpi', __call_sighandler: function(fp, sig) { {{{ makeDynCall('vi', 'fp') }}}(sig); }, @@ -2329,12 +2302,10 @@ mergeInto(LibraryManager.library, { // emscripten.h // ========================================================================== - emscripten_run_script__sig: 'vp', emscripten_run_script: function(ptr) { {{{ makeEval('eval(UTF8ToString(ptr));') }}} }, - emscripten_run_script_int__sig: 'ip', emscripten_run_script_int__docs: '/** @suppress{checkTypes} */', emscripten_run_script_int: function(ptr) { {{{ makeEval('return eval(UTF8ToString(ptr))|0;') }}} @@ -2343,7 +2314,6 @@ mergeInto(LibraryManager.library, { // Mark as `noleakcheck` otherwise lsan will report the last returned string // as a leak. emscripten_run_script_string__noleakcheck: true, - emscripten_run_script_string__sig: 'pp', emscripten_run_script_string: function(ptr) { {{{ makeEval("var s = eval(UTF8ToString(ptr));") }}} if (s == null) { @@ -2365,7 +2335,6 @@ mergeInto(LibraryManager.library, { return Math.random(); }, - emscripten_get_now__sig: 'd', emscripten_get_now: ';' + #if ENVIRONMENT_MAY_BE_NODE "if (ENVIRONMENT_IS_NODE) {\n" + @@ -2445,7 +2414,6 @@ mergeInto(LibraryManager.library, { $nowIsMonotonic: 'true;', #endif - _emscripten_get_now_is_monotonic__sig: 'i', _emscripten_get_now_is_monotonic__internal: true, _emscripten_get_now_is_monotonic__deps: ['$nowIsMonotonic'], _emscripten_get_now_is_monotonic: function() { @@ -2650,7 +2618,6 @@ mergeInto(LibraryManager.library, { } }, - emscripten_log__sig: 'vipp', emscripten_log__deps: ['$formatString', '$emscriptenLog'], emscripten_log: function(flags, format, varargs) { var result = formatString(format, varargs); @@ -2661,7 +2628,6 @@ mergeInto(LibraryManager.library, { // We never free the return values of this function so we need to allocate // using builtin_malloc to avoid LSan reporting these as leaks. emscripten_get_compiler_setting__noleakcheck: true, - emscripten_get_compiler_setting__sig: 'pp', emscripten_get_compiler_setting: function(name) { #if RETAIN_COMPILER_SETTINGS name = UTF8ToString(name); @@ -2689,7 +2655,6 @@ mergeInto(LibraryManager.library, { debugger; }, - emscripten_print_double__sig: 'idpi', emscripten_print_double: function(x, to, max) { var str = x + ''; if (to) return stringToUTF8(str, to, max); @@ -2732,7 +2697,6 @@ mergeInto(LibraryManager.library, { // Returns a representation of a call site of the caller of this function, in a manner // similar to __builtin_return_address. If level is 0, we return the call site of the // caller of this function. - emscripten_return_address__sig: 'pi', emscripten_return_address__deps: ['$convertFrameToPC', '$jsStackTrace'], emscripten_return_address: function(level) { var callstack = jsStackTrace().split('\n'); @@ -2790,7 +2754,6 @@ mergeInto(LibraryManager.library, { // must be able to unwind from a PC value that may no longer be on the // execution stack, and so we are forced to cache the entire call stack. emscripten_stack_snapshot__deps: ['$convertFrameToPC', '$UNWIND_CACHE', '$saveInUnwindCache', '$jsStackTrace'], - emscripten_stack_snapshot__sig: 'p', emscripten_stack_snapshot: function () { var callstack = jsStackTrace().split('\n'); if (callstack[0] == 'Error') { @@ -2821,7 +2784,6 @@ mergeInto(LibraryManager.library, { // emscripten_stack_snapshot, or this function will instead use the current // call stack. emscripten_stack_unwind_buffer__deps: ['$UNWIND_CACHE', '$saveInUnwindCache', '$convertFrameToPC', '$jsStackTrace'], - emscripten_stack_unwind_buffer__sig: 'ippi', emscripten_stack_unwind_buffer: function (addr, buffer, count) { var stack; if (UNWIND_CACHE.last_addr == addr) { @@ -2850,7 +2812,6 @@ mergeInto(LibraryManager.library, { emscripten_pc_get_function__deps: ['$UNWIND_CACHE', 'free', '$allocateUTF8'], // Don't treat allocation of _emscripten_pc_get_function.ret as a leak emscripten_pc_get_function__noleakcheck: true, - emscripten_pc_get_function__sig: 'pp', #endif emscripten_pc_get_function: function (pc) { #if !USE_OFFSET_CONVERTER @@ -2911,7 +2872,6 @@ mergeInto(LibraryManager.library, { emscripten_pc_get_file__deps: ['$convertPCtoSourceLocation', 'free', '$allocateUTF8'], // Don't treat allocation of _emscripten_pc_get_file.ret as a leak emscripten_pc_get_file__noleakcheck: true, - emscripten_pc_get_file__sig: 'pp', emscripten_pc_get_file: function (pc) { var result = convertPCtoSourceLocation(pc); if (!result) return 0; @@ -2923,7 +2883,6 @@ mergeInto(LibraryManager.library, { // Look up the line number from our stack frame cache with our PC representation. emscripten_pc_get_line__deps: ['$convertPCtoSourceLocation'], - emscripten_pc_get_line__sig: 'ip', emscripten_pc_get_line: function (pc) { var result = convertPCtoSourceLocation(pc); return result ? result.line : 0; @@ -2931,13 +2890,11 @@ mergeInto(LibraryManager.library, { // Look up the column number from our stack frame cache with our PC representation. emscripten_pc_get_column__deps: ['$convertPCtoSourceLocation'], - emscripten_pc_get_column__sig: 'ip', emscripten_pc_get_column: function (pc) { var result = convertPCtoSourceLocation(pc); return result ? result.column || 0 : 0; }, - emscripten_get_module_name__sig: 'ppp', emscripten_get_module_name: function(buf, length) { #if MINIMAL_RUNTIME return stringToUTF8('{{{ TARGET_BASENAME }}}.wasm', buf, length); @@ -3035,18 +2992,15 @@ mergeInto(LibraryManager.library, { return ASM_CONSTS[code].apply(null, args); }, - emscripten_asm_const_int__sig: 'ippp', emscripten_asm_const_int__deps: ['$runEmAsmFunction'], emscripten_asm_const_int: function(code, sigPtr, argbuf) { return runEmAsmFunction(code, sigPtr, argbuf); }, - emscripten_asm_const_double__sig: 'dppp', emscripten_asm_const_double__deps: ['$runEmAsmFunction'], emscripten_asm_const_double: function(code, sigPtr, argbuf) { return runEmAsmFunction(code, sigPtr, argbuf); }, - emscripten_asm_const_ptr__sig: 'pppp', emscripten_asm_const_ptr__deps: ['$runEmAsmFunction'], emscripten_asm_const_ptr: function(code, sigPtr, argbuf) { return runEmAsmFunction(code, sigPtr, argbuf); @@ -3077,13 +3031,11 @@ mergeInto(LibraryManager.library, { return ASM_CONSTS[code].apply(null, args); }, emscripten_asm_const_int_sync_on_main_thread__deps: ['$runMainThreadEmAsm'], - emscripten_asm_const_int_sync_on_main_thread__sig: 'ippp', emscripten_asm_const_int_sync_on_main_thread: function(code, sigPtr, argbuf) { return runMainThreadEmAsm(code, sigPtr, argbuf, 1); }, emscripten_asm_const_double_sync_on_main_thread: 'emscripten_asm_const_int_sync_on_main_thread', emscripten_asm_const_async_on_main_thread__deps: ['$runMainThreadEmAsm'], - emscripten_asm_const_async_on_main_thread__sig: 'vppp', emscripten_asm_const_async_on_main_thread: function(code, sigPtr, argbuf) { return runMainThreadEmAsm(code, sigPtr, argbuf, 0); }, @@ -3166,7 +3118,6 @@ mergeInto(LibraryManager.library, { #if STACK_OVERFLOW_CHECK // Used by wasm-emscripten-finalize to implement STACK_OVERFLOW_CHECK - __handle_stack_overflow__sig: 'vp', __handle_stack_overflow__deps: ['emscripten_stack_get_base', 'emscripten_stack_get_end', '$ptrToString'], __handle_stack_overflow: function(requested) { requested = requested >>> 0; @@ -3379,7 +3330,6 @@ mergeInto(LibraryManager.library, { #endif // SHRINK_LEVEL == 0 // Callable in pthread without __proxy needed. - emscripten_exit_with_live_runtime__sig: 'v', emscripten_exit_with_live_runtime: function() { {{{ runtimeKeepalivePush() }}} throw 'unwind'; @@ -3391,7 +3341,6 @@ mergeInto(LibraryManager.library, { #endif ], emscripten_force_exit__proxy: 'sync', - emscripten_force_exit__sig: 'vi', emscripten_force_exit: function(status) { #if RUNTIME_DEBUG dbg('emscripten_force_exit'); @@ -3406,18 +3355,15 @@ mergeInto(LibraryManager.library, { _exit(status); }, - _emscripten_out__sig: 'vp', _emscripten_out: function(str) { out(UTF8ToString(str)); }, - _emscripten_err__sig: 'vp', _emscripten_err: function(str) { err(UTF8ToString(str)); }, #if ASSERTIONS || RUNTIME_DEBUG - _emscripten_dbg__sig: 'vp', _emscripten_dbg: function(str) { dbg(UTF8ToString(str)); }, @@ -3425,7 +3371,6 @@ mergeInto(LibraryManager.library, { // Use program_invocation_short_name and program_invocation_name in compiled // programs. This function is for implementing them. - _emscripten_get_progname__sig: 'vpi', _emscripten_get_progname: function(str, len) { #if !MINIMAL_RUNTIME #if ASSERTIONS @@ -3436,7 +3381,6 @@ mergeInto(LibraryManager.library, { #endif }, - emscripten_console_log__sig: 'vp', emscripten_console_log: function(str) { #if ASSERTIONS assert(typeof str == 'number'); @@ -3444,7 +3388,6 @@ mergeInto(LibraryManager.library, { console.log(UTF8ToString(str)); }, - emscripten_console_warn__sig: 'vp', emscripten_console_warn: function(str) { #if ASSERTIONS assert(typeof str == 'number'); @@ -3452,7 +3395,6 @@ mergeInto(LibraryManager.library, { console.warn(UTF8ToString(str)); }, - emscripten_console_error__sig: 'vp', emscripten_console_error: function(str) { #if ASSERTIONS assert(typeof str == 'number'); @@ -3686,7 +3628,6 @@ mergeInto(LibraryManager.library, { #endif _emscripten_fs_load_embedded_files__deps: ['$FS', '$PATH'], - _emscripten_fs_load_embedded_files__sig: 'vp', _emscripten_fs_load_embedded_files: function(ptr) { #if RUNTIME_DEBUG dbg('preloading data files'); diff --git a/src/library_async.js b/src/library_async.js index 82c57b741f8a8..2d2843970986f 100644 --- a/src/library_async.js +++ b/src/library_async.js @@ -450,7 +450,6 @@ mergeInto(LibraryManager.library, { #endif }, - emscripten_sleep__sig: 'vi', emscripten_sleep__deps: ['$safeSetTimeout'], emscripten_sleep: function(ms) { // emscripten_sleep() does not return a value, but we still need a |return| @@ -460,7 +459,6 @@ mergeInto(LibraryManager.library, { return Asyncify.handleSleep((wakeUp) => safeSetTimeout(wakeUp, ms)); }, - emscripten_wget__sig: 'vpp', emscripten_wget__deps: ['$Browser', '$PATH_FS', '$FS'], emscripten_wget: function(url, file) { return Asyncify.handleSleep((wakeUp) => { @@ -488,7 +486,6 @@ mergeInto(LibraryManager.library, { }); }, - emscripten_wget_data__sig: 'vpppp', emscripten_wget_data__deps: ['$asyncLoad', 'malloc'], emscripten_wget_data: function(url, pbuffer, pnum, perror) { return Asyncify.handleSleep((wakeUp) => { @@ -507,7 +504,6 @@ mergeInto(LibraryManager.library, { }); }, - emscripten_scan_registers__sig: 'vp', emscripten_scan_registers__deps: ['$safeSetTimeout'], emscripten_scan_registers: function(func) { return Asyncify.handleSleep((wakeUp) => { @@ -608,7 +604,6 @@ mergeInto(LibraryManager.library, { }, }, - emscripten_fiber_swap__sig: 'vpp', emscripten_fiber_swap__deps: ["$Asyncify", "$Fibers"], emscripten_fiber_swap: function(oldFiber, newFiber) { if (ABORT) return; diff --git a/src/library_browser.js b/src/library_browser.js index 7062da465f461..ff9de924298f7 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -779,7 +779,6 @@ var LibraryBrowser = { emscripten_run_preload_plugins__deps: ['$PATH'], emscripten_run_preload_plugins__proxy: 'sync', - emscripten_run_preload_plugins__sig: 'ippp', emscripten_run_preload_plugins: function(file, onload, onerror) { {{{ runtimeKeepalivePush() }}} @@ -805,7 +804,6 @@ var LibraryBrowser = { emscripten_run_preload_plugins_data__proxy: 'sync', emscripten_run_preload_plugins_data__deps: ['malloc'], - emscripten_run_preload_plugins_data__sig: 'vpipppp', emscripten_run_preload_plugins_data: function(data, size, suffix, arg, onload, onerror) { {{{ runtimeKeepalivePush() }}} @@ -875,14 +873,12 @@ var LibraryBrowser = { }, // Runs natively in pthread, no __proxy needed. - emscripten_get_main_loop_timing__sig: 'vpp', emscripten_get_main_loop_timing: function(mode, value) { if (mode) {{{ makeSetValue('mode', 0, 'Browser.mainLoop.timingMode', 'i32') }}}; if (value) {{{ makeSetValue('value', 0, 'Browser.mainLoop.timingValue', 'i32') }}}; }, // Runs natively in pthread, no __proxy needed. - emscripten_set_main_loop_timing__sig: 'iii', emscripten_set_main_loop_timing: function(mode, value) { Browser.mainLoop.timingMode = mode; Browser.mainLoop.timingValue = value; @@ -942,7 +938,6 @@ var LibraryBrowser = { }, emscripten_set_main_loop__deps: ['$setMainLoop'], - emscripten_set_main_loop__sig: 'vpii', emscripten_set_main_loop: function(func, fps, simulateInfiniteLoop) { var browserIterationFunc = {{{ makeDynCall('v', 'func') }}}; setMainLoop(browserIterationFunc, fps, simulateInfiniteLoop); @@ -1104,27 +1099,23 @@ var LibraryBrowser = { // Runs natively in pthread, no __proxy needed. emscripten_set_main_loop_arg__deps: ['$setMainLoop'], - emscripten_set_main_loop_arg__sig: 'vppii', emscripten_set_main_loop_arg: function(func, arg, fps, simulateInfiniteLoop) { var browserIterationFunc = () => {{{ makeDynCall('vi', 'func') }}}(arg); setMainLoop(browserIterationFunc, fps, simulateInfiniteLoop, arg); }, // Runs natively in pthread, no __proxy needed. - emscripten_cancel_main_loop__sig: 'v', emscripten_cancel_main_loop: function() { Browser.mainLoop.pause(); Browser.mainLoop.func = null; }, // Runs natively in pthread, no __proxy needed. - emscripten_pause_main_loop__sig: 'v', emscripten_pause_main_loop: function() { Browser.mainLoop.pause(); }, // Runs natively in pthread, no __proxy needed. - emscripten_resume_main_loop__sig: 'v', emscripten_resume_main_loop: function() { Browser.mainLoop.resume(); }, @@ -1146,7 +1137,6 @@ var LibraryBrowser = { }, // Runs natively in pthread, no __proxy needed. - emscripten_set_main_loop_expected_blockers__sig: 'vi', emscripten_set_main_loop_expected_blockers: function(num) { Browser.mainLoop.expectedBlockers = num; Browser.mainLoop.remainingBlockers = num; @@ -1154,7 +1144,6 @@ var LibraryBrowser = { }, // Runs natively in pthread, no __proxy needed. - emscripten_async_call__sig: 'vppi', emscripten_async_call__deps: ['$safeSetTimeout'], emscripten_async_call: function(func, arg, millis) { function wrapper() { @@ -1174,7 +1163,6 @@ var LibraryBrowser = { }, emscripten_get_window_title__proxy: 'sync', - emscripten_get_window_title__sig: 'p', emscripten_get_window_title: function() { var buflen = 256; @@ -1188,20 +1176,17 @@ var LibraryBrowser = { }, emscripten_set_window_title__proxy: 'sync', - emscripten_set_window_title__sig: 'vp', emscripten_set_window_title: function(title) { setWindowTitle(UTF8ToString(title)); }, emscripten_get_screen_size__proxy: 'sync', - emscripten_get_screen_size__sig: 'vpp', emscripten_get_screen_size: function(width, height) { {{{ makeSetValue('width', '0', 'screen.width', 'i32') }}}; {{{ makeSetValue('height', '0', 'screen.height', 'i32') }}}; }, emscripten_hide_mouse__proxy: 'sync', - emscripten_hide_mouse__sig: 'v', emscripten_hide_mouse: function() { var styleSheet = document.styleSheets[0]; var rules = styleSheet.cssRules; @@ -1215,13 +1200,11 @@ var LibraryBrowser = { }, emscripten_set_canvas_size__proxy: 'sync', - emscripten_set_canvas_size__sig: 'vii', emscripten_set_canvas_size: function(width, height) { Browser.setCanvasSize(width, height); }, emscripten_get_canvas_size__proxy: 'sync', - emscripten_get_canvas_size__sig: 'vppp', emscripten_get_canvas_size: function(width, height, isFullscreen) { var canvas = Module['canvas']; {{{ makeSetValue('width', '0', 'canvas.width', 'i32') }}}; @@ -1231,7 +1214,6 @@ var LibraryBrowser = { // To avoid creating worker parent->child chains, always proxies to execute on the main thread. emscripten_create_worker__proxy: 'sync', - emscripten_create_worker__sig: 'ip', emscripten_create_worker: function(url) { url = UTF8ToString(url); var id = Browser.workers.length; @@ -1274,7 +1256,6 @@ var LibraryBrowser = { }, emscripten_destroy_worker__proxy: 'sync', - emscripten_destroy_worker__sig: 'vi', emscripten_destroy_worker: function(id) { var info = Browser.workers[id]; info.worker.terminate(); @@ -1283,7 +1264,6 @@ var LibraryBrowser = { }, emscripten_call_worker__proxy: 'sync', - emscripten_call_worker__sig: 'vippipp', emscripten_call_worker: function(id, funcName, data, size, callback, arg) { funcName = UTF8ToString(funcName); var info = Browser.workers[id]; @@ -1349,7 +1329,6 @@ var LibraryBrowser = { #endif emscripten_get_worker_queue_size__proxy: 'sync', - emscripten_get_worker_queue_size__sig: 'ii', emscripten_get_worker_queue_size: function(id) { var info = Browser.workers[id]; if (!info) return -1; @@ -1358,7 +1337,6 @@ var LibraryBrowser = { emscripten_get_preloaded_image_data__deps: ['$PATH_FS', 'malloc'], emscripten_get_preloaded_image_data__proxy: 'sync', - emscripten_get_preloaded_image_data__sig: 'pppp', emscripten_get_preloaded_image_data: function(path, w, h) { if ((path | 0) === path) path = UTF8ToString(path); @@ -1382,7 +1360,6 @@ var LibraryBrowser = { emscripten_get_preloaded_image_data_from_FILE__deps: ['emscripten_get_preloaded_image_data', 'fileno'], emscripten_get_preloaded_image_data_from_FILE__proxy: 'sync', - emscripten_get_preloaded_image_data_from_FILE__sig: 'pppp', emscripten_get_preloaded_image_data_from_FILE: function(file, w, h) { var fd = _fileno(file); var stream = FS.getStream(fd); diff --git a/src/library_dylink.js b/src/library_dylink.js index 4053ac83c0751..39c3cf2bc1519 100644 --- a/src/library_dylink.js +++ b/src/library_dylink.js @@ -1087,7 +1087,6 @@ var LibraryDylink = { }, _dlopen_js__deps: ['$dlopenInternal'], - _dlopen_js__sig: 'pp', _dlopen_js: function(handle) { #if ASYNCIFY return Asyncify.handleSleep(function(wakeUp) { @@ -1109,7 +1108,6 @@ var LibraryDylink = { // Async version of dlopen. _emscripten_dlopen_js__deps: ['$dlopenInternal', '$callUserCallback', '$dlSetError'], - _emscripten_dlopen_js__sig: 'vpppp', _emscripten_dlopen_js: function(handle, onsuccess, onerror, user_data) { /** @param {Object=} e */ function errorCallback(e) { @@ -1132,7 +1130,6 @@ var LibraryDylink = { } }, - _dlsym_catchup_js__sig: 'ppi', _dlsym_catchup_js: function(handle, symbolIndex) { #if DYLINK_DEBUG dbg("_dlsym_catchup: handle=" + ptrToString(handle) + " symbolIndex=" + symbolIndex); @@ -1150,7 +1147,6 @@ var LibraryDylink = { // void* dlsym(void* handle, const char* symbol); _dlsym_js__deps: ['$dlSetError', '$getFunctionAddress', '$addFunction'], - _dlsym_js__sig: 'pppp', _dlsym_js: function(handle, symbol, symbolIndex) { // void *dlsym(void *restrict handle, const char *restrict name); // http://pubs.opengroup.org/onlinepubs/009695399/functions/dlsym.html diff --git a/src/library_eventloop.js b/src/library_eventloop.js index 394507fd93a3a..ca6dba8c0277c 100644 --- a/src/library_eventloop.js +++ b/src/library_eventloop.js @@ -70,7 +70,6 @@ LibraryJSEventLoop = { // emscripten_set_immediate_loop() if application links to both of them. }, - emscripten_set_immediate__sig: 'ipp', emscripten_set_immediate__deps: ['$polyfillSetImmediate', '$callUserCallback'], emscripten_set_immediate: function(cb, userData) { polyfillSetImmediate(); @@ -83,14 +82,12 @@ LibraryJSEventLoop = { }); }, - emscripten_clear_immediate__sig: 'vi', emscripten_clear_immediate__deps: ['$polyfillSetImmediate'], emscripten_clear_immediate: function(id) { {{{ runtimeKeepalivePop(); }}} emClearImmediate(id); }, - emscripten_set_immediate_loop__sig: 'vpp', emscripten_set_immediate_loop__deps: ['$polyfillSetImmediate', '$callUserCallback'], emscripten_set_immediate_loop: function(cb, userData) { polyfillSetImmediate(); @@ -107,18 +104,15 @@ LibraryJSEventLoop = { emSetImmediate(tick); }, - emscripten_set_timeout__sig: 'ipdp', emscripten_set_timeout__deps: ['$safeSetTimeout'], emscripten_set_timeout: function(cb, msecs, userData) { return safeSetTimeout(() => {{{ makeDynCall('vp', 'cb') }}}(userData), msecs); }, - emscripten_clear_timeout__sig: 'vi', emscripten_clear_timeout: function(id) { clearTimeout(id); }, - emscripten_set_timeout_loop__sig: 'vpdp', emscripten_set_timeout_loop__deps: ['$callUserCallback'], emscripten_set_timeout_loop: function(cb, msecs, userData) { function tick() { @@ -139,7 +133,6 @@ LibraryJSEventLoop = { return setTimeout(tick, 0); }, - emscripten_set_interval__sig: 'ipdp', emscripten_set_interval__deps: ['$callUserCallback'], emscripten_set_interval: function(cb, msecs, userData) { {{{ runtimeKeepalivePush() }}} @@ -150,7 +143,6 @@ LibraryJSEventLoop = { }, msecs); }, - emscripten_clear_interval__sig: 'vi', emscripten_clear_interval: function(id) { {{{ runtimeKeepalivePop() }}} clearInterval(id); diff --git a/src/library_glew.js b/src/library_glew.js index 5e270c54623f4..8bb1100e3be23 100644 --- a/src/library_glew.js +++ b/src/library_glew.js @@ -127,7 +127,6 @@ var LibraryGLEW = { return GLEW.extensionIsSupported(UTF8ToString(name)); }, - glewGetErrorString__sig: 'pi', glewGetErrorString: function(error) { return GLEW.errorString(error); }, diff --git a/src/library_glut.js b/src/library_glut.js index 5d37dd69f412e..37da07279d548 100644 --- a/src/library_glut.js +++ b/src/library_glut.js @@ -302,12 +302,10 @@ var LibraryGLUT = { }, glutGetModifiers__proxy: 'sync', - glutGetModifiers__sig: 'i', glutGetModifiers: function() { return GLUT.modifiers; }, glutInit__deps: ['$Browser'], glutInit__proxy: 'sync', - glutInit__sig: 'vpp', glutInit: function(argcp, argv) { // Ignore arguments GLUT.initTime = Date.now(); @@ -366,14 +364,12 @@ var LibraryGLUT = { }, glutInitWindowSize__proxy: 'sync', - glutInitWindowSize__sig: 'vii', glutInitWindowSize: function(width, height) { Browser.setCanvasSize( GLUT.initWindowWidth = width, GLUT.initWindowHeight = height ); }, glutInitWindowPosition__proxy: 'sync', - glutInitWindowPosition__sig: 'vii', glutInitWindowPosition: function(x, y) { // Ignore for now }, @@ -419,7 +415,6 @@ var LibraryGLUT = { glutIdleFunc__proxy: 'sync', glutIdleFunc__deps: ['$safeSetTimeout'], - glutIdleFunc__sig: 'vp', glutIdleFunc: function(func) { function callback() { if (GLUT.idleFunc) { @@ -435,67 +430,56 @@ var LibraryGLUT = { glutTimerFunc__proxy: 'sync', glutTimerFunc__deps: ['$safeSetTimeout'], - glutTimerFunc__sig: 'vipi', glutTimerFunc: function(msec, func, value) { safeSetTimeout(function() { {{{ makeDynCall('vi', 'func') }}}(value); }, msec); }, glutDisplayFunc__proxy: 'sync', - glutDisplayFunc__sig: 'vp', glutDisplayFunc: function(func) { GLUT.displayFunc = func; }, glutKeyboardFunc__proxy: 'sync', - glutKeyboardFunc__sig: 'vp', glutKeyboardFunc: function(func) { GLUT.keyboardFunc = func; }, glutKeyboardUpFunc__proxy: 'sync', - glutKeyboardUpFunc__sig: 'vp', glutKeyboardUpFunc: function(func) { GLUT.keyboardUpFunc = func; }, glutSpecialFunc__proxy: 'sync', - glutSpecialFunc__sig: 'vp', glutSpecialFunc: function(func) { GLUT.specialFunc = func; }, glutSpecialUpFunc__proxy: 'sync', - glutSpecialUpFunc__sig: 'vp', glutSpecialUpFunc: function(func) { GLUT.specialUpFunc = func; }, glutReshapeFunc__proxy: 'sync', - glutReshapeFunc__sig: 'vp', glutReshapeFunc: function(func) { GLUT.reshapeFunc = func; }, glutMotionFunc__proxy: 'sync', - glutMotionFunc__sig: 'vp', glutMotionFunc: function(func) { GLUT.motionFunc = func; }, glutPassiveMotionFunc__proxy: 'sync', - glutPassiveMotionFunc__sig: 'vp', glutPassiveMotionFunc: function(func) { GLUT.passiveMotionFunc = func; }, glutMouseFunc__proxy: 'sync', - glutMouseFunc__sig: 'vp', glutMouseFunc: function(func) { GLUT.mouseFunc = func; }, glutSetCursor__proxy: 'sync', - glutSetCursor__sig: 'vi', glutSetCursor: function(cursor) { var cursorStyle = 'auto'; switch (cursor) { @@ -573,7 +557,6 @@ var LibraryGLUT = { glutCreateWindow__proxy: 'sync', glutCreateWindow__deps: ['$Browser'], - glutCreateWindow__sig: 'ip', glutCreateWindow: function(name) { var contextAttributes = { antialias: ((GLUT.initDisplayMode & 0x0080 /*GLUT_MULTISAMPLE*/) != 0), @@ -591,7 +574,6 @@ var LibraryGLUT = { glutDestroyWindow__proxy: 'sync', glutDestroyWindow__deps: ['$Browser'], - glutDestroyWindow__sig: 'vi', glutDestroyWindow: function(name) { Module.ctx = Browser.destroyContext(Module['canvas'], true, true); return 1; @@ -599,7 +581,6 @@ var LibraryGLUT = { glutReshapeWindow__proxy: 'sync', glutReshapeWindow__deps: ['$GLUT', 'glutPostRedisplay'], - glutReshapeWindow__sig: 'vii', glutReshapeWindow: function(width, height) { Browser.exitFullscreen(); Browser.setCanvasSize(width, height, true); // N.B. GLUT.reshapeFunc is also registered as a canvas resize callback. @@ -612,7 +593,6 @@ var LibraryGLUT = { glutPositionWindow__proxy: 'sync', glutPositionWindow__deps: ['$GLUT', 'glutPostRedisplay'], - glutPositionWindow__sig: 'vii', glutPositionWindow: function(x, y) { Browser.exitFullscreen(); /* TODO */ @@ -621,7 +601,6 @@ var LibraryGLUT = { glutFullScreen__proxy: 'sync', glutFullScreen__deps: ['$GLUT', 'glutPostRedisplay'], - glutFullScreen__sig: 'v', glutFullScreen: function() { GLUT.windowX = 0; // TODO GLUT.windowY = 0; // TODO @@ -634,17 +613,14 @@ var LibraryGLUT = { }, glutInitDisplayMode__proxy: 'sync', - glutInitDisplayMode__sig: 'vi', glutInitDisplayMode: function(mode) { GLUT.initDisplayMode = mode; }, glutSwapBuffers__proxy: 'sync', - glutSwapBuffers__sig: 'v', glutSwapBuffers: function() {}, glutPostRedisplay__proxy: 'sync', - glutPostRedisplay__sig: 'v', glutPostRedisplay: function() { if (GLUT.displayFunc && !GLUT.requestedAnimationFrame) { GLUT.requestedAnimationFrame = true; @@ -659,7 +635,6 @@ var LibraryGLUT = { glutMainLoop__proxy: 'sync', glutMainLoop__deps: ['$GLUT', 'glutReshapeWindow', 'glutPostRedisplay'], - glutMainLoop__sig: 'v', glutMainLoop: function() { _glutReshapeWindow(Module['canvas'].width, Module['canvas'].height); _glutPostRedisplay(); diff --git a/src/library_html5.js b/src/library_html5.js index 3f75f317f25bc..692f8bdcd82c4 100644 --- a/src/library_html5.js +++ b/src/library_html5.js @@ -399,7 +399,6 @@ var LibraryHTML5 = { #endif emscripten_set_keypress_callback_on_thread__proxy: 'sync', - emscripten_set_keypress_callback_on_thread__sig: 'ippipp', emscripten_set_keypress_callback_on_thread__deps: ['$registerKeyEventCallback'], emscripten_set_keypress_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerKeyEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_KEYPRESS }}}, "keypress", targetThread); @@ -407,7 +406,6 @@ var LibraryHTML5 = { }, emscripten_set_keydown_callback_on_thread__proxy: 'sync', - emscripten_set_keydown_callback_on_thread__sig: 'ippipp', emscripten_set_keydown_callback_on_thread__deps: ['$registerKeyEventCallback'], emscripten_set_keydown_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerKeyEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_KEYDOWN }}}, "keydown", targetThread); @@ -415,7 +413,6 @@ var LibraryHTML5 = { }, emscripten_set_keyup_callback_on_thread__proxy: 'sync', - emscripten_set_keyup_callback_on_thread__sig: 'ippipp', emscripten_set_keyup_callback_on_thread__deps: ['$registerKeyEventCallback'], emscripten_set_keyup_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerKeyEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_KEYUP }}}, "keyup", targetThread); @@ -546,7 +543,6 @@ var LibraryHTML5 = { }, emscripten_set_click_callback_on_thread__proxy: 'sync', - emscripten_set_click_callback_on_thread__sig: 'ippipp', emscripten_set_click_callback_on_thread__deps: ['$registerMouseEventCallback'], emscripten_set_click_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_CLICK }}}, "click", targetThread); @@ -554,7 +550,6 @@ var LibraryHTML5 = { }, emscripten_set_mousedown_callback_on_thread__proxy: 'sync', - emscripten_set_mousedown_callback_on_thread__sig: 'ippipp', emscripten_set_mousedown_callback_on_thread__deps: ['$registerMouseEventCallback'], emscripten_set_mousedown_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_MOUSEDOWN }}}, "mousedown", targetThread); @@ -562,7 +557,6 @@ var LibraryHTML5 = { }, emscripten_set_mouseup_callback_on_thread__proxy: 'sync', - emscripten_set_mouseup_callback_on_thread__sig: 'ippipp', emscripten_set_mouseup_callback_on_thread__deps: ['$registerMouseEventCallback'], emscripten_set_mouseup_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_MOUSEUP }}}, "mouseup", targetThread); @@ -570,7 +564,6 @@ var LibraryHTML5 = { }, emscripten_set_dblclick_callback_on_thread__proxy: 'sync', - emscripten_set_dblclick_callback_on_thread__sig: 'ippipp', emscripten_set_dblclick_callback_on_thread__deps: ['$registerMouseEventCallback'], emscripten_set_dblclick_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_DBLCLICK }}}, "dblclick", targetThread); @@ -578,7 +571,6 @@ var LibraryHTML5 = { }, emscripten_set_mousemove_callback_on_thread__proxy: 'sync', - emscripten_set_mousemove_callback_on_thread__sig: 'ippipp', emscripten_set_mousemove_callback_on_thread__deps: ['$registerMouseEventCallback'], emscripten_set_mousemove_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_MOUSEMOVE }}}, "mousemove", targetThread); @@ -586,7 +578,6 @@ var LibraryHTML5 = { }, emscripten_set_mouseenter_callback_on_thread__proxy: 'sync', - emscripten_set_mouseenter_callback_on_thread__sig: 'ippipp', emscripten_set_mouseenter_callback_on_thread__deps: ['$registerMouseEventCallback'], emscripten_set_mouseenter_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_MOUSEENTER }}}, "mouseenter", targetThread); @@ -594,7 +585,6 @@ var LibraryHTML5 = { }, emscripten_set_mouseleave_callback_on_thread__proxy: 'sync', - emscripten_set_mouseleave_callback_on_thread__sig: 'ippipp', emscripten_set_mouseleave_callback_on_thread__deps: ['$registerMouseEventCallback'], emscripten_set_mouseleave_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_MOUSELEAVE }}}, "mouseleave", targetThread); @@ -602,7 +592,6 @@ var LibraryHTML5 = { }, emscripten_set_mouseover_callback_on_thread__proxy: 'sync', - emscripten_set_mouseover_callback_on_thread__sig: 'ippipp', emscripten_set_mouseover_callback_on_thread__deps: ['$registerMouseEventCallback'], emscripten_set_mouseover_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_MOUSEOVER }}}, "mouseover", targetThread); @@ -610,7 +599,6 @@ var LibraryHTML5 = { }, emscripten_set_mouseout_callback_on_thread__proxy: 'sync', - emscripten_set_mouseout_callback_on_thread__sig: 'ippipp', emscripten_set_mouseout_callback_on_thread__deps: ['$registerMouseEventCallback'], emscripten_set_mouseout_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_MOUSEOUT }}}, "mouseout", targetThread); @@ -618,7 +606,6 @@ var LibraryHTML5 = { }, emscripten_get_mouse_status__proxy: 'sync', - emscripten_get_mouse_status__sig: 'ip', emscripten_get_mouse_status__deps: ['$JSEvents'], emscripten_get_mouse_status: function(mouseState) { if (!JSEvents.mouseEvent) return {{{ cDefs.EMSCRIPTEN_RESULT_NO_DATA }}}; @@ -689,7 +676,6 @@ var LibraryHTML5 = { }, emscripten_set_wheel_callback_on_thread__proxy: 'sync', - emscripten_set_wheel_callback_on_thread__sig: 'ippipp', emscripten_set_wheel_callback_on_thread__deps: ['$JSEvents', '$registerWheelEventCallback', '$findEventTarget'], emscripten_set_wheel_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { target = findEventTarget(target); @@ -769,7 +755,6 @@ var LibraryHTML5 = { }, emscripten_set_resize_callback_on_thread__proxy: 'sync', - emscripten_set_resize_callback_on_thread__sig: 'ippipp', emscripten_set_resize_callback_on_thread__deps: ['$registerUiEventCallback'], emscripten_set_resize_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerUiEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_RESIZE }}}, "resize", targetThread); @@ -777,7 +762,6 @@ var LibraryHTML5 = { }, emscripten_set_scroll_callback_on_thread__proxy: 'sync', - emscripten_set_scroll_callback_on_thread__sig: 'ippipp', emscripten_set_scroll_callback_on_thread__deps: ['$registerUiEventCallback'], emscripten_set_scroll_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerUiEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_SCROLL }}}, "scroll", targetThread); @@ -821,7 +805,6 @@ var LibraryHTML5 = { }, emscripten_set_blur_callback_on_thread__proxy: 'sync', - emscripten_set_blur_callback_on_thread__sig: 'ippipp', emscripten_set_blur_callback_on_thread__deps: ['$registerFocusEventCallback'], emscripten_set_blur_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_BLUR }}}, "blur", targetThread); @@ -829,7 +812,6 @@ var LibraryHTML5 = { }, emscripten_set_focus_callback_on_thread__proxy: 'sync', - emscripten_set_focus_callback_on_thread__sig: 'ippipp', emscripten_set_focus_callback_on_thread__deps: ['$registerFocusEventCallback'], emscripten_set_focus_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_FOCUS }}}, "focus", targetThread); @@ -837,7 +819,6 @@ var LibraryHTML5 = { }, emscripten_set_focusin_callback_on_thread__proxy: 'sync', - emscripten_set_focusin_callback_on_thread__sig: 'ippipp', emscripten_set_focusin_callback_on_thread__deps: ['$registerFocusEventCallback'], emscripten_set_focusin_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_FOCUSIN }}}, "focusin", targetThread); @@ -845,7 +826,6 @@ var LibraryHTML5 = { }, emscripten_set_focusout_callback_on_thread__proxy: 'sync', - emscripten_set_focusout_callback_on_thread__sig: 'ippipp', emscripten_set_focusout_callback_on_thread__deps: ['$registerFocusEventCallback'], emscripten_set_focusout_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_FOCUSOUT }}}, "focusout", targetThread); @@ -891,7 +871,6 @@ var LibraryHTML5 = { }, emscripten_set_deviceorientation_callback_on_thread__proxy: 'sync', - emscripten_set_deviceorientation_callback_on_thread__sig: 'ipipp', emscripten_set_deviceorientation_callback_on_thread__deps: ['$registerDeviceOrientationEventCallback'], emscripten_set_deviceorientation_callback_on_thread: function(userData, useCapture, callbackfunc, targetThread) { registerDeviceOrientationEventCallback({{{ cDefs.EMSCRIPTEN_EVENT_TARGET_WINDOW }}}, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_DEVICEORIENTATION }}}, "deviceorientation", targetThread); @@ -899,7 +878,6 @@ var LibraryHTML5 = { }, emscripten_get_deviceorientation_status__proxy: 'sync', - emscripten_get_deviceorientation_status__sig: 'ip', emscripten_get_deviceorientation_status__deps: ['$JSEvents', '$registerDeviceOrientationEventCallback'], emscripten_get_deviceorientation_status: function(orientationState) { if (!JSEvents.deviceOrientationEvent) return {{{ cDefs.EMSCRIPTEN_RESULT_NO_DATA }}}; @@ -964,7 +942,6 @@ var LibraryHTML5 = { }, emscripten_set_devicemotion_callback_on_thread__proxy: 'sync', - emscripten_set_devicemotion_callback_on_thread__sig: 'ipipp', emscripten_set_devicemotion_callback_on_thread__deps: ['$registerDeviceMotionEventCallback'], emscripten_set_devicemotion_callback_on_thread: function(userData, useCapture, callbackfunc, targetThread) { registerDeviceMotionEventCallback({{{ cDefs.EMSCRIPTEN_EVENT_TARGET_WINDOW }}}, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_DEVICEMOTION }}}, "devicemotion", targetThread); @@ -972,7 +949,6 @@ var LibraryHTML5 = { }, emscripten_get_devicemotion_status__proxy: 'sync', - emscripten_get_devicemotion_status__sig: 'ip', emscripten_get_devicemotion_status__deps: ['$JSEvents'], emscripten_get_devicemotion_status: function(motionState) { if (!JSEvents.deviceMotionEvent) return {{{ cDefs.EMSCRIPTEN_RESULT_NO_DATA }}}; @@ -1041,7 +1017,6 @@ var LibraryHTML5 = { }, emscripten_set_orientationchange_callback_on_thread__proxy: 'sync', - emscripten_set_orientationchange_callback_on_thread__sig: 'ipipp', emscripten_set_orientationchange_callback_on_thread__deps: ['$registerOrientationChangeEventCallback'], emscripten_set_orientationchange_callback_on_thread: function(userData, useCapture, callbackfunc, targetThread) { if (!screen || !screen['addEventListener']) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; @@ -1050,7 +1025,6 @@ var LibraryHTML5 = { }, emscripten_get_orientation_status__proxy: 'sync', - emscripten_get_orientation_status__sig: 'ip', emscripten_get_orientation_status__deps: ['$fillOrientationChangeEventData', '$screenOrientation'], emscripten_get_orientation_status: function(orientationChangeEvent) { if (!screenOrientation() && typeof orientation == 'undefined') return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; @@ -1059,7 +1033,6 @@ var LibraryHTML5 = { }, emscripten_lock_orientation__proxy: 'sync', - emscripten_lock_orientation__sig: 'ii', emscripten_lock_orientation: function(allowedOrientations) { var orientations = []; if (allowedOrientations & 1) orientations.push("portrait-primary"); @@ -1085,7 +1058,6 @@ var LibraryHTML5 = { }, emscripten_unlock_orientation__proxy: 'sync', - emscripten_unlock_orientation__sig: 'i', emscripten_unlock_orientation: function() { if (screen.unlockOrientation) { screen.unlockOrientation(); @@ -1161,7 +1133,6 @@ var LibraryHTML5 = { }, emscripten_set_fullscreenchange_callback_on_thread__proxy: 'sync', - emscripten_set_fullscreenchange_callback_on_thread__sig: 'ippipp', emscripten_set_fullscreenchange_callback_on_thread__deps: ['$JSEvents', '$registerFullscreenChangeEventCallback', '$findEventTarget', '$specialHTMLTargets'], emscripten_set_fullscreenchange_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { if (!JSEvents.fullscreenEnabled()) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; @@ -1190,7 +1161,6 @@ var LibraryHTML5 = { }, emscripten_get_fullscreen_status__proxy: 'sync', - emscripten_get_fullscreen_status__sig: 'ip', emscripten_get_fullscreen_status__deps: ['$JSEvents', '$fillFullscreenChangeEventData'], emscripten_get_fullscreen_status: function(fullscreenStatus) { if (!JSEvents.fullscreenEnabled()) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; @@ -1559,7 +1529,6 @@ var LibraryHTML5 = { emscripten_request_fullscreen__deps: ['$doRequestFullscreen'], emscripten_request_fullscreen__proxy: 'sync', - emscripten_request_fullscreen__sig: 'ipi', emscripten_request_fullscreen: function(target, deferUntilInEventHandler) { var strategy = { // These options perform no added logic, but just bare request fullscreen. @@ -1576,7 +1545,6 @@ var LibraryHTML5 = { emscripten_request_fullscreen_strategy__deps: ['$doRequestFullscreen', '$currentFullscreenStrategy', '$registerRestoreOldStyle'], emscripten_request_fullscreen_strategy__proxy: 'sync', - emscripten_request_fullscreen_strategy__sig: 'ipip', emscripten_request_fullscreen_strategy: function(target, deferUntilInEventHandler, fullscreenStrategy) { var strategy = { scaleMode: {{{ makeGetValue('fullscreenStrategy', C_STRUCTS.EmscriptenFullscreenStrategy.scaleMode, 'i32') }}}, @@ -1597,7 +1565,6 @@ var LibraryHTML5 = { emscripten_enter_soft_fullscreen__deps: ['$JSEvents', '$setLetterbox', '$hideEverythingExceptGivenElement', '$restoreOldWindowedStyle', '$registerRestoreOldStyle', '$restoreHiddenElements', '$currentFullscreenStrategy', '$softFullscreenResizeWebGLRenderTarget', '$getCanvasElementSize', '$setCanvasElementSize', '$JSEvents_resizeCanvasForFullscreen', '$findEventTarget'], emscripten_enter_soft_fullscreen__proxy: 'sync', - emscripten_enter_soft_fullscreen__sig: 'ipp', emscripten_enter_soft_fullscreen: function(target, fullscreenStrategy) { #if !DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR if (!target) target = '#canvas'; @@ -1657,7 +1624,6 @@ var LibraryHTML5 = { emscripten_exit_soft_fullscreen__deps: ['$restoreOldWindowedStyle'], emscripten_exit_soft_fullscreen__proxy: 'sync', - emscripten_exit_soft_fullscreen__sig: 'i', emscripten_exit_soft_fullscreen: function() { if (restoreOldWindowedStyle) restoreOldWindowedStyle(); restoreOldWindowedStyle = null; @@ -1667,7 +1633,6 @@ var LibraryHTML5 = { emscripten_exit_fullscreen__deps: ['$JSEvents', '$currentFullscreenStrategy', '$JSEvents_requestFullscreen', '$specialHTMLTargets'], emscripten_exit_fullscreen__proxy: 'sync', - emscripten_exit_fullscreen__sig: 'i', emscripten_exit_fullscreen: function() { if (!JSEvents.fullscreenEnabled()) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; #if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS @@ -1745,7 +1710,6 @@ var LibraryHTML5 = { }, emscripten_set_pointerlockchange_callback_on_thread__proxy: 'sync', - emscripten_set_pointerlockchange_callback_on_thread__sig: 'ippipp', emscripten_set_pointerlockchange_callback_on_thread__deps: ['$JSEvents', '$registerPointerlockChangeEventCallback', '$findEventTarget', '$specialHTMLTargets'], emscripten_set_pointerlockchange_callback_on_thread__docs: '/** @suppress {missingProperties} */', // Closure does not see document.body.mozRequestPointerLock etc. emscripten_set_pointerlockchange_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { @@ -1792,7 +1756,6 @@ var LibraryHTML5 = { }, emscripten_set_pointerlockerror_callback_on_thread__proxy: 'sync', - emscripten_set_pointerlockerror_callback_on_thread__sig: 'ippipp', emscripten_set_pointerlockerror_callback_on_thread__deps: ['$JSEvents', '$registerPointerlockErrorEventCallback', '$findEventTarget', '$specialHTMLTargets'], emscripten_set_pointerlockerror_callback_on_thread__docs: '/** @suppress {missingProperties} */', // Closure does not see document.body.mozRequestPointerLock etc. emscripten_set_pointerlockerror_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { @@ -1816,7 +1779,6 @@ var LibraryHTML5 = { }, emscripten_get_pointerlock_status__proxy: 'sync', - emscripten_get_pointerlock_status__sig: 'ip', emscripten_get_pointerlock_status__deps: ['$fillPointerlockChangeEventData'], emscripten_get_pointerlock_status__docs: '/** @suppress {missingProperties} */', // Closure does not see document.body.mozRequestPointerLock etc. emscripten_get_pointerlock_status: function(pointerlockStatus) { @@ -1864,7 +1826,6 @@ var LibraryHTML5 = { }, emscripten_request_pointerlock__proxy: 'sync', - emscripten_request_pointerlock__sig: 'ipi', emscripten_request_pointerlock__deps: ['$JSEvents', '$requestPointerLock', '$findEventTarget'], emscripten_request_pointerlock: function(target, deferUntilInEventHandler) { #if !DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR @@ -1903,7 +1864,6 @@ var LibraryHTML5 = { }, emscripten_exit_pointerlock__proxy: 'sync', - emscripten_exit_pointerlock__sig: 'i', emscripten_exit_pointerlock__deps: ['$JSEvents', '$requestPointerLock'], emscripten_exit_pointerlock: function() { #if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS @@ -1932,7 +1892,6 @@ var LibraryHTML5 = { }, emscripten_vibrate__proxy: 'sync', - emscripten_vibrate__sig: 'ii', emscripten_vibrate: function(msecs) { if (!navigator.vibrate) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; navigator.vibrate(msecs); @@ -1940,7 +1899,6 @@ var LibraryHTML5 = { }, emscripten_vibrate_pattern__proxy: 'sync', - emscripten_vibrate_pattern__sig: 'ipi', emscripten_vibrate_pattern: function(msecsArray, numEntries) { if (!navigator.vibrate) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; @@ -1999,7 +1957,6 @@ var LibraryHTML5 = { }, emscripten_set_visibilitychange_callback_on_thread__proxy: 'sync', - emscripten_set_visibilitychange_callback_on_thread__sig: 'ipipp', emscripten_set_visibilitychange_callback_on_thread__deps: ['$registerVisibilityChangeEventCallback', '$specialHTMLTargets'], emscripten_set_visibilitychange_callback_on_thread: function(userData, useCapture, callbackfunc, targetThread) { #if ENVIRONMENT_MAY_BE_WORKER || ENVIRONMENT_MAY_BE_NODE || ENVIRONMENT_MAY_BE_SHELL @@ -2012,7 +1969,6 @@ var LibraryHTML5 = { }, emscripten_get_visibility_status__proxy: 'sync', - emscripten_get_visibility_status__sig: 'ip', emscripten_get_visibility_status__deps: ['$fillVisibilityChangeEventData'], emscripten_get_visibility_status: function(visibilityStatus) { if (typeof document.visibilityState == 'undefined' && typeof document.hidden == 'undefined') { @@ -2122,7 +2078,6 @@ var LibraryHTML5 = { }, emscripten_set_touchstart_callback_on_thread__proxy: 'sync', - emscripten_set_touchstart_callback_on_thread__sig: 'ippipp', emscripten_set_touchstart_callback_on_thread__deps: ['$registerTouchEventCallback'], emscripten_set_touchstart_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_TOUCHSTART }}}, "touchstart", targetThread); @@ -2130,7 +2085,6 @@ var LibraryHTML5 = { }, emscripten_set_touchend_callback_on_thread__proxy: 'sync', - emscripten_set_touchend_callback_on_thread__sig: 'ippipp', emscripten_set_touchend_callback_on_thread__deps: ['$registerTouchEventCallback'], emscripten_set_touchend_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_TOUCHEND }}}, "touchend", targetThread); @@ -2138,7 +2092,6 @@ var LibraryHTML5 = { }, emscripten_set_touchmove_callback_on_thread__proxy: 'sync', - emscripten_set_touchmove_callback_on_thread__sig: 'ippipp', emscripten_set_touchmove_callback_on_thread__deps: ['$registerTouchEventCallback'], emscripten_set_touchmove_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_TOUCHMOVE }}}, "touchmove", targetThread); @@ -2146,7 +2099,6 @@ var LibraryHTML5 = { }, emscripten_set_touchcancel_callback_on_thread__proxy: 'sync', - emscripten_set_touchcancel_callback_on_thread__sig: 'ippipp', emscripten_set_touchcancel_callback_on_thread__deps: ['$registerTouchEventCallback'], emscripten_set_touchcancel_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_TOUCHCANCEL }}}, "touchcancel", targetThread); @@ -2220,7 +2172,6 @@ var LibraryHTML5 = { }, emscripten_set_gamepadconnected_callback_on_thread__proxy: 'sync', - emscripten_set_gamepadconnected_callback_on_thread__sig: 'ipipp', emscripten_set_gamepadconnected_callback_on_thread__deps: ['$registerGamepadEventCallback'], emscripten_set_gamepadconnected_callback_on_thread: function(userData, useCapture, callbackfunc, targetThread) { if (!navigator.getGamepads && !navigator.webkitGetGamepads) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; @@ -2229,7 +2180,6 @@ var LibraryHTML5 = { }, emscripten_set_gamepaddisconnected_callback_on_thread__proxy: 'sync', - emscripten_set_gamepaddisconnected_callback_on_thread__sig: 'ipipp', emscripten_set_gamepaddisconnected_callback_on_thread__deps: ['$registerGamepadEventCallback'], emscripten_set_gamepaddisconnected_callback_on_thread: function(userData, useCapture, callbackfunc, targetThread) { if (!navigator.getGamepads && !navigator.webkitGetGamepads) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; @@ -2238,7 +2188,6 @@ var LibraryHTML5 = { }, emscripten_sample_gamepad_data__proxy: 'sync', - emscripten_sample_gamepad_data__sig: 'i', emscripten_sample_gamepad_data__deps: ['$JSEvents'], emscripten_sample_gamepad_data: function() { return (JSEvents.lastGamepadState = (navigator.getGamepads ? navigator.getGamepads() : (navigator.webkitGetGamepads ? navigator.webkitGetGamepads() : null))) @@ -2246,7 +2195,6 @@ var LibraryHTML5 = { }, emscripten_get_num_gamepads__proxy: 'sync', - emscripten_get_num_gamepads__sig: 'i', emscripten_get_num_gamepads__deps: ['$JSEvents'], emscripten_get_num_gamepads: function() { #if ASSERTIONS @@ -2258,7 +2206,6 @@ var LibraryHTML5 = { }, emscripten_get_gamepad_status__proxy: 'sync', - emscripten_get_gamepad_status__sig: 'iip', emscripten_get_gamepad_status__deps: ['$JSEvents', '$fillGamepadEventData'], emscripten_get_gamepad_status: function(index, gamepadState) { #if ASSERTIONS @@ -2305,7 +2252,6 @@ var LibraryHTML5 = { }, emscripten_set_beforeunload_callback_on_thread__proxy: 'sync', - emscripten_set_beforeunload_callback_on_thread__sig: 'ippp', emscripten_set_beforeunload_callback_on_thread__deps: ['$registerBeforeUnloadEventCallback'], emscripten_set_beforeunload_callback_on_thread: function(userData, callbackfunc, targetThread) { if (typeof onbeforeunload == 'undefined') return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; @@ -2358,7 +2304,6 @@ var LibraryHTML5 = { }, emscripten_set_batterychargingchange_callback_on_thread__proxy: 'sync', - emscripten_set_batterychargingchange_callback_on_thread__sig: 'ippp', emscripten_set_batterychargingchange_callback_on_thread__deps: ['$registerBatteryEventCallback', '$battery', 'malloc'], emscripten_set_batterychargingchange_callback_on_thread: function(userData, callbackfunc, targetThread) { if (!battery()) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; @@ -2367,7 +2312,6 @@ var LibraryHTML5 = { }, emscripten_set_batterylevelchange_callback_on_thread__proxy: 'sync', - emscripten_set_batterylevelchange_callback_on_thread__sig: 'ippp', emscripten_set_batterylevelchange_callback_on_thread__deps: ['$registerBatteryEventCallback', '$battery', 'malloc'], emscripten_set_batterylevelchange_callback_on_thread: function(userData, callbackfunc, targetThread) { if (!battery()) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; @@ -2376,7 +2320,6 @@ var LibraryHTML5 = { }, emscripten_get_battery_status__proxy: 'sync', - emscripten_get_battery_status__sig: 'ip', emscripten_get_battery_status__deps: ['$fillBatteryEventData', '$battery'], emscripten_get_battery_status: function(batteryState) { if (!battery()) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; @@ -2489,7 +2432,6 @@ var LibraryHTML5 = { }, emscripten_set_canvas_element_size__deps: ['$JSEvents', '$setCanvasElementSizeCallingThread', '$setCanvasElementSizeMainThread', '$findCanvasEventTarget'], - emscripten_set_canvas_element_size__sig: 'ipii', emscripten_set_canvas_element_size: function(target, width, height) { #if GL_DEBUG dbg('emscripten_set_canvas_element_size(target='+target+',width='+width+',height='+height); @@ -2502,7 +2444,6 @@ var LibraryHTML5 = { }, #else emscripten_set_canvas_element_size__deps: ['$JSEvents', '$findCanvasEventTarget'], - emscripten_set_canvas_element_size__sig: 'ipii', emscripten_set_canvas_element_size: function(target, width, height) { #if GL_DEBUG dbg('emscripten_set_canvas_element_size(target='+target+',width='+width+',height='+height); @@ -2574,7 +2515,6 @@ var LibraryHTML5 = { emscripten_get_canvas_element_size_main_thread__deps: ['emscripten_get_canvas_element_size_calling_thread'], emscripten_get_canvas_element_size_main_thread: function(target, width, height) { return _emscripten_get_canvas_element_size_calling_thread(target, width, height); }, - emscripten_get_canvas_element_size__sig: 'ippp', emscripten_get_canvas_element_size__deps: ['$JSEvents', 'emscripten_get_canvas_element_size_calling_thread', 'emscripten_get_canvas_element_size_main_thread', '$findCanvasEventTarget'], emscripten_get_canvas_element_size: function(target, width, height) { var canvas = findCanvasEventTarget(target); @@ -2585,7 +2525,6 @@ var LibraryHTML5 = { }, #else emscripten_get_canvas_element_size__deps: ['$JSEvents', '$findCanvasEventTarget'], - emscripten_get_canvas_element_size__sig: 'ippp', emscripten_get_canvas_element_size: function(target, width, height) { var canvas = findCanvasEventTarget(target); if (!canvas) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}}; @@ -2610,7 +2549,6 @@ var LibraryHTML5 = { }, emscripten_set_element_css_size__proxy: 'sync', - emscripten_set_element_css_size__sig: 'ipdd', emscripten_set_element_css_size__deps: ['$JSEvents', '$findEventTarget'], emscripten_set_element_css_size: function(target, width, height) { #if DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR @@ -2627,7 +2565,6 @@ var LibraryHTML5 = { }, emscripten_get_element_css_size__proxy: 'sync', - emscripten_get_element_css_size__sig: 'ippp', emscripten_get_element_css_size__deps: ['$JSEvents', '$findEventTarget', '$getBoundingClientRect'], emscripten_get_element_css_size: function(target, width, height) { #if DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR @@ -2651,7 +2588,6 @@ var LibraryHTML5 = { return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, - emscripten_html5_remove_all_event_listeners__sig: 'v', emscripten_html5_remove_all_event_listeners__deps: ['$JSEvents'], emscripten_html5_remove_all_event_listeners: function() { JSEvents.removeAllEventListeners(); @@ -2676,7 +2612,6 @@ var LibraryHTML5 = { return requestAnimationFrame(tick); }, - emscripten_date_now__sig: 'd', emscripten_date_now: function() { return Date.now(); }, @@ -2686,7 +2621,6 @@ var LibraryHTML5 = { }, emscripten_get_device_pixel_ratio__proxy: 'sync', - emscripten_get_device_pixel_ratio__sig: 'd', emscripten_get_device_pixel_ratio: function() { #if ENVIRONMENT_MAY_BE_NODE || ENVIRONMENT_MAY_BE_SHELL return (typeof devicePixelRatio == 'number' && devicePixelRatio) || 1.0; diff --git a/src/library_html5_webgl.js b/src/library_html5_webgl.js index 5edd57452040c..8c36727abfc34 100644 --- a/src/library_html5_webgl.js +++ b/src/library_html5_webgl.js @@ -61,13 +61,10 @@ var LibraryHtml5WebGL = { #else // When not in offscreen framebuffer mode, these functions are implemented // in JS and forwarded without any proxying. - emscripten_webgl_create_context__sig: 'ipp', emscripten_webgl_create_context: 'emscripten_webgl_do_create_context', - emscripten_webgl_get_current_context__sig: 'i', emscripten_webgl_get_current_context: 'emscripten_webgl_do_get_current_context', - emscripten_webgl_commit_frame__sig: 'i', emscripten_webgl_commit_frame: 'emscripten_webgl_do_commit_frame', #endif @@ -84,7 +81,6 @@ var LibraryHtml5WebGL = { #endif '$JSEvents', '$emscripten_webgl_power_preferences', '$findEventTarget', '$findCanvasEventTarget'], // This function performs proxying manually, depending on the style of context that is to be created. - emscripten_webgl_do_create_context__sig: 'ipp', emscripten_webgl_do_create_context: function(target, attributes) { #if ASSERTIONS assert(attributes); @@ -231,7 +227,6 @@ var LibraryHtml5WebGL = { GL.currentContextIsProxied = true; }, #else - emscripten_webgl_make_context_current__sig: 'ii', emscripten_webgl_make_context_current: function(contextHandle) { var success = GL.makeContextCurrent(contextHandle); return success ? {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}} : {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_PARAM }}}; @@ -243,7 +238,6 @@ var LibraryHtml5WebGL = { }, emscripten_webgl_get_drawing_buffer_size__proxy: 'sync_on_webgl_context_handle_thread', - emscripten_webgl_get_drawing_buffer_size__sig: 'iipp', emscripten_webgl_get_drawing_buffer_size: function(contextHandle, width, height) { var GLContext = GL.getContext(contextHandle); @@ -255,7 +249,6 @@ var LibraryHtml5WebGL = { return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, - emscripten_webgl_do_commit_frame__sig: 'i', emscripten_webgl_do_commit_frame: function() { #if TRACE_WEBGL_CALLS var threadId = (typeof _pthread_self != 'undefined') ? _pthread_self : function() { return 1; }; @@ -290,7 +283,6 @@ var LibraryHtml5WebGL = { }, emscripten_webgl_get_context_attributes__proxy: 'sync_on_webgl_context_handle_thread', - emscripten_webgl_get_context_attributes__sig: 'iip', emscripten_webgl_get_context_attributes__deps: ['$emscripten_webgl_power_preferences'], emscripten_webgl_get_context_attributes: function(c, a) { if (!a) return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_PARAM }}}; @@ -321,7 +313,6 @@ var LibraryHtml5WebGL = { }, emscripten_webgl_destroy_context__proxy: 'sync_on_webgl_context_handle_thread', - emscripten_webgl_destroy_context__sig: 'ii', emscripten_webgl_destroy_context: function(contextHandle) { if (GL.currentContext == contextHandle) GL.currentContext = 0; GL.deleteContext(contextHandle); @@ -351,7 +342,6 @@ var LibraryHtml5WebGL = { #endif ], emscripten_webgl_enable_extension__proxy: 'sync_on_webgl_context_handle_thread', - emscripten_webgl_enable_extension__sig: 'iip', emscripten_webgl_enable_extension: function(contextHandle, extension) { var context = GL.getContext(contextHandle); var extString = UTF8ToString(extension); @@ -436,7 +426,6 @@ var LibraryHtml5WebGL = { }, emscripten_set_webglcontextlost_callback_on_thread__proxy: 'sync', - emscripten_set_webglcontextlost_callback_on_thread__sig: 'ippipp', emscripten_set_webglcontextlost_callback_on_thread__deps: ['$registerWebGlEventCallback'], emscripten_set_webglcontextlost_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerWebGlEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_WEBGLCONTEXTLOST }}}, "webglcontextlost", targetThread); @@ -444,7 +433,6 @@ var LibraryHtml5WebGL = { }, emscripten_set_webglcontextrestored_callback_on_thread__proxy: 'sync', - emscripten_set_webglcontextrestored_callback_on_thread__sig: 'ippipp', emscripten_set_webglcontextrestored_callback_on_thread__deps: ['$registerWebGlEventCallback'], emscripten_set_webglcontextrestored_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { registerWebGlEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_WEBGLCONTEXTRESTORED }}}, "webglcontextrestored", targetThread); @@ -452,113 +440,96 @@ var LibraryHtml5WebGL = { }, emscripten_is_webgl_context_lost__proxy: 'sync_on_webgl_context_handle_thread', - emscripten_is_webgl_context_lost__sig: 'ii', emscripten_is_webgl_context_lost: function(contextHandle) { return !GL.contexts[contextHandle] || GL.contexts[contextHandle].GLctx.isContextLost(); // No context ~> lost context. }, - emscripten_webgl_get_supported_extensions__sig: 'p', emscripten_webgl_get_supported_extensions__proxy: 'sync_on_current_webgl_context_thread', emscripten_webgl_get_supported_extensions__deps: ['$stringToNewUTF8'], emscripten_webgl_get_supported_extensions: function() { return stringToNewUTF8(GLctx.getSupportedExtensions().join(' ')); }, - emscripten_webgl_get_program_parameter_d__sig: 'dii', emscripten_webgl_get_program_parameter_d__proxy: 'sync_on_current_webgl_context_thread', emscripten_webgl_get_program_parameter_d: function(program, param) { return GLctx.getProgramParameter(GL.programs[program], param); }, - emscripten_webgl_get_program_info_log_utf8__sig: 'pi', emscripten_webgl_get_program_info_log_utf8__proxy: 'sync_on_current_webgl_context_thread', emscripten_webgl_get_program_info_log_utf8__deps: ['$stringToNewUTF8'], emscripten_webgl_get_program_info_log_utf8: function(program) { return stringToNewUTF8(GLctx.getProgramInfoLog(GL.programs[program])); }, - emscripten_webgl_get_shader_parameter_d__sig: 'dii', emscripten_webgl_get_shader_parameter_d__proxy: 'sync_on_current_webgl_context_thread', emscripten_webgl_get_shader_parameter_d: function(shader, param) { return GLctx.getShaderParameter(GL.shaders[shader], param); }, - emscripten_webgl_get_shader_info_log_utf8__sig: 'pi', emscripten_webgl_get_shader_info_log_utf8__proxy: 'sync_on_current_webgl_context_thread', emscripten_webgl_get_shader_info_log_utf8__deps: ['$stringToNewUTF8'], emscripten_webgl_get_shader_info_log_utf8: function(shader) { return stringToNewUTF8(GLctx.getShaderInfoLog(GL.shaders[shader])); }, - emscripten_webgl_get_shader_source_utf8__sig: 'pi', emscripten_webgl_get_shader_source_utf8__proxy: 'sync_on_current_webgl_context_thread', emscripten_webgl_get_shader_source_utf8__deps: ['$stringToNewUTF8'], emscripten_webgl_get_shader_source_utf8: function(shader) { return stringToNewUTF8(GLctx.getShaderSource(GL.shaders[shader])); }, - emscripten_webgl_get_vertex_attrib_d__sig: 'dii', emscripten_webgl_get_vertex_attrib_d__proxy: 'sync_on_current_webgl_context_thread', emscripten_webgl_get_vertex_attrib_d: function(index, param) { return GLctx.getVertexAttrib(index, param); }, - emscripten_webgl_get_vertex_attrib_o__sig: 'iii', emscripten_webgl_get_vertex_attrib_o__proxy: 'sync_on_current_webgl_context_thread', emscripten_webgl_get_vertex_attrib_o: function(index, param) { var obj = GLctx.getVertexAttrib(index, param); return obj && obj.name; }, - emscripten_webgl_get_vertex_attrib_v__sig: 'iiipii', emscripten_webgl_get_vertex_attrib_v__proxy: 'sync_on_current_webgl_context_thread', emscripten_webgl_get_vertex_attrib_v__deps: ['$writeGLArray'], emscripten_webgl_get_vertex_attrib_v: function(index, param, dst, dstLength, dstType) { return writeGLArray(GLctx.getVertexAttrib(index, param), dst, dstLength, dstType); }, - emscripten_webgl_get_uniform_d__sig: 'dii', emscripten_webgl_get_uniform_d__proxy: 'sync_on_current_webgl_context_thread', emscripten_webgl_get_uniform_d__deps: ['$webglGetUniformLocation'], emscripten_webgl_get_uniform_d: function(program, location) { return GLctx.getUniform(GL.programs[program], webglGetUniformLocation(location)); }, - emscripten_webgl_get_uniform_v__sig: 'iiipii', emscripten_webgl_get_uniform_v__proxy: 'sync_on_current_webgl_context_thread', emscripten_webgl_get_uniform_v__deps: ['$writeGLArray', '$webglGetUniformLocation'], emscripten_webgl_get_uniform_v: function(program, location, dst, dstLength, dstType) { return writeGLArray(GLctx.getUniform(GL.programs[program], webglGetUniformLocation(location)), dst, dstLength, dstType); }, - emscripten_webgl_get_parameter_v__sig: 'iipii', emscripten_webgl_get_parameter_v__proxy: 'sync_on_current_webgl_context_thread', emscripten_webgl_get_parameter_v__deps: ['$writeGLArray'], emscripten_webgl_get_parameter_v: function(param, dst, dstLength, dstType) { return writeGLArray(GLctx.getParameter(param), dst, dstLength, dstType); }, - emscripten_webgl_get_parameter_d__sig: 'di', emscripten_webgl_get_parameter_d__proxy: 'sync_on_current_webgl_context_thread', emscripten_webgl_get_parameter_d: function(param) { return GLctx.getParameter(param); }, - emscripten_webgl_get_parameter_o__sig: 'ii', emscripten_webgl_get_parameter_o__proxy: 'sync_on_current_webgl_context_thread', emscripten_webgl_get_parameter_o: function(param) { var obj = GLctx.getParameter(param); return obj && obj.name; }, - emscripten_webgl_get_parameter_utf8__sig: 'pi', emscripten_webgl_get_parameter_utf8__deps: ['$stringToNewUTF8'], emscripten_webgl_get_parameter_utf8__proxy: 'sync_on_current_webgl_context_thread', emscripten_webgl_get_parameter_utf8: function(param) { return stringToNewUTF8(GLctx.getParameter(param)); }, - emscripten_webgl_get_parameter_i64v__sig: 'vip', emscripten_webgl_get_parameter_i64v__proxy: 'sync_on_current_webgl_context_thread', emscripten_webgl_get_parameter_i64v__deps: ['$writeI53ToI64'], emscripten_webgl_get_parameter_i64v: function(param, dst) { @@ -605,17 +576,19 @@ function handleWebGLProxying(funcs) { // Dynamically check at runtime whether the current thread owns the GL context handle/current GL context // object. If not, proxy the call to main thread. // TODO: this handles the calling pthread and main thread cases, but not yet the case from pthread->pthread. + const sig = funcs[i + '__sig'] || LibraryManager.library[i + '__sig'] + assert(sig); funcs[i + '_calling_thread'] = funcs[i]; funcs[i + '_main_thread'] = i + '_calling_thread'; funcs[i + '_main_thread__proxy'] = 'sync'; - funcs[i + '_main_thread__sig'] = funcs[i + '__sig']; + funcs[i + '_main_thread__sig'] = sig; if (!funcs[i + '__deps']) funcs[i + '__deps'] = []; funcs[i + '__deps'].push(i + '_calling_thread'); funcs[i + '__deps'].push(i + '_main_thread'); delete funcs[i + '__proxy']; var funcArgs = listOfNFunctionArgs(funcs[i]); var funcArgsString = funcArgs.join(','); - var retStatement = funcs[i + '__sig'][0] != 'v' ? 'return' : ''; + var retStatement = sig[0] != 'v' ? 'return' : ''; var contextCheck = proxyContextHandle ? 'GL.contexts[p0]' : 'GLctx'; var funcBody = `${retStatement} ${contextCheck} ? _${i}_calling_thread(${funcArgsString}) : _${i}_main_thread(${funcArgsString});`; if (funcs[i + '_before_on_calling_thread']) { diff --git a/src/library_idbstore.js b/src/library_idbstore.js index c28da22e7f7a1..e6fe74f67ca02 100644 --- a/src/library_idbstore.js +++ b/src/library_idbstore.js @@ -13,7 +13,6 @@ var LibraryIDBStore = { $IDBStore: #include IDBStore.js , - emscripten_idb_async_load__sig: 'vppppp', emscripten_idb_async_load: function(db, id, arg, onload, onerror) { IDBStore.getFile(UTF8ToString(db), UTF8ToString(id), function(error, byteArray) { if (error) { @@ -26,7 +25,6 @@ var LibraryIDBStore = { _free(buffer); }); }, - emscripten_idb_async_store__sig: 'vpppippp', emscripten_idb_async_store: function(db, id, ptr, num, arg, onstore, onerror) { // note that we copy the data here, as these are async operatins - changes to HEAPU8 meanwhile should not affect us! IDBStore.setFile(UTF8ToString(db), UTF8ToString(id), new Uint8Array(HEAPU8.subarray(ptr, ptr+num)), function(error) { @@ -37,7 +35,6 @@ var LibraryIDBStore = { if (onstore) {{{ makeDynCall('vi', 'onstore') }}}(arg); }); }, - emscripten_idb_async_delete__sig: 'vppppp', emscripten_idb_async_delete: function(db, id, arg, ondelete, onerror) { IDBStore.deleteFile(UTF8ToString(db), UTF8ToString(id), function(error) { if (error) { @@ -47,7 +44,6 @@ var LibraryIDBStore = { if (ondelete) {{{ makeDynCall('vi', 'ondelete') }}}(arg); }); }, - emscripten_idb_async_exists__sig: 'vppppp', emscripten_idb_async_exists: function(db, id, arg, oncheck, onerror) { IDBStore.existsFile(UTF8ToString(db), UTF8ToString(id), function(error, exists) { if (error) { diff --git a/src/library_math.js b/src/library_math.js index 757314763d90d..f2fcbcb4a12dc 100644 --- a/src/library_math.js +++ b/src/library_math.js @@ -65,7 +65,6 @@ mergeInto(LibraryManager.library, { emscripten_math_cosh: function(x) { return Math.cosh(x); }, - emscripten_math_hypot__sig: 'dip', emscripten_math_hypot: function(count, varargs) { var args = []; for (var i = 0; i < count; ++i) args.push(HEAPF64[(varargs>>3) + i]); diff --git a/src/library_openal.js b/src/library_openal.js index e89642506a1dc..f09a6b427b04c 100644 --- a/src/library_openal.js +++ b/src/library_openal.js @@ -1613,7 +1613,6 @@ var LibraryOpenAL = { // bufferFrameCapacity here for clarity. alcCaptureOpenDevice__deps: ['$autoResumeAudioContext'], alcCaptureOpenDevice__proxy: 'sync', - alcCaptureOpenDevice__sig: 'ppiii', alcCaptureOpenDevice: function(pDeviceName, requestedSampleRate, format, bufferFrameCapacity) { var resolvedDeviceName = AL.CAPTURE_DEVICE_NAME; @@ -1905,7 +1904,6 @@ var LibraryOpenAL = { }, alcCaptureCloseDevice__proxy: 'sync', - alcCaptureCloseDevice__sig: 'ip', alcCaptureCloseDevice: function(deviceId) { var c = AL.requireValidCaptureDevice(deviceId, 'alcCaptureCloseDevice'); if (!c) return false; @@ -1938,7 +1936,6 @@ var LibraryOpenAL = { }, alcCaptureStart__proxy: 'sync', - alcCaptureStart__sig: 'vp', alcCaptureStart: function(deviceId) { var c = AL.requireValidCaptureDevice(deviceId, 'alcCaptureStart'); if (!c) return; @@ -1959,7 +1956,6 @@ var LibraryOpenAL = { }, alcCaptureStop__proxy: 'sync', - alcCaptureStop__sig: 'vp', alcCaptureStop: function(deviceId) { var c = AL.requireValidCaptureDevice(deviceId, 'alcCaptureStop'); if (!c) return; @@ -1978,7 +1974,6 @@ var LibraryOpenAL = { // The last parameter is actually 'number of sample frames', so was // renamed accordingly here alcCaptureSamples__proxy: 'sync', - alcCaptureSamples__sig: 'vppi', alcCaptureSamples: function(deviceId, pFrames, requestedFrameCount) { var c = AL.requireValidCaptureDevice(deviceId, 'alcCaptureSamples'); if (!c) return; @@ -2066,7 +2061,6 @@ var LibraryOpenAL = { // ------------------------------------------------------- alcOpenDevice__proxy: 'sync', - alcOpenDevice__sig: 'pp', alcOpenDevice: function(pDeviceName) { if (pDeviceName) { var name = UTF8ToString(pDeviceName); @@ -2084,7 +2078,6 @@ var LibraryOpenAL = { }, alcCloseDevice__proxy: 'sync', - alcCloseDevice__sig: 'ip', alcCloseDevice: function(deviceId) { if (!(deviceId in AL.deviceRefCounts) || AL.deviceRefCounts[deviceId] > 0) { return {{{ cDefs.ALC_FALSE }}}; @@ -2097,7 +2090,6 @@ var LibraryOpenAL = { alcCreateContext__deps: ['$autoResumeAudioContext'], alcCreateContext__proxy: 'sync', - alcCreateContext__sig: 'ppp', alcCreateContext: function(deviceId, pAttrList) { if (!(deviceId in AL.deviceRefCounts)) { #if OPENAL_DEBUG @@ -2252,7 +2244,6 @@ var LibraryOpenAL = { }, alcDestroyContext__proxy: 'sync', - alcDestroyContext__sig: 'vp', alcDestroyContext: function(contextId) { var ctx = AL.contexts[contextId]; if (AL.currentCtx === ctx) { @@ -2277,7 +2268,6 @@ var LibraryOpenAL = { // ------------------------------------------------------- alcGetError__proxy: 'sync', - alcGetError__sig: 'ip', alcGetError: function(deviceId) { var err = AL.alcErr; AL.alcErr = {{{ cDefs.ALC_NO_ERROR }}}; @@ -2285,7 +2275,6 @@ var LibraryOpenAL = { }, alcGetCurrentContext__proxy: 'sync', - alcGetCurrentContext__sig: 'p', alcGetCurrentContext: function() { if (AL.currentCtx !== null) { return AL.currentCtx.id; @@ -2294,7 +2283,6 @@ var LibraryOpenAL = { }, alcMakeContextCurrent__proxy: 'sync', - alcMakeContextCurrent__sig: 'ip', alcMakeContextCurrent: function(contextId) { if (contextId === 0) { AL.currentCtx = null; @@ -2305,7 +2293,6 @@ var LibraryOpenAL = { }, alcGetContextsDevice__proxy: 'sync', - alcGetContextsDevice__sig: 'pp', alcGetContextsDevice: function(contextId) { if (contextId in AL.contexts) { return AL.contexts[contextId].deviceId; @@ -2314,13 +2301,10 @@ var LibraryOpenAL = { }, // The spec is vague about what these are actually supposed to do, and NOP is a reasonable implementation - alcProcessContext__sig: 'vp', alcProcessContext: function(contextId) {}, - alcSuspendContext__sig: 'vp', alcSuspendContext: function(contextId) {}, alcIsExtensionPresent__proxy: 'sync', - alcIsExtensionPresent__sig: 'ipp', alcIsExtensionPresent: function(deviceId, pExtName) { var name = UTF8ToString(pExtName); @@ -2328,7 +2312,6 @@ var LibraryOpenAL = { }, alcGetEnumValue__proxy: 'sync', - alcGetEnumValue__sig: 'ipp', alcGetEnumValue: function(deviceId, pEnumName) { // Spec says : // Using a NULL handle is legal, but only the @@ -2393,7 +2376,6 @@ var LibraryOpenAL = { }, alcGetString__proxy: 'sync', - alcGetString__sig: 'ppi', alcGetString__deps: ['$allocateUTF8'], alcGetString: function(deviceId, param) { if (AL.alcStringCache[param]) { @@ -2474,7 +2456,6 @@ var LibraryOpenAL = { }, alcGetIntegerv__proxy: 'sync', - alcGetIntegerv__sig: 'vpiip', alcGetIntegerv: function(deviceId, param, size, pValues) { if (size === 0 || !pValues) { // Ignore the query, per the spec @@ -2751,7 +2732,6 @@ var LibraryOpenAL = { // ------------------------------------------------------- alGenBuffers__proxy: 'sync', - alGenBuffers__sig: 'vip', alGenBuffers: function(count, pBufferIds) { if (!AL.currentCtx) { #if OPENAL_DEBUG @@ -2778,7 +2758,6 @@ var LibraryOpenAL = { }, alDeleteBuffers__proxy: 'sync', - alDeleteBuffers__sig: 'vip', alDeleteBuffers: function(count, pBufferIds) { if (!AL.currentCtx) { #if OPENAL_DEBUG @@ -2826,7 +2805,6 @@ var LibraryOpenAL = { }, alGenSources__proxy: 'sync', - alGenSources__sig: 'vip', alGenSources: function(count, pSourceIds) { if (!AL.currentCtx) { #if OPENAL_DEBUG @@ -2878,7 +2856,6 @@ var LibraryOpenAL = { alDeleteSources__deps: ['alSourcei'], alDeleteSources__proxy: 'sync', - alDeleteSources__sig: 'vip', alDeleteSources: function(count, pSourceIds) { if (!AL.currentCtx) { #if OPENAL_DEBUG @@ -2912,7 +2889,6 @@ var LibraryOpenAL = { // ------------------------------------------------------- alGetError__proxy: 'sync', - alGetError__sig: 'i', alGetError: function() { if (!AL.currentCtx) { return {{{ cDefs.AL_INVALID_OPERATION }}}; @@ -2924,7 +2900,6 @@ var LibraryOpenAL = { }, alIsExtensionPresent__proxy: 'sync', - alIsExtensionPresent__sig: 'ip', alIsExtensionPresent: function(pExtName) { var name = UTF8ToString(pExtName); @@ -2932,7 +2907,6 @@ var LibraryOpenAL = { }, alGetEnumValue__proxy: 'sync', - alGetEnumValue__sig: 'ip', alGetEnumValue: function(pEnumName) { if (!AL.currentCtx) { #if OPENAL_DEBUG @@ -3044,7 +3018,6 @@ var LibraryOpenAL = { }, alGetString__proxy: 'sync', - alGetString__sig: 'pi', alGetString__deps: ['$allocateUTF8'], alGetString: function(param) { if (AL.stringCache[param]) { @@ -3105,7 +3078,6 @@ var LibraryOpenAL = { }, alEnable__proxy: 'sync', - alEnable__sig: 'vi', alEnable: function(param) { if (!AL.currentCtx) { #if OPENAL_DEBUG @@ -3128,7 +3100,6 @@ var LibraryOpenAL = { }, alDisable__proxy: 'sync', - alDisable__sig: 'vi', alDisable: function(param) { if (!AL.currentCtx) { #if OPENAL_DEBUG @@ -3151,7 +3122,6 @@ var LibraryOpenAL = { }, alIsEnabled__proxy: 'sync', - alIsEnabled__sig: 'ii', alIsEnabled: function(param) { if (!AL.currentCtx) { #if OPENAL_DEBUG @@ -3172,7 +3142,6 @@ var LibraryOpenAL = { }, alGetDouble__proxy: 'sync', - alGetDouble__sig: 'di', alGetDouble: function(param) { var val = AL.getGlobalParam('alGetDouble', param); if (val === null) { @@ -3194,7 +3163,6 @@ var LibraryOpenAL = { }, alGetDoublev__proxy: 'sync', - alGetDoublev__sig: 'vip', alGetDoublev: function(param, pValues) { var val = AL.getGlobalParam('alGetDoublev', param); // Silently ignore null destinations, as per the spec for global state functions @@ -3218,7 +3186,6 @@ var LibraryOpenAL = { }, alGetFloat__proxy: 'sync', - alGetFloat__sig: 'fi', alGetFloat: function(param) { var val = AL.getGlobalParam('alGetFloat', param); if (val === null) { @@ -3239,7 +3206,6 @@ var LibraryOpenAL = { }, alGetFloatv__proxy: 'sync', - alGetFloatv__sig: 'vip', alGetFloatv: function(param, pValues) { var val = AL.getGlobalParam('alGetFloatv', param); // Silently ignore null destinations, as per the spec for global state functions @@ -3263,7 +3229,6 @@ var LibraryOpenAL = { }, alGetInteger__proxy: 'sync', - alGetInteger__sig: 'ii', alGetInteger: function(param) { var val = AL.getGlobalParam('alGetInteger', param); if (val === null) { @@ -3285,7 +3250,6 @@ var LibraryOpenAL = { }, alGetIntegerv__proxy: 'sync', - alGetIntegerv__sig: 'vip', alGetIntegerv: function(param, pValues) { var val = AL.getGlobalParam('alGetIntegerv', param); // Silently ignore null destinations, as per the spec for global state functions @@ -3309,7 +3273,6 @@ var LibraryOpenAL = { }, alGetBoolean__proxy: 'sync', - alGetBoolean__sig: 'ii', alGetBoolean: function(param) { var val = AL.getGlobalParam('alGetBoolean', param); if (val === null) { @@ -3331,7 +3294,6 @@ var LibraryOpenAL = { }, alGetBooleanv__proxy: 'sync', - alGetBooleanv__sig: 'vip', alGetBooleanv: function(param, pValues) { var val = AL.getGlobalParam('alGetBooleanv', param); // Silently ignore null destinations, as per the spec for global state functions @@ -3355,19 +3317,16 @@ var LibraryOpenAL = { }, alDistanceModel__proxy: 'sync', - alDistanceModel__sig: 'vi', alDistanceModel: function(model) { AL.setGlobalParam('alDistanceModel', {{{ cDefs.AL_DISTANCE_MODEL }}}, model); }, alSpeedOfSound__proxy: 'sync', - alSpeedOfSound__sig: 'vf', alSpeedOfSound: function(value) { AL.setGlobalParam('alSpeedOfSound', {{{ cDefs.AL_SPEED_OF_SOUND }}}, value); }, alDopplerFactor__proxy: 'sync', - alDopplerFactor__sig: 'vf', alDopplerFactor: function(value) { AL.setGlobalParam('alDopplerFactor', {{{ cDefs.AL_DOPPLER_FACTOR }}}, value); }, @@ -3377,7 +3336,6 @@ var LibraryOpenAL = { // It's deprecated since it's equivalent to directly calling // alSpeedOfSound() with an appropriately premultiplied value. alDopplerVelocity__proxy: 'sync', - alDopplerVelocity__sig: 'vf', alDopplerVelocity: function(value) { warnOnce('alDopplerVelocity() is deprecated, and only kept for compatibility with OpenAL 1.0. Use alSpeedOfSound() instead.'); if (!AL.currentCtx) { @@ -3397,7 +3355,6 @@ var LibraryOpenAL = { // ------------------------------------------------------- alGetListenerf__proxy: 'sync', - alGetListenerf__sig: 'vip', alGetListenerf: function(param, pValue) { var val = AL.getListenerParam('alGetListenerf', param); if (val === null) { @@ -3425,7 +3382,6 @@ var LibraryOpenAL = { }, alGetListener3f__proxy: 'sync', - alGetListener3f__sig: 'vippp', alGetListener3f: function(param, pValue0, pValue1, pValue2) { var val = AL.getListenerParam('alGetListener3f', param); if (val === null) { @@ -3456,7 +3412,6 @@ var LibraryOpenAL = { }, alGetListenerfv__proxy: 'sync', - alGetListenerfv__sig: 'vip', alGetListenerfv: function(param, pValues) { var val = AL.getListenerParam('alGetListenerfv', param); if (val === null) { @@ -3495,7 +3450,6 @@ var LibraryOpenAL = { }, alGetListeneri__proxy: 'sync', - alGetListeneri__sig: 'vip', alGetListeneri: function(param, pValue) { var val = AL.getListenerParam('alGetListeneri', param); if (val === null) { @@ -3516,7 +3470,6 @@ var LibraryOpenAL = { }, alGetListener3i__proxy: 'sync', - alGetListener3i__sig: 'vippp', alGetListener3i: function(param, pValue0, pValue1, pValue2) { var val = AL.getListenerParam('alGetListener3i', param); if (val === null) { @@ -3547,7 +3500,6 @@ var LibraryOpenAL = { }, alGetListeneriv__proxy: 'sync', - alGetListeneriv__sig: 'vip', alGetListeneriv: function(param, pValues) { var val = AL.getListenerParam('alGetListeneriv', param); if (val === null) { @@ -3586,7 +3538,6 @@ var LibraryOpenAL = { }, alListenerf__proxy: 'sync', - alListenerf__sig: 'vif', alListenerf: function(param, value) { switch (param) { case {{{ cDefs.AL_GAIN }}}: @@ -3599,7 +3550,6 @@ var LibraryOpenAL = { }, alListener3f__proxy: 'sync', - alListener3f__sig: 'vifff', alListener3f: function(param, value0, value1, value2) { switch (param) { case {{{ cDefs.AL_POSITION }}}: @@ -3616,7 +3566,6 @@ var LibraryOpenAL = { }, alListenerfv__proxy: 'sync', - alListenerfv__sig: 'vip', alListenerfv: function(param, pValues) { if (!AL.currentCtx) { #if OPENAL_DEBUG @@ -3656,13 +3605,11 @@ var LibraryOpenAL = { }, alListeneri__proxy: 'sync', - alListeneri__sig: 'vii', alListeneri: function(param, value) { AL.setListenerParam('alListeneri', param, null); }, alListener3i__proxy: 'sync', - alListener3i__sig: 'viiii', alListener3i: function(param, value0, value1, value2) { switch (param) { case {{{ cDefs.AL_POSITION }}}: @@ -3679,7 +3626,6 @@ var LibraryOpenAL = { }, alListeneriv__proxy: 'sync', - alListeneriv__sig: 'vip', alListeneriv: function(param, pValues) { if (!AL.currentCtx) { #if OPENAL_DEBUG @@ -3723,7 +3669,6 @@ var LibraryOpenAL = { // ------------------------------------------------------- alIsBuffer__proxy: 'sync', - alIsBuffer__sig: 'ii', alIsBuffer: function(bufferId) { if (!AL.currentCtx) { return false; @@ -3739,7 +3684,6 @@ var LibraryOpenAL = { }, alBufferData__proxy: 'sync', - alBufferData__sig: 'viipii', alBufferData: function(bufferId, format, pData, size, freq) { if (!AL.currentCtx) { #if OPENAL_DEBUG @@ -3867,7 +3811,6 @@ var LibraryOpenAL = { }, alGetBufferf__proxy: 'sync', - alGetBufferf__sig: 'viip', alGetBufferf: function(bufferId, param, pValue) { var val = AL.getBufferParam('alGetBufferf', bufferId, param); if (val === null) { @@ -3888,7 +3831,6 @@ var LibraryOpenAL = { }, alGetBuffer3f__proxy: 'sync', - alGetBuffer3f__sig: 'viippp', alGetBuffer3f: function(bufferId, param, pValue0, pValue1, pValue2) { var val = AL.getBufferParam('alGetBuffer3f', bufferId, param); if (val === null) { @@ -3909,7 +3851,6 @@ var LibraryOpenAL = { }, alGetBufferfv__proxy: 'sync', - alGetBufferfv__sig: 'viip', alGetBufferfv: function(bufferId, param, pValues) { var val = AL.getBufferParam('alGetBufferfv', bufferId, param); if (val === null) { @@ -3930,7 +3871,6 @@ var LibraryOpenAL = { }, alGetBufferi__proxy: 'sync', - alGetBufferi__sig: 'viip', alGetBufferi: function(bufferId, param, pValue) { var val = AL.getBufferParam('alGetBufferi', bufferId, param); if (val === null) { @@ -3961,7 +3901,6 @@ var LibraryOpenAL = { }, alGetBuffer3i__proxy: 'sync', - alGetBuffer3i__sig: 'viippp', alGetBuffer3i: function(bufferId, param, pValue0, pValue1, pValue2) { var val = AL.getBufferParam('alGetBuffer3i', bufferId, param); if (val === null) { @@ -3982,7 +3921,6 @@ var LibraryOpenAL = { }, alGetBufferiv__proxy: 'sync', - alGetBufferiv__sig: 'viip', alGetBufferiv: function(bufferId, param, pValues) { var val = AL.getBufferParam('alGetBufferiv', bufferId, param); if (val === null) { @@ -4021,19 +3959,16 @@ var LibraryOpenAL = { // property for these. alBufferf__proxy: 'sync', - alBufferf__sig: 'viif', alBufferf: function(bufferId, param, value) { AL.setBufferParam('alBufferf', bufferId, param, null); }, alBuffer3f__proxy: 'sync', - alBuffer3f__sig: 'viifff', alBuffer3f: function(bufferId, param, value0, value1, value2) { AL.setBufferParam('alBuffer3f', bufferId, param, null); }, alBufferfv__proxy: 'sync', - alBufferfv__sig: 'viip', alBufferfv: function(bufferId, param, pValues) { if (!AL.currentCtx) { #if OPENAL_DEBUG @@ -4053,19 +3988,16 @@ var LibraryOpenAL = { }, alBufferi__proxy: 'sync', - alBufferi__sig: 'viii', alBufferi: function(bufferId, param, value) { AL.setBufferParam('alBufferi', bufferId, param, null); }, alBuffer3i__proxy: 'sync', - alBuffer3i__sig: 'viiiii', alBuffer3i: function(bufferId, param, value0, value1, value2) { AL.setBufferParam('alBuffer3i', bufferId, param, null); }, alBufferiv__proxy: 'sync', - alBufferiv__sig: 'viip', alBufferiv: function(bufferId, param, pValues) { if (!AL.currentCtx) { #if OPENAL_DEBUG @@ -4098,7 +4030,6 @@ var LibraryOpenAL = { // ------------------------------------------------------- alIsSource__proxy: 'sync', - alIsSource__sig: 'ii', alIsSource: function(sourceId) { if (!AL.currentCtx) { return false; @@ -4111,7 +4042,6 @@ var LibraryOpenAL = { }, alSourceQueueBuffers__proxy: 'sync', - alSourceQueueBuffers__sig: 'viip', alSourceQueueBuffers: function(sourceId, count, pBufferIds) { if (!AL.currentCtx) { #if OPENAL_DEBUG @@ -4195,7 +4125,6 @@ var LibraryOpenAL = { }, alSourceUnqueueBuffers__proxy: 'sync', - alSourceUnqueueBuffers__sig: 'viip', alSourceUnqueueBuffers: function(sourceId, count, pBufferIds) { if (!AL.currentCtx) { #if OPENAL_DEBUG @@ -4238,7 +4167,6 @@ var LibraryOpenAL = { }, alSourcePlay__proxy: 'sync', - alSourcePlay__sig: 'vi', alSourcePlay: function(sourceId) { if (!AL.currentCtx) { #if OPENAL_DEBUG @@ -4258,7 +4186,6 @@ var LibraryOpenAL = { }, alSourcePlayv__proxy: 'sync', - alSourcePlayv__sig: 'vip', alSourcePlayv: function(count, pSourceIds) { if (!AL.currentCtx) { #if OPENAL_DEBUG @@ -4289,7 +4216,6 @@ var LibraryOpenAL = { }, alSourceStop__proxy: 'sync', - alSourceStop__sig: 'vi', alSourceStop: function(sourceId) { if (!AL.currentCtx) { #if OPENAL_DEBUG @@ -4309,7 +4235,6 @@ var LibraryOpenAL = { }, alSourceStopv__proxy: 'sync', - alSourceStopv__sig: 'vip', alSourceStopv: function(count, pSourceIds) { if (!AL.currentCtx) { #if OPENAL_DEBUG @@ -4340,7 +4265,6 @@ var LibraryOpenAL = { }, alSourceRewind__proxy: 'sync', - alSourceRewind__sig: 'vi', alSourceRewind: function(sourceId) { if (!AL.currentCtx) { #if OPENAL_DEBUG @@ -4363,7 +4287,6 @@ var LibraryOpenAL = { }, alSourceRewindv__proxy: 'sync', - alSourceRewindv__sig: 'vip', alSourceRewindv: function(count, pSourceIds) { if (!AL.currentCtx) { #if OPENAL_DEBUG @@ -4394,7 +4317,6 @@ var LibraryOpenAL = { }, alSourcePause__proxy: 'sync', - alSourcePause__sig: 'vi', alSourcePause: function(sourceId) { if (!AL.currentCtx) { #if OPENAL_DEBUG @@ -4414,7 +4336,6 @@ var LibraryOpenAL = { }, alSourcePausev__proxy: 'sync', - alSourcePausev__sig: 'vip', alSourcePausev: function(count, pSourceIds) { if (!AL.currentCtx) { #if OPENAL_DEBUG @@ -4445,7 +4366,6 @@ var LibraryOpenAL = { }, alGetSourcef__proxy: 'sync', - alGetSourcef__sig: 'viip', alGetSourcef: function(sourceId, param, pValue) { var val = AL.getSourceParam('alGetSourcef', sourceId, param); if (val === null) { @@ -4486,7 +4406,6 @@ var LibraryOpenAL = { }, alGetSource3f__proxy: 'sync', - alGetSource3f__sig: 'viippp', alGetSource3f: function(sourceId, param, pValue0, pValue1, pValue2) { var val = AL.getSourceParam('alGetSource3f', sourceId, param); if (val === null) { @@ -4518,7 +4437,6 @@ var LibraryOpenAL = { }, alGetSourcefv__proxy: 'sync', - alGetSourcefv__sig: 'viip', alGetSourcefv: function(sourceId, param, pValues) { var val = AL.getSourceParam('alGetSourcefv', sourceId, param); if (val === null) { @@ -4566,7 +4484,6 @@ var LibraryOpenAL = { }, alGetSourcei__proxy: 'sync', - alGetSourcei__sig: 'viip', alGetSourcei: function(sourceId, param, pValue) { var val = AL.getSourceParam('alGetSourcei', sourceId, param); if (val === null) { @@ -4612,7 +4529,6 @@ var LibraryOpenAL = { }, alGetSource3i__proxy: 'sync', - alGetSource3i__sig: 'viippp', alGetSource3i: function(sourceId, param, pValue0, pValue1, pValue2) { var val = AL.getSourceParam('alGetSource3i', sourceId, param); if (val === null) { @@ -4644,7 +4560,6 @@ var LibraryOpenAL = { }, alGetSourceiv__proxy: 'sync', - alGetSourceiv__sig: 'viip', alGetSourceiv: function(sourceId, param, pValues) { var val = AL.getSourceParam('alGetSourceiv', sourceId, param); if (val === null) { @@ -4697,7 +4612,6 @@ var LibraryOpenAL = { }, alSourcef__proxy: 'sync', - alSourcef__sig: 'viif', alSourcef: function(sourceId, param, value) { switch (param) { case 0x1001 /* AL_CONE_INNER_ANGLE */: @@ -4723,7 +4637,6 @@ var LibraryOpenAL = { }, alSource3f__proxy: 'sync', - alSource3f__sig: 'viifff', alSource3f: function(sourceId, param, value0, value1, value2) { switch (param) { case {{{ cDefs.AL_POSITION }}}: @@ -4741,7 +4654,6 @@ var LibraryOpenAL = { }, alSourcefv__proxy: 'sync', - alSourcefv__sig: 'viip', alSourcefv: function(sourceId, param, pValues) { if (!AL.currentCtx) { #if OPENAL_DEBUG @@ -4790,7 +4702,6 @@ var LibraryOpenAL = { }, alSourcei__proxy: 'sync', - alSourcei__sig: 'viii', alSourcei: function(sourceId, param, value) { switch (param) { case 0x202 /* AL_SOURCE_RELATIVE */: @@ -4817,7 +4728,6 @@ var LibraryOpenAL = { }, alSource3i__proxy: 'sync', - alSource3i__sig: 'viiiii', alSource3i: function(sourceId, param, value0, value1, value2) { switch (param) { case {{{ cDefs.AL_POSITION }}}: @@ -4835,7 +4745,6 @@ var LibraryOpenAL = { }, alSourceiv__proxy: 'sync', - alSourceiv__sig: 'viip', alSourceiv: function(sourceId, param, pValues) { if (!AL.currentCtx) { #if OPENAL_DEBUG diff --git a/src/library_promise.js b/src/library_promise.js index 4ef9fed97d216..1ee467c88efb2 100644 --- a/src/library_promise.js +++ b/src/library_promise.js @@ -28,13 +28,11 @@ mergeInto(LibraryManager.library, { }, emscripten_promise_create__deps: ['$makePromise'], - emscripten_promise_create__sig: 'p', emscripten_promise_create: function() { return makePromise().id; }, emscripten_promise_destroy__deps: ['$promiseMap'], - emscripten_promise_destroy__sig: 'vp', emscripten_promise_destroy: function(id) { #if RUNTIME_DEBUG dbg('emscripten_promise_destroy: ' + id); @@ -45,7 +43,6 @@ mergeInto(LibraryManager.library, { emscripten_promise_resolve__deps: ['$promiseMap', '$getPromise', 'emscripten_promise_destroy'], - emscripten_promise_resolve__sig: 'vpip', emscripten_promise_resolve: function(id, result, value) { #if RUNTIME_DEBUG dbg('emscripten_promise_resolve: ' + id); @@ -130,7 +127,6 @@ mergeInto(LibraryManager.library, { emscripten_promise_then__deps: ['$promiseMap', '$getPromise', '$makePromiseCallback'], - emscripten_promise_then__sig: 'ppppp', emscripten_promise_then: function(id, onFulfilled, onRejected, @@ -151,7 +147,6 @@ mergeInto(LibraryManager.library, { }, emscripten_promise_all__deps: ['$promiseMap', '$getPromise'], - emscripten_promise_all__sig: 'pppp', emscripten_promise_all: function(idBuf, resultBuf, size) { var promises = []; for (var i = 0; i < size; i++) { diff --git a/src/library_sdl.js b/src/library_sdl.js index 59271962490e5..6a0b1a0c6887c 100644 --- a/src/library_sdl.js +++ b/src/library_sdl.js @@ -1337,7 +1337,6 @@ var LibrarySDL = { }, SDL_Linked_Version__proxy: 'sync', - SDL_Linked_Version__sig: 'p', SDL_Linked_Version: function() { if (SDL.version === null) { SDL.version = _malloc({{{ C_STRUCTS.SDL_version.__size__ }}}); @@ -1350,7 +1349,6 @@ var LibrarySDL = { SDL_Init__deps: ['$zeroMemory', 'malloc', 'free', 'memcpy'], SDL_Init__proxy: 'sync', - SDL_Init__sig: 'ii', SDL_Init__docs: '/** @param{number} initFlags */', SDL_Init: function(initFlags) { SDL.startTime = Date.now(); @@ -1398,7 +1396,6 @@ var LibrarySDL = { SDL_WasInit__deps: ['SDL_Init'], SDL_WasInit__proxy: 'sync', - SDL_WasInit__sig: 'ii', SDL_WasInit: function(flags) { if (SDL.startTime === null) { _SDL_Init(0); @@ -1408,7 +1405,6 @@ var LibrarySDL = { SDL_GetVideoInfo__deps: ['$zeroMemory'], SDL_GetVideoInfo__proxy: 'sync', - SDL_GetVideoInfo__sig: 'p', SDL_GetVideoInfo: function() { var ret = _malloc({{{ C_STRUCTS.SDL_VideoInfo.__size__ }}}); zeroMemory(ret, {{{ C_STRUCTS.SDL_version.__size__ }}}); @@ -1433,7 +1429,6 @@ var LibrarySDL = { }, SDL_VideoDriverName__proxy: 'sync', - SDL_VideoDriverName__sig: 'ppi', SDL_VideoDriverName: function(buf, max_size) { if (SDL.startTime === null) { return 0; //return NULL @@ -1461,7 +1456,6 @@ var LibrarySDL = { SDL_SetVideoMode__deps: ['$GL'], SDL_SetVideoMode__proxy: 'sync', - SDL_SetVideoMode__sig: 'piiii', SDL_SetVideoMode: function(width, height, depth, flags) { ['touchstart', 'touchend', 'touchmove', 'mousedown', 'mouseup', 'mousemove', 'DOMMouseScroll', 'mousewheel', 'wheel', 'mouseout'].forEach(function(event) { Module['canvas'].addEventListener(event, SDL.receiveEvent, true); @@ -1506,13 +1500,11 @@ var LibrarySDL = { }, SDL_GetVideoSurface__proxy: 'sync', - SDL_GetVideoSurface__sig: 'p', SDL_GetVideoSurface: function() { return SDL.screen; }, SDL_AudioQuit__proxy: 'sync', - SDL_AudioQuit__sig: 'v', SDL_AudioQuit: function() { for (var i = 0; i < SDL.numChannels; ++i) { var chan = /** @type {{ audio: (HTMLMediaElement|undefined) }} */ (SDL.channels[i]); @@ -1542,7 +1534,6 @@ var LibrarySDL = { // Copy data from the canvas backing to a C++-accessible storage SDL_LockSurface__proxy: 'sync', - SDL_LockSurface__sig: 'ip', SDL_LockSurface: function(surf) { var surfData = SDL.surfaces[surf]; @@ -1612,7 +1603,6 @@ var LibrarySDL = { // Copy data from the C++-accessible storage to the canvas backing SDL_UnlockSurface__proxy: 'sync', - SDL_UnlockSurface__sig: 'vp', SDL_UnlockSurface: function(surf) { assert(!SDL.GL); // in GL mode we do not keep around 2D canvases and contexts @@ -1746,7 +1736,6 @@ var LibrarySDL = { #endif SDL_WM_SetCaption__proxy: 'sync', - SDL_WM_SetCaption__sig: 'vpp', SDL_WM_SetCaption: function(title, icon) { if (title && typeof setWindowTitle != 'undefined') { setWindowTitle(UTF8ToString(title)); @@ -1759,7 +1748,6 @@ var LibrarySDL = { }, SDL_GetKeyboardState__proxy: 'sync', - SDL_GetKeyboardState__sig: 'pp', SDL_GetKeyboardState__docs: '/** @param {number} numKeys */', SDL_GetKeyboardState: function(numKeys) { if (numKeys) { @@ -1774,7 +1762,6 @@ var LibrarySDL = { }, SDL_GetKeyName__proxy: 'sync', - SDL_GetKeyName__sig: 'pi', SDL_GetKeyName__deps: ['$allocateUTF8'], SDL_GetKeyName: function(key) { if (!SDL.keyName) { @@ -1784,13 +1771,11 @@ var LibrarySDL = { }, SDL_GetModState__proxy: 'sync', - SDL_GetModState__sig: 'i', SDL_GetModState: function() { return SDL.modState; }, SDL_GetMouseState__proxy: 'sync', - SDL_GetMouseState__sig: 'ipp', SDL_GetMouseState: function(x, y) { if (x) {{{ makeSetValue('x', '0', 'Browser.mouseX', 'i32') }}}; if (y) {{{ makeSetValue('y', '0', 'Browser.mouseY', 'i32') }}}; @@ -1798,7 +1783,6 @@ var LibrarySDL = { }, SDL_WarpMouse__proxy: 'sync', - SDL_WarpMouse__sig: 'vii', SDL_WarpMouse: function(x, y) { return; // TODO: implement this in a non-buggy way. Need to keep relative mouse movements correct after calling this /* @@ -1812,7 +1796,6 @@ var LibrarySDL = { }, SDL_ShowCursor__proxy: 'sync', - SDL_ShowCursor__sig: 'ii', SDL_ShowCursor: function(toggle) { switch (toggle) { case 0: // SDL_DISABLE @@ -1834,7 +1817,6 @@ var LibrarySDL = { }, SDL_GetError__proxy: 'sync', - SDL_GetError__sig: 'p', SDL_GetError__deps: ['$allocateUTF8'], SDL_GetError: function() { if (!SDL.errorMessage) { @@ -1847,13 +1829,11 @@ var LibrarySDL = { SDL_CreateRGBSurface__deps: ['malloc', 'free'], SDL_CreateRGBSurface__proxy: 'sync', - SDL_CreateRGBSurface__sig: 'piiiiiiii', SDL_CreateRGBSurface: function(flags, width, height, depth, rmask, gmask, bmask, amask) { return SDL.makeSurface(width, height, flags, false, 'CreateRGBSurface', rmask, gmask, bmask, amask); }, SDL_CreateRGBSurfaceFrom__proxy: 'sync', - SDL_CreateRGBSurfaceFrom__sig: 'ppiiiiiiii', SDL_CreateRGBSurfaceFrom: function(pixels, width, height, depth, pitch, rmask, gmask, bmask, amask) { var surf = SDL.makeSurface(width, height, 0, false, 'CreateRGBSurfaceFrom', rmask, gmask, bmask, amask); @@ -1883,7 +1863,6 @@ var LibrarySDL = { }, SDL_ConvertSurface__proxy: 'sync', - SDL_ConvertSurface__sig: 'pppi', SDL_ConvertSurface__docs: '/** @param {number} format @param {number} flags */', SDL_ConvertSurface: function(surf, format, flags) { if (format) { @@ -1906,19 +1885,16 @@ var LibrarySDL = { }, SDL_FreeSurface__proxy: 'sync', - SDL_FreeSurface__sig: 'vp', SDL_FreeSurface: function(surf) { if (surf) SDL.freeSurface(surf); }, SDL_UpperBlit__proxy: 'sync', - SDL_UpperBlit__sig: 'ipppp', SDL_UpperBlit: function(src, srcrect, dst, dstrect) { return SDL.blitSurface(src, srcrect, dst, dstrect, false); }, SDL_UpperBlitScaled__proxy: 'sync', - SDL_UpperBlitScaled__sig: 'ipppp', SDL_UpperBlitScaled: function(src, srcrect, dst, dstrect) { return SDL.blitSurface(src, srcrect, dst, dstrect, true); }, @@ -1927,7 +1903,6 @@ var LibrarySDL = { SDL_LowerBlitScaled: 'SDL_UpperBlitScaled', SDL_GetClipRect__proxy: 'sync', - SDL_GetClipRect__sig: 'vpp', SDL_GetClipRect: function(surf, rect) { assert(rect); @@ -1937,7 +1912,6 @@ var LibrarySDL = { }, SDL_SetClipRect__proxy: 'sync', - SDL_SetClipRect__sig: 'ipp', SDL_SetClipRect: function(surf, rect) { var surfData = SDL.surfaces[surf]; @@ -1949,7 +1923,6 @@ var LibrarySDL = { }, SDL_FillRect__proxy: 'sync', - SDL_FillRect__sig: 'ippi', SDL_FillRect: function(surf, rect, color) { var surfData = SDL.surfaces[surf]; assert(!surfData.locked); // but we could unlock and re-lock if we must.. @@ -2014,7 +1987,6 @@ var LibrarySDL = { }, SDL_SetAlpha__proxy: 'sync', - SDL_SetAlpha__sig: 'ipii', SDL_SetAlpha: function(surf, flag, alpha) { var surfData = SDL.surfaces[surf]; surfData.alpha = alpha; @@ -2033,19 +2005,16 @@ var LibrarySDL = { }, SDL_GetTicks__proxy: 'sync', - SDL_GetTicks__sig: 'i', SDL_GetTicks: function() { return (Date.now() - SDL.startTime)|0; }, SDL_PollEvent__proxy: 'sync', - SDL_PollEvent__sig: 'ip', SDL_PollEvent: function(ptr) { return SDL.pollEvent(ptr); }, SDL_PushEvent__proxy: 'sync', - SDL_PushEvent__sig: 'ip', SDL_PushEvent__deps: ['malloc'], SDL_PushEvent: function(ptr) { var copy = _malloc({{{ C_STRUCTS.SDL_KeyboardEvent.__size__ }}}); @@ -2055,7 +2024,6 @@ var LibrarySDL = { }, SDL_PeepEvents__proxy: 'sync', - SDL_PeepEvents__sig: 'ipiiii', SDL_PeepEvents: function(events, requestedEventCount, action, from, to) { switch (action) { case 2: { // SDL_GETEVENT @@ -2087,7 +2055,6 @@ var LibrarySDL = { }, SDL_PumpEvents__proxy: 'sync', - SDL_PumpEvents__sig: 'v', SDL_PumpEvents: function(){ SDL.events.forEach(function(event) { SDL.handleEvent(event); @@ -2098,7 +2065,6 @@ var LibrarySDL = { // Allow recording a callback that will be called for each received event. emscripten_SDL_SetEventHandler__proxy: 'sync', emscripten_SDL_SetEventHandler__deps: ['malloc'], - emscripten_SDL_SetEventHandler__sig: 'vpp', emscripten_SDL_SetEventHandler: function(handler, userdata) { SDL.eventHandler = handler; SDL.eventHandlerContext = userdata; @@ -2108,7 +2074,6 @@ var LibrarySDL = { }, SDL_SetColors__proxy: 'sync', - SDL_SetColors__sig: 'ippii', SDL_SetColors: function(surf, colors, firstColor, nColors) { var surfData = SDL.surfaces[surf]; @@ -2139,7 +2104,6 @@ var LibrarySDL = { }, SDL_MapRGB__proxy: 'sync', - SDL_MapRGB__sig: 'ipiii', SDL_MapRGB: function(fmt, r, g, b) { SDL.checkPixelFormat(fmt); // We assume the machine is little-endian. @@ -2147,7 +2111,6 @@ var LibrarySDL = { }, SDL_MapRGBA__proxy: 'sync', - SDL_MapRGBA__sig: 'ipiiii', SDL_MapRGBA: function(fmt, r, g, b, a) { SDL.checkPixelFormat(fmt); // We assume the machine is little-endian. @@ -2155,7 +2118,6 @@ var LibrarySDL = { }, SDL_GetRGB__proxy: 'sync', - SDL_GetRGB__sig: 'vipppp', SDL_GetRGB: function(pixel, fmt, r, g, b) { SDL.checkPixelFormat(fmt); // We assume the machine is little-endian. @@ -2171,7 +2133,6 @@ var LibrarySDL = { }, SDL_GetRGBA__proxy: 'sync', - SDL_GetRGBA__sig: 'vippppp', SDL_GetRGBA: function(pixel, fmt, r, g, b, a) { SDL.checkPixelFormat(fmt); // We assume the machine is little-endian. @@ -2190,7 +2151,6 @@ var LibrarySDL = { }, SDL_GetAppState__proxy: 'sync', - SDL_GetAppState__sig: 'i', SDL_GetAppState: function() { var state = 0; @@ -2208,7 +2168,6 @@ var LibrarySDL = { SDL_WM_GrabInput: function() {}, SDL_WM_ToggleFullScreen__proxy: 'sync', - SDL_WM_ToggleFullScreen__sig: 'ip', SDL_WM_ToggleFullScreen: function(surf) { if (Browser.exitFullscreen()) { return 1; @@ -2228,7 +2187,6 @@ var LibrarySDL = { IMG_Load_RW__deps: ['SDL_LockSurface', 'SDL_FreeRW', '$PATH_FS', 'malloc'], IMG_Load_RW__proxy: 'sync', - IMG_Load_RW__sig: 'ppi', IMG_Load_RW: function(rwopsID, freeSrc) { try { // stb_image integration support @@ -2380,7 +2338,6 @@ var LibrarySDL = { IMG_Load__deps: ['IMG_Load_RW', 'SDL_RWFromFile'], IMG_Load__proxy: 'sync', - IMG_Load__sig: 'pp', IMG_Load: function(filename){ var rwops = _SDL_RWFromFile(filename, 0); var result = _IMG_Load_RW(rwops, 1); @@ -2395,7 +2352,6 @@ var LibrarySDL = { SDL_OpenAudio__deps: ['$autoResumeAudioContext', '$safeSetTimeout', 'malloc'], SDL_OpenAudio__proxy: 'sync', - SDL_OpenAudio__sig: 'ipp', SDL_OpenAudio: function(desired, obtained) { try { SDL.audio = { @@ -2618,7 +2574,6 @@ var LibrarySDL = { SDL_PauseAudio__proxy: 'sync', SDL_PauseAudio__deps: ['$safeSetTimeout'], - SDL_PauseAudio__sig: 'vi', SDL_PauseAudio: function(pauseOn) { if (!SDL.audio) { return; @@ -2639,7 +2594,6 @@ var LibrarySDL = { SDL_CloseAudio__deps: ['SDL_PauseAudio'], SDL_CloseAudio__proxy: 'sync', - SDL_CloseAudio__sig: 'v', SDL_CloseAudio: function() { if (SDL.audio) { if (SDL.audio.callbackRemover) { @@ -2667,12 +2621,10 @@ var LibrarySDL = { SDL_DestroyCond: function(cond) {}, SDL_StartTextInput__proxy: 'sync', - SDL_StartTextInput__sig: 'v', SDL_StartTextInput: function() { SDL.textInput = true; }, SDL_StopTextInput__proxy: 'sync', - SDL_StopTextInput__sig: 'v', SDL_StopTextInput: function() { SDL.textInput = false; }, @@ -2687,7 +2639,6 @@ var LibrarySDL = { Mix_OpenAudio__deps: ['$autoResumeAudioContext'], Mix_OpenAudio__proxy: 'sync', - Mix_OpenAudio__sig: 'iiiii', Mix_OpenAudio: function(frequency, format, channels, chunksize) { SDL.openAudioContext(); autoResumeAudioContext(SDL.audioContext); @@ -2703,20 +2654,17 @@ var LibrarySDL = { Mix_CloseAudio: 'SDL_CloseAudio', Mix_AllocateChannels__proxy: 'sync', - Mix_AllocateChannels__sig: 'ii', Mix_AllocateChannels: function(num) { SDL.allocateChannels(num); return num; }, Mix_ChannelFinished__proxy: 'sync', - Mix_ChannelFinished__sig: 'vp', Mix_ChannelFinished: function(func) { SDL.channelFinished = func; }, Mix_Volume__proxy: 'sync', - Mix_Volume__sig: 'iii', Mix_Volume: function(channel, volume) { if (channel == -1) { for (var i = 0; i < SDL.numChannels-1; i++) { @@ -2729,7 +2677,6 @@ var LibrarySDL = { // Note: Mix_SetPanning requires WebAudio (file loaded from memory). Mix_SetPanning__proxy: 'sync', - Mix_SetPanning__sig: 'iiii', Mix_SetPanning: function(channel, left, right) { // SDL API uses [0-255], while PannerNode has an (x, y, z) position. @@ -2745,7 +2692,6 @@ var LibrarySDL = { Mix_LoadWAV_RW__deps: ['$PATH_FS', 'fileno'], Mix_LoadWAV_RW__proxy: 'sync', - Mix_LoadWAV_RW__sig: 'ppi', Mix_LoadWAV_RW__docs: '/** @param {number} freesrc */', Mix_LoadWAV_RW: function(rwopsID, freesrc) { var rwops = SDL.rwops[rwopsID]; @@ -2852,7 +2798,6 @@ var LibrarySDL = { Mix_LoadWAV__deps: ['Mix_LoadWAV_RW', 'SDL_RWFromFile', 'SDL_FreeRW'], Mix_LoadWAV__proxy: 'sync', - Mix_LoadWAV__sig: 'pp', Mix_LoadWAV: function(filename) { var rwops = _SDL_RWFromFile(filename, 0); var result = _Mix_LoadWAV_RW(rwops, 0); @@ -2861,7 +2806,6 @@ var LibrarySDL = { }, Mix_QuickLoad_RAW__proxy: 'sync', - Mix_QuickLoad_RAW__sig: 'ppi', Mix_QuickLoad_RAW: function(mem, len) { var audio; var webAudio; @@ -2895,17 +2839,14 @@ var LibrarySDL = { }, Mix_FreeChunk__proxy: 'sync', - Mix_FreeChunk__sig: 'vp', Mix_FreeChunk: function(id) { SDL.audios[id] = null; }, Mix_ReserveChannels__proxy: 'sync', - Mix_ReserveChannels__sig: 'ii', Mix_ReserveChannels: function(num) { SDL.channelMinimumNumber = num; }, Mix_PlayChannelTimed__proxy: 'sync', - Mix_PlayChannelTimed__sig: 'iipii', Mix_PlayChannelTimed: function(channel, id, loops, ticks) { // TODO: handle fixed amount of N loops. Currently loops either 0 or infinite times. assert(ticks == -1); @@ -2964,7 +2905,6 @@ var LibrarySDL = { }, Mix_HaltChannel__proxy: 'sync', - Mix_HaltChannel__sig: 'ii', Mix_HaltChannel: function(channel) { function halt(channel) { var info = /** @type {{ audio: HTMLMediaElement }} */ (SDL.channels[channel]); @@ -2986,7 +2926,6 @@ var LibrarySDL = { Mix_HookMusicFinished__deps: ['Mix_HaltMusic'], Mix_HookMusicFinished__proxy: 'sync', - Mix_HookMusicFinished__sig: 'vp', Mix_HookMusicFinished: function(func) { SDL.hookMusicFinished = func; if (SDL.music.audio) { // ensure the callback will be called, if a music is already playing @@ -2995,7 +2934,6 @@ var LibrarySDL = { }, Mix_VolumeMusic__proxy: 'sync', - Mix_VolumeMusic__sig: 'ii', Mix_VolumeMusic: function(volume) { return SDL.setGetVolume(SDL.music, volume); }, @@ -3005,7 +2943,6 @@ var LibrarySDL = { Mix_LoadMUS__deps: ['Mix_LoadMUS_RW', 'SDL_RWFromFile', 'SDL_FreeRW'], Mix_LoadMUS__proxy: 'sync', - Mix_LoadMUS__sig: 'pp', Mix_LoadMUS: function(filename) { var rwops = _SDL_RWFromFile(filename, 0); var result = _Mix_LoadMUS_RW(rwops, 0); @@ -3017,7 +2954,6 @@ var LibrarySDL = { Mix_PlayMusic__deps: ['Mix_HaltMusic'], Mix_PlayMusic__proxy: 'sync', - Mix_PlayMusic__sig: 'ipi', Mix_PlayMusic: function(id, loops) { // Pause old music if it exists. if (SDL.music.audio) { @@ -3046,21 +2982,18 @@ var LibrarySDL = { }, Mix_PauseMusic__proxy: 'sync', - Mix_PauseMusic__sig: 'v', Mix_PauseMusic: function() { var audio = /** @type {HTMLMediaElement} */ (SDL.music.audio); if (audio) audio.pause(); }, Mix_ResumeMusic__proxy: 'sync', - Mix_ResumeMusic__sig: 'v', Mix_ResumeMusic: function() { var audio = SDL.music.audio; if (audio) audio.play(); }, Mix_HaltMusic__proxy: 'sync', - Mix_HaltMusic__sig: 'i', Mix_HaltMusic: function() { var audio = /** @type {HTMLMediaElement} */ (SDL.music.audio); if (audio) { @@ -3080,7 +3013,6 @@ var LibrarySDL = { Mix_FadeOutMusic: 'Mix_HaltMusic', // XXX ignore fading out effect Mix_PlayingMusic__proxy: 'sync', - Mix_PlayingMusic__sig: 'i', Mix_PlayingMusic: function() { return (SDL.music.audio && !SDL.music.audio.paused) ? 1 : 0; }, @@ -3088,7 +3020,6 @@ var LibrarySDL = { // http://www.libsdl.org/projects/SDL_mixer/docs/SDL_mixer_38.html#SEC38 // "Note: Does not check if the channel has been paused." Mix_Playing__proxy: 'sync', - Mix_Playing__sig: 'ii', Mix_Playing: function(channel) { if (channel === -1) { var count = 0; @@ -3105,7 +3036,6 @@ var LibrarySDL = { }, Mix_Pause__proxy: 'sync', - Mix_Pause__sig: 'vi', Mix_Pause: function(channel) { if (channel === -1) { for (var i = 0; i axis) { @@ -3634,7 +3534,6 @@ var LibrarySDL = { SDL_JoystickGetBall: function(joystick, ball, dxptr, dyptr) { return -1; }, SDL_JoystickGetButton__proxy: 'sync', - SDL_JoystickGetButton__sig: 'ipi', SDL_JoystickGetButton: function(joystick, button) { var gamepad = SDL.getGamepad(joystick - 1); if (gamepad && gamepad.buttons.length > button) { @@ -3644,7 +3543,6 @@ var LibrarySDL = { }, SDL_JoystickClose__proxy: 'sync', - SDL_JoystickClose__sig: 'vp', SDL_JoystickClose: function(joystick) { delete SDL.lastJoystickState[joystick]; }, @@ -3654,7 +3552,6 @@ var LibrarySDL = { SDL_InitSubSystem: function(flags) { return 0 }, SDL_RWFromConstMem__proxy: 'sync', - SDL_RWFromConstMem__sig: 'ppi', SDL_RWFromConstMem: function(mem, size) { var id = SDL.rwops.length; // TODO: recycle ids when they are null SDL.rwops.push({ bytes: mem, count: size }); @@ -3663,7 +3560,6 @@ var LibrarySDL = { SDL_RWFromMem: 'SDL_RWFromConstMem', SDL_RWFromFile__proxy: 'sync', - SDL_RWFromFile__sig: 'ppp', SDL_RWFromFile__docs: '/** @param {number} mode */', SDL_RWFromFile: function(_name, mode) { var id = SDL.rwops.length; // TODO: recycle ids when they are null @@ -3673,7 +3569,6 @@ var LibrarySDL = { }, SDL_FreeRW__proxy: 'sync', - SDL_FreeRW__sig: 'vp', SDL_FreeRW: function(rwopsID) { SDL.rwops[rwopsID] = null; while (SDL.rwops.length > 0 && SDL.rwops[SDL.rwops.length-1] === null) { @@ -3693,7 +3588,6 @@ var LibrarySDL = { SDL_GetAudioDriver: function(index) { return _SDL_GetCurrentAudioDriver() }, SDL_EnableUNICODE__proxy: 'sync', - SDL_EnableUNICODE__sig: 'ii', SDL_EnableUNICODE: function(on) { var ret = SDL.unicode || 0; SDL.unicode = on; @@ -3702,14 +3596,12 @@ var LibrarySDL = { SDL_AddTimer__proxy: 'sync', SDL_AddTimer__deps: ['$safeSetTimeout'], - SDL_AddTimer__sig: 'iipp', SDL_AddTimer: function(interval, callback, param) { return safeSetTimeout( () => {{{ makeDynCall('iii', 'callback') }}}(interval, param), interval); }, SDL_RemoveTimer__proxy: 'sync', - SDL_RemoveTimer__sig: 'ii', SDL_RemoveTimer: function(id) { clearTimeout(id); return true; diff --git a/src/library_sigs.js b/src/library_sigs.js index dc424111eba65..a503df85dcc8c 100644 --- a/src/library_sigs.js +++ b/src/library_sigs.js @@ -908,4 +908,7 @@ sigs = { uuid_variant__sig: 'ip', zoomSurface__sig: 'ppddi', } -mergeInto(LibraryManager.library, sigs); + +// We have to merge with `allowMissing` since this file contains signatures +// for functions that might not exist in all build configurations. +mergeInto(LibraryManager.library, sigs, {allowMissing: true}); diff --git a/src/library_syscall.js b/src/library_syscall.js index e9b69cbd06b99..bc08ecb93aa97 100644 --- a/src/library_syscall.js +++ b/src/library_syscall.js @@ -124,7 +124,6 @@ var SyscallsLibrary = { #endif // SYSCALLS_REQUIRE_FILESYSTEM }, - _mmap_js__sig: 'ipiiippp', _mmap_js__deps: ['$SYSCALLS', #if FILESYSTEM && SYSCALLS_REQUIRE_FILESYSTEM '$FS', @@ -151,7 +150,6 @@ var SyscallsLibrary = { '$FS', #endif ], - _munmap_js__sig: 'ippiiip', _munmap_js: function(addr, len, prot, flags, fd, offset) { #if FILESYSTEM && SYSCALLS_REQUIRE_FILESYSTEM var stream = SYSCALLS.getStreamFromFD(fd); @@ -163,31 +161,26 @@ var SyscallsLibrary = { #endif }, - __syscall_chdir__sig: 'ip', __syscall_chdir: function(path) { path = SYSCALLS.getStr(path); FS.chdir(path); return 0; }, - __syscall_chmod__sig: 'ipi', __syscall_chmod: function(path, mode) { path = SYSCALLS.getStr(path); FS.chmod(path, mode); return 0; }, - __syscall_rmdir__sig: 'ip', __syscall_rmdir: function(path) { path = SYSCALLS.getStr(path); FS.rmdir(path); return 0; }, - __syscall_dup__sig: 'ii', __syscall_dup: function(fd) { var old = SYSCALLS.getStreamFromFD(fd); return FS.createStream(old, 0).fd; }, __syscall_pipe__deps: ['$PIPEFS'], - __syscall_pipe__sig: 'ip', __syscall_pipe: function(fdPtr) { if (fdPtr == 0) { throw new FS.ErrnoError({{{ cDefs.EFAULT }}}); @@ -200,7 +193,6 @@ var SyscallsLibrary = { return 0; }, - __syscall_ioctl__sig: 'iiip', __syscall_ioctl: function(fd, op, varargs) { #if SYSCALLS_REQUIRE_FILESYSTEM == 0 #if SYSCALL_DEBUG @@ -258,7 +250,6 @@ var SyscallsLibrary = { } #endif // SYSCALLS_REQUIRE_FILESYSTEM }, - __syscall_symlink__sig: 'ipp', __syscall_symlink: function(target, linkpath) { target = SYSCALLS.getStr(target); linkpath = SYSCALLS.getStr(linkpath); @@ -328,7 +319,6 @@ var SyscallsLibrary = { return 0; }, __syscall_connect__deps: ['$getSocketFromFD', '$getSocketAddress'], - __syscall_connect__sig: 'iippiii', __syscall_connect: function(fd, addr, addrlen, d1, d2, d3) { var sock = getSocketFromFD(fd); var info = getSocketAddress(addr, addrlen); @@ -353,7 +343,6 @@ var SyscallsLibrary = { return newsock.stream.fd; }, __syscall_bind__deps: ['$getSocketFromFD', '$getSocketAddress'], - __syscall_bind__sig: 'iippiii', __syscall_bind: function(fd, addr, addrlen, d1, d2, d3) { var sock = getSocketFromFD(fd); var info = getSocketAddress(addr, addrlen); @@ -381,7 +370,6 @@ var SyscallsLibrary = { return msg.buffer.byteLength; }, __syscall_sendto__deps: ['$getSocketFromFD', '$getSocketAddress'], - __syscall_sendto__sig: 'iippipp', __syscall_sendto: function(fd, message, length, flags, addr, addr_len) { var sock = getSocketFromFD(fd); var dest = getSocketAddress(addr, addr_len, true); @@ -582,7 +570,6 @@ var SyscallsLibrary = { return total; }, - _msync_js__sig: 'ippiiip', _msync_js: function(addr, len, prot, flags, fd, offset) { SYSCALLS.doMsync(addr, SYSCALLS.getStreamFromFD(fd), len, flags, 0); return 0; @@ -591,7 +578,6 @@ var SyscallsLibrary = { var stream = SYSCALLS.getStreamFromFD(fd); return 0; // we can't do anything synchronously; the in-memory FS is already synced to }, - __syscall_poll__sig: 'ipii', __syscall_poll: function(fds, nfds, timeout) { var nonzero = 0; for (var i = 0; i < nfds; i++) { @@ -612,7 +598,6 @@ var SyscallsLibrary = { } return nonzero; }, - __syscall_getcwd__sig: 'ipp', __syscall_getcwd: function(buf, size) { if (size === 0) return -{{{ cDefs.EINVAL }}}; var cwd = FS.cwd(); @@ -621,7 +606,6 @@ var SyscallsLibrary = { stringToUTF8(cwd, buf, size); return cwdLengthInBytes; }, - __syscall_truncate64__sig: 'ipj', __syscall_truncate64__deps: i53ConversionDeps, __syscall_truncate64: function(path, {{{ defineI64Param('length') }}}) { {{{ receiveI64ParamAsI53('length', -cDefs.EOVERFLOW) }}} @@ -629,24 +613,20 @@ var SyscallsLibrary = { FS.truncate(path, length); return 0; }, - __syscall_ftruncate64__sig: 'iij', __syscall_ftruncate64__deps: i53ConversionDeps, __syscall_ftruncate64: function(fd, {{{ defineI64Param('length') }}}) { {{{ receiveI64ParamAsI53('length', -cDefs.EOVERFLOW) }}} FS.ftruncate(fd, length); return 0; }, - __syscall_stat64__sig: 'ipp', __syscall_stat64: function(path, buf) { path = SYSCALLS.getStr(path); return SYSCALLS.doStat(FS.stat, path, buf); }, - __syscall_lstat64__sig: 'ipp', __syscall_lstat64: function(path, buf) { path = SYSCALLS.getStr(path); return SYSCALLS.doStat(FS.lstat, path, buf); }, - __syscall_fstat64__sig: 'iip', __syscall_fstat64: function(fd, buf) { var stream = SYSCALLS.getStreamFromFD(fd); return SYSCALLS.doStat(FS.stat, stream.path, buf); @@ -655,7 +635,6 @@ var SyscallsLibrary = { FS.fchown(fd, owner, group); return 0; }, - __syscall_getdents64__sig: 'iipp', __syscall_getdents64: function(fd, dirp, count) { var stream = SYSCALLS.getStreamFromFD(fd) if (!stream.getdents) { @@ -704,7 +683,6 @@ var SyscallsLibrary = { return pos; }, __syscall_fcntl64__deps: ['$setErrNo'], - __syscall_fcntl64__sig: 'iiip', __syscall_fcntl64: function(fd, cmd, varargs) { #if SYSCALLS_REQUIRE_FILESYSTEM == 0 #if SYSCALL_DEBUG @@ -766,7 +744,6 @@ var SyscallsLibrary = { #endif // SYSCALLS_REQUIRE_FILESYSTEM }, - __syscall_statfs64__sig: 'ippp', __syscall_statfs64: function(path, size, buf) { path = SYSCALLS.getStr(path); #if ASSERTIONS @@ -796,14 +773,12 @@ var SyscallsLibrary = { __syscall_fadvise64: function(fd, offset, len, advice) { return 0; // your advice is important to us (but we can't use it) }, - __syscall_openat__sig: 'iipip', __syscall_openat: function(dirfd, path, flags, varargs) { path = SYSCALLS.getStr(path); path = SYSCALLS.calculateAt(dirfd, path); var mode = varargs ? SYSCALLS.get() : 0; return FS.open(path, flags, mode).fd; }, - __syscall_mkdirat__sig: 'iipi', __syscall_mkdirat: function(dirfd, path, mode) { #if SYSCALL_DEBUG dbg('warning: untested syscall'); @@ -817,7 +792,6 @@ var SyscallsLibrary = { FS.mkdir(path, mode, 0); return 0; }, - __syscall_mknodat__sig: 'iipii', __syscall_mknodat: function(dirfd, path, mode, dev) { #if SYSCALL_DEBUG dbg('warning: untested syscall'); @@ -837,7 +811,6 @@ var SyscallsLibrary = { FS.mknod(path, mode, dev); return 0; }, - __syscall_fchownat__sig: 'iipiii', __syscall_fchownat: function(dirfd, path, owner, group, flags) { #if SYSCALL_DEBUG dbg('warning: untested syscall'); @@ -852,7 +825,6 @@ var SyscallsLibrary = { (nofollow ? FS.lchown : FS.chown)(path, owner, group); return 0; }, - __syscall_newfstatat__sig: 'iippi', __syscall_newfstatat: function(dirfd, path, buf, flags) { path = SYSCALLS.getStr(path); var nofollow = flags & {{{ cDefs.AT_SYMLINK_NOFOLLOW }}}; @@ -864,7 +836,6 @@ var SyscallsLibrary = { path = SYSCALLS.calculateAt(dirfd, path, allowEmpty); return SYSCALLS.doStat(nofollow ? FS.lstat : FS.stat, path, buf); }, - __syscall_unlinkat__sig: 'iipi', __syscall_unlinkat: function(dirfd, path, flags) { path = SYSCALLS.getStr(path); path = SYSCALLS.calculateAt(dirfd, path); @@ -877,7 +848,6 @@ var SyscallsLibrary = { } return 0; }, - __syscall_renameat__sig: 'iipip', __syscall_renameat: function(olddirfd, oldpath, newdirfd, newpath) { oldpath = SYSCALLS.getStr(oldpath); newpath = SYSCALLS.getStr(newpath); @@ -899,7 +869,6 @@ var SyscallsLibrary = { FS.symlink(target, linkpath); return 0; }, - __syscall_readlinkat__sig: 'iippp', __syscall_readlinkat: function(dirfd, path, buf, bufsize) { path = SYSCALLS.getStr(path); path = SYSCALLS.calculateAt(dirfd, path); @@ -914,7 +883,6 @@ var SyscallsLibrary = { HEAP8[buf+len] = endChar; return len; }, - __syscall_fchmodat__sig: 'iipip', __syscall_fchmodat: function(dirfd, path, mode, varargs) { #if SYSCALL_DEBUG dbg('warning: untested syscall'); @@ -924,7 +892,6 @@ var SyscallsLibrary = { FS.chmod(path, mode); return 0; }, - __syscall_faccessat__sig: 'iipii', __syscall_faccessat: function(dirfd, path, amode, flags) { #if SYSCALL_DEBUG dbg('warning: untested syscall'); @@ -952,7 +919,6 @@ var SyscallsLibrary = { } return 0; }, - __syscall_utimensat__sig: 'iippi', __syscall_utimensat__deps: ['$readI53FromI64'], __syscall_utimensat: function(dirfd, path, times, flags) { path = SYSCALLS.getStr(path); diff --git a/src/library_wasi.js b/src/library_wasi.js index a57b9326bc43b..905613d3bbd11 100644 --- a/src/library_wasi.js +++ b/src/library_wasi.js @@ -16,7 +16,6 @@ var WasiLibrary = { #endif proc_exit__nothrow: true, - proc_exit__sig: 'vi', proc_exit: function(code) { #if MINIMAL_RUNTIME throw 'exit(' + code + ')'; @@ -77,7 +76,6 @@ var WasiLibrary = { environ_sizes_get__deps: ['$getEnvStrings'], environ_sizes_get__nothrow: true, - environ_sizes_get__sig: 'ipp', environ_sizes_get: function(penviron_count, penviron_buf_size) { var strings = getEnvStrings(); {{{ makeSetValue('penviron_count', 0, 'strings.length', SIZE_TYPE) }}}; @@ -91,7 +89,6 @@ var WasiLibrary = { environ_get__deps: ['$getEnvStrings', '$writeAsciiToMemory'], environ_get__nothrow: true, - environ_get__sig: 'ipp', environ_get: function(__environ, environ_buf) { var bufSize = 0; getEnvStrings().forEach(function(string, i) { @@ -107,7 +104,6 @@ var WasiLibrary = { // to main, and the `mainArgs` global does not exist. #if STANDALONE_WASM args_sizes_get__nothrow: true, - args_sizes_get__sig: 'ipp', args_sizes_get: function(pargc, pargv_buf_size) { #if MAIN_READS_PARAMS {{{ makeSetValue('pargc', 0, 'mainArgs.length', SIZE_TYPE) }}}; @@ -123,7 +119,6 @@ var WasiLibrary = { }, args_get__nothrow: true, - args_get__sig: 'ipp', args_get__deps: ['$writeAsciiToMemory'], args_get: function(argv, argv_buf) { #if MAIN_READS_PARAMS @@ -151,7 +146,6 @@ var WasiLibrary = { // this is needed. To get this code to be usable as a JS shim we need to // either wait for BigInt support or to legalize on the client. clock_time_get__nothrow: true, - clock_time_get__sig: 'iijp', clock_time_get__deps: ['emscripten_get_now', '$nowIsMonotonic', '$checkWasiClock'], clock_time_get: function(clk_id, {{{ defineI64Param('ignored_precision') }}}, ptime) { if (!checkWasiClock(clk_id)) { @@ -174,7 +168,6 @@ var WasiLibrary = { }, clock_res_get__nothrow: true, - clock_res_get__sig: 'iip', clock_res_get__deps: ['emscripten_get_now', 'emscripten_get_now_res', '$nowIsMonotonic', '$checkWasiClock'], clock_res_get: function(clk_id, pres) { if (!checkWasiClock(clk_id)) { @@ -267,7 +260,6 @@ var WasiLibrary = { #else fd_write__deps: ['$printChar'], #endif - fd_write__sig: 'iippp', fd_write: function(fd, iov, iovcnt, pnum) { #if SYSCALLS_REQUIRE_FILESYSTEM var stream = SYSCALLS.getStreamFromFD(fd); @@ -294,7 +286,6 @@ var WasiLibrary = { '$doWritev', #endif ].concat(i53ConversionDeps), - fd_pwrite__sig: 'iippjp', fd_pwrite: function(fd, iov, iovcnt, {{{ defineI64Param('offset') }}}, pnum) { #if SYSCALLS_REQUIRE_FILESYSTEM {{{ receiveI64ParamAsI53('offset', cDefs.EOVERFLOW) }}} @@ -309,7 +300,6 @@ var WasiLibrary = { #endif }, - fd_close__sig: 'ii', fd_close: function(fd) { #if SYSCALLS_REQUIRE_FILESYSTEM var stream = SYSCALLS.getStreamFromFD(fd); @@ -329,7 +319,6 @@ var WasiLibrary = { #endif // SYSCALLS_REQUIRE_FILESYSTEM }, - fd_read__sig: 'iippp', #if SYSCALLS_REQUIRE_FILESYSTEM fd_read__deps: ['$doReadv'], #endif @@ -351,7 +340,6 @@ var WasiLibrary = { '$doReadv', #endif ].concat(i53ConversionDeps), - fd_pread__sig: 'iippjp', fd_pread: function(fd, iov, iovcnt, {{{ defineI64Param('offset') }}}, pnum) { #if SYSCALLS_REQUIRE_FILESYSTEM {{{ receiveI64ParamAsI53('offset', cDefs.EOVERFLOW) }}} @@ -366,7 +354,6 @@ var WasiLibrary = { #endif }, - fd_seek__sig: 'iijip', fd_seek__deps: i53ConversionDeps, fd_seek: function(fd, {{{ defineI64Param('offset') }}}, whence, newOffset) { #if SYSCALLS_REQUIRE_FILESYSTEM @@ -381,7 +368,6 @@ var WasiLibrary = { #endif }, - fd_fdstat_get__sig: 'iip', fd_fdstat_get: function(fd, pbuf) { #if SYSCALLS_REQUIRE_FILESYSTEM var stream = SYSCALLS.getStreamFromFD(fd); @@ -402,7 +388,6 @@ var WasiLibrary = { return 0; }, - fd_sync__sig: 'ii', fd_sync: function(fd) { #if SYSCALLS_REQUIRE_FILESYSTEM var stream = SYSCALLS.getStreamFromFD(fd); diff --git a/src/library_webaudio.js b/src/library_webaudio.js index 149699838bb98..d0e6da3075404 100644 --- a/src/library_webaudio.js +++ b/src/library_webaudio.js @@ -95,7 +95,6 @@ let LibraryWebAudio = { return ['suspended', 'running', 'closed', 'interrupted'].indexOf(EmAudio[contextHandle].state); }, - emscripten_destroy_audio_context__sig: 'vi', emscripten_destroy_audio_context: function(contextHandle) { #if ASSERTIONS assert(EmAudio[contextHandle], `Called emscripten_destroy_audio_context() on an already freed context handle ${contextHandle}`); @@ -284,7 +283,6 @@ let LibraryWebAudio = { return typeof AudioWorkletGlobalScope !== 'undefined'; }, - emscripten_audio_worklet_post_function_v__sig: 'vip', emscripten_audio_worklet_post_function_v: function(audioContext, funcPtr) { (audioContext ? EmAudio[audioContext].audioWorklet.bootstrapMessage.port : globalThis['messagePort']).postMessage({'_wsc': funcPtr, 'x': [] }); // "WaSm Call" }, @@ -293,13 +291,11 @@ let LibraryWebAudio = { (audioContext ? EmAudio[audioContext].audioWorklet.bootstrapMessage.port : globalThis['messagePort']).postMessage({'_wsc': funcPtr, 'x': [arg0] }); // "WaSm Call" }, - emscripten_audio_worklet_post_function_vi__sig: 'vipi', emscripten_audio_worklet_post_function_vi__deps: ['$emscripten_audio_worklet_post_function_1'], emscripten_audio_worklet_post_function_vi(audioContext, funcPtr, arg0) { emscripten_audio_worklet_post_function_1(audioContext, funcPtr, arg0) }, - emscripten_audio_worklet_post_function_vd__sig: 'vipd', emscripten_audio_worklet_post_function_vd__deps: ['$emscripten_audio_worklet_post_function_1'], emscripten_audio_worklet_post_function_vd(audioContext, funcPtr, arg0) { emscripten_audio_worklet_post_function_1(audioContext, funcPtr, arg0) @@ -309,13 +305,11 @@ let LibraryWebAudio = { (audioContext ? EmAudio[audioContext].audioWorklet.bootstrapMessage.port : globalThis['messagePort']).postMessage({'_wsc': funcPtr, 'x': [arg0, arg1] }); // "WaSm Call" }, - emscripten_audio_worklet_post_function_vii__sig: 'vipii', emscripten_audio_worklet_post_function_vii__deps: ['$emscripten_audio_worklet_post_function_2'], emscripten_audio_worklet_post_function_vii: function(audioContext, funcPtr, arg0, arg1) { emscripten_audio_worklet_post_function_2(audioContext, funcPtr, arg0, arg1); }, - emscripten_audio_worklet_post_function_vdd__sig: 'vipdd', emscripten_audio_worklet_post_function_vdd__deps: ['$emscripten_audio_worklet_post_function_2'], emscripten_audio_worklet_post_function_vdd: function(audioContext, funcPtr, arg0, arg1) { emscripten_audio_worklet_post_function_2(audioContext, funcPtr, arg0, arg1); @@ -324,19 +318,16 @@ let LibraryWebAudio = { $emscripten_audio_worklet_post_function_3: function(audioContext, funcPtr, arg0, arg1, arg2) { (audioContext ? EmAudio[audioContext].audioWorklet.bootstrapMessage.port : globalThis['messagePort']).postMessage({'_wsc': funcPtr, 'x': [arg0, arg1, arg2] }); // "WaSm Call" }, - emscripten_audio_worklet_post_function_viii__sig: 'vipiii', emscripten_audio_worklet_post_function_viii__deps: ['$emscripten_audio_worklet_post_function_3'], emscripten_audio_worklet_post_function_viii: function(audioContext, funcPtr, arg0, arg1, arg2) { emscripten_audio_worklet_post_function_3(audioContext, funcPtr, arg0, arg1, arg2); }, - emscripten_audio_worklet_post_function_vddd__sig: 'vipddd', emscripten_audio_worklet_post_function_vddd__deps: ['$emscripten_audio_worklet_post_function_3'], emscripten_audio_worklet_post_function_vddd: function(audioContext, funcPtr, arg0, arg1, arg2) { emscripten_audio_worklet_post_function_3(audioContext, funcPtr, arg0, arg1, arg2); }, emscripten_audio_worklet_post_function_sig__deps: ['$readAsmConstArgs'], - emscripten_audio_worklet_post_function_sig__sig: 'vippp', emscripten_audio_worklet_post_function_sig: function(audioContext, funcPtr, sigPtr, varargs) { #if ASSERTIONS assert(audioContext >= 0); diff --git a/src/library_webgl.js b/src/library_webgl.js index 7e7012379fbfc..c2e2066a2a17a 100644 --- a/src/library_webgl.js +++ b/src/library_webgl.js @@ -1141,7 +1141,6 @@ var LibraryGL = { #endif }, - glPixelStorei__sig: 'vii', glPixelStorei: function(pname, param) { if (pname == 0xCF5 /* GL_UNPACK_ALIGNMENT */) { GL.unpackAlignment = param; @@ -1149,7 +1148,6 @@ var LibraryGL = { GLctx.pixelStorei(pname, param); }, - glGetString__sig: 'pi', glGetString__deps: ['$stringToNewUTF8'], glGetString: function(name_) { var ret = GL.stringCache[name_]; @@ -1400,25 +1398,21 @@ var LibraryGL = { } }, - glGetIntegerv__sig: 'vip', glGetIntegerv__deps: ['$emscriptenWebGLGet'], glGetIntegerv: function(name_, p) { emscriptenWebGLGet(name_, p, {{{ cDefs.EM_FUNC_SIG_PARAM_I }}}); }, - glGetFloatv__sig: 'vip', glGetFloatv__deps: ['$emscriptenWebGLGet'], glGetFloatv: function(name_, p) { emscriptenWebGLGet(name_, p, {{{ cDefs.EM_FUNC_SIG_PARAM_F }}}); }, - glGetBooleanv__sig: 'vip', glGetBooleanv__deps: ['$emscriptenWebGLGet'], glGetBooleanv: function(name_, p) { emscriptenWebGLGet(name_, p, {{{ cDefs.EM_FUNC_SIG_PARAM_B }}}); }, - glDeleteTextures__sig: 'vip', glDeleteTextures: function(n, textures) { for (var i = 0; i < n; i++) { var id = {{{ makeGetValue('textures', 'i*4', 'i32') }}}; @@ -1430,7 +1424,6 @@ var LibraryGL = { } }, - glCompressedTexImage2D__sig: 'viiiiiiip', glCompressedTexImage2D: function(target, level, internalFormat, width, height, border, imageSize, data) { #if MAX_WEBGL_VERSION >= 2 if ({{{ isCurrentContextWebGL2() }}}) { // WebGL 2 provides new garbage-free entry points to call to WebGL. Use those always when possible. @@ -1446,7 +1439,6 @@ var LibraryGL = { }, - glCompressedTexSubImage2D__sig: 'viiiiiiiip', glCompressedTexSubImage2D: function(target, level, xoffset, yoffset, width, height, format, imageSize, data) { #if MAX_WEBGL_VERSION >= 2 if ({{{ isCurrentContextWebGL2() }}}) { // WebGL 2 provides new garbage-free entry points to call to WebGL. Use those always when possible. @@ -1520,7 +1512,6 @@ var LibraryGL = { return heap.subarray(pixels >> shift, pixels + bytes >> shift); }, - glTexImage2D__sig: 'viiiiiiiip', glTexImage2D__deps: ['$emscriptenWebGLGetTexPixelData' #if MAX_WEBGL_VERSION >= 2 , '$heapObjectForWebGLType', '$heapAccessShiftForWebGLHeap' @@ -1562,7 +1553,6 @@ var LibraryGL = { GLctx.texImage2D(target, level, internalFormat, width, height, border, format, type, pixels ? emscriptenWebGLGetTexPixelData(type, format, width, height, pixels, internalFormat) : null); }, - glTexSubImage2D__sig: 'viiiiiiiip', glTexSubImage2D__deps: ['$emscriptenWebGLGetTexPixelData' #if MAX_WEBGL_VERSION >= 2 , '$heapObjectForWebGLType', '$heapAccessShiftForWebGLHeap' @@ -1596,7 +1586,6 @@ var LibraryGL = { GLctx.texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixelData); }, - glReadPixels__sig: 'viiiiiip', glReadPixels__deps: ['$emscriptenWebGLGetTexPixelData' #if MAX_WEBGL_VERSION >= 2 , '$heapObjectForWebGLType', '$heapAccessShiftForWebGLHeap' @@ -1625,7 +1614,6 @@ var LibraryGL = { GLctx.readPixels(x, y, width, height, format, type, pixelData); }, - glBindTexture__sig: 'vii', glBindTexture: function(target, texture) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.textures, texture, 'glBindTexture', 'texture'); @@ -1633,7 +1621,6 @@ var LibraryGL = { GLctx.bindTexture(target, GL.textures[texture]); }, - glGetTexParameterfv__sig: 'viip', glGetTexParameterfv: function(target, pname, params) { if (!params) { // GLES2 specification does not specify how to behave if params is a null pointer. Since calling this function does not make sense @@ -1647,7 +1634,6 @@ var LibraryGL = { {{{ makeSetValue('params', '0', 'GLctx.getTexParameter(target, pname)', 'float') }}}; }, - glGetTexParameteriv__sig: 'viip', glGetTexParameteriv: function(target, pname, params) { if (!params) { // GLES2 specification does not specify how to behave if params is a null pointer. Since calling this function does not make sense @@ -1661,19 +1647,16 @@ var LibraryGL = { {{{ makeSetValue('params', '0', 'GLctx.getTexParameter(target, pname)', 'i32') }}}; }, - glTexParameterfv__sig: 'viip', glTexParameterfv: function(target, pname, params) { var param = {{{ makeGetValue('params', '0', 'float') }}}; GLctx.texParameterf(target, pname, param); }, - glTexParameteriv__sig: 'viip', glTexParameteriv: function(target, pname, params) { var param = {{{ makeGetValue('params', '0', 'i32') }}}; GLctx.texParameteri(target, pname, param); }, - glIsTexture__sig: 'ii', glIsTexture: function(id) { var texture = GL.textures[id]; if (!texture) return 0; @@ -1706,7 +1689,6 @@ var LibraryGL = { }, glGenBuffers__deps: ['$__glGenObject'], - glGenBuffers__sig: 'vip', glGenBuffers: function(n, buffers) { __glGenObject(n, buffers, 'createBuffer', GL.buffers #if GL_ASSERTIONS @@ -1716,7 +1698,6 @@ var LibraryGL = { }, glGenTextures__deps: ['$__glGenObject'], - glGenTextures__sig: 'vip', glGenTextures: function(n, textures) { __glGenObject(n, textures, 'createTexture', GL.textures #if GL_ASSERTIONS @@ -1725,7 +1706,6 @@ var LibraryGL = { ); }, - glDeleteBuffers__sig: 'vip', glDeleteBuffers: function(n, buffers) { for (var i = 0; i < n; i++) { var id = {{{ makeGetValue('buffers', 'i*4', 'i32') }}}; @@ -1750,7 +1730,6 @@ var LibraryGL = { } }, - glGetBufferParameteriv__sig: 'viip', glGetBufferParameteriv: function(target, value, data) { if (!data) { // GLES2 specification does not specify how to behave if data is a null pointer. Since calling this function does not make sense @@ -1764,7 +1743,6 @@ var LibraryGL = { {{{ makeSetValue('data', '0', 'GLctx.getBufferParameter(target, value)', 'i32') }}}; }, - glBufferData__sig: 'vippi', glBufferData: function(target, size, data, usage) { #if LEGACY_GL_EMULATION switch (usage) { // fix usages, WebGL 1 only has *_DRAW @@ -1803,7 +1781,6 @@ var LibraryGL = { #endif }, - glBufferSubData__sig: 'vippp', glBufferSubData: function(target, offset, size, data) { #if MAX_WEBGL_VERSION >= 2 if ({{{ isCurrentContextWebGL2() }}}) { // WebGL 2 provides new garbage-free entry points to call to WebGL. Use those always when possible. @@ -1954,14 +1931,12 @@ var LibraryGL = { }, glGetQueryObjectui64vEXT: 'glGetQueryObjecti64vEXT', - glIsBuffer__sig: 'ii', glIsBuffer: function(buffer) { var b = GL.buffers[buffer]; if (!b) return 0; return GLctx.isBuffer(b); }, - glGenRenderbuffers__sig: 'vip', glGenRenderbuffers__deps: ['$__glGenObject'], glGenRenderbuffers: function(n, renderbuffers) { __glGenObject(n, renderbuffers, 'createRenderbuffer', GL.renderbuffers @@ -1971,7 +1946,6 @@ var LibraryGL = { ); }, - glDeleteRenderbuffers__sig: 'vip', glDeleteRenderbuffers: function(n, renderbuffers) { for (var i = 0; i < n; i++) { var id = {{{ makeGetValue('renderbuffers', 'i*4', 'i32') }}}; @@ -1983,7 +1957,6 @@ var LibraryGL = { } }, - glBindRenderbuffer__sig: 'vii', glBindRenderbuffer: function(target, renderbuffer) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.renderbuffers, renderbuffer, 'glBindRenderbuffer', 'renderbuffer'); @@ -1991,7 +1964,6 @@ var LibraryGL = { GLctx.bindRenderbuffer(target, GL.renderbuffers[renderbuffer]); }, - glGetRenderbufferParameteriv__sig: 'viip', glGetRenderbufferParameteriv: function(target, pname, params) { if (!params) { // GLES2 specification does not specify how to behave if params is a null pointer. Since calling this function does not make sense @@ -2005,7 +1977,6 @@ var LibraryGL = { {{{ makeSetValue('params', '0', 'GLctx.getRenderbufferParameter(target, pname)', 'i32') }}}; }, - glIsRenderbuffer__sig: 'ii', glIsRenderbuffer: function(renderbuffer) { var rb = GL.renderbuffers[renderbuffer]; if (!rb) return 0; @@ -2052,13 +2023,11 @@ var LibraryGL = { } }, - glGetUniformfv__sig: 'viip', glGetUniformfv__deps: ['$emscriptenWebGLGetUniform'], glGetUniformfv: function(program, location, params) { emscriptenWebGLGetUniform(program, location, params, {{{ cDefs.EM_FUNC_SIG_PARAM_F }}}); }, - glGetUniformiv__sig: 'viip', glGetUniformiv__deps: ['$emscriptenWebGLGetUniform'], glGetUniformiv: function(program, location, params) { emscriptenWebGLGetUniform(program, location, params, {{{ cDefs.EM_FUNC_SIG_PARAM_I }}}); @@ -2150,7 +2119,6 @@ var LibraryGL = { return name.slice(-1) == ']' && name.lastIndexOf('['); }, - glGetUniformLocation__sig: 'iip', glGetUniformLocation__deps: ['$jstoi_q', '$webglPrepareUniformLocationsBeforeFirstUse', '$webglGetLeftBracePos'], glGetUniformLocation: function(program, name) { @@ -2249,7 +2217,6 @@ var LibraryGL = { } }, - glGetVertexAttribfv__sig: 'viip', glGetVertexAttribfv__deps: ['$emscriptenWebGLGetVertexAttrib'], glGetVertexAttribfv: function(index, pname, params) { // N.B. This function may only be called if the vertex attribute was specified using the function glVertexAttrib*f(), @@ -2257,7 +2224,6 @@ var LibraryGL = { emscriptenWebGLGetVertexAttrib(index, pname, params, {{{ cDefs.EM_FUNC_SIG_PARAM_F }}}); }, - glGetVertexAttribiv__sig: 'viip', glGetVertexAttribiv__deps: ['$emscriptenWebGLGetVertexAttrib'], glGetVertexAttribiv: function(index, pname, params) { // N.B. This function may only be called if the vertex attribute was specified using the function glVertexAttrib*f(), @@ -2265,7 +2231,6 @@ var LibraryGL = { emscriptenWebGLGetVertexAttrib(index, pname, params, {{{ cDefs.EM_FUNC_SIG_PARAM_F2I }}}); }, - glGetVertexAttribPointerv__sig: 'viip', glGetVertexAttribPointerv: function(index, pname, pointer) { if (!pointer) { // GLES2 specification does not specify how to behave if pointer is a null pointer. Since calling this function does not make sense @@ -2284,7 +2249,6 @@ var LibraryGL = { {{{ makeSetValue('pointer', '0', 'GLctx.getVertexAttribOffset(index, pname)', 'i32') }}}; }, - glUniform1f__sig: 'vif', glUniform1f__deps: ['$webglGetUniformLocation'], glUniform1f: function(location, v0) { #if GL_ASSERTIONS @@ -2293,7 +2257,6 @@ var LibraryGL = { GLctx.uniform1f(webglGetUniformLocation(location), v0); }, - glUniform2f__sig: 'viff', glUniform2f__deps: ['$webglGetUniformLocation'], glUniform2f: function(location, v0, v1) { #if GL_ASSERTIONS @@ -2302,7 +2265,6 @@ var LibraryGL = { GLctx.uniform2f(webglGetUniformLocation(location), v0, v1); }, - glUniform3f__sig: 'vifff', glUniform3f__deps: ['$webglGetUniformLocation'], glUniform3f: function(location, v0, v1, v2) { #if GL_ASSERTIONS @@ -2311,7 +2273,6 @@ var LibraryGL = { GLctx.uniform3f(webglGetUniformLocation(location), v0, v1, v2); }, - glUniform4f__sig: 'viffff', glUniform4f__deps: ['$webglGetUniformLocation'], glUniform4f: function(location, v0, v1, v2, v3) { #if GL_ASSERTIONS @@ -2320,7 +2281,6 @@ var LibraryGL = { GLctx.uniform4f(webglGetUniformLocation(location), v0, v1, v2, v3); }, - glUniform1i__sig: 'vii', glUniform1i__deps: ['$webglGetUniformLocation'], glUniform1i: function(location, v0) { #if GL_ASSERTIONS @@ -2329,7 +2289,6 @@ var LibraryGL = { GLctx.uniform1i(webglGetUniformLocation(location), v0); }, - glUniform2i__sig: 'viii', glUniform2i__deps: ['$webglGetUniformLocation'], glUniform2i: function(location, v0, v1) { #if GL_ASSERTIONS @@ -2338,7 +2297,6 @@ var LibraryGL = { GLctx.uniform2i(webglGetUniformLocation(location), v0, v1); }, - glUniform3i__sig: 'viiii', glUniform3i__deps: ['$webglGetUniformLocation'], glUniform3i: function(location, v0, v1, v2) { #if GL_ASSERTIONS @@ -2347,7 +2305,6 @@ var LibraryGL = { GLctx.uniform3i(webglGetUniformLocation(location), v0, v1, v2); }, - glUniform4i__sig: 'viiiii', glUniform4i__deps: ['$webglGetUniformLocation'], glUniform4i: function(location, v0, v1, v2, v3) { #if GL_ASSERTIONS @@ -2356,7 +2313,6 @@ var LibraryGL = { GLctx.uniform4i(webglGetUniformLocation(location), v0, v1, v2, v3); }, - glUniform1iv__sig: 'viip', glUniform1iv__deps: ['$webglGetUniformLocation' #if GL_POOL_TEMP_BUFFERS && MIN_WEBGL_VERSION == 1 , '$miniTempWebGLIntBuffers' @@ -2401,7 +2357,6 @@ var LibraryGL = { #endif // MIN_WEBGL_VERSION >= 2 }, - glUniform2iv__sig: 'viip', glUniform2iv__deps: ['$webglGetUniformLocation' #if GL_POOL_TEMP_BUFFERS && MIN_WEBGL_VERSION == 1 , '$miniTempWebGLIntBuffers' @@ -2447,7 +2402,6 @@ var LibraryGL = { #endif // MIN_WEBGL_VERSION >= 2 }, - glUniform3iv__sig: 'viip', glUniform3iv__deps: ['$webglGetUniformLocation' #if GL_POOL_TEMP_BUFFERS && MIN_WEBGL_VERSION == 1 , '$miniTempWebGLIntBuffers' @@ -2494,7 +2448,6 @@ var LibraryGL = { #endif // MIN_WEBGL_VERSION >= 2 }, - glUniform4iv__sig: 'viip', glUniform4iv__deps: ['$webglGetUniformLocation' #if GL_POOL_TEMP_BUFFERS && MIN_WEBGL_VERSION == 1 , '$miniTempWebGLIntBuffers' @@ -2542,7 +2495,6 @@ var LibraryGL = { #endif // MIN_WEBGL_VERSION >= 2 }, - glUniform1fv__sig: 'viip', glUniform1fv__deps: ['$webglGetUniformLocation' #if GL_POOL_TEMP_BUFFERS && MIN_WEBGL_VERSION == 1 , '$miniTempWebGLFloatBuffers' @@ -2587,7 +2539,6 @@ var LibraryGL = { #endif // MIN_WEBGL_VERSION >= 2 }, - glUniform2fv__sig: 'viip', glUniform2fv__deps: ['$webglGetUniformLocation' #if GL_POOL_TEMP_BUFFERS && MIN_WEBGL_VERSION == 1 , '$miniTempWebGLFloatBuffers' @@ -2633,7 +2584,6 @@ var LibraryGL = { #endif // MIN_WEBGL_VERSION >= 2 }, - glUniform3fv__sig: 'viip', glUniform3fv__deps: ['$webglGetUniformLocation' #if GL_POOL_TEMP_BUFFERS && MIN_WEBGL_VERSION == 1 , '$miniTempWebGLFloatBuffers' @@ -2680,7 +2630,6 @@ var LibraryGL = { #endif // MIN_WEBGL_VERSION >= 2 }, - glUniform4fv__sig: 'viip', glUniform4fv__deps: ['$webglGetUniformLocation' #if GL_POOL_TEMP_BUFFERS && MIN_WEBGL_VERSION == 1 , '$miniTempWebGLFloatBuffers' @@ -2732,7 +2681,6 @@ var LibraryGL = { #endif // MIN_WEBGL_VERSION >= 2 }, - glUniformMatrix2fv__sig: 'viiip', glUniformMatrix2fv__deps: ['$webglGetUniformLocation' #if GL_POOL_TEMP_BUFFERS && MIN_WEBGL_VERSION == 1 , '$miniTempWebGLFloatBuffers' @@ -2780,7 +2728,6 @@ var LibraryGL = { #endif // MIN_WEBGL_VERSION >= 2 }, - glUniformMatrix3fv__sig: 'viiip', glUniformMatrix3fv__deps: ['$webglGetUniformLocation' #if GL_POOL_TEMP_BUFFERS && MIN_WEBGL_VERSION == 1 , '$miniTempWebGLFloatBuffers' @@ -2833,7 +2780,6 @@ var LibraryGL = { #endif // MIN_WEBGL_VERSION >= 2 }, - glUniformMatrix4fv__sig: 'viiip', glUniformMatrix4fv__deps: ['$webglGetUniformLocation' #if GL_POOL_TEMP_BUFFERS && MIN_WEBGL_VERSION == 1 , '$miniTempWebGLFloatBuffers' @@ -2897,7 +2843,6 @@ var LibraryGL = { #endif // MIN_WEBGL_VERSION >= 2 }, - glBindBuffer__sig: 'vii', glBindBuffer: function(target, buffer) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.buffers, buffer, 'glBindBuffer', 'buffer'); @@ -2931,7 +2876,6 @@ var LibraryGL = { GLctx.bindBuffer(target, GL.buffers[buffer]); }, - glVertexAttrib1fv__sig: 'vip', glVertexAttrib1fv: function(index, v) { #if GL_ASSERTIONS assert((v & 3) == 0, 'Pointer to float data passed to glVertexAttrib1fv must be aligned to four bytes!'); @@ -2941,7 +2885,6 @@ var LibraryGL = { GLctx.vertexAttrib1f(index, HEAPF32[v>>2]); }, - glVertexAttrib2fv__sig: 'vip', glVertexAttrib2fv: function(index, v) { #if GL_ASSERTIONS assert((v & 3) == 0, 'Pointer to float data passed to glVertexAttrib2fv must be aligned to four bytes!'); @@ -2951,7 +2894,6 @@ var LibraryGL = { GLctx.vertexAttrib2f(index, HEAPF32[v>>2], HEAPF32[v+4>>2]); }, - glVertexAttrib3fv__sig: 'vip', glVertexAttrib3fv: function(index, v) { #if GL_ASSERTIONS assert((v & 3) == 0, 'Pointer to float data passed to glVertexAttrib3fv must be aligned to four bytes!'); @@ -2961,7 +2903,6 @@ var LibraryGL = { GLctx.vertexAttrib3f(index, HEAPF32[v>>2], HEAPF32[v+4>>2], HEAPF32[v+8>>2]); }, - glVertexAttrib4fv__sig: 'vip', glVertexAttrib4fv: function(index, v) { #if GL_ASSERTIONS assert((v & 3) == 0, 'Pointer to float data passed to glVertexAttrib4fv must be aligned to four bytes!'); @@ -2971,7 +2912,6 @@ var LibraryGL = { GLctx.vertexAttrib4f(index, HEAPF32[v>>2], HEAPF32[v+4>>2], HEAPF32[v+8>>2], HEAPF32[v+12>>2]); }, - glGetAttribLocation__sig: 'iip', glGetAttribLocation: function(program, name) { return GLctx.getAttribLocation(GL.programs[program], UTF8ToString(name)); }, @@ -2990,19 +2930,16 @@ var LibraryGL = { } }, - glGetActiveAttrib__sig: 'viiipppp', glGetActiveAttrib__deps: ['$__glGetActiveAttribOrUniform'], glGetActiveAttrib: function(program, index, bufSize, length, size, type, name) { __glGetActiveAttribOrUniform('getActiveAttrib', program, index, bufSize, length, size, type, name); }, - glGetActiveUniform__sig: 'viiipppp', glGetActiveUniform__deps: ['$__glGetActiveAttribOrUniform'], glGetActiveUniform: function(program, index, bufSize, length, size, type, name) { __glGetActiveAttribOrUniform('getActiveUniform', program, index, bufSize, length, size, type, name); }, - glCreateShader__sig: 'ii', glCreateShader: function(shaderType) { var id = GL.getNewId(GL.shaders); GL.shaders[id] = GLctx.createShader(shaderType); @@ -3015,7 +2952,6 @@ var LibraryGL = { return id; }, - glDeleteShader__sig: 'vi', glDeleteShader: function(id) { if (!id) return; var shader = GL.shaders[id]; @@ -3027,7 +2963,6 @@ var LibraryGL = { GL.shaders[id] = null; }, - glGetAttachedShaders__sig: 'viipp', glGetAttachedShaders: function(program, maxCount, count, shaders) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.programs, program, 'glGetAttachedShaders', 'program'); @@ -3047,7 +2982,6 @@ var LibraryGL = { } }, - glShaderSource__sig: 'viipp', #if GL_EXPLICIT_UNIFORM_LOCATION || GL_EXPLICIT_UNIFORM_BINDING glShaderSource__deps: ['$preprocess_c_code', '$remove_cpp_comments_in_shaders', '$jstoi_q', '$find_closing_parens_index'], #endif @@ -3212,7 +3146,6 @@ var LibraryGL = { GLctx.shaderSource(GL.shaders[shader], source); }, - glGetShaderSource__sig: 'viipp', glGetShaderSource: function(shader, bufSize, length, source) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.shaders, shader, 'glGetShaderSource', 'shader'); @@ -3223,7 +3156,6 @@ var LibraryGL = { if (length) {{{ makeSetValue('length', '0', 'numBytesWrittenExclNull', 'i32') }}}; }, - glCompileShader__sig: 'vi', glCompileShader: function(shader) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.shaders, shader, 'glCompileShader', 'shader'); @@ -3235,7 +3167,6 @@ var LibraryGL = { #endif }, - glGetShaderInfoLog__sig: 'viipp', glGetShaderInfoLog: function(shader, maxLength, length, infoLog) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.shaders, shader, 'glGetShaderInfoLog', 'shader'); @@ -3248,7 +3179,6 @@ var LibraryGL = { if (length) {{{ makeSetValue('length', '0', 'numBytesWrittenExclNull', 'i32') }}}; }, - glGetShaderiv__sig: 'viip', glGetShaderiv : function(shader, pname, p) { if (!p) { // GLES2 specification does not specify how to behave if p is a null pointer. Since calling this function does not make sense @@ -3284,7 +3214,6 @@ var LibraryGL = { } }, - glGetProgramiv__sig: 'viip', glGetProgramiv : function(program, pname, p) { if (!p) { // GLES2 specification does not specify how to behave if p is a null pointer. Since calling this function does not make sense @@ -3341,14 +3270,12 @@ var LibraryGL = { } }, - glIsShader__sig: 'ii', glIsShader: function(shader) { var s = GL.shaders[shader]; if (!s) return 0; return GLctx.isShader(s); }, - glCreateProgram__sig: 'i', glCreateProgram: function() { var id = GL.getNewId(GL.programs); var program = GLctx.createProgram(); @@ -3361,7 +3288,6 @@ var LibraryGL = { return id; }, - glDeleteProgram__sig: 'vi', glDeleteProgram: function(id) { if (!id) return; var program = GL.programs[id]; @@ -3374,7 +3300,6 @@ var LibraryGL = { GL.programs[id] = null; }, - glAttachShader__sig: 'vii', glAttachShader: function(program, shader) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.programs, program, 'glAttachShader', 'program'); @@ -3390,7 +3315,6 @@ var LibraryGL = { #endif }, - glDetachShader__sig: 'vii', glDetachShader: function(program, shader) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.programs, program, 'glDetachShader', 'program'); @@ -3399,7 +3323,6 @@ var LibraryGL = { GLctx.detachShader(GL.programs[program], GL.shaders[shader]); }, - glGetShaderPrecisionFormat__sig: 'viipp', glGetShaderPrecisionFormat: function(shaderType, precisionType, range, precision) { var result = GLctx.getShaderPrecisionFormat(shaderType, precisionType); {{{ makeSetValue('range', '0', 'result.rangeMin', 'i32') }}}; @@ -3407,7 +3330,6 @@ var LibraryGL = { {{{ makeSetValue('precision', '0', 'result.precision', 'i32') }}}; }, - glLinkProgram__sig: 'vi', glLinkProgram: function(program) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.programs, program, 'glLinkProgram', 'program'); @@ -3462,7 +3384,6 @@ var LibraryGL = { #endif }, - glGetProgramInfoLog__sig: 'viipp', glGetProgramInfoLog: function(program, maxLength, length, infoLog) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.programs, program, 'glGetProgramInfoLog', 'program'); @@ -3513,7 +3434,6 @@ var LibraryGL = { }, #endif - glUseProgram__sig: 'vi', #if GL_EXPLICIT_UNIFORM_BINDING glUseProgram__deps: ['$webglApplyExplicitProgramBindings'], #endif @@ -3534,7 +3454,6 @@ var LibraryGL = { #endif }, - glValidateProgram__sig: 'vi', glValidateProgram: function(program) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.programs, program, 'glValidateProgram', 'program'); @@ -3542,14 +3461,12 @@ var LibraryGL = { GLctx.validateProgram(GL.programs[program]); }, - glIsProgram__sig: 'ii', glIsProgram: function(program) { program = GL.programs[program]; if (!program) return 0; return GLctx.isProgram(program); }, - glBindAttribLocation__sig: 'viip', glBindAttribLocation: function(program, index, name) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.programs, program, 'glBindAttribLocation', 'program'); @@ -3557,7 +3474,6 @@ var LibraryGL = { GLctx.bindAttribLocation(GL.programs[program], index, UTF8ToString(name)); }, - glBindFramebuffer__sig: 'vii', glBindFramebuffer: function(target, framebuffer) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.framebuffers, framebuffer, 'glBindFramebuffer', 'framebuffer'); @@ -3574,7 +3490,6 @@ var LibraryGL = { }, - glGenFramebuffers__sig: 'vip', glGenFramebuffers__deps: ['$__glGenObject'], glGenFramebuffers: function(n, ids) { __glGenObject(n, ids, 'createFramebuffer', GL.framebuffers @@ -3584,7 +3499,6 @@ var LibraryGL = { ); }, - glDeleteFramebuffers__sig: 'vip', glDeleteFramebuffers: function(n, framebuffers) { for (var i = 0; i < n; ++i) { var id = {{{ makeGetValue('framebuffers', 'i*4', 'i32') }}}; @@ -3596,7 +3510,6 @@ var LibraryGL = { } }, - glFramebufferRenderbuffer__sig: 'viiii', glFramebufferRenderbuffer: function(target, attachment, renderbuffertarget, renderbuffer) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.renderbuffers, renderbuffer, 'glFramebufferRenderbuffer', 'renderbuffer'); @@ -3605,7 +3518,6 @@ var LibraryGL = { GL.renderbuffers[renderbuffer]); }, - glFramebufferTexture2D__sig: 'viiiii', glFramebufferTexture2D: function(target, attachment, textarget, texture, level) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.textures, texture, 'glFramebufferTexture2D', 'texture'); @@ -3614,7 +3526,6 @@ var LibraryGL = { GL.textures[texture], level); }, - glGetFramebufferAttachmentParameteriv__sig: 'viiip', glGetFramebufferAttachmentParameteriv: function(target, attachment, pname, params) { var result = GLctx.getFramebufferAttachmentParameter(target, attachment, pname); if (result instanceof WebGLRenderbuffer || @@ -3624,7 +3535,6 @@ var LibraryGL = { {{{ makeSetValue('params', '0', 'result', 'i32') }}}; }, - glIsFramebuffer__sig: 'ii', glIsFramebuffer: function(framebuffer) { var fb = GL.framebuffers[framebuffer]; if (!fb) return 0; @@ -3636,7 +3546,6 @@ var LibraryGL = { , 'emulGlGenVertexArrays' #endif ], - glGenVertexArrays__sig: 'vip', glGenVertexArrays: function (n, arrays) { #if LEGACY_GL_EMULATION _emulGlGenVertexArrays(n, arrays); @@ -3655,7 +3564,6 @@ var LibraryGL = { #if LEGACY_GL_EMULATION glDeleteVertexArrays__deps: ['emulGlDeleteVertexArrays'], #endif - glDeleteVertexArrays__sig: 'vip', glDeleteVertexArrays: function(n, vaos) { #if LEGACY_GL_EMULATION _emulGlDeleteVertexArrays(n, vaos); @@ -3674,7 +3582,6 @@ var LibraryGL = { #if LEGACY_GL_EMULATION glBindVertexArray__deps: ['emulGlBindVertexArray'], #endif - glBindVertexArray__sig: 'vi', glBindVertexArray: function(vao) { #if LEGACY_GL_EMULATION _emulGlBindVertexArray(vao); @@ -3693,7 +3600,6 @@ var LibraryGL = { #if LEGACY_GL_EMULATION glIsVertexArray__deps: ['emulGlIsVertexArray'], #endif - glIsVertexArray__sig: 'ii', glIsVertexArray: function(array) { #if LEGACY_GL_EMULATION return _emulGlIsVertexArray(array); @@ -3734,7 +3640,6 @@ var LibraryGL = { // GLES2 emulation - glVertexAttribPointer__sig: 'viiiiip', glVertexAttribPointer: function(index, size, type, normalized, stride, ptr) { #if FULL_ES2 var cb = GL.currentContext.clientBuffers[index]; @@ -3761,7 +3666,6 @@ var LibraryGL = { GLctx.vertexAttribPointer(index, size, type, !!normalized, stride, ptr); }, - glEnableVertexAttribArray__sig: 'vi', glEnableVertexAttribArray: function(index) { #if FULL_ES2 var cb = GL.currentContext.clientBuffers[index]; @@ -3773,7 +3677,6 @@ var LibraryGL = { GLctx.enableVertexAttribArray(index); }, - glDisableVertexAttribArray__sig: 'vi', glDisableVertexAttribArray: function(index) { #if FULL_ES2 var cb = GL.currentContext.clientBuffers[index]; @@ -3786,7 +3689,6 @@ var LibraryGL = { }, #if !LEGACY_GL_EMULATION - glDrawArrays__sig: 'viii', glDrawArrays: function(mode, first, count) { #if FULL_ES2 // bind any client-side buffers @@ -3800,7 +3702,6 @@ var LibraryGL = { #endif }, - glDrawElements__sig: 'viiip', glDrawElements: function(mode, count, type, indices) { #if FULL_ES2 var buf; @@ -3831,7 +3732,6 @@ var LibraryGL = { }, #endif // ~#if !LEGACY_GL_EMULATION - glShaderBinary__sig: 'vipipi', glShaderBinary: function(count, shaders, binaryformat, binary, length) { GL.recordError(0x500/*GL_INVALID_ENUM*/); #if GL_ASSERTIONS @@ -3839,12 +3739,10 @@ var LibraryGL = { #endif }, - glReleaseShaderCompiler__sig: 'v', glReleaseShaderCompiler: function() { // NOP (as allowed by GLES 2.0 spec) }, - glGetError__sig: 'i', glGetError: function() { #if GL_TRACK_ERRORS var error = GLctx.getError() || GL.lastError; @@ -3857,7 +3755,6 @@ var LibraryGL = { // ANGLE_instanced_arrays WebGL extension related functions (in core in WebGL 2) - glVertexAttribDivisor__sig: 'vii', glVertexAttribDivisor: function(index, divisor) { #if GL_ASSERTIONS assert(GLctx['vertexAttribDivisor'], 'Must have ANGLE_instanced_arrays extension or WebGL 2 to use WebGL instancing'); @@ -3865,7 +3762,6 @@ var LibraryGL = { GLctx['vertexAttribDivisor'](index, divisor); }, - glDrawArraysInstanced__sig: 'viiii', glDrawArraysInstanced: function(mode, first, count, primcount) { #if GL_ASSERTIONS assert(GLctx['drawArraysInstanced'], 'Must have ANGLE_instanced_arrays extension or WebGL 2 to use WebGL instancing'); @@ -3873,7 +3769,6 @@ var LibraryGL = { GLctx['drawArraysInstanced'](mode, first, count, primcount); }, - glDrawElementsInstanced__sig: 'viiipi', glDrawElementsInstanced: function(mode, count, type, indices, primcount) { #if GL_ASSERTIONS assert(GLctx['drawElementsInstanced'], 'Must have ANGLE_instanced_arrays extension or WebGL 2 to use WebGL instancing'); @@ -3898,7 +3793,6 @@ var LibraryGL = { glDrawBuffers__deps: ['$tempFixedLengthArray'], - glDrawBuffers__sig: 'vip', glDrawBuffers: function(n, bufs) { #if GL_ASSERTIONS assert(GLctx['drawBuffers'], 'Must have WebGL2 or WEBGL_draw_buffers extension to use drawBuffers'); @@ -3922,17 +3816,14 @@ var LibraryGL = { // passthrough functions with GLboolean parameters - glColorMask__sig: 'viiii', glColorMask: function(red, green, blue, alpha) { GLctx.colorMask(!!red, !!green, !!blue, !!alpha); }, - glDepthMask__sig: 'vi', glDepthMask: function(flag) { GLctx.depthMask(!!flag); }, - glSampleCoverage__sig: 'vfi', glSampleCoverage: function(value, invert) { GLctx.sampleCoverage(value, !!invert); }, @@ -4030,7 +3921,6 @@ var LibraryGL = { } }, - glMapBufferRange__sig: 'pippi', glMapBufferRange__deps: ['$emscriptenWebGLGetBufferBinding', '$emscriptenWebGLValidateMapBufferTarget'], glMapBufferRange: function(target, offset, length, access) { if ((access & (0x1/*GL_MAP_READ_BIT*/ | 0x20/*GL_MAP_UNSYNCHRONIZED_BIT*/)) != 0) { @@ -4066,7 +3956,6 @@ var LibraryGL = { return mem; }, - glGetBufferPointerv__sig: 'viip', glGetBufferPointerv__deps: ['$emscriptenWebGLGetBufferBinding'], glGetBufferPointerv: function(target, pname, params) { if (pname == 0x88BD/*GL_BUFFER_MAP_POINTER*/) { @@ -4082,7 +3971,6 @@ var LibraryGL = { } }, - glFlushMappedBufferRange__sig: 'vipp', glFlushMappedBufferRange__deps: ['$emscriptenWebGLGetBufferBinding', '$emscriptenWebGLValidateMapBufferTarget'], glFlushMappedBufferRange: function(target, offset, length) { if (!emscriptenWebGLValidateMapBufferTarget(target)) { @@ -4115,7 +4003,6 @@ var LibraryGL = { HEAPU8.subarray(mapping.mem + offset, mapping.mem + offset + length)); }, - glUnmapBuffer__sig: 'ii', glUnmapBuffer__deps: ['$emscriptenWebGLGetBufferBinding', '$emscriptenWebGLValidateMapBufferTarget'], glUnmapBuffer: function(target) { if (!emscriptenWebGLValidateMapBufferTarget(target)) { @@ -4143,40 +4030,6 @@ var LibraryGL = { return 1; }, #endif - - // signatures of simple pass-through functions, see later - - glActiveTexture__sig: 'vi', - glCheckFramebufferStatus__sig: 'ii', - glRenderbufferStorage__sig: 'viiii', - glClearStencil__sig: 'vi', - glStencilFunc__sig: 'viii', - glLineWidth__sig: 'vf', - glBlendEquation__sig: 'vi', - glBlendEquationSeparate__sig: 'vii', - glVertexAttrib1f__sig: 'vif', - glVertexAttrib2f__sig: 'viff', - glVertexAttrib3f__sig: 'vifff', - glVertexAttrib4f__sig: 'viffff', - glCullFace__sig: 'vi', - glBlendFunc__sig: 'vii', - glBlendFuncSeparate__sig: 'viiii', - glBlendColor__sig: 'vffff', - glPolygonOffset__sig: 'vff', - glStencilOp__sig: 'viii', - glStencilOpSeparate__sig: 'viiii', - glGenerateMipmap__sig: 'vi', - glHint__sig: 'vii', - glViewport__sig: 'viiii', - glDepthFunc__sig: 'vi', - glStencilMask__sig: 'vi', - glStencilMaskSeparate__sig: 'vii', - glClearDepthf__sig: 'vf', - glFinish__sig: 'v', - glFlush__sig: 'v', - glClearColor__sig: 'vffff', - glIsEnabled__sig: 'ii', - glFrontFace__sig: 'vi', }; // Simple pass-through functions. @@ -4218,7 +4071,7 @@ function createGLPassthroughFunctions(lib, funcs) { cName = 'gl' + cName[0].toUpperCase() + cName.substr(1); assert(!(cName in lib), "Cannot reimplement the existing function " + cName); lib[cName] = eval(stub.replace('NAME', name)); - if (!lib[cName + '__sig']) lib[cName + '__sig'] = sig; + assert(lib[cName + '__sig'] || LibraryManager.library[cName + '__sig'], 'missing sig for ' + cName); }); }); } diff --git a/src/library_websocket.js b/src/library_websocket.js index 88f3f77839fff..0817853173d31 100644 --- a/src/library_websocket.js +++ b/src/library_websocket.js @@ -12,7 +12,6 @@ var LibraryWebSocket = { emscripten_websocket_get_ready_state__deps: ['$WS'], emscripten_websocket_get_ready_state__proxy: 'sync', - emscripten_websocket_get_ready_state__sig: 'iip', emscripten_websocket_get_ready_state: function(socketId, readyState) { var socket = WS.sockets[socketId]; if (!socket) { @@ -28,7 +27,6 @@ var LibraryWebSocket = { emscripten_websocket_get_buffered_amount__deps: ['$WS'], emscripten_websocket_get_buffered_amount__proxy: 'sync', - emscripten_websocket_get_buffered_amount__sig: 'iip', emscripten_websocket_get_buffered_amount: function(socketId, bufferedAmount) { var socket = WS.sockets[socketId]; if (!socket) { @@ -44,7 +42,6 @@ var LibraryWebSocket = { emscripten_websocket_get_extensions__deps: ['$WS'], emscripten_websocket_get_extensions__proxy: 'sync', - emscripten_websocket_get_extensions__sig: 'iipi', emscripten_websocket_get_extensions: function(socketId, extensions, extensionsLength) { var socket = WS.sockets[socketId]; if (!socket) { @@ -60,7 +57,6 @@ var LibraryWebSocket = { emscripten_websocket_get_extensions_length__deps: ['$WS'], emscripten_websocket_get_extensions_length__proxy: 'sync', - emscripten_websocket_get_extensions_length__sig: 'iip', emscripten_websocket_get_extensions_length: function(socketId, extensionsLength) { var socket = WS.sockets[socketId]; if (!socket) { @@ -76,7 +72,6 @@ var LibraryWebSocket = { emscripten_websocket_get_protocol__deps: ['$WS'], emscripten_websocket_get_protocol__proxy: 'sync', - emscripten_websocket_get_protocol__sig: 'iipi', emscripten_websocket_get_protocol: function(socketId, protocol, protocolLength) { var socket = WS.sockets[socketId]; if (!socket) { @@ -92,7 +87,6 @@ var LibraryWebSocket = { emscripten_websocket_get_protocol_length__deps: ['$WS'], emscripten_websocket_get_protocol_length__proxy: 'sync', - emscripten_websocket_get_protocol_length__sig: 'iip', emscripten_websocket_get_protocol_length: function(socketId, protocolLength) { var socket = WS.sockets[socketId]; if (!socket) { @@ -108,7 +102,6 @@ var LibraryWebSocket = { emscripten_websocket_get_url__deps: ['$WS'], emscripten_websocket_get_url__proxy: 'sync', - emscripten_websocket_get_url__sig: 'iipi', emscripten_websocket_get_url: function(socketId, url, urlLength) { var socket = WS.sockets[socketId]; if (!socket) { @@ -124,7 +117,6 @@ var LibraryWebSocket = { emscripten_websocket_get_url_length__deps: ['$WS'], emscripten_websocket_get_url_length__proxy: 'sync', - emscripten_websocket_get_url_length__sig: 'iip', emscripten_websocket_get_url_length: function(socketId, urlLength) { var socket = WS.sockets[socketId]; if (!socket) { @@ -140,7 +132,6 @@ var LibraryWebSocket = { emscripten_websocket_set_onopen_callback_on_thread__deps: ['$WS'], emscripten_websocket_set_onopen_callback_on_thread__proxy: 'sync', - emscripten_websocket_set_onopen_callback_on_thread__sig: 'iippp', emscripten_websocket_set_onopen_callback_on_thread: function(socketId, userData, callbackFunc, thread) { // TODO: // if (thread == {{{ cDefs.EM_CALLBACK_THREAD_CONTEXT_CALLING_THREAD }}} || @@ -171,7 +162,6 @@ var LibraryWebSocket = { emscripten_websocket_set_onerror_callback_on_thread__deps: ['$WS'], emscripten_websocket_set_onerror_callback_on_thread__proxy: 'sync', - emscripten_websocket_set_onerror_callback_on_thread__sig: 'iippp', emscripten_websocket_set_onerror_callback_on_thread: function(socketId, userData, callbackFunc, thread) { if (!WS.socketEvent) WS.socketEvent = _malloc(1024); // TODO: sizeof(EmscriptenWebSocketCloseEvent), which is the largest event struct @@ -198,7 +188,6 @@ var LibraryWebSocket = { emscripten_websocket_set_onclose_callback_on_thread__deps: ['$WS'], emscripten_websocket_set_onclose_callback_on_thread__proxy: 'sync', - emscripten_websocket_set_onclose_callback_on_thread__sig: 'iippp', emscripten_websocket_set_onclose_callback_on_thread: function(socketId, userData, callbackFunc, thread) { if (!WS.socketEvent) WS.socketEvent = _malloc(1024); // TODO: sizeof(EmscriptenWebSocketCloseEvent), which is the largest event struct @@ -228,7 +217,6 @@ var LibraryWebSocket = { emscripten_websocket_set_onmessage_callback_on_thread__deps: ['$WS'], emscripten_websocket_set_onmessage_callback_on_thread__proxy: 'sync', - emscripten_websocket_set_onmessage_callback_on_thread__sig: 'iippp', emscripten_websocket_set_onmessage_callback_on_thread: function(socketId, userData, callbackFunc, thread) { if (!WS.socketEvent) WS.socketEvent = _malloc(1024); // TODO: sizeof(EmscriptenWebSocketCloseEvent), which is the largest event struct @@ -283,7 +271,6 @@ var LibraryWebSocket = { emscripten_websocket_new__deps: ['$WS'], emscripten_websocket_new__proxy: 'sync', - emscripten_websocket_new__sig: 'ip', emscripten_websocket_new: function(createAttributes) { if (typeof WebSocket == 'undefined') { #if WEBSOCKET_DEBUG @@ -319,7 +306,6 @@ var LibraryWebSocket = { emscripten_websocket_send_utf8_text__deps: ['$WS'], emscripten_websocket_send_utf8_text__proxy: 'sync', - emscripten_websocket_send_utf8_text__sig: 'iip', emscripten_websocket_send_utf8_text: function(socketId, textData) { var socket = WS.sockets[socketId]; if (!socket) { @@ -343,7 +329,6 @@ var LibraryWebSocket = { emscripten_websocket_send_binary__deps: ['$WS'], emscripten_websocket_send_binary__proxy: 'sync', - emscripten_websocket_send_binary__sig: 'iipi', emscripten_websocket_send_binary: function(socketId, binaryData, dataLength) { var socket = WS.sockets[socketId]; if (!socket) { @@ -375,7 +360,6 @@ var LibraryWebSocket = { emscripten_websocket_close__deps: ['$WS'], emscripten_websocket_close__proxy: 'sync', - emscripten_websocket_close__sig: 'iiip', emscripten_websocket_close: function(socketId, code, reason) { var socket = WS.sockets[socketId]; if (!socket) { @@ -402,7 +386,6 @@ var LibraryWebSocket = { emscripten_websocket_delete__deps: ['$WS'], emscripten_websocket_delete__proxy: 'sync', - emscripten_websocket_delete__sig: 'ii', emscripten_websocket_delete: function(socketId) { var socket = WS.sockets[socketId]; if (!socket) { @@ -421,14 +404,12 @@ var LibraryWebSocket = { }, emscripten_websocket_is_supported__proxy: 'sync', - emscripten_websocket_is_supported__sig: 'i', emscripten_websocket_is_supported: function() { return typeof WebSocket != 'undefined'; }, emscripten_websocket_deinitialize__deps: ['$WS'], emscripten_websocket_deinitialize__proxy: 'sync', - emscripten_websocket_deinitialize__sig: 'v', emscripten_websocket_deinitialize__deps: ['emscripten_websocket_delete'], emscripten_websocket_deinitialize: function() { #if WEBSOCKET_DEBUG diff --git a/src/library_wget.js b/src/library_wget.js index 37ce96522212f..1be95d5b8085b 100644 --- a/src/library_wget.js +++ b/src/library_wget.js @@ -18,7 +18,6 @@ var LibraryWget = { emscripten_async_wget__deps: ['$PATH_FS', '$wget', '$callUserCallback', '$Browser', '$withStackSave', '$allocateUTF8OnStack'], emscripten_async_wget__proxy: 'sync', - emscripten_async_wget__sig: 'vpppp', emscripten_async_wget: function(url, file, onload, onerror) { {{{ runtimeKeepalivePush() }}} @@ -61,7 +60,6 @@ var LibraryWget = { emscripten_async_wget_data__deps: ['$asyncLoad', 'malloc', 'free', '$callUserCallback'], emscripten_async_wget_data__proxy: 'sync', - emscripten_async_wget_data__sig: 'vpppp', emscripten_async_wget_data: function(url, arg, onload, onerror) { {{{ runtimeKeepalivePush() }}} asyncLoad(UTF8ToString(url), function(byteArray) { @@ -84,7 +82,6 @@ var LibraryWget = { emscripten_async_wget2__deps: ['$PATH_FS', '$wget', '$withStackSave', '$allocateUTF8OnStack'], emscripten_async_wget2__proxy: 'sync', - emscripten_async_wget2__sig: 'ipppppppp', emscripten_async_wget2: function(url, file, request, param, arg, onload, onerror, onprogress) { {{{ runtimeKeepalivePush() }}} @@ -163,7 +160,6 @@ var LibraryWget = { emscripten_async_wget2_data__deps: ['$wget', 'malloc', 'free'], emscripten_async_wget2_data__proxy: 'sync', - emscripten_async_wget2_data__sig: 'ippppippp', emscripten_async_wget2_data: function(url, request, param, arg, free, onload, onerror, onprogress) { var _url = UTF8ToString(url); var _request = UTF8ToString(request); @@ -232,7 +228,6 @@ var LibraryWget = { emscripten_async_wget2_abort__deps: ['$wget'], emscripten_async_wget2_abort__proxy: 'sync', - emscripten_async_wget2_abort__sig: 'vi', emscripten_async_wget2_abort: function(handle) { var http = wget.wgetRequests[handle]; if (http) { diff --git a/src/modules.js b/src/modules.js index d41779ce5bbbf..811ab7ddd8c57 100644 --- a/src/modules.js +++ b/src/modules.js @@ -37,9 +37,7 @@ global.LibraryManager = { // Core system libraries (always linked against) let libraries = [ 'library.js', - // TODO(sbc): Start using this auto-generated file instead of the hand - // written signatures in the indivudual libraries. - //'library_sigs.js', + 'library_sigs.js', 'library_int53.js', 'library_ccall.js', 'library_addfunction.js', @@ -242,16 +240,6 @@ global.LibraryManager = { } } } - - for (const ident of Object.keys(this.library)) { - if (isJsLibraryConfigIdentifier(ident)) { - const index = ident.lastIndexOf('__'); - const basename = ident.slice(0, index); - if (!(basename in this.library)) { - error(`Missing library element '${basename}' for library config '${ident}'`); - } - } - } }, }; diff --git a/src/utility.js b/src/utility.js index abd503c43373c..7738f041147a1 100644 --- a/src/utility.js +++ b/src/utility.js @@ -128,6 +128,18 @@ function mergeInto(obj, other, options = null) { } } + if (!options || !options.allowMissing) { + for (const ident of Object.keys(other)) { + if (isJsLibraryConfigIdentifier(ident)) { + const index = ident.lastIndexOf('__'); + const basename = ident.slice(0, index); + if (!(basename in obj) && !(basename in other)) { + error(`Missing library element '${basename}' for library config '${ident}'`); + } + } + } + } + for (const key of Object.keys(other)) { if (key.endsWith('__sig')) { if (obj.hasOwnProperty(key)) { diff --git a/test/test_other.py b/test/test_other.py index 429e344794a11..53833b55b7582 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -11625,7 +11625,7 @@ def test_jslib_bad_config(self): }); ''') err = self.expect_fail([EMCC, test_file('hello_world.c'), '--js-library=lib.js']) - self.assertContained("error: Missing library element 'foo' for library config 'foo__sig'", err) + self.assertContained("lib.js: Missing library element 'foo' for library config 'foo__sig'", err) def test_jslib_ifdef(self): create_file('lib.js', ''' diff --git a/tools/gen_sig_info.py b/tools/gen_sig_info.py index b35ad23706987..6467f7db4b883 100755 --- a/tools/gen_sig_info.py +++ b/tools/gen_sig_info.py @@ -161,11 +161,17 @@ def write_sig_library(filename, sig_info): lines = [ '/* Auto-generated by tools/gen_sig_info.py. DO NOT EDIT. */', '', - 'sigs = {'] + 'sigs = {' + ] for s, sig in sorted(sig_info.items()): lines.append(f" {s}__sig: '{sig}',") - lines.append('}') - lines.append('mergeInto(LibraryManager.library, sigs);') + lines += [ + '}', + '', + '// We have to merge with `allowMissing` since this file contains signatures', + '// for functions that might not exist in all build configurations.', + 'mergeInto(LibraryManager.library, sigs, {allowMissing: true});' + ] utils.write_file(filename, '\n'.join(lines) + '\n') From 6026829bd7f5fc6b6645c2a9c85de96bbbc63675 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 24 Mar 2023 14:33:06 -0700 Subject: [PATCH 0057/1523] Fix node version detection to handle non-numeric patch version. NFC (#19061) For example nightly builds of node report something like: v20.0.0-v8-canary202302081604228b65 --- .circleci/config.yml | 1 + src/shell.js | 2 +- test/test_other.py | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 83147d30b8bd5..f964b520d2973 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -589,6 +589,7 @@ jobs: other.test_gen_struct_info other.test_native_call_before_init other.test_node_unhandled_rejection + other.test_min_node_version other.test_node_emscripten_num_logical_cores core2.test_pthread_create core2.test_i64_invoke_bigint diff --git a/src/shell.js b/src/shell.js index a5cfbc2ce1a8e..0c21ed2b068dd 100644 --- a/src/shell.js +++ b/src/shell.js @@ -182,7 +182,7 @@ if (ENVIRONMENT_IS_NODE) { #if ASSERTIONS var nodeVersion = process.versions.node; var numericVersion = nodeVersion.split('.').slice(0, 3); - numericVersion = (numericVersion[0] * 10000) + (numericVersion[1] * 100) + numericVersion[2] * 1; + numericVersion = (numericVersion[0] * 10000) + (numericVersion[1] * 100) + (numericVersion[2].split('-')[0] * 1); var minVersion = {{{ MIN_NODE_VERSION }}}; if (numericVersion < {{{ MIN_NODE_VERSION }}}) { throw new Error('This emscripten-generated code requires node {{{ formattedMinNodeVersion() }}} (detected v' + nodeVersion + ')'); diff --git a/test/test_other.py b/test/test_other.py index 53833b55b7582..c03713e1aac8e 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -13270,7 +13270,7 @@ def test_min_node_version(self): node_version = shared.check_node_version() node_version = '.'.join(str(x) for x in node_version) self.set_setting('MIN_NODE_VERSION', 210000) - expected = 'This emscripten-generated code requires node v21.0.0 (detected v%s)' % node_version + expected = 'This emscripten-generated code requires node v21.0.0 (detected v%s' % node_version self.do_runf(test_file('hello_world.c'), expected, assert_returncode=NON_ZERO) def test_deprecated_macros(self): From 376c6ffee0b9653695b7e292249e699a4423ad67 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 24 Mar 2023 17:35:04 -0700 Subject: [PATCH 0058/1523] HandleAllocator: Always reserve handle zero. NFC (#19065) Also, set entries to `undefined` rather than using the `delete` operator on the handle array. Apparently using `delete` can lead to holes in the array which can damage perf. Reserving 0 also allows us to simplify the allocate function a little. This actually revealed a hidden bug in test/other/test_dlopen_promise.c. Split out from #19054 --- src/library.js | 19 ++++++++----------- src/library_wasmfs_opfs.js | 3 ++- system/lib/wasmfs/backends/opfs_backend.cpp | 2 +- test/core/test_promise.c | 2 +- test/other/test_dlopen_promise.c | 2 +- 5 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/library.js b/src/library.js index 983d3f7a966a6..c20baaaa511dd 100644 --- a/src/library.js +++ b/src/library.js @@ -3654,30 +3654,27 @@ mergeInto(LibraryManager.library, { $HandleAllocator__docs: '/** @constructor */', $HandleAllocator: function() { - this.allocated = []; + // Reserve slot 0 so that 0 is always and invalid handle + this.allocated = [undefined]; this.freelist = []; this.get = function(id) { #if ASSERTIONS - assert(this.allocated[id] !== undefined); + assert(this.allocated[id] !== undefined, 'invalid handle: ' + id); #endif return this.allocated[id]; }; this.allocate = function(handle) { - let id; - if (this.freelist.length > 0) { - id = this.freelist.pop(); - this.allocated[id] = handle; - } else { - id = this.allocated.length; - this.allocated.push(handle); - } + let id = this.freelist.pop() || this.allocated.length; + this.allocated[id] = handle; return id; }; this.free = function(id) { #if ASSERTIONS assert(this.allocated[id] !== undefined); #endif - delete this.allocated[id]; + // Set the slot to `undefined` rather than using `delete` here since + // apparently arrays with holes in them can be less efficient. + this.allocated[id] = undefined; this.freelist.push(id); }; }, diff --git a/src/library_wasmfs_opfs.js b/src/library_wasmfs_opfs.js index f048a381bf452..bad16a72330bc 100644 --- a/src/library_wasmfs_opfs.js +++ b/src/library_wasmfs_opfs.js @@ -16,7 +16,8 @@ mergeInto(LibraryManager.library, { _wasmfs_opfs_init_root_directory__deps: ['$wasmfsOPFSDirectoryHandles'], _wasmfs_opfs_init_root_directory: async function(ctx) { - if (wasmfsOPFSDirectoryHandles.allocated.length == 0) { + // allocated.length start of as 1 since 0 is a reserved handle + if (wasmfsOPFSDirectoryHandles.allocated.length == 1) { // Directory 0 is reserved as the root let root = await navigator.storage.getDirectory(); wasmfsOPFSDirectoryHandles.allocated.push(root); diff --git a/system/lib/wasmfs/backends/opfs_backend.cpp b/system/lib/wasmfs/backends/opfs_backend.cpp index 1c1dc12db6955..d77d5b1de50ea 100644 --- a/system/lib/wasmfs/backends/opfs_backend.cpp +++ b/system/lib/wasmfs/backends/opfs_backend.cpp @@ -456,7 +456,7 @@ class OPFSBackend : public Backend { std::shared_ptr createDirectory(mode_t mode) override { proxy([](auto ctx) { _wasmfs_opfs_init_root_directory(ctx.ctx); }); - return std::make_shared(mode, this, 0, proxy); + return std::make_shared(mode, this, 1, proxy); } std::shared_ptr createSymlink(std::string target) override { diff --git a/test/core/test_promise.c b/test/core/test_promise.c index 5117cbd36aff4..48d13a00dba66 100644 --- a/test/core/test_promise.c +++ b/test/core/test_promise.c @@ -253,7 +253,7 @@ static em_promise_result_t finish(void** result, void* data, void* value) { // We should not have leaked any handles. EM_ASM({ - promiseMap.allocated.forEach(() => assert(false, "non-destroyed handle")); + promiseMap.allocated.forEach((p) => assert(typeof p === "undefined", "non-destroyed handle")); }); // Cannot exit directly in a promise callback, since it would end up rejecting diff --git a/test/other/test_dlopen_promise.c b/test/other/test_dlopen_promise.c index 77914cb372160..ae368e0f068e6 100644 --- a/test/other/test_dlopen_promise.c +++ b/test/other/test_dlopen_promise.c @@ -22,7 +22,7 @@ em_promise_result_t on_rejected(void **result, void* data, void *value) { int main() { em_promise_t inner = emscripten_dlopen_promise("libside.so", RTLD_NOW); - em_promise_t outer = emscripten_promise_then(outer, on_fullfilled, on_rejected, NULL); + em_promise_t outer = emscripten_promise_then(inner, on_fullfilled, on_rejected, NULL); emscripten_promise_destroy(outer); emscripten_promise_destroy(inner); printf("returning from main\n"); From de7cbc56c3ac38b83cc3e8bbc17ac5fbb6b3bbd7 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 24 Mar 2023 18:39:28 -0700 Subject: [PATCH 0059/1523] Use HandleAllocator for emval handles. NFC (#19054) --- src/embind/emval.js | 62 ++++++++++++++++++--------------------------- 1 file changed, 24 insertions(+), 38 deletions(-) diff --git a/src/embind/emval.js b/src/embind/emval.js index 42f95b54071ac..bf177e3dc634e 100644 --- a/src/embind/emval.js +++ b/src/embind/emval.js @@ -12,49 +12,41 @@ /*jslint sub:true*/ /* The symbols 'fromWireType' and 'toWireType' must be accessed via array notation to be closure-safe since craftInvokerFunction crafts functions as strings that can't be closured. */ // -- jshint doesn't understand library syntax, so we need to mark the symbols exposed here -/*global getStringOrSymbol, emval_handle_array, Emval, __emval_unregister, count_emval_handles, emval_symbols, emval_free_list, get_first_emval, __emval_decref, emval_newers*/ +/*global getStringOrSymbol, emval_handles, Emval, __emval_unregister, count_emval_handles, emval_symbols, __emval_decref, emval_newers*/ /*global craftEmvalAllocator, emval_addMethodCaller, emval_methodCallers, LibraryManager, mergeInto, emval_allocateDestructors, global, emval_lookupTypes, makeLegalFunctionName*/ /*global emval_get_global*/ var LibraryEmVal = { - $emval_handle_array: [ - {}, - {value: undefined}, - {value: null}, - {value: true}, - {value: false} - ], // reserve zero and special values - $emval_free_list: [], + $emval_handles__deps: ['$HandleAllocator'], + $emval_handles: "new HandleAllocator();", $emval_symbols: {}, // address -> string - $init_emval__deps: ['$count_emval_handles', '$get_first_emval'], + $init_emval__deps: ['$count_emval_handles', '$emval_handles'], $init_emval__postset: 'init_emval();', $init_emval: function() { + // reserve some special values. These never get de-allocated. + // The HandleAllocator takes care of reserving zero. + emval_handles.allocated.push( + {value: undefined}, + {value: null}, + {value: true}, + {value: false}, + ); + emval_handles.reserved = emval_handles.allocated.length Module['count_emval_handles'] = count_emval_handles; - Module['get_first_emval'] = get_first_emval; }, - $count_emval_handles__deps: ['$emval_handle_array'], + $count_emval_handles__deps: ['$emval_handles'], $count_emval_handles: function() { var count = 0; - for (var i = 5; i < emval_handle_array.length; ++i) { - if (emval_handle_array[i] !== undefined) { + for (var i = emval_handles.reserved; i < emval_handles.allocated.length; ++i) { + if (emval_handles.allocated[i] !== undefined) { ++count; } } return count; }, - $get_first_emval__deps: ['$emval_handle_array'], - $get_first_emval: function() { - for (var i = 5; i < emval_handle_array.length; ++i) { - if (emval_handle_array[i] !== undefined) { - return emval_handle_array[i]; - } - } - return null; - }, - _emval_register_symbol__deps: ['$emval_symbols', '$readLatin1String'], _emval_register_symbol: function(address) { emval_symbols[address] = readLatin1String(address); @@ -69,13 +61,13 @@ var LibraryEmVal = { return symbol; }, - $Emval__deps: ['$emval_handle_array', '$emval_free_list', '$throwBindingError', '$init_emval'], + $Emval__deps: ['$emval_handles', '$throwBindingError', '$init_emval'], $Emval: { toValue: (handle) => { if (!handle) { throwBindingError('Cannot use deleted val. handle = ' + handle); } - return emval_handle_array[handle].value; + return emval_handles.get(handle).value; }, toHandle: (value) => { @@ -85,31 +77,25 @@ var LibraryEmVal = { case true: return 3; case false: return 4; default:{ - var handle = emval_free_list.length ? - emval_free_list.pop() : - emval_handle_array.length; - - emval_handle_array[handle] = {refcount: 1, value: value}; - return handle; + return emval_handles.allocate({refcount: 1, value: value}); } } } }, _emval_incref__sig: 'vp', - _emval_incref__deps: ['$emval_handle_array'], + _emval_incref__deps: ['$emval_handles'], _emval_incref: function(handle) { if (handle > 4) { - emval_handle_array[handle].refcount += 1; + emval_handles.get(handle).refcount += 1; } }, _emval_decref__sig: 'vp', - _emval_decref__deps: ['$emval_free_list', '$emval_handle_array'], + _emval_decref__deps: ['$emval_handles'], _emval_decref: function(handle) { - if (handle > 4 && 0 === --emval_handle_array[handle].refcount) { - emval_handle_array[handle] = undefined; - emval_free_list.push(handle); + if (handle >= emval_handles.reserved && 0 === --emval_handles.get(handle).refcount) { + emval_handles.free(handle); } }, From 055c6e881299691248b6347c0642baf8a4bae03a Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 27 Mar 2023 07:58:46 -0700 Subject: [PATCH 0060/1523] Fix warning in test code. NFC (#19068) --- test/test_other.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_other.py b/test/test_other.py index c03713e1aac8e..621db8b286773 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -11419,13 +11419,13 @@ def test_deterministic(self): int main () { timespec now; clock_gettime(CLOCK_REALTIME, &now); - printf("C now: %ld %ld\n", now.tv_sec, now.tv_nsec); + printf("C now: %lld %ld\n", now.tv_sec, now.tv_nsec); printf("js now: %f\n", emscripten_get_now()); printf("C randoms: %d %d %d\n", rand(), rand(), rand()); printf("JS random: %d\n", EM_ASM_INT({ return Math.random() })); } ''') - self.run_process([EMXX, 'src.cpp', '-sDETERMINISTIC']) + self.run_process([EMXX, 'src.cpp', '-sDETERMINISTIC'] + self.get_emcc_args()) one = self.run_js('a.out.js') # ensure even if the time resolution is 1 second, that if we see the real # time we'll see a difference From d790be74aa98f9d20a432eddf6f2a39e71817ebc Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 27 Mar 2023 12:24:14 -0700 Subject: [PATCH 0061/1523] Feedback from #19065. NFC (#19078) --- src/library.js | 2 +- src/library_wasmfs_opfs.js | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/library.js b/src/library.js index c20baaaa511dd..c85a3055c4e6b 100644 --- a/src/library.js +++ b/src/library.js @@ -3654,7 +3654,7 @@ mergeInto(LibraryManager.library, { $HandleAllocator__docs: '/** @constructor */', $HandleAllocator: function() { - // Reserve slot 0 so that 0 is always and invalid handle + // Reserve slot 0 so that 0 is always an invalid handle this.allocated = [undefined]; this.freelist = []; this.get = function(id) { diff --git a/src/library_wasmfs_opfs.js b/src/library_wasmfs_opfs.js index bad16a72330bc..26c77bdf8cb2e 100644 --- a/src/library_wasmfs_opfs.js +++ b/src/library_wasmfs_opfs.js @@ -16,9 +16,8 @@ mergeInto(LibraryManager.library, { _wasmfs_opfs_init_root_directory__deps: ['$wasmfsOPFSDirectoryHandles'], _wasmfs_opfs_init_root_directory: async function(ctx) { - // allocated.length start of as 1 since 0 is a reserved handle + // allocated.length starts off as 1 since 0 is a reserved handle if (wasmfsOPFSDirectoryHandles.allocated.length == 1) { - // Directory 0 is reserved as the root let root = await navigator.storage.getDirectory(); wasmfsOPFSDirectoryHandles.allocated.push(root); } From 03b00b7612241325315b72775f837d349dfc4c9c Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 27 Mar 2023 14:25:01 -0700 Subject: [PATCH 0062/1523] Disable test_preload_file_with_manual_data_download_pthreads under firefox (#19081) See #19080 --- test/test_browser.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test_browser.py b/test/test_browser.py index d0d2026155df6..5fb9b1465380d 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -422,6 +422,7 @@ def make_main_two_files(path1, path2, nonexistingpath): 'pthreads': (['-pthread', '-sPROXY_TO_PTHREAD', '-sEXIT_RUNTIME'],), }) @requires_threads + @no_firefox('https://github.com/emscripten-core/emscripten/issues/19080') def test_preload_file_with_manual_data_download(self, args): src = test_file('manual_download_data.cpp') From 8274bc46684f28c9a4f0e95212a345ac2d123285 Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Mon, 27 Mar 2023 15:33:00 -0700 Subject: [PATCH 0063/1523] [WasmFS] Ignore rather than asserting on O_NONBLOCK (#19084) O_NONBLOCK serves two purposes when passed to open. First, it prevents `open` from blocking for a "long time" to open the file. Second, it opens the file in nonblocking I/O mode which allows reads and writes to return error codes if I/O cannot be done without blocking. Ignoring O_NONBLOCK completely is a semantically valid implementation strategy, so for now just stop asserting when it is used. --- system/lib/wasmfs/syscalls.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/system/lib/wasmfs/syscalls.cpp b/system/lib/wasmfs/syscalls.cpp index a9146922ee6c4..9458ecb3710f4 100644 --- a/system/lib/wasmfs/syscalls.cpp +++ b/system/lib/wasmfs/syscalls.cpp @@ -418,9 +418,9 @@ static __wasi_fd_t doOpen(path::ParsedParent parsed, } // TODO: remove assert when all functionality is complete. - assert((flags & - ~(O_CREAT | O_EXCL | O_DIRECTORY | O_TRUNC | O_APPEND | O_RDWR | - O_WRONLY | O_RDONLY | O_LARGEFILE | O_NOFOLLOW | O_CLOEXEC)) == 0); + assert((flags & ~(O_CREAT | O_EXCL | O_DIRECTORY | O_TRUNC | O_APPEND | + O_RDWR | O_WRONLY | O_RDONLY | O_LARGEFILE | O_NOFOLLOW | + O_CLOEXEC | O_NONBLOCK)) == 0); if (auto err = parsed.getError()) { return err; From 30c720a97635c7bbe5f912746c85f2e24c4a3a64 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 27 Mar 2023 15:43:51 -0700 Subject: [PATCH 0064/1523] cmake: Use LINK_DEPENDS for em_link_js_library et al. NFC (#19071) Fixes: #19070 --- cmake/Modules/Platform/Emscripten.cmake | 51 ++++++------------------- test/cmake/target_js/CMakeLists.txt | 20 +++++----- test/cmake/target_js/out.txt | 3 +- 3 files changed, 22 insertions(+), 52 deletions(-) diff --git a/cmake/Modules/Platform/Emscripten.cmake b/cmake/Modules/Platform/Emscripten.cmake index df22f859c2898..0284977bf2648 100644 --- a/cmake/Modules/Platform/Emscripten.cmake +++ b/cmake/Modules/Platform/Emscripten.cmake @@ -306,50 +306,21 @@ function(em_validate_asmjs_after_build target) message(WARNING "em_validate_asmjs_after_build no longer exists") endfunction() -# A global counter to guarantee unique names for js library files. -set(link_js_counter 1) - # Internal function: Do not call from user CMakeLists.txt files. Use one of # em_link_js_library()/em_link_pre_js()/em_link_post_js() instead. -function(em_add_tracked_link_flag target flagname) - +function(em_add_link_deps target flagname) # User can input list of JS files either as a single list, or as variable # arguments to this function, so iterate over varargs, and treat each item in # varargs as a list itself, to support both syntax forms. foreach(jsFileList ${ARGN}) foreach(jsfile ${jsFileList}) - # If the user edits the JS file, we want to relink the emscripten - # application, but unfortunately it is not possible to make a link step - # depend directly on a source file. Instead, we must make a dummy no-op - # build target on that source file, and make the project depend on - # that target. - - # Sanitate the source .js filename to a good symbol name to use as a dummy - # filename. - get_filename_component(jsname "${jsfile}" NAME) - string(REGEX REPLACE "[/:\\\\.\ ]" "_" dummy_js_target ${jsname}) - set(dummy_lib_name ${target}_${link_js_counter}_${dummy_js_target}) - set(dummy_c_name "${CMAKE_BINARY_DIR}/${dummy_js_target}_tracker.c") - - # Create a new static library target that with a single dummy .c file. - add_library(${dummy_lib_name} STATIC ${dummy_c_name}) - # Make the dummy .c file depend on the .js file we are linking, so that if - # the .js file is edited, the dummy .c file, and hence the static library - # will be rebuild (no-op). This causes the main application to be - # relinked, which is what we want. This approach was recommended by - # http://www.cmake.org/pipermail/cmake/2010-May/037206.html - add_custom_command(OUTPUT ${dummy_c_name} COMMAND ${CMAKE_COMMAND} -E touch ${dummy_c_name} DEPENDS ${jsfile}) - target_link_libraries(${target} ${dummy_lib_name}) - - # Link the js-library to the target - # When a linked library starts with a "-" cmake will just add it to the - # linker command line as it is. The advantage of doing it this way is - # that the js-library will also be automatically linked to targets that - # depend on this target. - get_filename_component(js_file_absolute_path "${jsfile}" ABSOLUTE ) - target_link_libraries(${target} "${flagname} \"${js_file_absolute_path}\"") - - math(EXPR link_js_counter "${link_js_counter} + 1") + get_target_property(linkdeps ${target} LINK_DEPENDS) + if(linkdeps STREQUAL "linkdeps-NOTFOUND") + set(linkdeps "") + endif() + get_filename_component(jsfile_abs "${jsfile}" ABSOLUTE ) + set_target_properties(${target} PROPERTIES LINK_DEPENDS "${linkdeps};${jsfile_abs}") + target_link_libraries(${target} "${flagname} \"${jsfile_abs}\"") endforeach() endforeach() endfunction() @@ -361,21 +332,21 @@ endfunction() # between the linked .js files and the main project, so that editing the .js # file will cause the target project to be relinked. function(em_link_js_library target) - em_add_tracked_link_flag(${target} "--js-library" ${ARGN}) + em_add_link_deps(${target} "--js-library" ${ARGN}) endfunction() # This function is identical to em_link_js_library(), except the .js files will # be added with '--pre-js file.js' command line flag, which is generally used to # add some preamble .js code to a generated output file. function(em_link_pre_js target) - em_add_tracked_link_flag(${target} "--pre-js" ${ARGN}) + em_add_link_deps(${target} "--pre-js" ${ARGN}) endfunction() # This function is identical to em_link_js_library(), except the .js files will # be added with '--post-js file.js' command line flag, which is generally used # to add some postamble .js code to a generated output file. function(em_link_post_js target) - em_add_tracked_link_flag(${target} "--post-js" ${ARGN}) + em_add_link_deps(${target} "--post-js" ${ARGN}) endfunction() # Experimental support for targeting generation of Visual Studio project files diff --git a/test/cmake/target_js/CMakeLists.txt b/test/cmake/target_js/CMakeLists.txt index 916b7a40de44d..60a7a41403e06 100644 --- a/test/cmake/target_js/CMakeLists.txt +++ b/test/cmake/target_js/CMakeLists.txt @@ -4,17 +4,11 @@ project(test_cmake) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../cpp_lib ${CMAKE_CURRENT_BINARY_DIR}/cpp_lib) -file(GLOB sourceFiles main.cpp) - -file(GLOB preJsFiles pre*.js) -file(GLOB postJsFiles post*.js) -file(GLOB libraryJsFiles jslibrary*.js) - if (CMAKE_BUILD_TYPE STREQUAL Debug) - set(linkFlags "-g4 -sNO_EXIT_RUNTIME") + set(linkFlags "-g") else() # Either MinSizeRel, RelWithDebInfo or Release, all which run with optimizations enabled. - set(linkFlags "-O2 -sNO_EXIT_RUNTIME") + set(linkFlags "-O2") endif() # Ensure synchronous startup for this test, whose output expects it @@ -82,19 +76,23 @@ if (NOT ${endian_result} EQUAL 0) message(FATAL_ERROR "TEST_BIG_ENDIAN did not return 0!") endif() -add_executable(test_cmake ${sourceFiles}) +add_executable(test_cmake "main.cpp") target_link_libraries( test_cmake cpp_lib) # GOTCHA: If your project has custom link flags, these must be set *before* # calling any of the em_link_xxx functions! set_target_properties(test_cmake PROPERTIES LINK_FLAGS "${linkFlags}") +file(GLOB libraryJsFiles jslibrary*.js) message(STATUS "js libs '${libraryJsFiles}'") # To link .js files using the --js-library flag, use the following helper function. em_link_js_library(test_cmake ${libraryJsFiles}) # To link .js files using the --pre-js flag, use the following helper function. -em_link_pre_js(test_cmake ${preJsFiles}) +em_link_pre_js(test_cmake "prejs.js") + +# Ensure that calling em_link_pre_js multiple times works as expected. +em_link_pre_js(test_cmake "prejs.js") # To link .js files using the --post-js flag, use the following helper function. -em_link_post_js(test_cmake ${postJsFiles}) +em_link_post_js(test_cmake "postjs.js") diff --git a/test/cmake/target_js/out.txt b/test/cmake/target_js/out.txt index 76135df7ce431..07ef7fb43d599 100644 --- a/test/cmake/target_js/out.txt +++ b/test/cmake/target_js/out.txt @@ -1,4 +1,5 @@ prejs executed +prejs executed lib_function lib_function2 -postjs executed \ No newline at end of file +postjs executed From 79a7ca968d35833c89567609ec75aee3ff99cb92 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 27 Mar 2023 15:44:04 -0700 Subject: [PATCH 0065/1523] Make more use of allocateUTF8 helper. NFC (#19064) --- .../docs/api_reference/emscripten.h.rst | 9 ++------- src/library.js | 20 +++++++------------ src/library_browser.js | 6 ++---- src/library_ccall.js | 6 ++---- src/library_html5.js | 10 ++++------ src/library_sdl.js | 6 ++---- src/library_stack_trace.js | 6 ++---- src/library_websocket.js | 7 +++---- src/library_wget.js | 14 ++++++------- 9 files changed, 31 insertions(+), 53 deletions(-) diff --git a/site/source/docs/api_reference/emscripten.h.rst b/site/source/docs/api_reference/emscripten.h.rst index c6a9a950832b0..43d887dead88a 100644 --- a/site/source/docs/api_reference/emscripten.h.rst +++ b/site/source/docs/api_reference/emscripten.h.rst @@ -111,10 +111,7 @@ Defines var jsString = 'Hello with some exotic Unicode characters: Tässä on yksi lumiukko: ☃, ole hyvä.'; // 'jsString.length' would return the length of the string as UTF-16 // units, but Emscripten C strings operate as UTF-8. - var lengthBytes = lengthBytesUTF8(jsString)+1; - var stringOnWasmHeap = _malloc(lengthBytes); - stringToUTF8(jsString, stringOnWasmHeap, lengthBytes); - return stringOnWasmHeap; + return allocateUTF8(jsString); }); int main() { @@ -194,9 +191,7 @@ Defines var lengthBytes = lengthBytesUTF8(jsString)+1; // 'jsString.length' would return the length of the string as UTF-16 // units, but Emscripten C strings operate as UTF-8. - var stringOnWasmHeap = _malloc(lengthBytes); - stringToUTF8(jsString, stringOnWasmHeap, lengthBytes); - return stringOnWasmHeap; + return allocateUTF8(jsString); }); printf("UTF8 string says: %s\n", str); free(str); // Each call to _malloc() must be paired with free(), or heap memory will leak! diff --git a/src/library.js b/src/library.js index c85a3055c4e6b..c4d15efdf5d43 100644 --- a/src/library.js +++ b/src/library.js @@ -52,13 +52,7 @@ mergeInto(LibraryManager.library, { // JavaScript <-> C string interop // ========================================================================== - $stringToNewUTF8__deps: ['malloc'], - $stringToNewUTF8: function(jsString) { - var length = lengthBytesUTF8(jsString)+1; - var cString = _malloc(length); - stringToUTF8(jsString, cString, length); - return cString; - }, + $stringToNewUTF8: '$allocateUTF8', #if !MINIMAL_RUNTIME $exitJS__docs: '/** @param {boolean|number=} implicit */', @@ -1833,12 +1827,11 @@ mergeInto(LibraryManager.library, { return getHostByName(UTF8ToString(name)); }, - $getHostByName__deps: ['malloc', '$DNS', '$inetPton4'], + $getHostByName__deps: ['malloc', '$allocateUTF8', '$DNS', '$inetPton4'], $getHostByName: function(name) { // generate hostent var ret = _malloc({{{ C_STRUCTS.hostent.__size__ }}}); // XXX possibly leaked, as are others here - var nameBuf = {{{ makeMalloc('getHostByName', 'name.length+1') }}}; - stringToUTF8(name, nameBuf, name.length+1); + var nameBuf = allocateUTF8(name); {{{ makeSetValue('ret', C_STRUCTS.hostent.h_name, 'nameBuf', POINTER_TYPE) }}}; var aliasesBuf = _malloc(4); {{{ makeSetValue('aliasesBuf', '0', '0', POINTER_TYPE) }}}; @@ -2628,6 +2621,9 @@ mergeInto(LibraryManager.library, { // We never free the return values of this function so we need to allocate // using builtin_malloc to avoid LSan reporting these as leaks. emscripten_get_compiler_setting__noleakcheck: true, +#if RETAIN_COMPILER_SETTINGS + emscripten_get_compiler_setting__deps: ['$allocateUTF8'], +#endif emscripten_get_compiler_setting: function(name) { #if RETAIN_COMPILER_SETTINGS name = UTF8ToString(name); @@ -2639,9 +2635,7 @@ mergeInto(LibraryManager.library, { var cache = _emscripten_get_compiler_setting.cache; var fullret = cache[name]; if (fullret) return fullret; - cache[name] = _malloc(ret.length + 1); - stringToUTF8(ret + '', cache[name], ret.length + 1); - return cache[name]; + return cache[name] = allocateUTF8(ret); #else throw 'You must build with -sRETAIN_COMPILER_SETTINGS for getCompilerSetting or emscripten_get_compiler_setting to work'; #endif diff --git a/src/library_browser.js b/src/library_browser.js index ff9de924298f7..1d9181dbd4f8a 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -803,16 +803,14 @@ var LibraryBrowser = { }, emscripten_run_preload_plugins_data__proxy: 'sync', - emscripten_run_preload_plugins_data__deps: ['malloc'], + emscripten_run_preload_plugins_data__deps: ['$allocateUTF8'], emscripten_run_preload_plugins_data: function(data, size, suffix, arg, onload, onerror) { {{{ runtimeKeepalivePush() }}} var _suffix = UTF8ToString(suffix); if (!Browser.asyncPrepareDataCounter) Browser.asyncPrepareDataCounter = 0; var name = 'prepare_data_' + (Browser.asyncPrepareDataCounter++) + '.' + _suffix; - var lengthAsUTF8 = lengthBytesUTF8(name); - var cname = _malloc(lengthAsUTF8+1); - stringToUTF8(name, cname, lengthAsUTF8+1); + var cname = allocateUTF8(name); FS.createPreloadedFile( '/', name, diff --git a/src/library_ccall.js b/src/library_ccall.js index 4ad9fb31d5ed1..e4e7fb08298f1 100644 --- a/src/library_ccall.js +++ b/src/library_ccall.js @@ -15,7 +15,7 @@ mergeInto(LibraryManager.library, { }, // C calling interface. - $ccall__deps: ['$getCFunc', '$writeArrayToMemory'], + $ccall__deps: ['$getCFunc', '$writeArrayToMemory', '$allocateUTF8OnStack'], $ccall__docs: ` /** * @param {string|null=} returnType @@ -33,9 +33,7 @@ mergeInto(LibraryManager.library, { var ret = 0; if (str !== null && str !== undefined && str !== 0) { // null string // at most 4 bytes per UTF-8 code point, +1 for the trailing '\0' - var len = (str.length << 2) + 1; - ret = stackAlloc(len); - stringToUTF8(str, ret, len); + ret = allocateUTF8OnStack(str); } return {{{ to64('ret') }}}; }, diff --git a/src/library_html5.js b/src/library_html5.js index 692f8bdcd82c4..aa07c075bf1b9 100644 --- a/src/library_html5.js +++ b/src/library_html5.js @@ -2459,7 +2459,7 @@ var LibraryHTML5 = { }, #endif - $setCanvasElementSize__deps: ['emscripten_set_canvas_element_size', '$withStackSave'], + $setCanvasElementSize__deps: ['emscripten_set_canvas_element_size', '$withStackSave', '$allocateUTF8OnStack'], $setCanvasElementSize: function(target, width, height) { #if GL_DEBUG dbg('setCanvasElementSize(target='+target+',width='+width+',height='+height); @@ -2471,8 +2471,7 @@ var LibraryHTML5 = { // This function is being called from high-level JavaScript code instead of asm.js/Wasm, // and it needs to synchronously proxy over to another thread, so marshal the string onto the heap to do the call. withStackSave(function() { - var targetInt = stackAlloc(target.id.length+1); - stringToUTF8(target.id, targetInt, target.id.length+1); + var targetInt = allocateUTF8OnStack(target.id); _emscripten_set_canvas_element_size(targetInt, width, height); }); } @@ -2534,14 +2533,13 @@ var LibraryHTML5 = { #endif // JavaScript-friendly API, returns pair [width, height] - $getCanvasElementSize__deps: ['emscripten_get_canvas_element_size', '$withStackSave'], + $getCanvasElementSize__deps: ['emscripten_get_canvas_element_size', '$withStackSave', '$allocateUTF8OnStack'], $getCanvasElementSize: function(target) { return withStackSave(function() { var w = stackAlloc(8); var h = w + 4; - var targetInt = stackAlloc(target.id.length+1); - stringToUTF8(target.id, targetInt, target.id.length+1); + var targetInt = allocateUTF8OnStack(target.id); var ret = _emscripten_get_canvas_element_size(targetInt, w, h); var size = [{{{ makeGetValue('w', 0, 'i32')}}}, {{{ makeGetValue('h', 0, 'i32')}}}]; return size; diff --git a/src/library_sdl.js b/src/library_sdl.js index 6a0b1a0c6887c..d18c91f4270d0 100644 --- a/src/library_sdl.js +++ b/src/library_sdl.js @@ -2185,7 +2185,7 @@ var LibrarySDL = { return flags; // We support JPG, PNG, TIF because browsers do }, - IMG_Load_RW__deps: ['SDL_LockSurface', 'SDL_FreeRW', '$PATH_FS', 'malloc'], + IMG_Load_RW__deps: ['SDL_LockSurface', 'SDL_FreeRW', '$PATH_FS', 'malloc', '$allocateUTF8'], IMG_Load_RW__proxy: 'sync', IMG_Load_RW: function(rwopsID, freeSrc) { try { @@ -2245,9 +2245,7 @@ var LibrarySDL = { if (!raw) { if (raw === null) err('Trying to reuse preloaded image, but freePreloadedMediaOnUse is set!'); #if STB_IMAGE - var lengthBytes = lengthBytesUTF8(filename)+1; - var name = _malloc(lengthBytes); - stringToUTF8(filename, name, lengthBytes); + var name = allocateUTF8(filename); addCleanup(function() { _free(name); }); diff --git a/src/library_stack_trace.js b/src/library_stack_trace.js index 03af67b246244..51f32acdf0e9c 100644 --- a/src/library_stack_trace.js +++ b/src/library_stack_trace.js @@ -6,7 +6,7 @@ var LibraryStackTrace = { #if DEMANGLE_SUPPORT - $demangle__deps: ['$withStackSave', '__cxa_demangle', 'free'], + $demangle__deps: ['$withStackSave', '__cxa_demangle', 'free', '$allocateUTF8OnStack'], #endif $demangle: function(func) { #if DEMANGLE_SUPPORT @@ -19,9 +19,7 @@ var LibraryStackTrace = { var s = func; if (s.startsWith('__Z')) s = s.substr(1); - var len = lengthBytesUTF8(s)+1; - var buf = stackAlloc(len); - stringToUTF8(s, buf, len); + var buf = allocateUTF8OnStack(s); var status = stackAlloc(4); var ret = ___cxa_demangle(buf, 0, 0, status); if ({{{ makeGetValue('status', '0', 'i32') }}} === 0 && ret) { diff --git a/src/library_websocket.js b/src/library_websocket.js index 0817853173d31..4a4beeec32c9a 100644 --- a/src/library_websocket.js +++ b/src/library_websocket.js @@ -215,7 +215,7 @@ var LibraryWebSocket = { return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, - emscripten_websocket_set_onmessage_callback_on_thread__deps: ['$WS'], + emscripten_websocket_set_onmessage_callback_on_thread__deps: ['$WS', '$allocateUTF8'], emscripten_websocket_set_onmessage_callback_on_thread__proxy: 'sync', emscripten_websocket_set_onmessage_callback_on_thread: function(socketId, userData, callbackFunc, thread) { if (!WS.socketEvent) WS.socketEvent = _malloc(1024); // TODO: sizeof(EmscriptenWebSocketCloseEvent), which is the largest event struct @@ -237,10 +237,9 @@ var LibraryWebSocket = { #endif HEAPU32[WS.socketEvent>>2] = socketId; if (typeof e.data == 'string') { - var len = lengthBytesUTF8(e.data)+1; - var buf = _malloc(len); - stringToUTF8(e.data, buf, len); + var buf = allocateUTF8(e.data); #if WEBSOCKET_DEBUG + var len = lengthBytesUTF8(e.data)+1; var s = (e.data.length < 256) ? e.data : (e.data.substr(0, 256) + ' (' + (e.data.length-256) + ' more characters)'); dbg('WebSocket onmessage, received data: "' + e.data + '", ' + e.data.length + ' chars, ' + len + ' bytes encoded as UTF-8: "' + s + '"'); #endif diff --git a/src/library_wget.js b/src/library_wget.js index 1be95d5b8085b..a00508697b50d 100644 --- a/src/library_wget.js +++ b/src/library_wget.js @@ -173,13 +173,13 @@ var LibraryWget = { function onerrorjs() { if (onerror) { - var statusText = 0; - if (http.statusText) { - var len = lengthBytesUTF8(http.statusText) + 1; - statusText = stackAlloc(len); - stringToUTF8(http.statusText, statusText, len); - } - {{{ makeDynCall('viiii', 'onerror') }}}(handle, arg, http.status, statusText); + withStackSave(() => { + var statusText = 0; + if (http.statusText) { + statusText = allocateUTF8OnStack(http.statusText); + } + {{{ makeDynCall('viiii', 'onerror') }}}(handle, arg, http.status, statusText); + }); } } From a2a8b78deb861bd74952382d5eb27fbaa0c8460a Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 27 Mar 2023 16:13:01 -0700 Subject: [PATCH 0066/1523] Add auto-generated sigs for the fetch API. NFC (#19067) Followup to #19028 which laid the groundwork for auto-generated sigs. --- src/library_fetch.js | 3 --- src/library_sigs.js | 4 ++++ src/utility.js | 6 ++++-- system/lib/fetch/emscripten_fetch.c | 8 ++------ system/lib/libc/emscripten_internal.h | 7 +++++++ test/test_other.py | 19 ++++++++++++++----- tools/gen_sig_info.py | 9 +++++++-- tools/system_libs.py | 1 + 8 files changed, 39 insertions(+), 18 deletions(-) diff --git a/src/library_fetch.js b/src/library_fetch.js index 1467a90c5a279..88497f99bae70 100644 --- a/src/library_fetch.js +++ b/src/library_fetch.js @@ -13,9 +13,7 @@ var LibraryFetch = { $Fetch__postset: 'Fetch.staticInit();', #endif $Fetch: Fetch, - _emscripten_fetch_get_response_headers_length__sig: 'pi', _emscripten_fetch_get_response_headers_length: fetchGetResponseHeadersLength, - _emscripten_fetch_get_response_headers__sig: 'pipp', _emscripten_fetch_get_response_headers: fetchGetResponseHeaders, _emscripten_fetch_free: fetchFree, @@ -26,7 +24,6 @@ var LibraryFetch = { #endif $fetchXHR: fetchXHR, - emscripten_start_fetch__sig: 'vp', emscripten_start_fetch: startFetch, emscripten_start_fetch__deps: [ '$Fetch', diff --git a/src/library_sigs.js b/src/library_sigs.js index a503df85dcc8c..00e89727137a0 100644 --- a/src/library_sigs.js +++ b/src/library_sigs.js @@ -271,6 +271,9 @@ sigs = { _emscripten_dbg__sig: 'vp', _emscripten_dlopen_js__sig: 'vpppp', _emscripten_err__sig: 'vp', + _emscripten_fetch_free__sig: 'vi', + _emscripten_fetch_get_response_headers__sig: 'pipp', + _emscripten_fetch_get_response_headers_length__sig: 'pi', _emscripten_fs_load_embedded_files__sig: 'vp', _emscripten_get_now_is_monotonic__sig: 'i', _emscripten_get_progname__sig: 'vpi', @@ -601,6 +604,7 @@ sigs = { emscripten_sleep__sig: 'vi', emscripten_stack_snapshot__sig: 'p', emscripten_stack_unwind_buffer__sig: 'ippi', + emscripten_start_fetch__sig: 'vp', emscripten_supports_offscreencanvas__sig: 'i', emscripten_throw_number__sig: 'vd', emscripten_throw_string__sig: 'vp', diff --git a/src/utility.js b/src/utility.js index 7738f041147a1..69979a7abbd74 100644 --- a/src/utility.js +++ b/src/utility.js @@ -145,8 +145,10 @@ function mergeInto(obj, other, options = null) { if (obj.hasOwnProperty(key)) { const oldsig = obj[key]; const newsig = other[key]; - if (oldsig != newsig) { - error(`Signature redefinition for: ${key}. (old=${oldsig} vs new=${newsig})`); + if (oldsig == newsig) { + warn(`signature redefinition for: ${key}. (old=${oldsig} vs new=${newsig})`); + } else { + error(`signature redefinition for: ${key}. (old=${oldsig} vs new=${newsig})`); } } } diff --git a/system/lib/fetch/emscripten_fetch.c b/system/lib/fetch/emscripten_fetch.c index cb86ebb6eee04..01edeb3a7cce2 100644 --- a/system/lib/fetch/emscripten_fetch.c +++ b/system/lib/fetch/emscripten_fetch.c @@ -17,6 +17,8 @@ #include #include +#include "emscripten_internal.h" + // From https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/readyState #define STATE_UNSENT 0 // Client has been created. open() not called yet. #define STATE_OPENED 1 // open() has been called. @@ -31,12 +33,6 @@ static void fetch_free(emscripten_fetch_t* fetch); -// APIs defined in JS -void emscripten_start_fetch(emscripten_fetch_t* fetch); -size_t _emscripten_fetch_get_response_headers_length(int32_t fetchID); -size_t _emscripten_fetch_get_response_headers(int32_t fetchID, char *dst, size_t dstSizeBytes); -void _emscripten_fetch_free(unsigned int); - typedef struct emscripten_fetch_queue { emscripten_fetch_t** queuedOperations; int numQueuedItems; diff --git a/system/lib/libc/emscripten_internal.h b/system/lib/libc/emscripten_internal.h index 819755001da8f..811934040fdbf 100644 --- a/system/lib/libc/emscripten_internal.h +++ b/system/lib/libc/emscripten_internal.h @@ -107,6 +107,13 @@ void _emscripten_throw_longjmp(void); void __handle_stack_overflow(void* addr); +// Internal fetch API +struct emscripten_fetch_t; +void emscripten_start_fetch(struct emscripten_fetch_t* fetch); +size_t _emscripten_fetch_get_response_headers_length(int32_t fetchID); +size_t _emscripten_fetch_get_response_headers(int32_t fetchID, char *dst, size_t dstSizeBytes); +void _emscripten_fetch_free(unsigned int); + #ifdef __cplusplus } #endif diff --git a/test/test_other.py b/test/test_other.py index 621db8b286773..15e11150e155c 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -3849,7 +3849,7 @@ def test_js_internal_deps(self): err = self.run_process([EMCC, 'src.c', '--js-library', 'lib.js'], stderr=PIPE).stderr self.assertContained("warning: user library symbol 'jslibfunc' depends on internal symbol '$callRuntimeCallbacks'", err) - def test_js_lib_sig_mismatch(self): + def test_js_lib_sig_redefinition(self): create_file('lib.js', r''' mergeInto(LibraryManager.library, { jslibfunc__sig: 'ii', @@ -3857,10 +3857,9 @@ def test_js_lib_sig_mismatch(self): }); mergeInto(LibraryManager.library, { - jslibfunc__sig: 'dd', + jslibfunc__sig: 'ii', jslibfunc: function(x) {}, }); - ''') create_file('src.c', r''' #include @@ -3869,8 +3868,18 @@ def test_js_lib_sig_mismatch(self): printf("c calling: %d\n", jslibfunc()); } ''') - err = self.expect_fail([EMCC, 'src.c', '--js-library', 'lib.js']) - self.assertContained('lib.js: Signature redefinition for: jslibfunc__sig. (old=ii vs new=dd)', err) + err = self.run_process([EMCC, 'src.c', '--js-library', 'lib.js'], stderr=PIPE).stderr + self.assertContained('lib.js: signature redefinition for: jslibfunc__sig. (old=ii vs new=ii)', err) + + # Add another redefinition, this time not matching + create_file('lib2.js', r''' +mergeInto(LibraryManager.library, { + jslibfunc__sig: 'pp', + jslibfunc: function(x) {}, +}); +''') + err = self.expect_fail([EMCC, 'src.c', '--js-library', 'lib.js', '--js-library', 'lib2.js']) + self.assertContained('lib2.js: signature redefinition for: jslibfunc__sig. (old=ii vs new=pp)', err) def test_js_lib_invalid_deps(self): create_file('lib.js', r''' diff --git a/tools/gen_sig_info.py b/tools/gen_sig_info.py index 6467f7db4b883..a4d3a04eca79c 100755 --- a/tools/gen_sig_info.py +++ b/tools/gen_sig_info.py @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -228,12 +229,16 @@ def extract_sig_info(sig_info, extra_settings=None, extra_cflags=None): 'STACK_OVERFLOW_CHECK': 1, 'FULL_ES3': 1, 'USE_SDL': 1, + 'FETCH': 1, # Currently GLFW symbols have different sigs for the same symbol because the # signatures changed between v2 and v3, so for now we continue to maintain # them by hand. 'USE_GLFW': 0, - 'JS_LIBRARIES': ['src/library_websocket.js', - 'src/library_webaudio.js'], + 'JS_LIBRARIES': [ + 'src/library_websocket.js', + 'src/library_webaudio.js', + 'src/library_fetch.js' + ], 'SUPPORT_LONGJMP': 'emscripten' } if extra_settings: diff --git a/tools/system_libs.py b/tools/system_libs.py index 9287295df327f..7bebfb22b6bbc 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -1743,6 +1743,7 @@ def get_default_variation(cls, **kwargs): class libfetch(MTLibrary): name = 'libfetch' never_force = True + includes = ['system/lib/libc'] def get_files(self): return [utils.path_from_root('system/lib/fetch/emscripten_fetch.c')] From 48109afba5e4e4a3500fbc588e98997e4906dc01 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 27 Mar 2023 16:43:26 -0700 Subject: [PATCH 0067/1523] Rebaseline codesize expectations. NFC --- test/other/metadce/test_metadce_hello_O0.jssize | 2 +- test/other/metadce/test_metadce_minimal_O0.jssize | 2 +- test/other/test_unoptimized_code_size.js.size | 2 +- test/other/test_unoptimized_code_size_strict.js.size | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/other/metadce/test_metadce_hello_O0.jssize b/test/other/metadce/test_metadce_hello_O0.jssize index 45129635426fa..d3ea9f5793238 100644 --- a/test/other/metadce/test_metadce_hello_O0.jssize +++ b/test/other/metadce/test_metadce_hello_O0.jssize @@ -1 +1 @@ -23956 +23970 diff --git a/test/other/metadce/test_metadce_minimal_O0.jssize b/test/other/metadce/test_metadce_minimal_O0.jssize index 6ddb211dca615..0508df68b45cc 100644 --- a/test/other/metadce/test_metadce_minimal_O0.jssize +++ b/test/other/metadce/test_metadce_minimal_O0.jssize @@ -1 +1 @@ -20264 +20278 diff --git a/test/other/test_unoptimized_code_size.js.size b/test/other/test_unoptimized_code_size.js.size index 5b97533eb699e..08789b21f9bd1 100644 --- a/test/other/test_unoptimized_code_size.js.size +++ b/test/other/test_unoptimized_code_size.js.size @@ -1 +1 @@ -64449 +64465 diff --git a/test/other/test_unoptimized_code_size_strict.js.size b/test/other/test_unoptimized_code_size_strict.js.size index 119b34a173cdd..046dd3e1cb98c 100644 --- a/test/other/test_unoptimized_code_size_strict.js.size +++ b/test/other/test_unoptimized_code_size_strict.js.size @@ -1 +1 @@ -63483 +63499 From a22b02f966e9ac8af50327f134761a4dfbc23ee2 Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Mon, 27 Mar 2023 17:33:23 -0700 Subject: [PATCH 0068/1523] Avoid timed waits in test_pthread_proxying_canceled_work (#19083) In the test cases that proxy work and then exit or cancel the worker thread before the proxied work can be executed, avoid using a timed wait to determine when to cancel or exit the thread. Instead, signal the worker by setting an atomic flag to tell it that the proxied work has been sent. This requires removing the synchronous proxying from these test cases, but that's fairly safe because the synchronous and asynchronous proxying methods have the same internals and the cancellation is tested in combination with synchronous proxying in other test cases. This will fix the flake reported in #18921 if it was caused by the overloaded CI machines taking more than 20ms to execute the proxying calls. --- .../test_pthread_proxying_canceled_work.c | 51 +++++++++---------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/test/pthread/test_pthread_proxying_canceled_work.c b/test/pthread/test_pthread_proxying_canceled_work.c index c21a19553f495..6cdb2cee2e670 100644 --- a/test/pthread/test_pthread_proxying_canceled_work.c +++ b/test/pthread/test_pthread_proxying_canceled_work.c @@ -113,14 +113,18 @@ void test_exit_then_proxy() { pthread_join(thread, NULL); } -void* wait_then_cancel(void* running) { - *((_Atomic int*)running) = 1; +struct flags { + _Atomic int running; + _Atomic int proxied; +}; + +void* wait_then_cancel(void* arg) { + struct flags* flags = arg; + flags->running = 1; - // Wait 20 ms for the proxying to start. - // TODO: Test with with a cancellable async proxying API to avoid the wait. - int wait_val = 0; - int wait_time = 20000000; - __builtin_wasm_memory_atomic_wait32(&wait_val, 0, wait_time); + // Wait for the proxying to start. + while (!flags->proxied) { + } pthread_cancel(pthread_self()); pthread_testcancel(); @@ -128,14 +132,13 @@ void* wait_then_cancel(void* running) { return NULL; } -void* wait_then_exit(void* running) { - *((_Atomic int*)running) = 1; +void* wait_then_exit(void* arg) { + struct flags* flags = arg; + flags->running = 1; - // Wait 20 ms for the proxying to start. - // TODO: Test with with a cancellable async proxying API to avoid the wait. - int wait_val = 0; - int wait_time = 20000000; - __builtin_wasm_memory_atomic_wait32(&wait_val, 0, wait_time); + // Wait for the proxying to start. + while (!flags->proxied) { + } pthread_exit(NULL); assert(0 && "thread should have exited!"); @@ -145,11 +148,11 @@ void* wait_then_exit(void* running) { void test_proxy_then_cancel() { printf("testing proxy followed by cancel\n"); - _Atomic int running = 0; + struct flags flags = (struct flags){.running = 0, .proxied = 0}; pthread_t thread; - pthread_create(&thread, NULL, wait_then_cancel, &running); + pthread_create(&thread, NULL, wait_then_cancel, &flags); - while (!running) { + while (!flags.running) { } // The pending proxied work should be canceled when the thread is canceled. @@ -163,20 +166,18 @@ void test_proxy_then_cancel() { assert(ret == 1); add_promise(promise); - ret = emscripten_proxy_sync(queue, thread, explode, NULL); - assert(ret == 0); - + flags.proxied = 1; pthread_join(thread, NULL); } void test_proxy_then_exit() { printf("testing proxy followed by exit\n"); - _Atomic int running = 0; + struct flags flags = (struct flags){.running = 0, .proxied = 0}; pthread_t thread; - pthread_create(&thread, NULL, wait_then_exit, &running); + pthread_create(&thread, NULL, wait_then_exit, &flags); - while (!running) { + while (!flags.running) { } // The pending proxied work should be canceled when the thread exits. @@ -190,9 +191,7 @@ void test_proxy_then_exit() { assert(ret == 1); add_promise(promise); - ret = emscripten_proxy_sync(queue, thread, explode, NULL); - assert(ret == 0); - + flags.proxied = 1; pthread_join(thread, NULL); } From 67cee0ba219b7abccdd16ff09cbfab9689ce4368 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 27 Mar 2023 18:55:34 -0700 Subject: [PATCH 0069/1523] Remove use of logging from ports builds (#18624) This was just adding unnessary boilerplate to each individual port. We already print several lines of information when building a given port, and its all don't in generic code. e.g.: ``` ports:INFO: retrieving port: bullet from https://github.com/emscripten-ports/bullet/archive/version_1.zip ports:INFO: unpacking port: bullet cache:INFO: generating system library: sysroot/lib/wasm32-emscripten/libbullet.a... (this will be cached in "/usr/local/google/home/sbc/dev/wasm/emscripten/cache/sysroot/lib/wasm32-emscripten/libbullet.a" for subsequent builds) ``` For requests to make these things quieter in general see #18607 and 18622. --- test/test_browser.py | 1 + tools/ports/boost_headers.py | 3 --- tools/ports/bullet.py | 3 --- tools/ports/cocos2d.py | 4 ++-- tools/ports/giflib.py | 2 -- tools/ports/harfbuzz.py | 3 --- tools/ports/icu.py | 3 --- tools/ports/libjpeg.py | 2 -- tools/ports/libmodplug.py | 3 --- tools/ports/libpng.py | 3 --- tools/ports/mpg123.py | 3 --- tools/ports/ogg.py | 3 --- tools/ports/regal.py | 2 -- tools/ports/sdl2_gfx.py | 2 -- tools/ports/sdl2_mixer.py | 3 --- tools/ports/sdl2_net.py | 2 -- tools/ports/sqlite3.py | 3 --- tools/ports/vorbis.py | 2 -- 18 files changed, 3 insertions(+), 44 deletions(-) diff --git a/test/test_browser.py b/test/test_browser.py index 5fb9b1465380d..787fb009d0b08 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -3321,6 +3321,7 @@ def test_cocos2d_hello(self): self.btest('cocos2d_hello.cpp', reference='cocos2d_hello.png', reference_slack=1, args=['-sUSE_COCOS2D=3', '-sERROR_ON_UNDEFINED_SYMBOLS=0', '-Wno-js-compiler', + '-Wno-experimental', '--preload-file', preload_file, '--use-preload-plugins', '-Wno-inconsistent-missing-override', '-Wno-deprecated-declarations']) diff --git a/tools/ports/boost_headers.py b/tools/ports/boost_headers.py index 2468b42b81a38..7351fde984f8b 100644 --- a/tools/ports/boost_headers.py +++ b/tools/ports/boost_headers.py @@ -3,7 +3,6 @@ # University of Illinois/NCSA Open Source License. Both these licenses can be # found in the LICENSE file. -import logging import os TAG = '1.75.0' @@ -20,8 +19,6 @@ def get(ports, settings, shared): sha512hash=HASH) def create(final): - logging.info('building port: boost_headers') - # includes source_path = os.path.join(ports.get_dir(), 'boost_headers') source_path_include = os.path.join(source_path, 'boost') diff --git a/tools/ports/bullet.py b/tools/ports/bullet.py index 39f48ea231c14..74b681c6ad540 100644 --- a/tools/ports/bullet.py +++ b/tools/ports/bullet.py @@ -3,7 +3,6 @@ # University of Illinois/NCSA Open Source License. Both these licenses can be # found in the LICENSE file. -import logging import os import shutil @@ -19,8 +18,6 @@ def get(ports, settings, shared): ports.fetch_project('bullet', f'https://github.com/emscripten-ports/bullet/archive/{TAG}.zip', sha512hash=HASH) def create(final): - logging.info('building port: bullet') - source_path = os.path.join(ports.get_dir(), 'bullet', 'Bullet-' + TAG) src_path = os.path.join(source_path, 'bullet', 'src') diff --git a/tools/ports/cocos2d.py b/tools/ports/cocos2d.py index de717c1174b61..b1f3d624852c0 100644 --- a/tools/ports/cocos2d.py +++ b/tools/ports/cocos2d.py @@ -4,8 +4,8 @@ # found in the LICENSE file. import os -import logging import re +from tools import diagnostics TAG = 'version_3_3' HASH = 'd7b22660036c684f09754fcbbc7562984f02aa955eef2b76555270c63a717e6672c4fe695afb16280822e8b7c75d4b99ae21975a01a4ed51cad957f7783722cd' @@ -21,7 +21,7 @@ def get(ports, settings, shared): ports.fetch_project('cocos2d', f'https://github.com/emscripten-ports/Cocos2d/archive/{TAG}.zip', sha512hash=HASH) def create(final): - logging.warn('cocos2d: library is experimental, do not expect that it will work out of the box') + diagnostics.warning('experimental', 'cocos2d: library is experimental, do not expect that it will work out of the box') cocos2d_src = os.path.join(ports.get_dir(), 'cocos2d') cocos2d_root = os.path.join(cocos2d_src, 'Cocos2d-' + TAG) diff --git a/tools/ports/giflib.py b/tools/ports/giflib.py index 42b380144581e..4fe2bade5794c 100644 --- a/tools/ports/giflib.py +++ b/tools/ports/giflib.py @@ -4,7 +4,6 @@ # found in the LICENSE file. import os -import logging VERSION = '5.2.1' HASH = '4550e53c21cb1191a4581e363fc9d0610da53f7898ca8320f0d3ef6711e76bdda2609c2df15dc94c45e28bff8de441f1227ec2da7ea827cb3c0405af4faa4736' @@ -18,7 +17,6 @@ def get(ports, settings, shared): ports.fetch_project('giflib', f'https://storage.googleapis.com/webassembly/emscripten-ports/giflib-{VERSION}.tar.gz', sha512hash=HASH) def create(final): - logging.info('building port: giflib') source_path = os.path.join(ports.get_dir(), 'giflib', f'giflib-{VERSION}') ports.install_headers(source_path) exclude_files = [ diff --git a/tools/ports/harfbuzz.py b/tools/ports/harfbuzz.py index ed0537db18c08..133bbfdc3ca40 100644 --- a/tools/ports/harfbuzz.py +++ b/tools/ports/harfbuzz.py @@ -4,7 +4,6 @@ # found in the LICENSE file. import os -import logging VERSION = '3.2.0' HASH = 'c9d88068d8017046842f444f02f31dbae109026ede943aaf265db5508de8b4b2be84203950f274a237f515bf7cbd361629d2032c6e8ee8f50354b430bba3a8ca' @@ -83,8 +82,6 @@ def get(ports, settings, shared): ports.fetch_project('harfbuzz', f'https://github.com/harfbuzz/harfbuzz/releases/download/{VERSION}/harfbuzz-{VERSION}.tar.xz', sha512hash=HASH) def create(final): - logging.info('building port: harfbuzz') - source_path = os.path.join(ports.get_dir(), 'harfbuzz', 'harfbuzz-' + VERSION) freetype_include = ports.get_include_dir('freetype2') ports.install_headers(os.path.join(source_path, 'src'), target='harfbuzz') diff --git a/tools/ports/icu.py b/tools/ports/icu.py index ca0171ba97e09..bd6ffeb9a8bb4 100644 --- a/tools/ports/icu.py +++ b/tools/ports/icu.py @@ -3,7 +3,6 @@ # University of Illinois/NCSA Open Source License. Both these licenses can be # found in the LICENSE file. -import logging import os TAG = 'release-68-2' @@ -35,8 +34,6 @@ def prepare_build(): icu_source_path = os.path.join(source_path, 'source') def build_lib(lib_output, lib_src, other_includes, build_flags): - logging.debug('building port: icu- ' + lib_output) - additional_build_flags = [ # TODO: investigate why this is needed and remove '-Wno-macro-redefined', diff --git a/tools/ports/libjpeg.py b/tools/ports/libjpeg.py index 81af44e08477a..a8733cd8e82f1 100644 --- a/tools/ports/libjpeg.py +++ b/tools/ports/libjpeg.py @@ -4,7 +4,6 @@ # found in the LICENSE file. import os -import logging VERSION = '9c' HASH = 'b2affe9a1688bd49fc033f4682c4a242d4ee612f1affaef532f5adcb4602efc4433c4a52a4b3d69e7440ff1f6413b1b041b419bc90efd6d697999961a9a6afb7' @@ -21,7 +20,6 @@ def get(ports, settings, shared): ports.fetch_project('libjpeg', f'https://storage.googleapis.com/webassembly/emscripten-ports/jpegsrc.v{VERSION}.tar.gz', sha512hash=HASH) def create(final): - logging.info('building port: libjpeg') source_path = os.path.join(ports.get_dir(), 'libjpeg', f'jpeg-{VERSION}') ports.write_file(os.path.join(source_path, 'jconfig.h'), jconfig_h) ports.install_headers(source_path) diff --git a/tools/ports/libmodplug.py b/tools/ports/libmodplug.py index 20a996f113689..21badcc56288f 100644 --- a/tools/ports/libmodplug.py +++ b/tools/ports/libmodplug.py @@ -4,7 +4,6 @@ # found in the LICENSE file. import os -import logging TAG = '11022021' HASH = 'f770031ad6c2152cbed8c8eab8edf2be1d27f9e74bc255a9930c17019944ee5fdda5308ea992c66a78af9fe1d8dca090f6c956910ce323f8728247c10e44036b' @@ -18,8 +17,6 @@ def get(ports, settings, shared): ports.fetch_project('libmodplug', f'https://github.com/jancc/libmodplug/archive/v{TAG}.zip', sha512hash=HASH) def create(final): - logging.info('building port: libmodplug') - source_path = os.path.join(ports.get_dir(), 'libmodplug', 'libmodplug-' + TAG) src_dir = os.path.join(source_path, 'src') libmodplug_path = os.path.join(src_dir, 'libmodplug') diff --git a/tools/ports/libpng.py b/tools/ports/libpng.py index 19d30d1805666..c15fade4e9c87 100644 --- a/tools/ports/libpng.py +++ b/tools/ports/libpng.py @@ -4,7 +4,6 @@ # found in the LICENSE file. import os -import logging TAG = '1.6.37' HASH = '2ce2b855af307ca92a6e053f521f5d262c36eb836b4810cb53c809aa3ea2dcc08f834aee0ffd66137768a54397e28e92804534a74abb6fc9f6f3127f14c9c338' @@ -35,8 +34,6 @@ def get(ports, settings, shared): ports.fetch_project('libpng', f'https://storage.googleapis.com/webassembly/emscripten-ports/libpng-{TAG}.tar.gz', sha512hash=HASH) def create(final): - logging.info('building port: libpng') - source_path = os.path.join(ports.get_dir(), 'libpng', 'libpng-' + TAG) ports.write_file(os.path.join(source_path, 'pnglibconf.h'), pnglibconf_h) ports.install_headers(source_path) diff --git a/tools/ports/mpg123.py b/tools/ports/mpg123.py index 43f0c80ba2df5..e9f29a7878bbd 100644 --- a/tools/ports/mpg123.py +++ b/tools/ports/mpg123.py @@ -4,7 +4,6 @@ # found in the LICENSE file. import os -import logging TAG = '1.26.2' HASH = 'aa63fcb08b243a1e09f7701b3d84a19d7412a87253d54d49f014fdb9e75bbc81d152a41ed750fccde901453929b2a001585a7645351b41845ad205c17a73dcc9' @@ -18,8 +17,6 @@ def get(ports, settings, shared): ports.fetch_project('mpg123', f'https://www.mpg123.de/download/mpg123-{TAG}.tar.bz2', sha512hash=HASH) def create(final): - logging.info('building port: mpg123') - source_path = os.path.join(ports.get_dir(), 'mpg123', 'mpg123-' + TAG) src_path = os.path.join(source_path, 'src') diff --git a/tools/ports/ogg.py b/tools/ports/ogg.py index cebabd3a87795..7157fb9a0e431 100644 --- a/tools/ports/ogg.py +++ b/tools/ports/ogg.py @@ -3,7 +3,6 @@ # University of Illinois/NCSA Open Source License. Both these licenses can be # found in the LICENSE file. -import logging import os TAG = 'version_1' @@ -18,8 +17,6 @@ def get(ports, settings, shared): ports.fetch_project('ogg', f'https://github.com/emscripten-ports/ogg/archive/{TAG}.zip', sha512hash=HASH) def create(final): - logging.info('building port: ogg') - source_path = os.path.join(ports.get_dir(), 'ogg', 'Ogg-' + TAG) ports.write_file(os.path.join(source_path, 'include', 'ogg', 'config_types.h'), config_types_h) ports.install_header_dir(os.path.join(source_path, 'include', 'ogg'), 'ogg') diff --git a/tools/ports/regal.py b/tools/ports/regal.py index 7b16ea523bc35..dc4417cfa7a6a 100644 --- a/tools/ports/regal.py +++ b/tools/ports/regal.py @@ -3,7 +3,6 @@ # University of Illinois/NCSA Open Source License. Both these licenses can be # found in the LICENSE file. -import logging import os TAG = 'version_7' @@ -24,7 +23,6 @@ def get(ports, settings, shared): ports.fetch_project('regal', f'https://github.com/emscripten-ports/regal/archive/{TAG}.zip', sha512hash=HASH) def create(final): - logging.info('building port: regal') source_path = os.path.join(ports.get_dir(), 'regal', 'regal-' + TAG) # copy sources diff --git a/tools/ports/sdl2_gfx.py b/tools/ports/sdl2_gfx.py index 9b6ec0f30e315..702d8fc3d55b8 100644 --- a/tools/ports/sdl2_gfx.py +++ b/tools/ports/sdl2_gfx.py @@ -4,7 +4,6 @@ # found in the LICENSE file. import os -import logging TAG = '2b147ffef10ec541d3eace326eafe11a54e635f8' HASH = 'f39f1f50a039a1667fe92b87d28548d32adcf0eb8526008656de5315039aa21f29d230707caa47f80f6b3a412a577698cd4bbfb9458bb92ac47e6ba993b8efe6' @@ -22,7 +21,6 @@ def get(ports, settings, shared): ports.fetch_project('sdl2_gfx', f'https://github.com/svn2github/sdl2_gfx/archive/{TAG}.zip', sha512hash=HASH) def create(final): - logging.info('building port: sdl2_gfx') source_path = os.path.join(ports.get_dir(), 'sdl2_gfx', 'sdl2_gfx-' + TAG) ports.build_port(source_path, final, 'sdl2_gfx', exclude_dirs=['test'], flags=['-sUSE_SDL=2']) ports.install_headers(source_path, target='SDL2') diff --git a/tools/ports/sdl2_mixer.py b/tools/ports/sdl2_mixer.py index 332063199f592..5e59fcb9b1645 100644 --- a/tools/ports/sdl2_mixer.py +++ b/tools/ports/sdl2_mixer.py @@ -4,7 +4,6 @@ # found in the LICENSE file. import os -import logging TAG = 'release-2.0.4' HASH = '5ba387f997219a1deda868f380bf7ee8bc0842261dd54772ad2d560f5282fcbe7bc130e8d16dccc259eeb8cda993a0f34cd3be103fc38f8c6a68428a10e5db4c' @@ -39,8 +38,6 @@ def get(ports, settings, shared): libname = get_lib_name(settings) def create(final): - logging.info('building port: sdl2_mixer') - source_path = os.path.join(ports.get_dir(), 'sdl2_mixer', 'SDL_mixer-' + TAG) flags = [ '-sUSE_SDL=2', diff --git a/tools/ports/sdl2_net.py b/tools/ports/sdl2_net.py index f1ec8ed843053..b91d5424b5a5b 100644 --- a/tools/ports/sdl2_net.py +++ b/tools/ports/sdl2_net.py @@ -4,7 +4,6 @@ # found in the LICENSE file. import os -import logging TAG = 'version_2' HASH = '317b22ad9b6b2f7b40fac7b7c426da2fa2da1803bbe58d480631f1e5b190d730763f2768c77c72affa806c69a1e703f401b15a1be3ec611cd259950d5ebc3711' @@ -22,7 +21,6 @@ def get(ports, settings, shared): ports.fetch_project('sdl2_net', f'https://github.com/emscripten-ports/SDL2_net/archive/{TAG}.zip', sha512hash=HASH) def create(final): - logging.info('building port: sdl2_net') src_dir = os.path.join(ports.get_dir(), 'sdl2_net', 'SDL2_net-' + TAG) ports.install_headers(src_dir, target='SDL2') excludes = ['chatd.c', 'chat.cpp', 'showinterfaces.c'] diff --git a/tools/ports/sqlite3.py b/tools/ports/sqlite3.py index dcbb5b5b6020d..06bac51a8dcec 100644 --- a/tools/ports/sqlite3.py +++ b/tools/ports/sqlite3.py @@ -4,7 +4,6 @@ # found in the LICENSE file. import os -import logging # sqlite amalgamation download URL uses relase year and tag # 2022 and (3, 38, 5) -> '/2022/sqlite-amalgamation-3380500.zip' @@ -29,8 +28,6 @@ def get(ports, settings, shared): ports.fetch_project('sqlite3', f'https://www.sqlite.org/{VERSION_YEAR}/{release}.zip', sha512hash=HASH) def create(final): - logging.info('building port: libsqlite3') - source_path = os.path.join(ports.get_dir(), 'sqlite3', release) ports.install_headers(source_path) diff --git a/tools/ports/vorbis.py b/tools/ports/vorbis.py index b038cf85b4f34..baec1b67807ec 100644 --- a/tools/ports/vorbis.py +++ b/tools/ports/vorbis.py @@ -3,7 +3,6 @@ # University of Illinois/NCSA Open Source License. Both these licenses can be # found in the LICENSE file. -import logging import os TAG = 'version_1' @@ -20,7 +19,6 @@ def get(ports, settings, shared): ports.fetch_project('vorbis', f'https://github.com/emscripten-ports/vorbis/archive/{TAG}.zip', sha512hash=HASH) def create(final): - logging.info('building port: vorbis') source_path = os.path.join(ports.get_dir(), 'vorbis', 'Vorbis-' + TAG) ports.install_header_dir(os.path.join(source_path, 'include', 'vorbis')) ports.build_port(os.path.join(source_path, 'lib'), final, 'vorbis', From c144dfed4807291953f0724280321d574673b9e5 Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Tue, 28 Mar 2023 17:33:56 +0200 Subject: [PATCH 0070/1523] [EH] Avoid including the exception pointer within the assert info (#18784) --- site/source/docs/porting/exceptions.rst | 2 +- src/parseTools.js | 6 +++--- test/test_other.py | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/site/source/docs/porting/exceptions.rst b/site/source/docs/porting/exceptions.rst index 7b7286bf83b40..5cb606e26c6ae 100644 --- a/site/source/docs/porting/exceptions.rst +++ b/site/source/docs/porting/exceptions.rst @@ -28,7 +28,7 @@ the output: .. code-block:: text throw... - exception thrown: 5246024 - Exception catching is disabled, this exception cannot be caught. Compile with -sNO_DISABLE_EXCEPTION_CATCHING or -sEXCEPTION_CATCHING_ALLOWED=[..] to catch. + Aborted(Assertion failed: Exception thrown, but exception catching is not enabled. Compile with -sNO_DISABLE_EXCEPTION_CATCHING or -sEXCEPTION_CATCHING_ALLOWED=[..] to catch.) If you want to opt-in, you have two following options. diff --git a/src/parseTools.js b/src/parseTools.js index 9b7432349a292..43155493d46e4 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -489,11 +489,11 @@ function makeReturn64(value) { function makeThrow(excPtr) { if (ASSERTIONS && DISABLE_EXCEPTION_CATCHING) { - excPtr += ' + " - Exception catching is disabled, this exception cannot be caught. Compile with -sNO_DISABLE_EXCEPTION_CATCHING or -sEXCEPTION_CATCHING_ALLOWED=[..] to catch."'; + var assertInfo = 'Exception thrown, but exception catching is not enabled. Compile with -sNO_DISABLE_EXCEPTION_CATCHING or -sEXCEPTION_CATCHING_ALLOWED=[..] to catch.'; if (MAIN_MODULE) { - excPtr += ' + " (note: in dynamic linking, if a side module wants exceptions, the main module must be built with that support)"'; + assertInfo += ' (note: in dynamic linking, if a side module wants exceptions, the main module must be built with that support)'; } - return `throw ${excPtr};`; + return `assert(false, '${assertInfo}');`; } if (EXCEPTION_STACK_TRACES) { return `throw new CppException(${excPtr});`; diff --git a/test/test_other.py b/test/test_other.py index 15e11150e155c..2a81f512212ae 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -6763,7 +6763,7 @@ def build_main(args): build_main([]) out = self.run_js('a.out.js', assert_returncode=NON_ZERO) - self.assertContained('Exception catching is disabled, this exception cannot be caught.', out) + self.assertContained('Exception thrown, but exception catching is not enabled.', out) self.assertContained('note: in dynamic linking, if a side module wants exceptions, the main module must be built with that support', out) build_main(['-fexceptions']) From bd95d1086e2bdd1abde694a4ac537d73231a9d28 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 28 Mar 2023 12:51:19 -0700 Subject: [PATCH 0071/1523] Re-enable test_preload_file_with_manual_data_download_pthreads under firefox. NFC (#19088) --- test/manual_download_data.html | 2 +- test/test_browser.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/test/manual_download_data.html b/test/manual_download_data.html index 97c154fb8c056..5cc675fe99744 100644 --- a/test/manual_download_data.html +++ b/test/manual_download_data.html @@ -189,7 +189,7 @@ Module['downloadedData'] = data; var jsDownload = download('manual_download_data.js').then(function(data) { console.log('downloaded js file'); - Module['mainScriptUrlOrBlob'] = new Blob([data]); + Module['mainScriptUrlOrBlob'] = new Blob([data], { type: 'application/javascript' }); addScriptToDom(data); }); }); diff --git a/test/test_browser.py b/test/test_browser.py index 787fb009d0b08..2b908b2cd9b33 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -422,7 +422,6 @@ def make_main_two_files(path1, path2, nonexistingpath): 'pthreads': (['-pthread', '-sPROXY_TO_PTHREAD', '-sEXIT_RUNTIME'],), }) @requires_threads - @no_firefox('https://github.com/emscripten-core/emscripten/issues/19080') def test_preload_file_with_manual_data_download(self, args): src = test_file('manual_download_data.cpp') From 4e15675e29ce1d2bc826b21e79ac42b0acf3bccf Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 29 Mar 2023 09:48:17 -0700 Subject: [PATCH 0072/1523] Deprecate `allocateUTF8` in favor of `stringToNewUTF8` (#19089) Followup to #19064 --- ChangeLog.md | 2 ++ .../docs/api_reference/emscripten.h.rst | 4 +-- .../Interacting-with-code.rst | 2 +- src/library.js | 26 +++++++++---------- src/library_browser.js | 4 +-- src/library_egl.js | 10 +++---- src/library_glew.js | 6 ++--- src/library_glfw.js | 10 +++---- src/library_legacy.js | 2 ++ src/library_openal.js | 12 ++++----- src/library_sdl.js | 20 +++++++------- src/library_strings.js | 4 +-- src/library_wasmfs.js | 4 +-- src/library_webgpu.js | 26 +++++++++---------- src/library_websocket.js | 4 +-- .../lib/compiler-rt/lib/asan/asan_flags.cpp | 2 +- system/lib/compiler-rt/lib/lsan/lsan.cpp | 2 +- .../lib/compiler-rt/lib/ubsan/ubsan_flags.cpp | 2 +- test/test_other.py | 6 ++--- 19 files changed, 75 insertions(+), 73 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index e8f00c48d1de9..0059ebf5aa63a 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -20,6 +20,8 @@ See docs/process.md for more on how version tagging works. 3.1.35 (in development) ----------------------- +- `allocateUTF8` library function moved to `library_legacy.js`. Prefer the + more accurately named `stringToNewUTF8`. - `SDL_image` port was updated to version 2.6.0. - `-z` arguments are now passed directly to wasm-ld without the need for the `-Wl,` prefix. This matches the behaviour of both clang and gcc. (#18956) diff --git a/site/source/docs/api_reference/emscripten.h.rst b/site/source/docs/api_reference/emscripten.h.rst index 43d887dead88a..42cd1590fdc02 100644 --- a/site/source/docs/api_reference/emscripten.h.rst +++ b/site/source/docs/api_reference/emscripten.h.rst @@ -111,7 +111,7 @@ Defines var jsString = 'Hello with some exotic Unicode characters: Tässä on yksi lumiukko: ☃, ole hyvä.'; // 'jsString.length' would return the length of the string as UTF-16 // units, but Emscripten C strings operate as UTF-8. - return allocateUTF8(jsString); + return stringToNewUTF8(jsString); }); int main() { @@ -191,7 +191,7 @@ Defines var lengthBytes = lengthBytesUTF8(jsString)+1; // 'jsString.length' would return the length of the string as UTF-16 // units, but Emscripten C strings operate as UTF-8. - return allocateUTF8(jsString); + return stringToNewUTF8(jsString); }); printf("UTF8 string says: %s\n", str); free(str); // Each call to _malloc() must be paired with free(), or heap memory will leak! diff --git a/site/source/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.rst b/site/source/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.rst index cca9d5df4906e..eed087f3f90d5 100644 --- a/site/source/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.rst +++ b/site/source/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.rst @@ -235,7 +235,7 @@ The parameters you pass to and receive from functions need to be primitive value - Integer and floating point numbers can be passed as-is. - Pointers can be passed as-is also, as they are simply integers in the generated code. - - JavaScript string ``someString`` can be converted to a ``char *`` using ``ptr = allocateUTF8(someString)``. + - JavaScript string ``someString`` can be converted to a ``char *`` using ``ptr = stringToNewUTF8(someString)``. .. note:: The conversion to a pointer allocates memory, which needs to be freed up via a call to ``free(ptr)`` afterwards (``_free`` in JavaScript side) - diff --git a/src/library.js b/src/library.js index c4d15efdf5d43..dcb89e4abab17 100644 --- a/src/library.js +++ b/src/library.js @@ -52,8 +52,6 @@ mergeInto(LibraryManager.library, { // JavaScript <-> C string interop // ========================================================================== - $stringToNewUTF8: '$allocateUTF8', - #if !MINIMAL_RUNTIME $exitJS__docs: '/** @param {boolean|number=} implicit */', $exitJS__deps: ['proc_exit'], @@ -569,7 +567,7 @@ mergeInto(LibraryManager.library, { // TODO: Initialize these to defaults on startup from system settings. // Note: glibc has one fewer underscore for all of these. Also used in other related functions (timegm) - _tzset_js__deps: ['$allocateUTF8'], + _tzset_js__deps: ['$stringToNewUTF8'], _tzset_js__internal: true, _tzset_js: function(timezone, daylight, tzname) { // TODO: Use (malleable) environment variables instead of system settings. @@ -599,8 +597,8 @@ mergeInto(LibraryManager.library, { }; var winterName = extractZone(winter); var summerName = extractZone(summer); - var winterNamePtr = allocateUTF8(winterName); - var summerNamePtr = allocateUTF8(summerName); + var winterNamePtr = stringToNewUTF8(winterName); + var summerNamePtr = stringToNewUTF8(summerName); if (summerOffset < winterOffset) { // Northern hemisphere {{{ makeSetValue('tzname', '0', 'winterNamePtr', POINTER_TYPE) }}}; @@ -1827,11 +1825,11 @@ mergeInto(LibraryManager.library, { return getHostByName(UTF8ToString(name)); }, - $getHostByName__deps: ['malloc', '$allocateUTF8', '$DNS', '$inetPton4'], + $getHostByName__deps: ['malloc', '$stringToNewUTF8', '$DNS', '$inetPton4'], $getHostByName: function(name) { // generate hostent var ret = _malloc({{{ C_STRUCTS.hostent.__size__ }}}); // XXX possibly leaked, as are others here - var nameBuf = allocateUTF8(name); + var nameBuf = stringToNewUTF8(name); {{{ makeSetValue('ret', C_STRUCTS.hostent.h_name, 'nameBuf', POINTER_TYPE) }}}; var aliasesBuf = _malloc(4); {{{ makeSetValue('aliasesBuf', '0', '0', POINTER_TYPE) }}}; @@ -2622,7 +2620,7 @@ mergeInto(LibraryManager.library, { // using builtin_malloc to avoid LSan reporting these as leaks. emscripten_get_compiler_setting__noleakcheck: true, #if RETAIN_COMPILER_SETTINGS - emscripten_get_compiler_setting__deps: ['$allocateUTF8'], + emscripten_get_compiler_setting__deps: ['$stringToNewUTF8'], #endif emscripten_get_compiler_setting: function(name) { #if RETAIN_COMPILER_SETTINGS @@ -2635,7 +2633,7 @@ mergeInto(LibraryManager.library, { var cache = _emscripten_get_compiler_setting.cache; var fullret = cache[name]; if (fullret) return fullret; - return cache[name] = allocateUTF8(ret); + return cache[name] = stringToNewUTF8(ret); #else throw 'You must build with -sRETAIN_COMPILER_SETTINGS for getCompilerSetting or emscripten_get_compiler_setting to work'; #endif @@ -2803,7 +2801,7 @@ mergeInto(LibraryManager.library, { // Look up the function name from our stack frame cache with our PC representation. #if USE_OFFSET_CONVERTER - emscripten_pc_get_function__deps: ['$UNWIND_CACHE', 'free', '$allocateUTF8'], + emscripten_pc_get_function__deps: ['$UNWIND_CACHE', 'free', '$stringToNewUTF8'], // Don't treat allocation of _emscripten_pc_get_function.ret as a leak emscripten_pc_get_function__noleakcheck: true, #endif @@ -2829,7 +2827,7 @@ mergeInto(LibraryManager.library, { name = wasmOffsetConverter.getName(pc); } if (_emscripten_pc_get_function.ret) _free(_emscripten_pc_get_function.ret); - _emscripten_pc_get_function.ret = allocateUTF8(name); + _emscripten_pc_get_function.ret = stringToNewUTF8(name); return _emscripten_pc_get_function.ret; #endif }, @@ -2863,7 +2861,7 @@ mergeInto(LibraryManager.library, { }, // Look up the file name from our stack frame cache with our PC representation. - emscripten_pc_get_file__deps: ['$convertPCtoSourceLocation', 'free', '$allocateUTF8'], + emscripten_pc_get_file__deps: ['$convertPCtoSourceLocation', 'free', '$stringToNewUTF8'], // Don't treat allocation of _emscripten_pc_get_file.ret as a leak emscripten_pc_get_file__noleakcheck: true, emscripten_pc_get_file: function (pc) { @@ -2871,7 +2869,7 @@ mergeInto(LibraryManager.library, { if (!result) return 0; if (_emscripten_pc_get_file.ret) _free(_emscripten_pc_get_file.ret); - _emscripten_pc_get_file.ret = allocateUTF8(result.file); + _emscripten_pc_get_file.ret = stringToNewUTF8(result.file); return _emscripten_pc_get_file.ret; }, @@ -3714,7 +3712,7 @@ DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.push( '$UTF32ToString', '$stringToUTF32', '$lengthBytesUTF32', - '$allocateUTF8', + '$stringToNewUTF8', '$allocateUTF8OnStack', '$writeStringToMemory', '$writeArrayToMemory', diff --git a/src/library_browser.js b/src/library_browser.js index 1d9181dbd4f8a..07cc2d96b8d4c 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -803,14 +803,14 @@ var LibraryBrowser = { }, emscripten_run_preload_plugins_data__proxy: 'sync', - emscripten_run_preload_plugins_data__deps: ['$allocateUTF8'], + emscripten_run_preload_plugins_data__deps: ['$stringToNewUTF8'], emscripten_run_preload_plugins_data: function(data, size, suffix, arg, onload, onerror) { {{{ runtimeKeepalivePush() }}} var _suffix = UTF8ToString(suffix); if (!Browser.asyncPrepareDataCounter) Browser.asyncPrepareDataCounter = 0; var name = 'prepare_data_' + (Browser.asyncPrepareDataCounter++) + '.' + _suffix; - var cname = allocateUTF8(name); + var cname = stringToNewUTF8(name); FS.createPreloadedFile( '/', name, diff --git a/src/library_egl.js b/src/library_egl.js index 90577d3b23039..f4b6071b3b9e5 100644 --- a/src/library_egl.js +++ b/src/library_egl.js @@ -520,7 +520,7 @@ var LibraryEGL = { }, // EGLAPI const char * EGLAPIENTRY eglQueryString(EGLDisplay dpy, EGLint name); - eglQueryString__deps: ['$allocateUTF8'], + eglQueryString__deps: ['$stringToNewUTF8'], eglQueryString__proxy: 'sync', eglQueryString__sig: 'iii', eglQueryString: function(display, name) { @@ -533,10 +533,10 @@ var LibraryEGL = { if (EGL.stringCache[name]) return EGL.stringCache[name]; var ret; switch (name) { - case 0x3053 /* EGL_VENDOR */: ret = allocateUTF8("Emscripten"); break; - case 0x3054 /* EGL_VERSION */: ret = allocateUTF8("1.4 Emscripten EGL"); break; - case 0x3055 /* EGL_EXTENSIONS */: ret = allocateUTF8(""); break; // Currently not supporting any EGL extensions. - case 0x308D /* EGL_CLIENT_APIS */: ret = allocateUTF8("OpenGL_ES"); break; + case 0x3053 /* EGL_VENDOR */: ret = stringToNewUTF8("Emscripten"); break; + case 0x3054 /* EGL_VERSION */: ret = stringToNewUTF8("1.4 Emscripten EGL"); break; + case 0x3055 /* EGL_EXTENSIONS */: ret = stringToNewUTF8(""); break; // Currently not supporting any EGL extensions. + case 0x308D /* EGL_CLIENT_APIS */: ret = stringToNewUTF8("OpenGL_ES"); break; default: EGL.setErrorCode(0x300C /* EGL_BAD_PARAMETER */); return 0; diff --git a/src/library_glew.js b/src/library_glew.js index 8bb1100e3be23..817cc2e0f09cf 100644 --- a/src/library_glew.js +++ b/src/library_glew.js @@ -20,7 +20,7 @@ */ var LibraryGLEW = { - $GLEW__deps: ['glGetString', '$allocateUTF8'], + $GLEW__deps: ['glGetString', '$stringToNewUTF8'], $GLEW: { isLinaroFork: 1, extensions: null, @@ -73,7 +73,7 @@ var LibraryGLEW = { string = "Unknown error"; error = 8; // prevent array from growing more than this } - GLEW.error[error] = allocateUTF8(string); + GLEW.error[error] = stringToNewUTF8(string); } return GLEW.error[error]; }, @@ -93,7 +93,7 @@ var LibraryGLEW = { var string = GLEW.versionStringConstantFromCode(name); if (!string) return 0; - GLEW.version[name] = allocateUTF8(string); + GLEW.version[name] = stringToNewUTF8(string); } return GLEW.version[name]; }, diff --git a/src/library_glfw.js b/src/library_glfw.js index e12ec756d3520..944fc70474cb0 100644 --- a/src/library_glfw.js +++ b/src/library_glfw.js @@ -82,7 +82,7 @@ var LibraryGLFW = { }, $GLFW__deps: ['emscripten_get_now', '$GL', '$Browser', '$GLFW_Window', - '$allocateUTF8', + '$stringToNewUTF8', #if FILESYSTEM '$FS', #endif @@ -662,7 +662,7 @@ var LibraryGLFW = { if (!GLFW.joys[joy]) { out('glfw joystick connected:',joy); GLFW.joys[joy] = { - id: allocateUTF8(gamepad.id), + id: stringToNewUTF8(gamepad.id), buttonsCount: gamepad.buttons.length, axesCount: gamepad.axes.length, buttons: _malloc(gamepad.buttons.length), @@ -789,7 +789,7 @@ var LibraryGLFW = { }; reader.readAsArrayBuffer(file); - var filename = allocateUTF8(path); + var filename = stringToNewUTF8(path); filenamesArray.push(filename); {{{ makeSetValue('filenames + i*4', '0', 'filename', POINTER_TYPE) }}}; } @@ -1251,7 +1251,7 @@ var LibraryGLFW = { glfwGetVersionString__sig: 'i', glfwGetVersionString: function() { if (!GLFW.versionString) { - GLFW.versionString = allocateUTF8("3.2.1 JS WebGL Emscripten"); + GLFW.versionString = stringToNewUTF8("3.2.1 JS WebGL Emscripten"); } return GLFW.versionString; }, @@ -1318,7 +1318,7 @@ var LibraryGLFW = { glfwGetMonitorName__sig: 'ii', glfwGetMonitorName: function(mon) { if (!GLFW.monitorString) { - GLFW.monitorString = allocateUTF8("HTML5 WebGL Canvas"); + GLFW.monitorString = stringToNewUTF8("HTML5 WebGL Canvas"); } return GLFW.monitorString; }, diff --git a/src/library_legacy.js b/src/library_legacy.js index de902397615b5..43693e06910c7 100644 --- a/src/library_legacy.js +++ b/src/library_legacy.js @@ -37,4 +37,6 @@ mergeInto(LibraryManager.library, { HEAPU8.set(slab, ret); return ret; }, + + $allocateUTF8: '$stringToNewUTF8', }); diff --git a/src/library_openal.js b/src/library_openal.js index f09a6b427b04c..6d5ecf7d26db6 100644 --- a/src/library_openal.js +++ b/src/library_openal.js @@ -2376,7 +2376,7 @@ var LibraryOpenAL = { }, alcGetString__proxy: 'sync', - alcGetString__deps: ['$allocateUTF8'], + alcGetString__deps: ['$stringToNewUTF8'], alcGetString: function(deviceId, param) { if (AL.alcStringCache[param]) { return AL.alcStringCache[param]; @@ -2450,7 +2450,7 @@ var LibraryOpenAL = { return 0; } - ret = allocateUTF8(ret); + ret = stringToNewUTF8(ret); AL.alcStringCache[param] = ret; return ret; }, @@ -2631,7 +2631,7 @@ var LibraryOpenAL = { emscripten_alcGetStringiSOFT__proxy: 'sync', emscripten_alcGetStringiSOFT__sig: 'iiii', - emscripten_alcGetStringiSOFT__deps: ['alcGetString', '$allocateUTF8'], + emscripten_alcGetStringiSOFT__deps: ['alcGetString', '$stringToNewUTF8'], emscripten_alcGetStringiSOFT: function(deviceId, param, index) { if (!(deviceId in AL.deviceRefCounts)) { #if OPENAL_DEBUG @@ -2669,7 +2669,7 @@ var LibraryOpenAL = { return _alcGetString(deviceId, param); } - ret = allocateUTF8(ret); + ret = stringToNewUTF8(ret); AL.alcStringCache[param] = ret; return ret; }, @@ -3018,7 +3018,7 @@ var LibraryOpenAL = { }, alGetString__proxy: 'sync', - alGetString__deps: ['$allocateUTF8'], + alGetString__deps: ['$stringToNewUTF8'], alGetString: function(param) { if (AL.stringCache[param]) { return AL.stringCache[param]; @@ -3072,7 +3072,7 @@ var LibraryOpenAL = { return 0; } - ret = allocateUTF8(ret); + ret = stringToNewUTF8(ret); AL.stringCache[param] = ret; return ret; }, diff --git a/src/library_sdl.js b/src/library_sdl.js index d18c91f4270d0..f449677e226ad 100644 --- a/src/library_sdl.js +++ b/src/library_sdl.js @@ -1762,10 +1762,10 @@ var LibrarySDL = { }, SDL_GetKeyName__proxy: 'sync', - SDL_GetKeyName__deps: ['$allocateUTF8'], + SDL_GetKeyName__deps: ['$stringToNewUTF8'], SDL_GetKeyName: function(key) { if (!SDL.keyName) { - SDL.keyName = allocateUTF8('unknown key'); + SDL.keyName = stringToNewUTF8('unknown key'); } return SDL.keyName; }, @@ -1817,10 +1817,10 @@ var LibrarySDL = { }, SDL_GetError__proxy: 'sync', - SDL_GetError__deps: ['$allocateUTF8'], + SDL_GetError__deps: ['$stringToNewUTF8'], SDL_GetError: function() { if (!SDL.errorMessage) { - SDL.errorMessage = allocateUTF8("unknown SDL-emscripten error"); + SDL.errorMessage = stringToNewUTF8("unknown SDL-emscripten error"); } return SDL.errorMessage; }, @@ -2185,7 +2185,7 @@ var LibrarySDL = { return flags; // We support JPG, PNG, TIF because browsers do }, - IMG_Load_RW__deps: ['SDL_LockSurface', 'SDL_FreeRW', '$PATH_FS', 'malloc', '$allocateUTF8'], + IMG_Load_RW__deps: ['SDL_LockSurface', 'SDL_FreeRW', '$PATH_FS', 'malloc', '$stringToNewUTF8'], IMG_Load_RW__proxy: 'sync', IMG_Load_RW: function(rwopsID, freeSrc) { try { @@ -2245,7 +2245,7 @@ var LibrarySDL = { if (!raw) { if (raw === null) err('Trying to reuse preloaded image, but freePreloadedMediaOnUse is set!'); #if STB_IMAGE - var name = allocateUTF8(filename); + var name = stringToNewUTF8(filename); addCleanup(function() { _free(name); }); @@ -3447,7 +3447,7 @@ var LibrarySDL = { }, SDL_JoystickName__proxy: 'sync', - SDL_JoystickName__deps: ['$allocateUTF8'], + SDL_JoystickName__deps: ['$stringToNewUTF8'], SDL_JoystickName: function(deviceIndex) { var gamepad = SDL.getGamepad(deviceIndex); if (gamepad) { @@ -3455,7 +3455,7 @@ var LibrarySDL = { if (SDL.joystickNamePool.hasOwnProperty(name)) { return SDL.joystickNamePool[name]; } - return SDL.joystickNamePool[name] = allocateUTF8(name); + return SDL.joystickNamePool[name] = stringToNewUTF8(name); } return 0; }, @@ -3575,9 +3575,9 @@ var LibrarySDL = { }, SDL_GetNumAudioDrivers: function() { return 1 }, - SDL_GetCurrentAudioDriver__deps: ['$allocateUTF8'], + SDL_GetCurrentAudioDriver__deps: ['$stringToNewUTF8'], SDL_GetCurrentAudioDriver: function() { - return allocateUTF8('Emscripten Audio'); + return stringToNewUTF8('Emscripten Audio'); }, SDL_GetScancodeFromKey: function (key) { return SDL.scanCodes[key]; diff --git a/src/library_strings.js b/src/library_strings.js index 0763d6af4fb7d..8746cd357379c 100644 --- a/src/library_strings.js +++ b/src/library_strings.js @@ -226,9 +226,9 @@ mergeInto(LibraryManager.library, { // Allocate heap space for a JS string, and write it there. // It is the responsibility of the caller to free() that memory. - $allocateUTF8: function(str) { + $stringToNewUTF8: function(str) { var size = lengthBytesUTF8(str) + 1; - var ret = {{{ makeMalloc('allocateUTF8', 'size') }}}; + var ret = {{{ makeMalloc('stringToNewUTF8', 'size') }}}; if (ret) stringToUTF8Array(str, HEAP8, ret, size); return ret; }, diff --git a/src/library_wasmfs.js b/src/library_wasmfs.js index f984b74290b09..d04ccf1b972ff 100644 --- a/src/library_wasmfs.js +++ b/src/library_wasmfs.js @@ -16,7 +16,7 @@ mergeInto(LibraryManager.library, { '$wasmFSPreloadedDirs', '$asyncLoad', '$PATH', - '$allocateUTF8', + '$stringToNewUTF8', '$allocateUTF8OnStack', '$withStackSave', '$readI53FromI64', @@ -104,7 +104,7 @@ mergeInto(LibraryManager.library, { throw new Error('Invalid encoding type "' + opts.encoding + '"'); } - var pathName = allocateUTF8(path); + var pathName = stringToNewUTF8(path); // Copy the file into a JS buffer on the heap. var buf = __wasmfs_read_file(pathName); diff --git a/src/library_webgpu.js b/src/library_webgpu.js index 09e3911035748..1e787a3fbf10a 100644 --- a/src/library_webgpu.js +++ b/src/library_webgpu.js @@ -770,7 +770,7 @@ var LibraryWebGPU = { device["pushErrorScope"](WebGPU.ErrorFilter[filter]); }, - wgpuDevicePopErrorScope__deps: ['$callUserCallback', '$allocateUTF8'], + wgpuDevicePopErrorScope__deps: ['$callUserCallback', '$stringToNewUTF8'], wgpuDevicePopErrorScope: function(deviceId, callback, userdata) { var device = WebGPU.mgrDevice.get(deviceId); {{{ runtimeKeepalivePush() }}} @@ -787,7 +787,7 @@ var LibraryWebGPU = { #if ASSERTIONS assert(gpuError instanceof GPUValidationError); #endif - var messagePtr = allocateUTF8(gpuError.message); + var messagePtr = stringToNewUTF8(gpuError.message); {{{ makeDynCall('viii', 'callback') }}}({{{ gpu.ErrorType.Validation }}}, messagePtr, userdata); _free(messagePtr); } @@ -795,7 +795,7 @@ var LibraryWebGPU = { }, function(ex) { {{{ runtimeKeepalivePop() }}} callUserCallback(function() { - var messagePtr = allocateUTF8(ex.message); + var messagePtr = stringToNewUTF8(ex.message); // TODO: This can mean either the device was lost or the error scope stack was empty. Figure // out how to synthesize the DeviceLost error type. (Could be by simply tracking the error // scope depth, but that isn't ideal.) @@ -810,7 +810,7 @@ var LibraryWebGPU = { device.label = UTF8ToString(labelPtr); }, - wgpuDeviceSetDeviceLostCallback__deps: ['$callUserCallback', '$allocateUTF8'], + wgpuDeviceSetDeviceLostCallback__deps: ['$callUserCallback', '$stringToNewUTF8'], wgpuDeviceSetDeviceLostCallback: function(deviceId, callback, userdata) { var deviceWrapper = WebGPU.mgrDevice.objects[deviceId]; {{{ gpu.makeCheckDefined('deviceWrapper') }}} @@ -823,14 +823,14 @@ var LibraryWebGPU = { deviceWrapper.lostCallback = function(info) { // This will skip the callback if the runtime is no longer alive. callUserCallback(function() { - var messagePtr = allocateUTF8(info.message); + var messagePtr = stringToNewUTF8(info.message); {{{ makeDynCall('viii', 'callback') }}}(WebGPU.DeviceLostReason[info.reason], messagePtr, userdata); _free(messagePtr); }); }; }, - wgpuDeviceSetUncapturedErrorCallback__deps: ['$callUserCallback', '$allocateUTF8'], + wgpuDeviceSetUncapturedErrorCallback__deps: ['$callUserCallback', '$stringToNewUTF8'], wgpuDeviceSetUncapturedErrorCallback: function(deviceId, callback, userdata) { var device = WebGPU.mgrDevice.get(deviceId); device["onuncapturederror"] = function(ev) { @@ -847,7 +847,7 @@ var LibraryWebGPU = { if (ev.error instanceof GPUValidationError) type = Validation; else if (ev.error instanceof GPUOutOfMemoryError) type = OutOfMemory; - var messagePtr = allocateUTF8(ev.error.message); + var messagePtr = stringToNewUTF8(ev.error.message); {{{ makeDynCall('viii', 'callback') }}}(type, messagePtr, userdata); _free(messagePtr); }); @@ -2432,7 +2432,7 @@ var LibraryWebGPU = { #endif }, - wgpuInstanceRequestAdapter__deps: ['$callUserCallback', '$allocateUTF8'], + wgpuInstanceRequestAdapter__deps: ['$callUserCallback', '$stringToNewUTF8'], wgpuInstanceRequestAdapter: function(instanceId, options, callback, userdata) { {{{ gpu.makeCheck('instanceId === 0, "WGPUInstance is ignored"') }}} @@ -2448,7 +2448,7 @@ var LibraryWebGPU = { } if (!('gpu' in navigator)) { - var messagePtr = allocateUTF8('WebGPU not available on this browser (navigator.gpu is not available)'); + var messagePtr = stringToNewUTF8('WebGPU not available on this browser (navigator.gpu is not available)'); {{{ makeDynCall('viiii', 'callback') }}}({{{ gpu.RequestAdapterStatus.Unavailable }}}, 0, messagePtr, userdata); _free(messagePtr); return; @@ -2462,7 +2462,7 @@ var LibraryWebGPU = { var adapterId = WebGPU.mgrAdapter.create(adapter); {{{ makeDynCall('viiii', 'callback') }}}({{{ gpu.RequestAdapterStatus.Success }}}, adapterId, 0, userdata); } else { - var messagePtr = allocateUTF8('WebGPU not available on this system (requestAdapter returned null)'); + var messagePtr = stringToNewUTF8('WebGPU not available on this system (requestAdapter returned null)'); {{{ makeDynCall('viiii', 'callback') }}}({{{ gpu.RequestAdapterStatus.Unavailable }}}, 0, messagePtr, userdata); _free(messagePtr); } @@ -2470,7 +2470,7 @@ var LibraryWebGPU = { }, function(ex) { {{{ runtimeKeepalivePop() }}} callUserCallback(function() { - var messagePtr = allocateUTF8(ex.message); + var messagePtr = stringToNewUTF8(ex.message); {{{ makeDynCall('viiii', 'callback') }}}({{{ gpu.RequestAdapterStatus.Error }}}, 0, messagePtr, userdata); _free(messagePtr); }); @@ -2513,7 +2513,7 @@ var LibraryWebGPU = { return adapter.features.has(WebGPU.FeatureName[featureEnumValue]); }, - wgpuAdapterRequestDevice__deps: ['$callUserCallback', '$allocateUTF8'], + wgpuAdapterRequestDevice__deps: ['$callUserCallback', '$stringToNewUTF8'], wgpuAdapterRequestDevice: function(adapterId, descriptor, callback, userdata) { var adapter = WebGPU.mgrAdapter.get(adapterId); @@ -2602,7 +2602,7 @@ var LibraryWebGPU = { }, function(ex) { {{{ runtimeKeepalivePop() }}} callUserCallback(function() { - var messagePtr = allocateUTF8(ex.message); + var messagePtr = stringToNewUTF8(ex.message); {{{ makeDynCall('viiii', 'callback') }}}({{{ gpu.RequestDeviceStatus.Error }}}, 0, messagePtr, userdata); _free(messagePtr); }); diff --git a/src/library_websocket.js b/src/library_websocket.js index 4a4beeec32c9a..e6e7ad6ee50ea 100644 --- a/src/library_websocket.js +++ b/src/library_websocket.js @@ -215,7 +215,7 @@ var LibraryWebSocket = { return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, - emscripten_websocket_set_onmessage_callback_on_thread__deps: ['$WS', '$allocateUTF8'], + emscripten_websocket_set_onmessage_callback_on_thread__deps: ['$WS', '$stringToNewUTF8'], emscripten_websocket_set_onmessage_callback_on_thread__proxy: 'sync', emscripten_websocket_set_onmessage_callback_on_thread: function(socketId, userData, callbackFunc, thread) { if (!WS.socketEvent) WS.socketEvent = _malloc(1024); // TODO: sizeof(EmscriptenWebSocketCloseEvent), which is the largest event struct @@ -237,7 +237,7 @@ var LibraryWebSocket = { #endif HEAPU32[WS.socketEvent>>2] = socketId; if (typeof e.data == 'string') { - var buf = allocateUTF8(e.data); + var buf = stringToNewUTF8(e.data); #if WEBSOCKET_DEBUG var len = lengthBytesUTF8(e.data)+1; var s = (e.data.length < 256) ? e.data : (e.data.substr(0, 256) + ' (' + (e.data.length-256) + ' more characters)'); diff --git a/system/lib/compiler-rt/lib/asan/asan_flags.cpp b/system/lib/compiler-rt/lib/asan/asan_flags.cpp index b1feaf903e206..d4930dff5559f 100644 --- a/system/lib/compiler-rt/lib/asan/asan_flags.cpp +++ b/system/lib/compiler-rt/lib/asan/asan_flags.cpp @@ -132,7 +132,7 @@ void InitializeFlags() { #define MAKE_OPTION_LOAD(parser, name) \ options = (char*)(long)EM_ASM_DOUBLE({ \ return withBuiltinMalloc(function () { \ - return allocateUTF8(Module[name] || 0); \ + return stringToNewUTF8(Module[name] || 0); \ }); \ }); \ parser.ParseString(options); \ diff --git a/system/lib/compiler-rt/lib/lsan/lsan.cpp b/system/lib/compiler-rt/lib/lsan/lsan.cpp index 12f107970eb00..78bc5b7241048 100644 --- a/system/lib/compiler-rt/lib/lsan/lsan.cpp +++ b/system/lib/compiler-rt/lib/lsan/lsan.cpp @@ -84,7 +84,7 @@ static void InitializeFlags() { #if SANITIZER_EMSCRIPTEN char *options = (char*) EM_ASM_PTR({ return withBuiltinMalloc(function () { - return allocateUTF8(Module['LSAN_OPTIONS'] || 0); + return stringToNewUTF8(Module['LSAN_OPTIONS'] || 0); }); }); parser.ParseString(options); diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_flags.cpp b/system/lib/compiler-rt/lib/ubsan/ubsan_flags.cpp index d26a153ec79dc..39aa638824df0 100644 --- a/system/lib/compiler-rt/lib/ubsan/ubsan_flags.cpp +++ b/system/lib/compiler-rt/lib/ubsan/ubsan_flags.cpp @@ -79,7 +79,7 @@ void InitializeFlags() { #if SANITIZER_EMSCRIPTEN char *options = (char*) EM_ASM_PTR({ return withBuiltinMalloc(function () { - return allocateUTF8(Module['UBSAN_OPTIONS'] || 0); + return stringToNewUTF8(Module['UBSAN_OPTIONS'] || 0); }); }); parser.ParseString(options); diff --git a/test/test_other.py b/test/test_other.py index 2a81f512212ae..85b83df398745 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -11522,18 +11522,18 @@ def test_missing_malloc_export_indirect(self): # requires malloc create_file('unincluded_malloc.c', r''' #include - EM_JS_DEPS(main, "$allocateUTF8"); + EM_JS_DEPS(main, "$stringToNewUTF8"); int main() { EM_ASM({ try { - allocateUTF8("foo"); + stringToNewUTF8("foo"); } catch(e) { console.log('exception:', e); } }); } ''') - self.do_runf('unincluded_malloc.c', 'malloc was not included, but is needed in allocateUTF8. Adding "_malloc" to EXPORTED_FUNCTIONS should fix that. This may be a bug in the compiler, please file an issue.') + self.do_runf('unincluded_malloc.c', 'malloc was not included, but is needed in stringToNewUTF8. Adding "_malloc" to EXPORTED_FUNCTIONS should fix that. This may be a bug in the compiler, please file an issue.') def test_getrusage(self): self.do_runf(test_file('other/test_getrusage.c')) From 099af34541186629e6dbf1dafe59362e05798f67 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 29 Mar 2023 12:29:51 -0700 Subject: [PATCH 0073/1523] Remove likely unused `FS.loadFilesFromDB` and `FS.saveFilesToDB` helpers (#19049) These were added back in 1b134c8 but we are not aware of anyone using them. We have a separate IDBFS filesystem that provides indexDB persistence so this seems like duplicate/redundant code. Fixes: #19025 --- ChangeLog.md | 3 + .../docs/api_reference/advanced-apis.rst | 2 - src/library_fs.js | 83 ------------------- src/preamble.js | 1 - test/file_db.cpp | 52 ------------ test/test_browser.py | 11 --- test/test_other.py | 1 - 7 files changed, 3 insertions(+), 150 deletions(-) delete mode 100644 test/file_db.cpp diff --git a/ChangeLog.md b/ChangeLog.md index 0059ebf5aa63a..3814516b72200 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -20,6 +20,9 @@ See docs/process.md for more on how version tagging works. 3.1.35 (in development) ----------------------- +- `FS.loadFilesFromDB` and `FS.saveFilesToDB` were removed. We think it's + unlikly there were any users of these functions since there is now a separate + IDBFS filesystem for folks that want persistence. (#19049) - `allocateUTF8` library function moved to `library_legacy.js`. Prefer the more accurately named `stringToNewUTF8`. - `SDL_image` port was updated to version 2.6.0. diff --git a/site/source/docs/api_reference/advanced-apis.rst b/site/source/docs/api_reference/advanced-apis.rst index f837a9b0136f0..36656726b6267 100644 --- a/site/source/docs/api_reference/advanced-apis.rst +++ b/site/source/docs/api_reference/advanced-apis.rst @@ -98,8 +98,6 @@ example, writing a new local file system) or legacy file system compatibility. .. js:function:: FS.quit() .. js:function:: FS.indexedDB() .. js:function:: FS.DB_NAME() -.. js:function:: FS.saveFilesToDB(paths, onload, onerror) -.. js:function:: FS.loadFilesFromDB(paths, onload, onerror) For advanced users only. diff --git a/src/library_fs.js b/src/library_fs.js index b051144958551..b47020340b7c4 100644 --- a/src/library_fs.js +++ b/src/library_fs.js @@ -1911,89 +1911,6 @@ FS.staticInit();` + } }, - // - // persistence - // - indexedDB: () => { - return window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB; - }, - - DB_NAME: () => { - return 'EM_FS_' + window.location.pathname; - }, - DB_VERSION: 20, - DB_STORE_NAME: 'FILE_DATA', - - // asynchronously saves a list of files to an IndexedDB. The DB will be created if not already existing. - saveFilesToDB: (paths, onload = (() => {}), onerror = (() => {})) => { - var indexedDB = FS.indexedDB(); - try { - var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION); - } catch (e) { - return onerror(e); - } - openRequest.onupgradeneeded = () => { - out('creating db'); - var db = openRequest.result; - db.createObjectStore(FS.DB_STORE_NAME); - }; - openRequest.onsuccess = () => { - var db = openRequest.result; - var transaction = db.transaction([FS.DB_STORE_NAME], 'readwrite'); - var files = transaction.objectStore(FS.DB_STORE_NAME); - var ok = 0, fail = 0, total = paths.length; - function finish() { - if (fail == 0) onload(); else onerror(); - } - paths.forEach((path) => { - var putRequest = files.put(FS.analyzePath(path).object.contents, path); - putRequest.onsuccess = () => { ok++; if (ok + fail == total) finish() }; - putRequest.onerror = () => { fail++; if (ok + fail == total) finish() }; - }); - transaction.onerror = onerror; - }; - openRequest.onerror = onerror; - }, - - // asynchronously loads a file from IndexedDB. - loadFilesFromDB: (paths, onload = (() => {}), onerror = (() => {})) => { - var indexedDB = FS.indexedDB(); - try { - var openRequest = indexedDB.open(FS.DB_NAME(), FS.DB_VERSION); - } catch (e) { - return onerror(e); - } - openRequest.onupgradeneeded = onerror; // no database to load from - openRequest.onsuccess = () => { - var db = openRequest.result; - try { - var transaction = db.transaction([FS.DB_STORE_NAME], 'readonly'); - } catch(e) { - onerror(e); - return; - } - var files = transaction.objectStore(FS.DB_STORE_NAME); - var ok = 0, fail = 0, total = paths.length; - function finish() { - if (fail == 0) onload(); else onerror(); - } - paths.forEach((path) => { - var getRequest = files.get(path); - getRequest.onsuccess = () => { - if (FS.analyzePath(path).exists) { - FS.unlink(path); - } - FS.createDataFile(PATH.dirname(path), PATH.basename(path), getRequest.result, true, true, true); - ok++; - if (ok + fail == total) finish(); - }; - getRequest.onerror = () => { fail++; if (ok + fail == total) finish() }; - }); - transaction.onerror = onerror; - }; - openRequest.onerror = onerror; - }, - // Removed v1 functions #if ASSERTIONS absolutePath: () => { diff --git a/src/preamble.js b/src/preamble.js index 042e591ac2067..5d1c9f5b610ef 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -512,7 +512,6 @@ var FS = { mkdev: function() { FS.error() }, registerDevice: function() { FS.error() }, analyzePath: function() { FS.error() }, - loadFilesFromDB: function() { FS.error() }, ErrnoError: function ErrnoError() { FS.error() }, }; diff --git a/test/file_db.cpp b/test/file_db.cpp deleted file mode 100644 index ffcc51f4f7a52..0000000000000 --- a/test/file_db.cpp +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2013 The Emscripten Authors. All rights reserved. -// Emscripten is available under two separate licenses, the MIT license and the -// University of Illinois/NCSA Open Source License. Both these licenses can be -// found in the LICENSE file. - -#include -#include - -void later(void *) {} - -int main() { -#if FIRST - FILE *f = fopen("waka.txt", "w"); - fputc('a', f); - fputc('z', f); - fclose(f); - - EM_ASM( - FS.saveFilesToDB(['waka.txt', 'moar.txt'], function() { - out('save ok'); - var xhr = new XMLHttpRequest(); - xhr.open('GET', 'http://localhost:8888/report_result?1'); - xhr.send(); - setTimeout(function() { window.close() }, 1000); - }, function(e) { - abort('saving should succeed ' + e); - }); - ); -#else - EM_ASM( - FS.loadFilesFromDB(['waka.txt', 'moar.txt'], function() { - function stringy(arr) { - return Array.prototype.map.call(arr, function(x) { return String.fromCharCode(x) }).join(""); - } - assert(stringy(FS.analyzePath('waka.txt').object.contents) == 'az'); - var secret = stringy(FS.analyzePath('moar.txt').object.contents); - out('load: ' + secret); - var xhr = new XMLHttpRequest(); - xhr.open('GET', 'http://localhost:8888/report_result?' + secret); - xhr.send(); - setTimeout(function() { window.close() }, 1000); - }, function() { - abort('loading should succeed'); - }); - ); -#endif - - emscripten_async_call(later, NULL, 100); // keep runtime alive - - return 0; -} - diff --git a/test/test_browser.py b/test/test_browser.py index 2b908b2cd9b33..8c031df58e385 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -1345,17 +1345,6 @@ def test_write_file_in_environment_web(self): def test_fflush(self): self.btest('test_fflush.cpp', '0', args=['-sEXIT_RUNTIME', '--shell-file', test_file('test_fflush.html')], reporting=Reporting.NONE) - def test_file_db(self): - secret = str(time.time()) - create_file('moar.txt', secret) - self.btest('file_db.cpp', '1', args=['--preload-file', 'moar.txt', '-DFIRST']) - shutil.copyfile('test.html', 'first.html') - self.btest('file_db.cpp', secret, args=['-sFORCE_FILESYSTEM']) - shutil.copyfile('test.html', 'second.html') - create_file('moar.txt', 'aliantha') - self.btest('file_db.cpp', secret, args=['--preload-file', 'moar.txt']) # even with a file there, we load over it - shutil.move('test.html', 'third.html') - def test_fs_idbfs_sync(self): self.set_setting('DEFAULT_LIBRARY_FUNCS_TO_INCLUDE', '$ccall') for extra in [[], ['-DEXTRA_WORK']]: diff --git a/test/test_other.py b/test/test_other.py index 85b83df398745..b1ccceba519c1 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -7497,7 +7497,6 @@ def test(contents): test("FS.createPreloadedFile('waka waka, just warning check')") test("FS.createDataFile('waka waka, just warning check')") test("FS.analyzePath('waka waka, just warning check')") - test("FS.loadFilesFromDB('waka waka, just warning check')") # might appear in filesystem code from a separate script tag test("Module['FS_createDataFile']('waka waka, just warning check')") test("Module['FS_createPreloadedFile']('waka waka, just warning check')") From 43068312b072b32bedd65dd0f51ecb911078545c Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 29 Mar 2023 16:53:22 -0700 Subject: [PATCH 0074/1523] embind: Remove unused `long double` memory view (#19096) This was a legacy of fastcomp where sizeof(double) and sizeof(long double) were the same. --- system/lib/embind/bind.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp index 732c8ae59d45e..815a86eada52b 100644 --- a/system/lib/embind/bind.cpp +++ b/system/lib/embind/bind.cpp @@ -176,7 +176,4 @@ EMSCRIPTEN_BINDINGS(builtin) { register_memory_view("emscripten::memory_view"); register_memory_view("emscripten::memory_view"); -#if __SIZEOF_LONG_DOUBLE__ == __SIZEOF_DOUBLE__ - register_memory_view("emscripten::memory_view"); -#endif } From b735d4b8570a55c3e4fe05b1b6a4bbd0541d3ef5 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 29 Mar 2023 17:45:31 -0700 Subject: [PATCH 0075/1523] Rebaseline codesize expectations. NFC --- test/other/test_unoptimized_code_size.js.size | 2 +- test/other/test_unoptimized_code_size_strict.js.size | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/other/test_unoptimized_code_size.js.size b/test/other/test_unoptimized_code_size.js.size index 08789b21f9bd1..6215919ad39b3 100644 --- a/test/other/test_unoptimized_code_size.js.size +++ b/test/other/test_unoptimized_code_size.js.size @@ -1 +1 @@ -64465 +64419 diff --git a/test/other/test_unoptimized_code_size_strict.js.size b/test/other/test_unoptimized_code_size_strict.js.size index 046dd3e1cb98c..af0da47a1dd5f 100644 --- a/test/other/test_unoptimized_code_size_strict.js.size +++ b/test/other/test_unoptimized_code_size_strict.js.size @@ -1 +1 @@ -63499 +63435 From 2a1319079b8e05cb33c8ee3a5f4e654d51d62978 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 30 Mar 2023 10:18:02 -0700 Subject: [PATCH 0076/1523] Acorn optimizer: Fix a crash on a direct call in isExportWrapperFunction (#19101) We assumed that a call in there is of a special expression, but it could also be just a call to an identifier, a normal call like z(). We just need to ignore that and not crash. Fixes #19052 --- test/optimizer/emitDCEGraph.js | 4 ++++ tools/acorn-optimizer.js | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/test/optimizer/emitDCEGraph.js b/test/optimizer/emitDCEGraph.js index 2814eea3db21c..cabb1ea20609e 100644 --- a/test/optimizer/emitDCEGraph.js +++ b/test/optimizer/emitDCEGraph.js @@ -110,3 +110,7 @@ dynCall('vii', ptr, [2, 3]); // use indirectly, depending on analysis of dynCall x++; }); +// Don't crash on this code pattern, which we should ignore. +var _bad = function() { + return something(); +}; diff --git a/tools/acorn-optimizer.js b/tools/acorn-optimizer.js index a6874c04c9329..690829b942b8d 100755 --- a/tools/acorn-optimizer.js +++ b/tools/acorn-optimizer.js @@ -601,7 +601,9 @@ function isExportWrapperFunction(f) { const expr = f.body.body[0]; if (expr.type == 'ReturnStatement') { const rtn = expr.argument; - if (rtn.type == 'CallExpression') { + // We are looking for a call of special target, like (x = y)(), and not a + // non-call or a normal direct call such as z(). + if (rtn.type == 'CallExpression' && rtn.callee.object) { let target = rtn.callee.object; if (target.type == 'ParenthesizedExpression') { target = target.expression; From cd1aacc7ed6dd0a5e9d6ba8ef98639d3b4c98bea Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 30 Mar 2023 13:27:49 -0700 Subject: [PATCH 0077/1523] Rename allocateUTF8OnStack -> stringToNewUTF8OnStack (#19092) The old name is still available as an alias in library_legacy.js. Followup to #19089 --- ChangeLog.md | 5 +++-- emscripten.py | 2 +- src/library.js | 2 +- src/library_ccall.js | 4 ++-- src/library_dylink.js | 4 ++-- src/library_html5.js | 8 ++++---- src/library_legacy.js | 1 + src/library_sockfs.js | 4 ++-- src/library_stack_trace.js | 4 ++-- src/library_strings.js | 2 +- src/library_wasmfs.js | 20 ++++++++++---------- src/library_wasmfs_node.js | 2 +- src/library_wasmfs_opfs.js | 2 +- src/library_wget.js | 10 +++++----- src/postamble.js | 2 +- test/core/test_asan_js_stack_op.c | 4 ++-- test/stack_overflow.cpp | 6 +++--- test/test_other.py | 4 ++-- 18 files changed, 44 insertions(+), 42 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 3814516b72200..779ce8f629491 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -23,8 +23,9 @@ See docs/process.md for more on how version tagging works. - `FS.loadFilesFromDB` and `FS.saveFilesToDB` were removed. We think it's unlikly there were any users of these functions since there is now a separate IDBFS filesystem for folks that want persistence. (#19049) -- `allocateUTF8` library function moved to `library_legacy.js`. Prefer the - more accurately named `stringToNewUTF8`. +- `allocateUTF8` and `allocateUTF8OnStack` library function moved to + `library_legacy.js`. Prefer the more accurately named `stringToNewUTF8` and + `stringToUTF8OnStack`. (#19089) - `SDL_image` port was updated to version 2.6.0. - `-z` arguments are now passed directly to wasm-ld without the need for the `-Wl,` prefix. This matches the behaviour of both clang and gcc. (#18956) diff --git a/emscripten.py b/emscripten.py index 41d750aee4c19..d4109061e77f0 100644 --- a/emscripten.py +++ b/emscripten.py @@ -157,7 +157,7 @@ def update_settings_glue(wasm_file, metadata): settings.MAIN_READS_PARAMS = metadata.mainReadsParams or bool(settings.MAIN_MODULE) if settings.MAIN_READS_PARAMS and not settings.STANDALONE_WASM: # callMain depends on this library function - settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['$allocateUTF8OnStack'] + settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['$stringToUTF8OnStack'] if settings.STACK_OVERFLOW_CHECK and not settings.SIDE_MODULE: # writeStackCookie and checkStackCookie both rely on emscripten_stack_get_end being diff --git a/src/library.js b/src/library.js index dcb89e4abab17..816703e50f7d9 100644 --- a/src/library.js +++ b/src/library.js @@ -3713,7 +3713,7 @@ DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.push( '$stringToUTF32', '$lengthBytesUTF32', '$stringToNewUTF8', - '$allocateUTF8OnStack', + '$stringToUTF8OnStack', '$writeStringToMemory', '$writeArrayToMemory', '$writeAsciiToMemory', diff --git a/src/library_ccall.js b/src/library_ccall.js index e4e7fb08298f1..fc623dc7e3b3f 100644 --- a/src/library_ccall.js +++ b/src/library_ccall.js @@ -15,7 +15,7 @@ mergeInto(LibraryManager.library, { }, // C calling interface. - $ccall__deps: ['$getCFunc', '$writeArrayToMemory', '$allocateUTF8OnStack'], + $ccall__deps: ['$getCFunc', '$writeArrayToMemory', '$stringToUTF8OnStack'], $ccall__docs: ` /** * @param {string|null=} returnType @@ -33,7 +33,7 @@ mergeInto(LibraryManager.library, { var ret = 0; if (str !== null && str !== undefined && str !== 0) { // null string // at most 4 bytes per UTF-8 code point, +1 for the trailing '\0' - ret = allocateUTF8OnStack(str); + ret = stringToUTF8OnStack(str); } return {{{ to64('ret') }}}; }, diff --git a/src/library_dylink.js b/src/library_dylink.js index 39c3cf2bc1519..0b102e91742af 100644 --- a/src/library_dylink.js +++ b/src/library_dylink.js @@ -296,13 +296,13 @@ var LibraryDylink = { }, $dlSetError__internal: true, - $dlSetError__deps: ['__dl_seterr', '$allocateUTF8OnStack', '$withStackSave'], + $dlSetError__deps: ['__dl_seterr', '$stringToUTF8OnStack', '$withStackSave'], $dlSetError: function(msg) { #if DYLINK_DEBUG dbg('dlSetError: ' + msg); #endif withStackSave(function() { - var cmsg = allocateUTF8OnStack(msg); + var cmsg = stringToUTF8OnStack(msg); ___dl_seterr(cmsg, 0); }); }, diff --git a/src/library_html5.js b/src/library_html5.js index aa07c075bf1b9..4994e6919cc07 100644 --- a/src/library_html5.js +++ b/src/library_html5.js @@ -2459,7 +2459,7 @@ var LibraryHTML5 = { }, #endif - $setCanvasElementSize__deps: ['emscripten_set_canvas_element_size', '$withStackSave', '$allocateUTF8OnStack'], + $setCanvasElementSize__deps: ['emscripten_set_canvas_element_size', '$withStackSave', '$stringToUTF8OnStack'], $setCanvasElementSize: function(target, width, height) { #if GL_DEBUG dbg('setCanvasElementSize(target='+target+',width='+width+',height='+height); @@ -2471,7 +2471,7 @@ var LibraryHTML5 = { // This function is being called from high-level JavaScript code instead of asm.js/Wasm, // and it needs to synchronously proxy over to another thread, so marshal the string onto the heap to do the call. withStackSave(function() { - var targetInt = allocateUTF8OnStack(target.id); + var targetInt = stringToUTF8OnStack(target.id); _emscripten_set_canvas_element_size(targetInt, width, height); }); } @@ -2533,13 +2533,13 @@ var LibraryHTML5 = { #endif // JavaScript-friendly API, returns pair [width, height] - $getCanvasElementSize__deps: ['emscripten_get_canvas_element_size', '$withStackSave', '$allocateUTF8OnStack'], + $getCanvasElementSize__deps: ['emscripten_get_canvas_element_size', '$withStackSave', '$stringToUTF8OnStack'], $getCanvasElementSize: function(target) { return withStackSave(function() { var w = stackAlloc(8); var h = w + 4; - var targetInt = allocateUTF8OnStack(target.id); + var targetInt = stringToUTF8OnStack(target.id); var ret = _emscripten_get_canvas_element_size(targetInt, w, h); var size = [{{{ makeGetValue('w', 0, 'i32')}}}, {{{ makeGetValue('h', 0, 'i32')}}}]; return size; diff --git a/src/library_legacy.js b/src/library_legacy.js index 43693e06910c7..1ff8678448bc0 100644 --- a/src/library_legacy.js +++ b/src/library_legacy.js @@ -39,4 +39,5 @@ mergeInto(LibraryManager.library, { }, $allocateUTF8: '$stringToNewUTF8', + $allocateUTF8OnStack: '$stringToUTF8OnStack', }); diff --git a/src/library_sockfs.js b/src/library_sockfs.js index 1704ee5bf2d2e..9be1547662959 100644 --- a/src/library_sockfs.js +++ b/src/library_sockfs.js @@ -727,13 +727,13 @@ mergeInto(LibraryManager.library, { * Passing a NULL callback function to a emscripten_set_socket_*_callback call * will deregister the callback registered for that Event. */ - $_setNetworkCallback__deps: ['$withStackSave', '$allocateUTF8OnStack'], + $_setNetworkCallback__deps: ['$withStackSave', '$stringToUTF8OnStack'], $_setNetworkCallback: function(event, userData, callback) { function _callback(data) { try { if (event === 'error') { withStackSave(function() { - var msg = allocateUTF8OnStack(data[2]); + var msg = stringToUTF8OnStack(data[2]); {{{ makeDynCall('viiii', 'callback') }}}(data[0], data[1], msg, userData); }); } else { diff --git a/src/library_stack_trace.js b/src/library_stack_trace.js index 51f32acdf0e9c..6702bc1b676f6 100644 --- a/src/library_stack_trace.js +++ b/src/library_stack_trace.js @@ -6,7 +6,7 @@ var LibraryStackTrace = { #if DEMANGLE_SUPPORT - $demangle__deps: ['$withStackSave', '__cxa_demangle', 'free', '$allocateUTF8OnStack'], + $demangle__deps: ['$withStackSave', '__cxa_demangle', 'free', '$stringToUTF8OnStack'], #endif $demangle: function(func) { #if DEMANGLE_SUPPORT @@ -19,7 +19,7 @@ var LibraryStackTrace = { var s = func; if (s.startsWith('__Z')) s = s.substr(1); - var buf = allocateUTF8OnStack(s); + var buf = stringToUTF8OnStack(s); var status = stackAlloc(4); var ret = ___cxa_demangle(buf, 0, 0, status); if ({{{ makeGetValue('status', '0', 'i32') }}} === 0 && ret) { diff --git a/src/library_strings.js b/src/library_strings.js index 8746cd357379c..983d0a7a6f877 100644 --- a/src/library_strings.js +++ b/src/library_strings.js @@ -234,7 +234,7 @@ mergeInto(LibraryManager.library, { }, // Allocate stack space for a JS string, and write it there. - $allocateUTF8OnStack: function(str) { + $stringToUTF8OnStack: function(str) { var size = lengthBytesUTF8(str) + 1; var ret = stackAlloc(size); stringToUTF8Array(str, HEAP8, ret, size); diff --git a/src/library_wasmfs.js b/src/library_wasmfs.js index d04ccf1b972ff..2b6136a78a41e 100644 --- a/src/library_wasmfs.js +++ b/src/library_wasmfs.js @@ -17,7 +17,7 @@ mergeInto(LibraryManager.library, { '$asyncLoad', '$PATH', '$stringToNewUTF8', - '$allocateUTF8OnStack', + '$stringToUTF8OnStack', '$withStackSave', '$readI53FromI64', ], @@ -134,7 +134,7 @@ mergeInto(LibraryManager.library, { mkdir: (path, mode) => { return withStackSave(() => { mode = mode !== undefined ? mode : 511 /* 0777 */; - var buffer = allocateUTF8OnStack(path); + var buffer = stringToUTF8OnStack(path); return __wasmfs_mkdir({{{ to64('buffer') }}}, mode); }); }, @@ -145,7 +145,7 @@ mergeInto(LibraryManager.library, { flags = typeof flags == 'string' ? FS.modeStringToFlags(flags) : flags; mode = typeof mode == 'undefined' ? 438 /* 0666 */ : mode; return withStackSave(() => { - var buffer = allocateUTF8OnStack(path); + var buffer = stringToUTF8OnStack(path); return __wasmfs_open({{{ to64('buffer') }}}, flags, mode); }) }, @@ -153,13 +153,13 @@ mergeInto(LibraryManager.library, { // TODO: close unlink: (path) => { return withStackSave(() => { - var buffer = allocateUTF8OnStack(path); + var buffer = stringToUTF8OnStack(path); return __wasmfs_unlink(buffer); }); }, chdir: (path) => { return withStackSave(() => { - var buffer = allocateUTF8OnStack(path); + var buffer = stringToUTF8OnStack(path); return __wasmfs_chdir(buffer); }); }, @@ -171,7 +171,7 @@ mergeInto(LibraryManager.library, { // TODO: munmap writeFile: (path, data) => { return withStackSave(() => { - var pathBuffer = allocateUTF8OnStack(path); + var pathBuffer = stringToUTF8OnStack(path); if (typeof data == 'string') { var buf = new Uint8Array(lengthBytesUTF8(data) + 1); var actualNumBytes = stringToUTF8Array(data, buf, 0, buf.length); @@ -191,8 +191,8 @@ mergeInto(LibraryManager.library, { }, symlink: (target, linkpath) => { return withStackSave(() => { - var targetBuffer = allocateUTF8OnStack(target); - var linkpathBuffer = allocateUTF8OnStack(linkpath); + var targetBuffer = stringToUTF8OnStack(target); + var linkpathBuffer = stringToUTF8OnStack(linkpath); return __wasmfs_symlink(targetBuffer, linkpathBuffer); }); }, @@ -201,7 +201,7 @@ mergeInto(LibraryManager.library, { // TODO: lstat chmod: (path, mode) => { return withStackSave(() => { - var buffer = allocateUTF8OnStack(path); + var buffer = stringToUTF8OnStack(path); return __wasmfs_chmod(buffer, mode); }); }, @@ -225,7 +225,7 @@ mergeInto(LibraryManager.library, { }, readdir: (path) => { return withStackSave(() => { - var pathBuffer = allocateUTF8OnStack(path); + var pathBuffer = stringToUTF8OnStack(path); var entries = []; var state = __wasmfs_readdir_start(pathBuffer); if (!state) { diff --git a/src/library_wasmfs_node.js b/src/library_wasmfs_node.js index 3ff4e2b1bdbed..d805104d3e0e7 100644 --- a/src/library_wasmfs_node.js +++ b/src/library_wasmfs_node.js @@ -62,7 +62,7 @@ mergeInto(LibraryManager.library, { } entries.forEach((entry) => { withStackSave(() => { - let name = allocateUTF8OnStack(entry.name); + let name = stringToUTF8OnStack(entry.name); let type; // TODO: Figure out how to use `cDefine` here. if (entry.isFile()) { diff --git a/src/library_wasmfs_opfs.js b/src/library_wasmfs_opfs.js index 26c77bdf8cb2e..9aeb35d1ebe45 100644 --- a/src/library_wasmfs_opfs.js +++ b/src/library_wasmfs_opfs.js @@ -100,7 +100,7 @@ mergeInto(LibraryManager.library, { for (let entry; entry = await iter.next(), !entry.done;) { let [name, child] = entry.value; withStackSave(() => { - let namePtr = allocateUTF8OnStack(name); + let namePtr = stringToUTF8OnStack(name); let type = child.kind == "file" ? {{{ cDefine('File::DataFileKind') }}} : {{{ cDefine('File::DirectoryKind') }}}; diff --git a/src/library_wget.js b/src/library_wget.js index a00508697b50d..91e024d33ee23 100644 --- a/src/library_wget.js +++ b/src/library_wget.js @@ -16,7 +16,7 @@ var LibraryWget = { }, }, - emscripten_async_wget__deps: ['$PATH_FS', '$wget', '$callUserCallback', '$Browser', '$withStackSave', '$allocateUTF8OnStack'], + emscripten_async_wget__deps: ['$PATH_FS', '$wget', '$callUserCallback', '$Browser', '$withStackSave', '$stringToUTF8OnStack'], emscripten_async_wget__proxy: 'sync', emscripten_async_wget: function(url, file, onload, onerror) { {{{ runtimeKeepalivePush() }}} @@ -29,7 +29,7 @@ var LibraryWget = { {{{ runtimeKeepalivePop() }}} callUserCallback(function() { withStackSave(function() { - {{{ makeDynCall('vi', 'callback') }}}(allocateUTF8OnStack(_file)); + {{{ makeDynCall('vi', 'callback') }}}(stringToUTF8OnStack(_file)); }); }); } @@ -80,7 +80,7 @@ var LibraryWget = { }, true /* no need for run dependency, this is async but will not do any prepare etc. step */ ); }, - emscripten_async_wget2__deps: ['$PATH_FS', '$wget', '$withStackSave', '$allocateUTF8OnStack'], + emscripten_async_wget2__deps: ['$PATH_FS', '$wget', '$withStackSave', '$stringToUTF8OnStack'], emscripten_async_wget2__proxy: 'sync', emscripten_async_wget2: function(url, file, request, param, arg, onload, onerror, onprogress) { {{{ runtimeKeepalivePush() }}} @@ -114,7 +114,7 @@ var LibraryWget = { FS.createDataFile( _file.substr(0, index), _file.substr(index + 1), new Uint8Array(/** @type{ArrayBuffer}*/(http.response)), true, true, false); if (onload) { withStackSave(function() { - {{{ makeDynCall('viii', 'onload') }}}(handle, arg, allocateUTF8OnStack(_file)); + {{{ makeDynCall('viii', 'onload') }}}(handle, arg, stringToUTF8OnStack(_file)); }); } } else { @@ -176,7 +176,7 @@ var LibraryWget = { withStackSave(() => { var statusText = 0; if (http.statusText) { - statusText = allocateUTF8OnStack(http.statusText); + statusText = stringToUTF8OnStack(http.statusText); } {{{ makeDynCall('viiii', 'onerror') }}}(handle, arg, http.status, statusText); }); diff --git a/src/postamble.js b/src/postamble.js index 125c7a6bd0faa..91e91f003d977 100644 --- a/src/postamble.js +++ b/src/postamble.js @@ -54,7 +54,7 @@ function callMain() { var argv = stackAlloc((argc + 1) * {{{ POINTER_SIZE }}}); var argv_ptr = argv >> {{{ POINTER_SHIFT }}}; args.forEach((arg) => { - {{{ POINTER_HEAP }}}[argv_ptr++] = {{{ to64('allocateUTF8OnStack(arg)') }}}; + {{{ POINTER_HEAP }}}[argv_ptr++] = {{{ to64('stringToUTF8OnStack(arg)') }}}; }); {{{ POINTER_HEAP }}}[argv_ptr] = {{{ to64('0') }}}; #else diff --git a/test/core/test_asan_js_stack_op.c b/test/core/test_asan_js_stack_op.c index 05895192e9633..72392bc67cc18 100644 --- a/test/core/test_asan_js_stack_op.c +++ b/test/core/test_asan_js_stack_op.c @@ -5,10 +5,10 @@ EMSCRIPTEN_KEEPALIVE void c_func(char *str) { printf("%s\n", str); } -EM_JS_DEPS(js_func, "$allocateUTF8OnStack"); +EM_JS_DEPS(js_func, "$stringToUTF8OnStack"); EM_JS(void, js_func, (void), { - _c_func(allocateUTF8OnStack('Hello, World!')); + _c_func(stringToUTF8OnStack('Hello, World!')); }); int main(void) { diff --git a/test/stack_overflow.cpp b/test/stack_overflow.cpp index 506aa19447958..3671522c00505 100644 --- a/test/stack_overflow.cpp +++ b/test/stack_overflow.cpp @@ -9,7 +9,7 @@ #include #include -EM_JS_DEPS(main, "$allocateUTF8OnStack"); +EM_JS_DEPS(main, "$stringToUTF8OnStack"); void __attribute__((noinline)) InteropString(char *staticBuffer) { char *string = (char*)EM_ASM_PTR({ @@ -19,11 +19,11 @@ void __attribute__((noinline)) InteropString(char *staticBuffer) { for (var i = 0; i < 15; ++i) { str = str + str; } - allocateUTF8OnStack(str); + stringToUTF8OnStack(str); #else // allocate as many times as we need to overflow for (var i = 0; i < 1024 * 1024; i++) { - allocateUTF8OnStack(str); + stringToUTF8OnStack(str); } abort("we should never get here!"); #endif diff --git a/test/test_other.py b/test/test_other.py index b1ccceba519c1..79173f0d8086b 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -13117,7 +13117,7 @@ def test_em_js_deps(self): create_file('f1.c', ''' #include - EM_JS_DEPS(other, "$allocateUTF8OnStack"); + EM_JS_DEPS(other, "$stringToUTF8OnStack"); ''') create_file('f2.c', ''' #include @@ -13128,7 +13128,7 @@ def test_em_js_deps(self): EM_ASM({ err(getHeapMax()); var x = stackSave(); - allocateUTF8OnStack("hello"); + stringToUTF8OnStack("hello"); stackRestore(x); }); return 0; From 41f442cc4670a22f46f10e5c47d9c03ff12cc92b Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 30 Mar 2023 14:24:17 -0700 Subject: [PATCH 0078/1523] Move writeStringToMemory/writeAsciiToMemory to library_legacy.js (#19103) `writeStringToMemory` was already marked as deprecated. We have `stringToAscii` and `stringToUTF8` which we recommend over these function. Also, change `stringToUTF8Array` to `stringToUTF8` in a couple of places here the target is `HEAPU8`. --- .../source/docs/api_reference/preamble.js.rst | 51 +------------------ src/library.js | 6 +-- src/library_legacy.js | 34 +++++++++++++ src/library_strings.js | 49 ++++-------------- src/library_wasi.js | 8 +-- .../metadce/test_metadce_hello_dylink.jssize | 2 +- .../metadce/test_metadce_mem_O3_grow.jssize | 2 +- .../test_unoptimized_code_size_strict.js.size | 2 +- test/test_core.py | 4 +- 9 files changed, 59 insertions(+), 99 deletions(-) diff --git a/site/source/docs/api_reference/preamble.js.rst b/site/source/docs/api_reference/preamble.js.rst index 6f5e5102ec2fe..eeb8249ed768c 100644 --- a/site/source/docs/api_reference/preamble.js.rst +++ b/site/source/docs/api_reference/preamble.js.rst @@ -252,32 +252,6 @@ Conversion functions — strings, pointers and arrays :returns: A ``String``, containing the content of ``array``. - -.. js:function:: writeStringToMemory(string, buffer, dontAddNull) - - Writes a JavaScript string to a specified address in the heap. - - .. warning:: This function is deprecated, you should call the function ``stringToUTF8`` instead, which provides a secure bounded version of the same functionality instead. - - .. code-block:: javascript - - // Allocate space for string and extra '0' at the end - var buffer = Module._malloc(myString.length+1); - - // Write the string to memory - Module.writeStringToMemory(myString, buffer); - - // We can now send buffer into a C function, it is just a normal char* pointer - - :param string: The string to write into memory. - :type string: String - :param buffer: The address (number) where ``string`` is to be written. - :type buffer: Number - :param dontAddNull: If ``true``, the new array is not zero-terminated. - :type dontAddNull: bool - - - .. js:function:: writeArrayToMemory(array, buffer) Writes an array to a specified address in the heap. Note that memory should to be allocated for the array before it is written. @@ -288,29 +262,8 @@ Conversion functions — strings, pointers and arrays -.. js:function:: writeAsciiToMemory(str, buffer, dontAddNull) - - Writes an ASCII string to a specified address in the heap. Note that memory should to be allocated for the string before it is written. - - The string is assumed to only have characters in the ASCII character set. If ASSERTIONS are enabled and this is not the case, it will fail. - - .. code-block:: javascript - - // Allocate space for string - var buffer = Module._malloc(myString.length); - - // Write the string to memory - Module.writeStringToMemory(myString, buffer); - - :param string: The string to write into memory. - :param buffer: The address where ``string`` is to be written. - :param dontAddNull: If ``true``, the new string is not zero-terminated. - :type dontAddNull: bool - - - Run dependencies -===================================== +================ Note that generally run dependencies are managed by the file packager and other parts of the system. It is rare for developers to use this API directly. @@ -338,7 +291,7 @@ Note that generally run dependencies are managed by the file packager and other Stack trace -===================== +=========== .. js:function:: stackTrace() diff --git a/src/library.js b/src/library.js index 816703e50f7d9..9044c3687fd57 100644 --- a/src/library.js +++ b/src/library.js @@ -2078,7 +2078,7 @@ mergeInto(LibraryManager.library, { list: [], map: {} }, - setprotoent__deps: ['$Protocols', '$writeAsciiToMemory', 'malloc'], + setprotoent__deps: ['$Protocols', '$stringToAscii', 'malloc'], setprotoent: function(stayopen) { // void setprotoent(int stayopen); @@ -2086,7 +2086,7 @@ mergeInto(LibraryManager.library, { function allocprotoent(name, proto, aliases) { // write name into buffer var nameBuf = _malloc(name.length + 1); - writeAsciiToMemory(name, nameBuf); + stringToAscii(name, nameBuf); // write aliases into buffer var j = 0; @@ -2096,7 +2096,7 @@ mergeInto(LibraryManager.library, { for (var i = 0; i < length; i++, j += 4) { var alias = aliases[i]; var aliasBuf = _malloc(alias.length + 1); - writeAsciiToMemory(alias, aliasBuf); + stringToAscii(alias, aliasBuf); {{{ makeSetValue('aliasListBuf', 'j', 'aliasBuf', POINTER_TYPE) }}}; } {{{ makeSetValue('aliasListBuf', 'j', '0', POINTER_TYPE) }}}; // Terminating NULL pointer. diff --git a/src/library_legacy.js b/src/library_legacy.js index 1ff8678448bc0..dbbcf433431d8 100644 --- a/src/library_legacy.js +++ b/src/library_legacy.js @@ -38,6 +38,40 @@ mergeInto(LibraryManager.library, { return ret; }, + // Deprecated: This function should not be called because it is unsafe and + // does not provide a maximum length limit of how many bytes it is allowed to + // write. Prefer calling the function stringToUTF8Array() instead, which takes + // in a maximum length that can be used to be secure from out of bounds + // writes. + $writeStringToMemory__docs: '/** @deprecated @param {boolean=} dontAddNull */', + $writeStringToMemory: function(string, buffer, dontAddNull) { + warnOnce('writeStringToMemory is deprecated and should not be called! Use stringToUTF8() instead!'); + + var /** @type {number} */ lastChar, /** @type {number} */ end; + if (dontAddNull) { + // stringToUTF8Array always appends null. If we don't want to do that, remember the + // character that existed at the location where the null will be placed, and restore + // that after the write (below). + end = buffer + lengthBytesUTF8(string); + lastChar = HEAP8[end]; + } + stringToUTF8(string, buffer, Infinity); + if (dontAddNull) HEAP8[end] = lastChar; // Restore the value under the null character. + }, + + // Deprecated: Use stringToAscii + $writeAsciiToMemory__docs: '/** @param {boolean=} dontAddNull */', + $writeAsciiToMemory: function(str, buffer, dontAddNull) { + for (var i = 0; i < str.length; ++i) { +#if ASSERTIONS + assert(str.charCodeAt(i) === (str.charCodeAt(i) & 0xff)); +#endif + {{{ makeSetValue('buffer++', 0, 'str.charCodeAt(i)', 'i8') }}}; + } + // Null-terminate the string + if (!dontAddNull) {{{ makeSetValue('buffer', 0, 0, 'i8') }}}; + }, + $allocateUTF8: '$stringToNewUTF8', $allocateUTF8OnStack: '$stringToUTF8OnStack', }); diff --git a/src/library_strings.js b/src/library_strings.js index 983d0a7a6f877..f72925a2f9ed1 100644 --- a/src/library_strings.js +++ b/src/library_strings.js @@ -29,9 +29,15 @@ mergeInto(LibraryManager.library, { // Copies the given Javascript String object 'str' to the emscripten HEAP at // address 'outPtr', null-terminated and encoded in ASCII form. The copy will // require at most str.length+1 bytes of space in the HEAP. - $stringToAscii__deps: ['$writeAsciiToMemory'], - $stringToAscii: function(str, outPtr) { - return writeAsciiToMemory(str, outPtr, false); + $stringToAscii: function(str, buffer) { + for (var i = 0; i < str.length; ++i) { +#if ASSERTIONS + assert(str.charCodeAt(i) === (str.charCodeAt(i) & 0xff)); +#endif + {{{ makeSetValue('buffer++', 0, 'str.charCodeAt(i)', 'i8') }}}; + } + // Null-terminate the string + {{{ makeSetValue('buffer', 0, 0, 'i8') }}}; }, #if TEXTDECODER == 2 @@ -229,7 +235,7 @@ mergeInto(LibraryManager.library, { $stringToNewUTF8: function(str) { var size = lengthBytesUTF8(str) + 1; var ret = {{{ makeMalloc('stringToNewUTF8', 'size') }}}; - if (ret) stringToUTF8Array(str, HEAP8, ret, size); + if (ret) stringToUTF8(str, ret, size); return ret; }, @@ -237,47 +243,14 @@ mergeInto(LibraryManager.library, { $stringToUTF8OnStack: function(str) { var size = lengthBytesUTF8(str) + 1; var ret = stackAlloc(size); - stringToUTF8Array(str, HEAP8, ret, size); + stringToUTF8(str, ret, size); return ret; }, - // Deprecated: This function should not be called because it is unsafe and - // does not provide a maximum length limit of how many bytes it is allowed to - // write. Prefer calling the function stringToUTF8Array() instead, which takes - // in a maximum length that can be used to be secure from out of bounds - // writes. - $writeStringToMemory__docs: '/** @deprecated @param {boolean=} dontAddNull */', - $writeStringToMemory: function(string, buffer, dontAddNull) { - warnOnce('writeStringToMemory is deprecated and should not be called! Use stringToUTF8() instead!'); - - var /** @type {number} */ lastChar, /** @type {number} */ end; - if (dontAddNull) { - // stringToUTF8Array always appends null. If we don't want to do that, remember the - // character that existed at the location where the null will be placed, and restore - // that after the write (below). - end = buffer + lengthBytesUTF8(string); - lastChar = HEAP8[end]; - } - stringToUTF8(string, buffer, Infinity); - if (dontAddNull) HEAP8[end] = lastChar; // Restore the value under the null character. - }, - $writeArrayToMemory: function(array, buffer) { #if ASSERTIONS assert(array.length >= 0, 'writeArrayToMemory array must have a length (should be an array or typed array)') #endif HEAP8.set(array, buffer); }, - - $writeAsciiToMemory__docs: '/** @param {boolean=} dontAddNull */', - $writeAsciiToMemory: function(str, buffer, dontAddNull) { - for (var i = 0; i < str.length; ++i) { -#if ASSERTIONS - assert(str.charCodeAt(i) === (str.charCodeAt(i) & 0xff)); -#endif - {{{ makeSetValue('buffer++', 0, 'str.charCodeAt(i)', 'i8') }}}; - } - // Null-terminate the pointer to the HEAP. - if (!dontAddNull) {{{ makeSetValue('buffer', 0, 0, 'i8') }}}; - }, }); diff --git a/src/library_wasi.js b/src/library_wasi.js index 905613d3bbd11..c9cca336316d5 100644 --- a/src/library_wasi.js +++ b/src/library_wasi.js @@ -87,14 +87,14 @@ var WasiLibrary = { return 0; }, - environ_get__deps: ['$getEnvStrings', '$writeAsciiToMemory'], + environ_get__deps: ['$getEnvStrings', '$stringToAscii'], environ_get__nothrow: true, environ_get: function(__environ, environ_buf) { var bufSize = 0; getEnvStrings().forEach(function(string, i) { var ptr = environ_buf + bufSize; {{{ makeSetValue('__environ', `i*${POINTER_SIZE}`, 'ptr', POINTER_TYPE) }}}; - writeAsciiToMemory(string, ptr); + stringToAscii(string, ptr); bufSize += string.length + 1; }); return 0; @@ -119,14 +119,14 @@ var WasiLibrary = { }, args_get__nothrow: true, - args_get__deps: ['$writeAsciiToMemory'], + args_get__deps: ['$stringToAscii'], args_get: function(argv, argv_buf) { #if MAIN_READS_PARAMS var bufSize = 0; mainArgs.forEach(function(arg, i) { var ptr = argv_buf + bufSize; {{{ makeSetValue('argv', `i*${POINTER_SIZE}`, 'ptr', POINTER_TYPE) }}}; - writeAsciiToMemory(arg, ptr); + stringToAscii(arg, ptr); bufSize += arg.length + 1; }); #endif diff --git a/test/other/metadce/test_metadce_hello_dylink.jssize b/test/other/metadce/test_metadce_hello_dylink.jssize index e8f92ab1737aa..2ef6bbb56d062 100644 --- a/test/other/metadce/test_metadce_hello_dylink.jssize +++ b/test/other/metadce/test_metadce_hello_dylink.jssize @@ -1 +1 @@ -27921 +27922 diff --git a/test/other/metadce/test_metadce_mem_O3_grow.jssize b/test/other/metadce/test_metadce_mem_O3_grow.jssize index 725a719f3bcb1..7b44e6c407b80 100644 --- a/test/other/metadce/test_metadce_mem_O3_grow.jssize +++ b/test/other/metadce/test_metadce_mem_O3_grow.jssize @@ -1 +1 @@ -6436 +6429 diff --git a/test/other/test_unoptimized_code_size_strict.js.size b/test/other/test_unoptimized_code_size_strict.js.size index af0da47a1dd5f..62df8c0b97d49 100644 --- a/test/other/test_unoptimized_code_size_strict.js.size +++ b/test/other/test_unoptimized_code_size_strict.js.size @@ -1 +1 @@ -63435 +63386 diff --git a/test/test_core.py b/test/test_core.py index e51021e5619d3..b9dbadf7ae087 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -5887,11 +5887,11 @@ def test_utf32(self): @crossplatform def test_utf16(self): - self.set_setting('EXPORTED_RUNTIME_METHODS', ['writeAsciiToMemory', 'UTF16ToString', 'stringToUTF16']) + self.set_setting('EXPORTED_RUNTIME_METHODS', ['UTF16ToString', 'stringToUTF16']) self.do_runf(test_file('core/test_utf16.cpp'), 'OK.') def test_utf8(self): - self.set_setting('EXPORTED_RUNTIME_METHODS', ['UTF8ToString', 'stringToUTF8', 'AsciiToString', 'stringToAscii', 'writeAsciiToMemory']) + self.set_setting('EXPORTED_RUNTIME_METHODS', ['UTF8ToString', 'stringToUTF8', 'AsciiToString', 'stringToAscii']) self.do_runf(test_file('utf8.cpp'), 'OK.') @also_with_wasm_bigint From 506f8776cd8d8c0139d7cfd1a2facb388e09e628 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 30 Mar 2023 14:49:10 -0700 Subject: [PATCH 0079/1523] Rebaseline codesize expectations. NFC --- test/other/metadce/test_metadce_cxx_ctors1.size | 2 +- test/other/metadce/test_metadce_cxx_ctors2.size | 2 +- test/other/metadce/test_metadce_cxx_except.size | 2 +- test/other/metadce/test_metadce_cxx_except_wasm.size | 2 +- test/other/metadce/test_metadce_cxx_mangle.size | 2 +- test/other/metadce/test_metadce_cxx_noexcept.size | 2 +- test/other/metadce/test_metadce_hello_O0.jssize | 2 +- test/other/metadce/test_metadce_minimal_O0.jssize | 2 +- test/other/test_unoptimized_code_size.js.size | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/test/other/metadce/test_metadce_cxx_ctors1.size b/test/other/metadce/test_metadce_cxx_ctors1.size index 9edba6c08d5a0..fba69b18f9001 100644 --- a/test/other/metadce/test_metadce_cxx_ctors1.size +++ b/test/other/metadce/test_metadce_cxx_ctors1.size @@ -1 +1 @@ -123469 +123454 diff --git a/test/other/metadce/test_metadce_cxx_ctors2.size b/test/other/metadce/test_metadce_cxx_ctors2.size index a9bc361837d96..96fcfdd147414 100644 --- a/test/other/metadce/test_metadce_cxx_ctors2.size +++ b/test/other/metadce/test_metadce_cxx_ctors2.size @@ -1 +1 @@ -123374 +123359 diff --git a/test/other/metadce/test_metadce_cxx_except.size b/test/other/metadce/test_metadce_cxx_except.size index 3cd84f4cd94ee..1dabda97be1a0 100644 --- a/test/other/metadce/test_metadce_cxx_except.size +++ b/test/other/metadce/test_metadce_cxx_except.size @@ -1 +1 @@ -165327 +165312 diff --git a/test/other/metadce/test_metadce_cxx_except_wasm.size b/test/other/metadce/test_metadce_cxx_except_wasm.size index d4b47f7c724ec..10c3b52813608 100644 --- a/test/other/metadce/test_metadce_cxx_except_wasm.size +++ b/test/other/metadce/test_metadce_cxx_except_wasm.size @@ -1 +1 @@ -137043 +137028 diff --git a/test/other/metadce/test_metadce_cxx_mangle.size b/test/other/metadce/test_metadce_cxx_mangle.size index 823c1a5c65668..66fd4fb1993fd 100644 --- a/test/other/metadce/test_metadce_cxx_mangle.size +++ b/test/other/metadce/test_metadce_cxx_mangle.size @@ -1 +1 @@ -220423 +220408 diff --git a/test/other/metadce/test_metadce_cxx_noexcept.size b/test/other/metadce/test_metadce_cxx_noexcept.size index f6e3e63abe9bf..f4b7350835a3f 100644 --- a/test/other/metadce/test_metadce_cxx_noexcept.size +++ b/test/other/metadce/test_metadce_cxx_noexcept.size @@ -1 +1 @@ -126266 +126251 diff --git a/test/other/metadce/test_metadce_hello_O0.jssize b/test/other/metadce/test_metadce_hello_O0.jssize index d3ea9f5793238..198c1f4e0790b 100644 --- a/test/other/metadce/test_metadce_hello_O0.jssize +++ b/test/other/metadce/test_metadce_hello_O0.jssize @@ -1 +1 @@ -23970 +23990 diff --git a/test/other/metadce/test_metadce_minimal_O0.jssize b/test/other/metadce/test_metadce_minimal_O0.jssize index 0508df68b45cc..fc4c8011f0552 100644 --- a/test/other/metadce/test_metadce_minimal_O0.jssize +++ b/test/other/metadce/test_metadce_minimal_O0.jssize @@ -1 +1 @@ -20278 +20298 diff --git a/test/other/test_unoptimized_code_size.js.size b/test/other/test_unoptimized_code_size.js.size index 6215919ad39b3..c406ed12e1d78 100644 --- a/test/other/test_unoptimized_code_size.js.size +++ b/test/other/test_unoptimized_code_size.js.size @@ -1 +1 @@ -64419 +64444 From 8385a1c5b0f83f39e957d1b304271aa3448edc75 Mon Sep 17 00:00:00 2001 From: Brendan Dahl Date: Thu, 30 Mar 2023 16:03:33 -0700 Subject: [PATCH 0080/1523] Add a new way to mark async imports in library files. (#19093) * Add a new way to mark async imports in library files. Allow library functions to be asyncify'd with either an `async` function or adding `$name_async`. * File extension. * Fix test. --- emcc.py | 39 +++++++++++++++------------------------ src/compiler.js | 2 +- src/jsifier.js | 22 +++++++++++++++++++++- src/library_async.js | 4 +++- src/utility.js | 1 + tools/gen_sig_info.py | 2 +- 6 files changed, 42 insertions(+), 28 deletions(-) diff --git a/emcc.py b/emcc.py index 1b3171b6d4c7d..ac1091db62a3f 100755 --- a/emcc.py +++ b/emcc.py @@ -101,7 +101,7 @@ } DEFAULT_ASYNCIFY_IMPORTS = [ - 'emscripten_sleep', 'emscripten_wget', 'emscripten_wget_data', 'emscripten_idb_load', + 'emscripten_wget', 'emscripten_wget_data', 'emscripten_idb_load', 'emscripten_idb_store', 'emscripten_idb_delete', 'emscripten_idb_exists', 'emscripten_idb_load_blob', 'emscripten_idb_store_blob', 'SDL_Delay', 'emscripten_scan_registers', 'emscripten_lazy_load_code', @@ -507,7 +507,7 @@ def ensure_archive_index(archive_file): run_process([shared.LLVM_RANLIB, archive_file]) -def generate_js_symbols(): +def generate_js_sym_info(): # Runs the js compiler to generate a list of all symbols available in the JS # libraries. This must be done separately for each linker invokation since the # list of symbols depends on what settings are used. @@ -520,11 +520,11 @@ def generate_js_symbols(): @ToolchainProfiler.profile_block('JS symbol generation') -def get_all_js_syms(): +def get_js_sym_info(): # Avoiding using the cache when generating struct info since # this step is performed while the cache is locked. if DEBUG or settings.BOOTSTRAPPING_STRUCT_INFO or config.FROZEN_CACHE: - return generate_js_symbols() + return generate_js_sym_info() # We define a cache hit as when the settings and `--js-library` contents are # identical. @@ -545,29 +545,16 @@ def get_all_js_syms(): def build_symbol_list(filename): """Only called when there is no existing symbol list for a given content hash. """ - library_syms = generate_js_symbols() - lines = [] + library_syms = generate_js_sym_info() - for name, deps in library_syms.items(): - if deps: - lines.append('%s: %s' % (name, ','.join(deps))) - else: - lines.append(name) - write_file(filename, '\n'.join(lines) + '\n') + write_file(filename, json.dumps(library_syms, separators=(',', ':'))) # We need to use a separate lock here for symbol lists because, unlike with system libraries, # it's normally for these file to get pruned as part of normal operation. This means that it # can be deleted between the `cache.get()` then the `read_file`. with filelock.FileLock(cache.get_path(cache.get_path('symbol_lists.lock'))): - filename = cache.get(f'symbol_lists/{content_hash}.txt', build_symbol_list) - lines = read_file(filename).splitlines() - library_syms = {} - for line in lines: - if ':' in line: - name, deps = line.split(':') - library_syms[name] = deps.strip().split(',') - else: - library_syms[line] = [] + filename = cache.get(f'symbol_lists/{content_hash}.json', build_symbol_list) + library_syms = json.loads(read_file(filename)) # Limit of the overall size of the cache to 100 files. # This code will get test coverage since a full test run of `other` or `core` @@ -1334,9 +1321,13 @@ def run(args): return 0 js_syms = {} - if not settings.SIDE_MODULE: - js_syms = get_all_js_syms() - deps_info.append_deps_info(js_syms) + if not settings.SIDE_MODULE or settings.ASYNCIFY: + js_info = get_js_sym_info() + if not settings.SIDE_MODULE: + js_syms = js_info['deps'] + deps_info.append_deps_info(js_syms) + if settings.ASYNCIFY: + settings.ASYNCIFY_IMPORTS += ['env.' + x for x in js_info['asyncFuncs']] phase_calculate_system_libraries(state, linker_arguments, linker_inputs, newargs) diff --git a/src/compiler.js b/src/compiler.js index ba7bebc6acfe4..de46f3396e024 100755 --- a/src/compiler.js +++ b/src/compiler.js @@ -74,7 +74,7 @@ if (symbolsOnly) { } // Side modules are pure wasm and have no JS -assert(!SIDE_MODULE, 'JS compiler should not run on side modules'); +assert(!SIDE_MODULE || (ASYNCIFY && global.symbolsOnly), 'JS compiler should only run on side modules if asyncify is used.'); // Output some info and warnings based on settings diff --git a/src/jsifier.js b/src/jsifier.js index 0357104dc8431..686e4ce9d7ab0 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -69,6 +69,7 @@ function isDefined(symName) { function runJSify() { const libraryItems = []; const symbolDeps = {}; + const asyncFuncs = []; let postSets = []; LibraryManager.load(); @@ -247,6 +248,18 @@ function ${name}(${args}) { const deps = LibraryManager.library[symbol + '__deps'] || []; + let isAsyncFunction = false; + if (ASYNCIFY) { + const original = LibraryManager.library[symbol]; + if (typeof original == 'function' ) { + isAsyncFunction = LibraryManager.library[symbol + '__async'] || + original.constructor.name == 'AsyncFunction' + } + if (isAsyncFunction) { + asyncFuncs.push(symbol); + } + } + if (symbolsOnly) { if (!isJsOnlySymbol(symbol) && LibraryManager.library.hasOwnProperty(symbol)) { externalDeps = deps.filter((d) => !isJsOnlySymbol(d) && !(d in LibraryManager.library) && typeof d === 'string'); @@ -423,6 +436,9 @@ function ${name}(${args}) { if (sig && (RELOCATABLE || ASYNCIFY == 2)) { contentText += `\n${mangled}.sig = '${sig}';`; } + if (ASYNCIFY && isAsyncFunction) { + contentText += `\n${mangled}.isAsync = true;`; + } if (isStub) { contentText += `\n${mangled}.stub = true;`; if (ASYNCIFY) { @@ -529,6 +545,7 @@ function ${name}(${args}) { print('//FORWARDED_DATA:' + JSON.stringify({ librarySymbols: librarySymbols, warnings: warnings, + asyncFuncs, ATINITS: ATINITS.join('\n'), ATMAINS: ATMAINS.join('\n'), ATEXITS: ATEXITS.join('\n'), @@ -540,7 +557,10 @@ function ${name}(${args}) { } if (symbolsOnly) { - print(JSON.stringify(symbolDeps)); + print(JSON.stringify({ + deps: symbolDeps, + asyncFuncs + })); return; } diff --git a/src/library_async.js b/src/library_async.js index 2d2843970986f..6df67bed9acb6 100644 --- a/src/library_async.js +++ b/src/library_async.js @@ -40,7 +40,8 @@ mergeInto(LibraryManager.library, { var original = imports[x]; var sig = original.sig; if (typeof original == 'function') { - var isAsyncifyImport = ASYNCIFY_IMPORTS.indexOf(x) >= 0 || + var isAsyncifyImport = original.isAsync || + ASYNCIFY_IMPORTS.indexOf(x) >= 0 || x.startsWith('__asyncjs__'); #if ASYNCIFY == 2 // Wrap async imports with a suspending WebAssembly function. @@ -451,6 +452,7 @@ mergeInto(LibraryManager.library, { }, emscripten_sleep__deps: ['$safeSetTimeout'], + emscripten_sleep__async: true, emscripten_sleep: function(ms) { // emscripten_sleep() does not return a value, but we still need a |return| // here for stack switching support (ASYNCIFY=2). In that mode this function diff --git a/src/utility.js b/src/utility.js index 69979a7abbd74..94a7b71897ebd 100644 --- a/src/utility.js +++ b/src/utility.js @@ -182,6 +182,7 @@ function isJsLibraryConfigIdentifier(ident) { '__noleakcheck', '__internal', '__user', + '__async', ]; return suffixes.some((suffix) => ident.endsWith(suffix)); } diff --git a/tools/gen_sig_info.py b/tools/gen_sig_info.py index a4d3a04eca79c..80344f59c6742 100755 --- a/tools/gen_sig_info.py +++ b/tools/gen_sig_info.py @@ -248,7 +248,7 @@ def extract_sig_info(sig_info, extra_settings=None, extra_cflags=None): output = shared.run_js_tool(utils.path_from_root('src/compiler.js'), ['--symbols-only', settings_json], stdout=subprocess.PIPE, cwd=utils.path_from_root()) - symbols = json.loads(output).keys() + symbols = json.loads(output)['deps'].keys() symbols = [s for s in symbols if not ignore_symbol(s)] with tempfiles.get_file('.c') as c_file: create_c_file(c_file, symbols) From 14657bc6f672d85404580c7d16473c2d011f0562 Mon Sep 17 00:00:00 2001 From: Brendan Dahl Date: Thu, 30 Mar 2023 16:05:23 -0700 Subject: [PATCH 0081/1523] Support embind memory_views of big ints. (#19102) --- system/lib/embind/bind.cpp | 2 ++ test/embind/test_i64_val.cpp | 16 ++++++++++++++++ test/embind/test_i64_val.out | 12 ++++++++++++ 3 files changed, 30 insertions(+) diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp index 815a86eada52b..12332b9dd6599 100644 --- a/system/lib/embind/bind.cpp +++ b/system/lib/embind/bind.cpp @@ -173,6 +173,8 @@ EMSCRIPTEN_BINDINGS(builtin) { register_memory_view("emscripten::memory_view"); register_memory_view("emscripten::memory_view"); register_memory_view("emscripten::memory_view"); + register_memory_view("emscripten::memory_view"); + register_memory_view("emscripten::memory_view"); register_memory_view("emscripten::memory_view"); register_memory_view("emscripten::memory_view"); diff --git a/test/embind/test_i64_val.cpp b/test/embind/test_i64_val.cpp index 53bd2b4462092..af5d09cf7e794 100644 --- a/test/embind/test_i64_val.cpp +++ b/test/embind/test_i64_val.cpp @@ -59,6 +59,8 @@ int main() const int64_t max_int64_t = numeric_limits::max(); const int64_t min_int64_t = numeric_limits::min(); const uint64_t max_uint64_t = numeric_limits::max(); + std::array uint64Array = {0, 1, 2, 3, 4}; + std::array int64Array = {-2, -1, 0, 1, 2}; printf("start\n"); @@ -90,6 +92,20 @@ int main() ensure_js(compare_a_64_js(min_int64_t)); ensure(val::global()["a"].as() == min_int64_t); + test("val(typed_memory_view)"); + val::global().set("a", val(typed_memory_view(uint64Array.size(), uint64Array.data()))); + ensure_js("a instanceof BigUint64Array"); + ensure_js("a.length === 5"); + ensure_js("a[0] === 0n"); + ensure_js("a[4] === 4n"); + + test("val(typed_memory_view)"); + val::global().set("a", val(typed_memory_view(int64Array.size(), int64Array.data()))); + ensure_js("a instanceof BigInt64Array"); + ensure_js("a.length === 5"); + ensure_js("a[0] === -2n"); + ensure_js("a[4] === 2n"); + printf("end\n"); return 0; } diff --git a/test/embind/test_i64_val.out b/test/embind/test_i64_val.out index b3db521a80eb1..19196845e8236 100644 --- a/test/embind/test_i64_val.out +++ b/test/embind/test_i64_val.out @@ -16,4 +16,16 @@ pass pass pass pass +test: +val(typed_memory_view) +pass +pass +pass +pass +test: +val(typed_memory_view) +pass +pass +pass +pass end From 3a285cb47581a07f833492df1eb261a254ec334e Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 30 Mar 2023 16:56:19 -0700 Subject: [PATCH 0082/1523] jsifier: Make JS libraries aliases work even when native export exists (#19046) Followup to #19033. Updating the `test_closure_full_js_library` to include webgl2 caused a lot of `JSC_REFERENCE_BEFORE_DECLARE` closure errors. This is because we had JS aliases who's target was defined both in JS and in native code. In this case the jsifier was choosing not to include the JS version, which in the case of the GL symbols not what we want. This is why, prior to #19033, we were duplicating the library entries. This this change JS symbol aliases now force the alias target to be included from the JS library, even in the case that the native code also emits its own version of a symbol. This happens in the case of pthreads + MAIN_MODULE + OFFSCREEN_FRAMEBUFFER. In this mode webgl2.c defines (and also exports) the entire set of GL library symbols. In this case we still want the `emscripten_XX` aliases to point to the original JS versions, no the natively exported version. Sadly it looks like we have at testing gab for that particular combination. --- embuilder.py | 3 +++ src/jsifier.js | 37 +++++++++++++++++++--------------- src/parseTools.js | 2 +- system/lib/gl/webgl2.c | 9 ++++++--- system/lib/gl/webgl_internal.h | 4 ++-- test/test_other.py | 2 ++ 6 files changed, 35 insertions(+), 22 deletions(-) diff --git a/embuilder.py b/embuilder.py index 1fc59af5c17ed..c6b01b677ee42 100755 --- a/embuilder.py +++ b/embuilder.py @@ -85,8 +85,11 @@ 'libc++-mt-noexcept', 'libdlmalloc-mt', 'libGL-emu', + 'libGL-emu-webgl2', 'libGL-mt', 'libGL-mt-emu', + 'libGL-mt-emu-webgl2', + 'libGL-mt-emu-webgl2-ofb', 'libsockets_proxy', 'libsockets-mt', 'crtbegin', diff --git a/src/jsifier.js b/src/jsifier.js index 686e4ce9d7ab0..7516f764b20d7 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -229,17 +229,12 @@ function ${name}(${args}) { // what we just added to the library. } - function addFromLibrary(symbol, dependent) { + function addFromLibrary(symbol, dependent, force = false) { // dependencies can be JS functions, which we just run if (typeof symbol == 'function') { return symbol(); } - if (symbol in addedLibraryItems) { - return; - } - addedLibraryItems[symbol] = true; - // don't process any special identifiers. These are looked up when // processing the base name of the identifier. if (isJsLibraryConfigIdentifier(symbol)) { @@ -270,9 +265,14 @@ function ${name}(${args}) { // if the function was implemented in compiled code, there is no need to // include the js version - if (WASM_EXPORTS.has(symbol)) { + if (WASM_EXPORTS.has(symbol) && !force) { + return; + } + + if (symbol in addedLibraryItems) { return; } + addedLibraryItems[symbol] = true; // This gets set to true in the case of dynamic linking for symbols that // are undefined in the main module. In this case we create a stub that @@ -347,17 +347,19 @@ function ${name}(${args}) { warn(`user library symbol '${symbol}' depends on internal symbol '${dep}'`); } }); + let isFunction = false; + let aliasTarget; if (typeof snippet == 'string') { if (snippet[0] != '=') { - const target = LibraryManager.library[snippet]; - if (target) { - // Redirection for aliases. We include the parent, and at runtime make ourselves equal to it. - // This avoid having duplicate functions with identical content. - const redirectedTarget = snippet; - deps.push(redirectedTarget); - snippet = mangleCSymbolName(redirectedTarget); + if (LibraryManager.library[snippet]) { + // Redirection for aliases. We include the parent, and at runtime + // make ourselves equal to it. This avoid having duplicate + // functions with identical content. + aliasTarget = snippet; + snippet = mangleCSymbolName(aliasTarget); + deps.push(aliasTarget); } } } else if (typeof snippet == 'object') { @@ -389,7 +391,7 @@ function ${name}(${args}) { const deps_list = deps.join("','"); const identDependents = symbol + `__deps: ['${deps_list}']`; function addDependency(dep) { - return addFromLibrary(dep, `${identDependents}, referenced by ${dependent}`); + return addFromLibrary(dep, `${identDependents}, referenced by ${dependent}`, dep === aliasTarget); } let contentText; if (isFunction) { @@ -447,8 +449,11 @@ function ${name}(${args}) { } let commentText = ''; + if (force) { + commentText += '/** @suppress {duplicate } */\n' + } if (LibraryManager.library[symbol + '__docs']) { - commentText = LibraryManager.library[symbol + '__docs'] + '\n'; + commentText += LibraryManager.library[symbol + '__docs'] + '\n'; } const depsText = (deps ? deps.map(addDependency).filter((x) => x != '').join('\n') + '\n' : ''); diff --git a/src/parseTools.js b/src/parseTools.js index 43155493d46e4..df880678d80e0 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -838,7 +838,7 @@ function hasExportedSymbol(sym) { // it is a BigInt. Otherwise, we legalize into pairs of i32s. function defineI64Param(name) { if (WASM_BIGINT) { - return `/** @type {!BigInt} */ ${name}`; + return name; } return `${name}_low, ${name}_high`; } diff --git a/system/lib/gl/webgl2.c b/system/lib/gl/webgl2.c index f4fee6ad59038..ea3d545578474 100644 --- a/system/lib/gl/webgl2.c +++ b/system/lib/gl/webgl2.c @@ -131,9 +131,10 @@ ASYNC_GL_FUNCTION_5(EM_FUNC_SIG_VIIIII, void, glTexStorage2D, GLenum, GLsizei, G ASYNC_GL_FUNCTION_6(EM_FUNC_SIG_VIIIIII, void, glTexStorage3D, GLenum, GLsizei, GLenum, GLsizei, GLsizei, GLsizei); VOID_SYNC_GL_FUNCTION_5(EM_FUNC_SIG_VIIIII, void, glGetInternalformativ, GLenum, GLenum, GLenum, GLsizei, GLint *); -#endif // ~__EMSCRIPTEN_PTHREADS__ - -// Extensions: +// Extensions that are aliases for the proxying functions defined above. +// Normally these aliases get defined in library_webgl.js but when building with +// __EMSCRIPTEN_OFFSCREEN_FRAMEBUFFER__ we want to intercept them in native +// code and redirect them to thier proxying couterparts. GL_APICALL void GL_APIENTRY glVertexAttribDivisorNV(GLuint index, GLuint divisor) { glVertexAttribDivisor(index, divisor); } GL_APICALL void GL_APIENTRY glVertexAttribDivisorEXT(GLuint index, GLuint divisor) { glVertexAttribDivisor(index, divisor); } GL_APICALL void GL_APIENTRY glVertexAttribDivisorARB(GLuint index, GLuint divisor) { glVertexAttribDivisor(index, divisor); } @@ -153,6 +154,8 @@ GL_APICALL GLboolean GL_APIENTRY glIsVertexArrayOES(GLuint array) { return glIsV GL_APICALL void GL_APIENTRY glDrawBuffersEXT(GLsizei n, const GLenum *bufs) { glDrawBuffers(n, bufs); } GL_APICALL void GL_APIENTRY glDrawBuffersWEBGL(GLsizei n, const GLenum *bufs) { glDrawBuffers(n, bufs); } +#endif // ~__EMSCRIPTEN_PTHREADS__) && __EMSCRIPTEN_OFFSCREEN_FRAMEBUFFER__ + // Returns a function pointer to the given WebGL 2 extension function, when queried without // a GL extension suffix such as "EXT", "OES", or "ANGLE". This function is used by // emscripten_GetProcAddress() to implement legacy GL emulation semantics for portability. diff --git a/system/lib/gl/webgl_internal.h b/system/lib/gl/webgl_internal.h index 01b84f2f20cf8..8edf22f18000c 100644 --- a/system/lib/gl/webgl_internal.h +++ b/system/lib/gl/webgl_internal.h @@ -7,6 +7,8 @@ EMSCRIPTEN_RESULT emscripten_webgl_do_commit_frame(void); EM_BOOL emscripten_supports_offscreencanvas(void); void _emscripten_proxied_gl_context_activated_from_main_browser_thread(EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context); +#if defined(__EMSCRIPTEN_PTHREADS__) && defined(__EMSCRIPTEN_OFFSCREEN_FRAMEBUFFER__) + #ifdef EMSCRIPTEN_WEBGL_TRACE #define GL_FUNCTION_TRACE(func) printf(#func "\n") #else @@ -52,8 +54,6 @@ void _emscripten_proxied_gl_context_activated_from_main_browser_thread(EMSCRIPTE #define VOID_SYNC_GL_FUNCTION_10(sig, ret, functionName, t0, t1, t2, t3, t4, t5, t6, t7, t8, t9) ret functionName(t0 p0, t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8, t9 p9) { GL_FUNCTION_TRACE(functionName); if (pthread_getspecific(currentThreadOwnsItsWebGLContext)) emscripten_##functionName(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9); else emscripten_sync_run_in_main_runtime_thread(sig, &emscripten_##functionName, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9); } #define VOID_SYNC_GL_FUNCTION_11(sig, ret, functionName, t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10) ret functionName(t0 p0, t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8, t9 p9, t10 p10) { GL_FUNCTION_TRACE(functionName); if (pthread_getspecific(currentThreadOwnsItsWebGLContext)) emscripten_##functionName(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); else emscripten_sync_run_in_main_runtime_thread(sig, &emscripten_##functionName, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); } -#if defined(__EMSCRIPTEN_PTHREADS__) && defined(__EMSCRIPTEN_OFFSCREEN_FRAMEBUFFER__) - #include extern pthread_key_t currentActiveWebGLContext; diff --git a/test/test_other.py b/test/test_other.py index 79173f0d8086b..c3d78dc3f082b 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -8693,6 +8693,7 @@ def test_full_js_library_minimal_runtime(self): # binaryen tools get run, which can affect how debug info is kept around 'bigint': [['-sWASM_BIGINT']], 'pthread': [['-pthread', '-Wno-experimental']], + 'pthread_offscreen': [['-pthread', '-Wno-experimental', '-sOFFSCREEN_FRAMEBUFFER']], }) def test_closure_full_js_library(self, args): # Test for closure errors and warnings in the entire JS library. @@ -8706,6 +8707,7 @@ def test_closure_full_js_library(self, args): '-sFETCH', '-sFETCH_SUPPORT_INDEXEDDB', '-sLEGACY_GL_EMULATION', + '-sMAX_WEBGL_VERSION=2', ] + args) def test_closure_webgpu(self): From 250ccb6da0aeaf5b56bfa54c67aeccfb48271031 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 30 Mar 2023 17:40:02 -0700 Subject: [PATCH 0083/1523] Fix test_closure_full_js_library (#19105) This test was updated in #19046, but went through CI before #19067 landed which made duplicate signatures into a warning. `glDrawRangeElements` is defined both in `library_glemu.js` and in `library_webgl2.js` with the former taking precedence because it is included later. This change avoid the duplicate definition. --- src/library_webgl2.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/library_webgl2.js b/src/library_webgl2.js index b70f33b89c87c..6db41182d1d25 100644 --- a/src/library_webgl2.js +++ b/src/library_webgl2.js @@ -1021,6 +1021,8 @@ var LibraryWebGL2 = { GLctx['vertexAttribIPointer'](index, size, type, stride, ptr); }, +#if !LEGACY_GL_EMULATION + // Defined in library_glemu.js when LEGACY_GL_EMULATION is set glDrawRangeElements__sig: 'viiiiii', glDrawRangeElements__deps: ['glDrawElements'], glDrawRangeElements: function(mode, start, end, count, type, indices) { @@ -1030,6 +1032,7 @@ var LibraryWebGL2 = { // we work around by ignoring the range. _glDrawElements(mode, count, type, indices); }, +#endif glDrawArraysInstancedBaseInstanceWEBGL__sig: 'viiiii', glDrawArraysInstancedBaseInstanceWEBGL: function(mode, first, count, instanceCount, baseInstance) { From bc3100472cc01d66f052aafa9a14fb61717a12f2 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 30 Mar 2023 20:38:50 -0700 Subject: [PATCH 0084/1523] Update webgl2 signatures in-place (#19107) This change is a result if updating `tools/gen_sig_info.py to` handle webgl2 symbols and then running with `--replace`. In a followup PR these will be all be removed and moved into `library_sigs.js` where they are auto-generated. --- src/library_glemu.js | 2 +- src/library_webgl2.js | 124 +++++++++++++++++++++--------------------- 2 files changed, 63 insertions(+), 63 deletions(-) diff --git a/src/library_glemu.js b/src/library_glemu.js index d9914cd0882bd..64a4abdc638b1 100644 --- a/src/library_glemu.js +++ b/src/library_glemu.js @@ -3434,7 +3434,7 @@ var LibraryGLEmulation = { // Additional non-GLES rendering calls glDrawRangeElements__deps: ['glDrawElements'], - glDrawRangeElements__sig: 'viiiiii', + glDrawRangeElements__sig: 'viiiiip', glDrawRangeElements: function(mode, start, end, count, type, indices) { _glDrawElements(mode, count, type, indices, start, end); }, diff --git a/src/library_webgl2.js b/src/library_webgl2.js index 6db41182d1d25..644edf9d69fb2 100644 --- a/src/library_webgl2.js +++ b/src/library_webgl2.js @@ -6,7 +6,7 @@ var LibraryWebGL2 = { glGetStringi__deps: ['$stringToNewUTF8'], - glGetStringi__sig: 'iii', + glGetStringi__sig: 'pii', glGetStringi: function(name, index) { if (GL.currentContext.version < 2) { GL.recordError(0x502 /* GL_INVALID_OPERATION */); // Calling GLES3/WebGL2 function with a GLES2/WebGL1 context @@ -49,13 +49,13 @@ var LibraryWebGL2 = { } }, - glGetInteger64v__sig: 'vii', + glGetInteger64v__sig: 'vip', glGetInteger64v__deps: ['$emscriptenWebGLGet'], glGetInteger64v: function(name_, p) { emscriptenWebGLGet(name_, p, {{{ cDefs.EM_FUNC_SIG_PARAM_I64 }}}); }, - glGetInternalformativ__sig: 'viiiii', + glGetInternalformativ__sig: 'viiiip', glGetInternalformativ: function(target, internalformat, pname, bufSize, params) { #if GL_TRACK_ERRORS if (bufSize < 0) { @@ -82,7 +82,7 @@ var LibraryWebGL2 = { } }, - glCompressedTexImage3D__sig: 'viiiiiiiii', + glCompressedTexImage3D__sig: 'viiiiiiiip', glCompressedTexImage3D: function(target, level, internalFormat, width, height, depth, border, imageSize, data) { if (GLctx.currentPixelUnpackBufferBinding) { GLctx['compressedTexImage3D'](target, level, internalFormat, width, height, depth, border, imageSize, data); @@ -91,7 +91,7 @@ var LibraryWebGL2 = { } }, - glCompressedTexSubImage3D__sig: 'viiiiiiiiiii', + glCompressedTexSubImage3D__sig: 'viiiiiiiiiip', glCompressedTexSubImage3D: function(target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data) { if (GLctx.currentPixelUnpackBufferBinding) { GLctx['compressedTexSubImage3D'](target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data); @@ -100,7 +100,7 @@ var LibraryWebGL2 = { } }, - glGetBufferParameteri64v__sig: 'viii', + glGetBufferParameteri64v__sig: 'viip', glGetBufferParameteri64v__deps: ['$writeI53ToI64'], glGetBufferParameteri64v: function(target, value, data) { #if GL_TRACK_ERRORS @@ -133,7 +133,7 @@ var LibraryWebGL2 = { }, glInvalidateFramebuffer__deps: ['$tempFixedLengthArray'], - glInvalidateFramebuffer__sig: 'viii', + glInvalidateFramebuffer__sig: 'viip', glInvalidateFramebuffer: function(target, numAttachments, attachments) { #if GL_ASSERTIONS assert(numAttachments < tempFixedLengthArray.length, 'Invalid count of numAttachments=' + numAttachments + ' passed to glInvalidateFramebuffer (that many attachment points do not exist in GL)'); @@ -147,7 +147,7 @@ var LibraryWebGL2 = { }, glInvalidateSubFramebuffer__deps: ['$tempFixedLengthArray'], - glInvalidateSubFramebuffer__sig: 'viiiiiii', + glInvalidateSubFramebuffer__sig: 'viipiiii', glInvalidateSubFramebuffer: function(target, numAttachments, attachments, x, y, width, height) { #if GL_ASSERTIONS assert(numAttachments < tempFixedLengthArray.length, 'Invalid count of numAttachments=' + numAttachments + ' passed to glInvalidateSubFramebuffer (that many attachment points do not exist in GL)'); @@ -160,7 +160,7 @@ var LibraryWebGL2 = { GLctx['invalidateSubFramebuffer'](target, list, x, y, width, height); }, - glTexImage3D__sig: 'viiiiiiiiii', + glTexImage3D__sig: 'viiiiiiiiip', glTexImage3D__deps: ['$heapObjectForWebGLType', '$heapAccessShiftForWebGLHeap'], glTexImage3D: function(target, level, internalFormat, width, height, depth, border, format, type, pixels) { if (GLctx.currentPixelUnpackBufferBinding) { @@ -173,7 +173,7 @@ var LibraryWebGL2 = { } }, - glTexSubImage3D__sig: 'viiiiiiiiiii', + glTexSubImage3D__sig: 'viiiiiiiiiip', glTexSubImage3D__deps: ['$heapObjectForWebGLType', '$heapAccessShiftForWebGLHeap'], glTexSubImage3D: function(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels) { if (GLctx.currentPixelUnpackBufferBinding) { @@ -187,7 +187,7 @@ var LibraryWebGL2 = { }, // Queries - glGenQueries__sig: 'vii', + glGenQueries__sig: 'vip', glGenQueries__deps: ['$__glGenObject'], glGenQueries: function(n, ids) { __glGenObject(n, ids, 'createQuery', GL.queries @@ -197,7 +197,7 @@ var LibraryWebGL2 = { ); }, - glDeleteQueries__sig: 'vii', + glDeleteQueries__sig: 'vip', glDeleteQueries: function(n, ids) { for (var i = 0; i < n; i++) { var id = {{{ makeGetValue('ids', 'i*4', 'i32') }}}; @@ -223,7 +223,7 @@ var LibraryWebGL2 = { GLctx['beginQuery'](target, GL.queries[id]); }, - glGetQueryiv__sig: 'viii', + glGetQueryiv__sig: 'viip', glGetQueryiv: function(target, pname, params) { #if GL_TRACK_ERRORS if (!params) { @@ -239,7 +239,7 @@ var LibraryWebGL2 = { {{{ makeSetValue('params', '0', 'GLctx[\'getQuery\'](target, pname)', 'i32') }}}; }, - glGetQueryObjectuiv__sig: 'viii', + glGetQueryObjectuiv__sig: 'viip', glGetQueryObjectuiv: function(id, pname, params) { #if GL_TRACK_ERRORS if (!params) { @@ -267,7 +267,7 @@ var LibraryWebGL2 = { }, // Sampler objects - glGenSamplers__sig: 'vii', + glGenSamplers__sig: 'vip', glGenSamplers__deps: ['$__glGenObject'], glGenSamplers: function(n, samplers) { __glGenObject(n, samplers, 'createSampler', GL.samplers @@ -277,7 +277,7 @@ var LibraryWebGL2 = { ); }, - glDeleteSamplers__sig: 'vii', + glDeleteSamplers__sig: 'vip', glDeleteSamplers: function(n, samplers) { for (var i = 0; i < n; i++) { var id = {{{ makeGetValue('samplers', 'i*4', 'i32') }}}; @@ -320,7 +320,7 @@ var LibraryWebGL2 = { GLctx['samplerParameteri'](GL.samplers[sampler], pname, param); }, - glSamplerParameterfv__sig: 'viii', + glSamplerParameterfv__sig: 'viip', glSamplerParameterfv: function(sampler, pname, params) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.samplers, sampler, 'glBindSampler', 'sampler'); @@ -329,7 +329,7 @@ var LibraryWebGL2 = { GLctx['samplerParameterf'](GL.samplers[sampler], pname, param); }, - glSamplerParameteriv__sig: 'viii', + glSamplerParameteriv__sig: 'viip', glSamplerParameteriv: function(sampler, pname, params) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.samplers, sampler, 'glBindSampler', 'sampler'); @@ -338,7 +338,7 @@ var LibraryWebGL2 = { GLctx['samplerParameteri'](GL.samplers[sampler], pname, param); }, - glGetSamplerParameterfv__sig: 'viii', + glGetSamplerParameterfv__sig: 'viip', glGetSamplerParameterfv: function(sampler, pname, params) { #if GL_TRACK_ERRORS if (!params) { @@ -354,7 +354,7 @@ var LibraryWebGL2 = { {{{ makeSetValue('params', '0', 'GLctx[\'getSamplerParameter\'](GL.samplers[sampler], pname)', 'float') }}}; }, - glGetSamplerParameteriv__sig: 'viii', + glGetSamplerParameteriv__sig: 'viip', glGetSamplerParameteriv: function(sampler, pname, params) { #if GL_TRACK_ERRORS if (!params) { @@ -371,7 +371,7 @@ var LibraryWebGL2 = { }, // Transform Feedback - glGenTransformFeedbacks__sig: 'vii', + glGenTransformFeedbacks__sig: 'vip', glGenTransformFeedbacks__deps: ['$__glGenObject'], glGenTransformFeedbacks: function(n, ids) { __glGenObject(n, ids, 'createTransformFeedback', GL.transformFeedbacks @@ -381,7 +381,7 @@ var LibraryWebGL2 = { ); }, - glDeleteTransformFeedbacks__sig: 'vii', + glDeleteTransformFeedbacks__sig: 'vip', glDeleteTransformFeedbacks: function(n, ids) { for (var i = 0; i < n; i++) { var id = {{{ makeGetValue('ids', 'i*4', 'i32') }}}; @@ -406,7 +406,7 @@ var LibraryWebGL2 = { GLctx['bindTransformFeedback'](target, GL.transformFeedbacks[id]); }, - glTransformFeedbackVaryings__sig: 'viiii', + glTransformFeedbackVaryings__sig: 'viipi', glTransformFeedbackVaryings: function(program, count, varyings, bufferMode) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.programs, program, 'glTransformFeedbackVaryings', 'program'); @@ -419,7 +419,7 @@ var LibraryWebGL2 = { GLctx['transformFeedbackVaryings'](program, vars, bufferMode); }, - glGetTransformFeedbackVarying__sig: 'viiiiiii', + glGetTransformFeedbackVarying__sig: 'viiipppp', glGetTransformFeedbackVarying: function(program, index, bufSize, length, size, type, name) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.programs, program, 'glGetTransformFeedbackVarying', 'program'); @@ -503,13 +503,13 @@ var LibraryWebGL2 = { } }, - glGetIntegeri_v__sig: 'viii', + glGetIntegeri_v__sig: 'viip', glGetIntegeri_v__deps: ['$emscriptenWebGLGetIndexed'], glGetIntegeri_v: function(target, index, data) { emscriptenWebGLGetIndexed(target, index, data, {{{ cDefs.EM_FUNC_SIG_PARAM_I }}}); }, - glGetInteger64i_v__sig: 'viii', + glGetInteger64i_v__sig: 'viip', glGetInteger64i_v__deps: ['$emscriptenWebGLGetIndexed'], glGetInteger64i_v: function(target, index, data) { emscriptenWebGLGetIndexed(target, index, data, {{{ cDefs.EM_FUNC_SIG_PARAM_I64 }}}); @@ -524,7 +524,7 @@ var LibraryWebGL2 = { GLctx['bindBufferBase'](target, index, GL.buffers[buffer]); }, - glBindBufferRange__sig: 'viiiii', + glBindBufferRange__sig: 'viiipp', glBindBufferRange: function(target, index, buffer, offset, ptrsize) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.buffers, buffer, 'glBindBufferRange', 'buffer'); @@ -532,7 +532,7 @@ var LibraryWebGL2 = { GLctx['bindBufferRange'](target, index, GL.buffers[buffer], offset, ptrsize); }, - glGetUniformIndices__sig: 'viiii', + glGetUniformIndices__sig: 'viipp', glGetUniformIndices: function(program, uniformCount, uniformNames, uniformIndices) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.programs, program, 'glGetUniformIndices', 'program'); @@ -566,7 +566,7 @@ var LibraryWebGL2 = { } }, - glGetActiveUniformsiv__sig: 'viiiii', + glGetActiveUniformsiv__sig: 'viipip', glGetActiveUniformsiv: function(program, uniformCount, uniformIndices, pname, params) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.programs, program, 'glGetActiveUniformsiv', 'program'); @@ -601,7 +601,7 @@ var LibraryWebGL2 = { } }, - glGetUniformBlockIndex__sig: 'iii', + glGetUniformBlockIndex__sig: 'iip', glGetUniformBlockIndex: function(program, uniformBlockName) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.programs, program, 'glGetUniformBlockIndex', 'program'); @@ -609,7 +609,7 @@ var LibraryWebGL2 = { return GLctx['getUniformBlockIndex'](GL.programs[program], UTF8ToString(uniformBlockName)); }, - glGetActiveUniformBlockiv__sig: 'viiii', + glGetActiveUniformBlockiv__sig: 'viiip', glGetActiveUniformBlockiv: function(program, uniformBlockIndex, pname, params) { #if GL_TRACK_ERRORS if (!params) { @@ -644,7 +644,7 @@ var LibraryWebGL2 = { } }, - glGetActiveUniformBlockName__sig: 'viiiii', + glGetActiveUniformBlockName__sig: 'viiipp', glGetActiveUniformBlockName: function(program, uniformBlockIndex, bufSize, length, uniformBlockName) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.programs, program, 'glGetActiveUniformBlockName', 'program'); @@ -671,7 +671,7 @@ var LibraryWebGL2 = { GLctx['uniformBlockBinding'](program, uniformBlockIndex, uniformBlockBinding); }, - glClearBufferiv__sig: 'viii', + glClearBufferiv__sig: 'viip', glClearBufferiv: function(buffer, drawbuffer, value) { #if GL_ASSERTIONS assert((value & 3) == 0, 'Pointer to integer data passed to glClearBufferiv must be aligned to four bytes!'); @@ -680,7 +680,7 @@ var LibraryWebGL2 = { GLctx['clearBufferiv'](buffer, drawbuffer, HEAP32, value>>2); }, - glClearBufferuiv__sig: 'viii', + glClearBufferuiv__sig: 'viip', glClearBufferuiv: function(buffer, drawbuffer, value) { #if GL_ASSERTIONS assert((value & 3) == 0, 'Pointer to integer data passed to glClearBufferuiv must be aligned to four bytes!'); @@ -689,7 +689,7 @@ var LibraryWebGL2 = { GLctx['clearBufferuiv'](buffer, drawbuffer, HEAPU32, value>>2); }, - glClearBufferfv__sig: 'viii', + glClearBufferfv__sig: 'viip', glClearBufferfv: function(buffer, drawbuffer, value) { #if GL_ASSERTIONS assert((value & 3) == 0, 'Pointer to float data passed to glClearBufferfv must be aligned to four bytes!'); @@ -698,7 +698,7 @@ var LibraryWebGL2 = { GLctx['clearBufferfv'](buffer, drawbuffer, HEAPF32, value>>2); }, - glFenceSync__sig: 'iii', + glFenceSync__sig: 'pii', glFenceSync: function(condition, flags) { var sync = GLctx.fenceSync(condition, flags); if (sync) { @@ -710,7 +710,7 @@ var LibraryWebGL2 = { return 0; // Failed to create a sync object }, - glDeleteSync__sig: 'vi', + glDeleteSync__sig: 'vp', glDeleteSync: function(id) { if (!id) return; var sync = GL.syncs[id]; @@ -723,7 +723,7 @@ var LibraryWebGL2 = { GL.syncs[id] = null; }, - glClientWaitSync__sig: 'iiij', + glClientWaitSync__sig: 'ipij', #if !WASM_BIGINT glClientWaitSync__deps: ['$convertI32PairToI53'], #endif @@ -736,7 +736,7 @@ var LibraryWebGL2 = { return GLctx.clientWaitSync(GL.syncs[sync], flags, timeout); }, - glWaitSync__sig: 'viij', + glWaitSync__sig: 'vpij', #if !WASM_BIGINT glWaitSync__deps: ['$convertI32PairToI53'], #endif @@ -746,7 +746,7 @@ var LibraryWebGL2 = { GLctx.waitSync(GL.syncs[sync], flags, timeout); }, - glGetSynciv__sig: 'viiiii', + glGetSynciv__sig: 'vpiipp', glGetSynciv: function(sync, pname, bufSize, length, values) { #if GL_TRACK_ERRORS if (bufSize < 0) { @@ -775,18 +775,18 @@ var LibraryWebGL2 = { } }, - glIsSync__sig: 'ii', + glIsSync__sig: 'ip', glIsSync: function(sync) { return GLctx.isSync(GL.syncs[sync]); }, - glGetUniformuiv__sig: 'viii', + glGetUniformuiv__sig: 'viip', glGetUniformuiv__deps: ['$emscriptenWebGLGetUniform'], glGetUniformuiv: function(program, location, params) { emscriptenWebGLGetUniform(program, location, params, {{{ cDefs.EM_FUNC_SIG_PARAM_I }}}); }, - glGetFragDataLocation__sig: 'iii', + glGetFragDataLocation__sig: 'iip', glGetFragDataLocation: function(program, name) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.programs, program, 'glGetFragDataLocation', 'program'); @@ -794,7 +794,7 @@ var LibraryWebGL2 = { return GLctx['getFragDataLocation'](GL.programs[program], UTF8ToString(name)); }, - glGetVertexAttribIiv__sig: 'viii', + glGetVertexAttribIiv__sig: 'viip', glGetVertexAttribIiv__deps: ['$emscriptenWebGLGetVertexAttrib'], glGetVertexAttribIiv: function(index, pname, params) { // N.B. This function may only be called if the vertex attribute was specified using the function glVertexAttribI4iv(), @@ -804,7 +804,7 @@ var LibraryWebGL2 = { // N.B. This function may only be called if the vertex attribute was specified using the function glVertexAttribI4uiv(), // otherwise the results are undefined. (GLES3 spec 6.1.12) - glGetVertexAttribIuiv__sig: 'viii', + glGetVertexAttribIuiv__sig: 'viip', glGetVertexAttribIuiv__deps: ['$emscriptenWebGLGetVertexAttrib'], glGetVertexAttribIuiv: 'glGetVertexAttribIiv', @@ -844,7 +844,7 @@ var LibraryWebGL2 = { GLctx.uniform4ui(webglGetUniformLocation(location), v0, v1, v2, v3); }, - glUniform1uiv__sig: 'viii', + glUniform1uiv__sig: 'viip', glUniform1uiv__deps: ['$webglGetUniformLocation'], glUniform1uiv: function(location, count, value) { #if GL_ASSERTIONS @@ -854,7 +854,7 @@ var LibraryWebGL2 = { count && GLctx.uniform1uiv(webglGetUniformLocation(location), HEAPU32, value>>2, count); }, - glUniform2uiv__sig: 'viii', + glUniform2uiv__sig: 'viip', glUniform2uiv__deps: ['$webglGetUniformLocation'], glUniform2uiv: function(location, count, value) { #if GL_ASSERTIONS @@ -864,7 +864,7 @@ var LibraryWebGL2 = { count && GLctx.uniform2uiv(webglGetUniformLocation(location), HEAPU32, value>>2, count*2); }, - glUniform3uiv__sig: 'viii', + glUniform3uiv__sig: 'viip', glUniform3uiv__deps: ['$webglGetUniformLocation'], glUniform3uiv: function(location, count, value) { #if GL_ASSERTIONS @@ -874,7 +874,7 @@ var LibraryWebGL2 = { count && GLctx.uniform3uiv(webglGetUniformLocation(location), HEAPU32, value>>2, count*3); }, - glUniform4uiv__sig: 'viii', + glUniform4uiv__sig: 'viip', glUniform4uiv__deps: ['$webglGetUniformLocation'], glUniform4uiv: function(location, count, value) { #if GL_ASSERTIONS @@ -884,7 +884,7 @@ var LibraryWebGL2 = { count && GLctx.uniform4uiv(webglGetUniformLocation(location), HEAPU32, value>>2, count*4); }, - glUniformMatrix2x3fv__sig: 'viiii', + glUniformMatrix2x3fv__sig: 'viiip', glUniformMatrix2x3fv__deps: ['$webglGetUniformLocation'], glUniformMatrix2x3fv: function(location, count, transpose, value) { #if GL_ASSERTIONS @@ -894,7 +894,7 @@ var LibraryWebGL2 = { count && GLctx.uniformMatrix2x3fv(webglGetUniformLocation(location), !!transpose, HEAPF32, value>>2, count*6); }, - glUniformMatrix3x2fv__sig: 'viiii', + glUniformMatrix3x2fv__sig: 'viiip', glUniformMatrix3x2fv__deps: ['$webglGetUniformLocation'], glUniformMatrix3x2fv: function(location, count, transpose, value) { #if GL_ASSERTIONS @@ -904,7 +904,7 @@ var LibraryWebGL2 = { count && GLctx.uniformMatrix3x2fv(webglGetUniformLocation(location), !!transpose, HEAPF32, value>>2, count*6); }, - glUniformMatrix2x4fv__sig: 'viiii', + glUniformMatrix2x4fv__sig: 'viiip', glUniformMatrix2x4fv__deps: ['$webglGetUniformLocation'], glUniformMatrix2x4fv: function(location, count, transpose, value) { #if GL_ASSERTIONS @@ -914,7 +914,7 @@ var LibraryWebGL2 = { count && GLctx.uniformMatrix2x4fv(webglGetUniformLocation(location), !!transpose, HEAPF32, value>>2, count*8); }, - glUniformMatrix4x2fv__sig: 'viiii', + glUniformMatrix4x2fv__sig: 'viiip', glUniformMatrix4x2fv__deps: ['$webglGetUniformLocation'], glUniformMatrix4x2fv: function(location, count, transpose, value) { #if GL_ASSERTIONS @@ -924,7 +924,7 @@ var LibraryWebGL2 = { count && GLctx.uniformMatrix4x2fv(webglGetUniformLocation(location), !!transpose, HEAPF32, value>>2, count*8); }, - glUniformMatrix3x4fv__sig: 'viiii', + glUniformMatrix3x4fv__sig: 'viiip', glUniformMatrix3x4fv__deps: ['$webglGetUniformLocation'], glUniformMatrix3x4fv: function(location, count, transpose, value) { #if GL_ASSERTIONS @@ -934,7 +934,7 @@ var LibraryWebGL2 = { count && GLctx.uniformMatrix3x4fv(webglGetUniformLocation(location), !!transpose, HEAPF32, value>>2, count*12); }, - glUniformMatrix4x3fv__sig: 'viiii', + glUniformMatrix4x3fv__sig: 'viiip', glUniformMatrix4x3fv__deps: ['$webglGetUniformLocation'], glUniformMatrix4x3fv: function(location, count, transpose, value) { #if GL_ASSERTIONS @@ -944,7 +944,7 @@ var LibraryWebGL2 = { count && GLctx.uniformMatrix4x3fv(webglGetUniformLocation(location), !!transpose, HEAPF32, value>>2, count*12); }, - glVertexAttribI4iv__sig: 'vii', + glVertexAttribI4iv__sig: 'vip', glVertexAttribI4iv: function(index, v) { #if GL_ASSERTIONS assert((v & 3) == 0, 'Pointer to integer data passed to glVertexAttribI4iv must be aligned to four bytes!'); @@ -953,7 +953,7 @@ var LibraryWebGL2 = { GLctx.vertexAttribI4i(index, HEAP32[v>>2], HEAP32[v+4>>2], HEAP32[v+8>>2], HEAP32[v+12>>2]); }, - glVertexAttribI4uiv__sig: 'vii', + glVertexAttribI4uiv__sig: 'vip', glVertexAttribI4uiv: function(index, v) { #if GL_ASSERTIONS assert((v & 3) == 0, 'Pointer to integer data passed to glVertexAttribI4uiv must be aligned to four bytes!'); @@ -970,7 +970,7 @@ var LibraryWebGL2 = { #endif }, - glGetProgramBinary__sig: 'viiiii', + glGetProgramBinary__sig: 'viippp', glGetProgramBinary: function(program, bufSize, length, binaryFormat, binary) { GL.recordError(0x502/*GL_INVALID_OPERATION*/); #if GL_ASSERTIONS @@ -978,7 +978,7 @@ var LibraryWebGL2 = { #endif }, - glProgramBinary__sig: 'viiii', + glProgramBinary__sig: 'viipi', glProgramBinary: function(program, binaryFormat, binary, length) { GL.recordError(0x500/*GL_INVALID_ENUM*/); #if GL_ASSERTIONS @@ -994,7 +994,7 @@ var LibraryWebGL2 = { GLctx.framebufferTextureLayer(target, attachment, GL.textures[texture], level, layer); }, - glVertexAttribIPointer__sig: 'viiiii', + glVertexAttribIPointer__sig: 'viiiip', glVertexAttribIPointer: function(index, size, type, stride, ptr) { #if FULL_ES3 var cb = GL.currentContext.clientBuffers[index]; @@ -1023,7 +1023,7 @@ var LibraryWebGL2 = { #if !LEGACY_GL_EMULATION // Defined in library_glemu.js when LEGACY_GL_EMULATION is set - glDrawRangeElements__sig: 'viiiiii', + glDrawRangeElements__sig: 'viiiiip', glDrawRangeElements__deps: ['glDrawElements'], glDrawRangeElements: function(mode, start, end, count, type, indices) { // TODO: This should be a trivial pass-though function registered at the bottom of this page as @@ -1104,7 +1104,7 @@ var LibraryWebGL2 = { glVertexAttribI4i__sig: 'viiiii', glVertexAttribI4ui__sig: 'viiiii', - glCopyBufferSubData__sig: 'viiiii', + glCopyBufferSubData__sig: 'viippp', glTexStorage2D__sig: 'viiiii', glTexStorage3D__sig: 'viiiiii', glBeginTransformFeedback__sig: 'vi', From 2282236a5180a64f422a74b0bc33738b918366ec Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 31 Mar 2023 10:18:49 -0700 Subject: [PATCH 0085/1523] Simplify embind $new_ helper. NFC (#19109) This function is only needed when DYNAMIC_EXECUTION is defined. Its also only got two callsites that both pass `Function` as arg0. I guess maybe this function previously had more callers that could explain why it seems to general but I looked back as far as the big refactor in 2014 (350f199fb9e1) and I couldn't find anything. I think this is can be even further simplified but this is a good first step. --- src/embind/embind.js | 29 ++++++++++++----------------- src/embind/emval.js | 12 +++++++++--- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 22e863ae7b2c9..95eabef2f3cfe 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -18,7 +18,7 @@ /*global simpleReadValueFromPointer, floatReadValueFromPointer, integerReadValueFromPointer, enumReadValueFromPointer, replacePublicSymbol, craftInvokerFunction, tupleRegistrations*/ /*global finalizationRegistry, attachFinalizer, detachFinalizer, releaseClassHandle, runDestructor*/ /*global ClassHandle, makeClassHandle, structRegistrations, whenDependentTypesAreResolved, BindingError, deletionQueue, delayFunction:true, upcastPointer*/ -/*global exposePublicSymbol, heap32VectorToArray, new_, RegisteredPointer_getPointee, RegisteredPointer_destructor, RegisteredPointer_deleteObject, char_0, char_9*/ +/*global exposePublicSymbol, heap32VectorToArray, newFunc, RegisteredPointer_getPointee, RegisteredPointer_destructor, RegisteredPointer_deleteObject, char_0, char_9*/ /*global getInheritedInstanceCount, getLiveInheritedInstances, setDelayFunction, InternalError, runDestructors*/ /*global requireRegisteredType, unregisterInheritedInstance, registerInheritedInstance, PureVirtualError, throwUnboundTypeError*/ /*global assert, validateThis, downcastPointer, registeredPointers, RegisteredClass, getInheritedInstance, ClassHandle_isAliasOf, ClassHandle_clone, ClassHandle_isDeleted, ClassHandle_deleteLater*/ @@ -906,20 +906,12 @@ var LibraryEmbind = { } }, - // Function implementation of operator new, per - // http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf - // 13.2.2 - // ES3 - $new___deps: ['$createNamedFunction'], - $new_: function(constructor, argumentList) { +#if DYNAMIC_EXECUTION + $newFunc__deps: ['$createNamedFunction'], + $newFunc: function(constructor, argumentList) { if (!(constructor instanceof Function)) { throw new TypeError('new_ called with constructor type ' + typeof(constructor) + " which is not a function"); } -#if DYNAMIC_EXECUTION == 0 - if (constructor === Function) { - throw new Error('new_ cannot create a new Function with DYNAMIC_EXECUTION == 0.'); - } -#endif /* * Previously, the following line was just: * function dummy() {}; @@ -937,15 +929,19 @@ var LibraryEmbind = { var r = constructor.apply(obj, argumentList); return (r instanceof Object) ? r : obj; }, +#endif // The path to interop from JS code to C++ code: // (hand-written JS code) -> (autogenerated JS invoker) -> (template-generated C++ invoker) -> (target C++ function) // craftInvokerFunction generates the JS invoker function for each function exposed to JS through embind. $craftInvokerFunction__deps: [ - '$makeLegalFunctionName', '$new_', '$runDestructors', '$throwBindingError', - #if ASYNCIFY + '$makeLegalFunctionName', '$runDestructors', '$throwBindingError', +#if DYNAMIC_EXECUTION + '$newFunc', +#endif +#if ASYNCIFY '$Asyncify', - #endif +#endif ], $craftInvokerFunction: function(humanName, argTypes, classType, cppInvokerFunc, cppTargetFunc, isAsync) { // humanName: a human-readable string name for the function to be generated. @@ -1149,8 +1145,7 @@ var LibraryEmbind = { args1.push(invokerFnBody); - var invokerFunction = new_(Function, args1).apply(null, args2); - return invokerFunction; + return newFunc(Function, args1).apply(null, args2); #endif }, diff --git a/src/embind/emval.js b/src/embind/emval.js index bf177e3dc634e..a3ae0862ea797 100644 --- a/src/embind/emval.js +++ b/src/embind/emval.js @@ -5,7 +5,7 @@ /*global Module:true, Runtime*/ /*global HEAP32*/ -/*global new_*/ +/*global newFunc*/ /*global createNamedFunction*/ /*global readLatin1String, stringToUTF8*/ /*global requireRegisteredType, throwBindingError, runDestructors*/ @@ -414,7 +414,13 @@ var LibraryEmVal = { $emval_registeredMethods: [], _emval_get_method_caller__sig: 'pip', - _emval_get_method_caller__deps: ['$emval_addMethodCaller', '$emval_lookupTypes', '$new_', '$makeLegalFunctionName', '$emval_registeredMethods'], + _emval_get_method_caller__deps: [ + '$emval_addMethodCaller', '$emval_lookupTypes',, + '$makeLegalFunctionName', '$emval_registeredMethods', +#if DYNAMIC_EXECUTION + '$newFunc', +#endif + ], _emval_get_method_caller: function(argCount, argTypes) { var types = emval_lookupTypes(argCount, argTypes); var retType = types[0]; @@ -479,7 +485,7 @@ var LibraryEmVal = { "};\n"; params.push(functionBody); - var invokerFunction = new_(Function, params).apply(null, args); + var invokerFunction = newFunc(Function, params).apply(null, args); #endif returnId = emval_addMethodCaller(invokerFunction); emval_registeredMethods[signatureName] = returnId; From 4ea7592c15ea8334c028773bb6a0583af10c1f3f Mon Sep 17 00:00:00 2001 From: Sumit Kumar Date: Fri, 31 Mar 2023 22:59:55 +0530 Subject: [PATCH 0086/1523] [Emscripten EH] Fix EXCEPTION_STACK_TRACES for resumeException case (#19099) --- src/library_exceptions.js | 21 ++++++++++++++------- src/parseTools.js | 8 +++++--- src/runtime_exceptions.js | 1 + test/test_other.py | 4 +++- 4 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/library_exceptions.js b/src/library_exceptions.js index 0157a792c266f..bb3281330a3ea 100644 --- a/src/library_exceptions.js +++ b/src/library_exceptions.js @@ -188,9 +188,9 @@ var LibraryExceptions = { var info = new ExceptionInfo(ptr); // Initialize ExceptionInfo content after it was allocated in __cxa_allocate_exception. info.init(type, destructor); - exceptionLast = ptr; + {{{ storeException('exceptionLast', 'ptr') }}} uncaughtExceptionCount++; - {{{ makeThrow('ptr') }}} + {{{ makeThrow('exceptionLast') }}} }, // This exception will be caught twice, but while begin_catch runs twice, @@ -215,8 +215,8 @@ var LibraryExceptions = { dbg('__cxa_rethrow, popped ' + [ptrToString(ptr), exceptionLast, 'stack', exceptionCaught]); #endif - exceptionLast = ptr; - {{{ makeThrow('ptr') }}} + {{{ storeException('exceptionLast', 'ptr') }}} + {{{ makeThrow('exceptionLast') }}} }, llvm_eh_typeid_for__sig: 'ip', @@ -316,7 +316,12 @@ var LibraryExceptions = { __cxa_find_matching_catch__deps: ['$exceptionLast', '$ExceptionInfo', '__resumeException', '__cxa_can_catch', 'setTempRet0'], //__cxa_find_matching_catch__sig: 'p', __cxa_find_matching_catch: function() { - var thrown = exceptionLast; + var thrown = +#if EXCEPTION_STACK_TRACES + exceptionLast && exceptionLast.excPtr; +#else + exceptionLast; +#endif if (!thrown) { // just pass through the null ptr setTempRet0(0); @@ -364,8 +369,10 @@ var LibraryExceptions = { #if EXCEPTION_DEBUG dbg("__resumeException " + [ptrToString(ptr), exceptionLast]); #endif - if (!exceptionLast) { exceptionLast = ptr; } - {{{ makeThrow('ptr') }}} + if (!exceptionLast) { + {{{ storeException('exceptionLast', 'ptr') }}} + } + {{{ makeThrow('exceptionLast') }}} }, #endif diff --git a/src/parseTools.js b/src/parseTools.js index df880678d80e0..b8a16c34b5411 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -495,12 +495,14 @@ function makeThrow(excPtr) { } return `assert(false, '${assertInfo}');`; } - if (EXCEPTION_STACK_TRACES) { - return `throw new CppException(${excPtr});`; - } return `throw ${excPtr};`; } +function storeException(varName, excPtr) { + var exceptionToStore = EXCEPTION_STACK_TRACES ? `new CppException(${excPtr})` : `${excPtr}`; + return `${varName} = ${exceptionToStore};`; +} + function charCode(char) { return char.charCodeAt(0); } diff --git a/src/runtime_exceptions.js b/src/runtime_exceptions.js index 4a56b560ddb1a..1446b27dd2002 100644 --- a/src/runtime_exceptions.js +++ b/src/runtime_exceptions.js @@ -15,6 +15,7 @@ class EmscriptenSjLj extends EmscriptenEH {} class CppException extends EmscriptenEH { constructor(excPtr) { super(excPtr); + this.excPtr = excPtr; #if !DISABLE_EXCEPTION_CATCHING const excInfo = getExceptionMessage(excPtr); this.name = excInfo[0]; diff --git a/test/test_other.py b/test/test_other.py index c3d78dc3f082b..eb84278d0db00 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -8296,7 +8296,9 @@ def test_exceptions_stack_trace_and_message(self, wasm_eh): throw std::runtime_error("my message"); } void foo() { - bar(); + try { + bar(); + } catch (const std::invalid_argument &err) {} } int main() { foo(); From 5d3e69f11313ef73433145f25a0367ee83c19923 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 31 Mar 2023 11:43:23 -0700 Subject: [PATCH 0087/1523] Use gen_sig_info to auto-generate webgl2 signature information. NFC (#19108) --- src/library_glemu.js | 1 - src/library_sigs.js | 96 +++++++++++++++++++++++++++++++++++++++++++ src/library_webgl2.js | 92 ----------------------------------------- src/utility.js | 2 +- test/test_other.py | 2 +- tools/gen_sig_info.py | 1 + 6 files changed, 99 insertions(+), 95 deletions(-) diff --git a/src/library_glemu.js b/src/library_glemu.js index 64a4abdc638b1..bf01ba6f531da 100644 --- a/src/library_glemu.js +++ b/src/library_glemu.js @@ -3434,7 +3434,6 @@ var LibraryGLEmulation = { // Additional non-GLES rendering calls glDrawRangeElements__deps: ['glDrawElements'], - glDrawRangeElements__sig: 'viiiiip', glDrawRangeElements: function(mode, start, end, count, type, indices) { _glDrawElements(mode, count, type, indices, start, end); }, diff --git a/src/library_sigs.js b/src/library_sigs.js index 00e89727137a0..3f5bb3b3e7428 100644 --- a/src/library_sigs.js +++ b/src/library_sigs.js @@ -621,7 +621,9 @@ sigs = { emscripten_webgl_enable_ANGLE_instanced_arrays__sig: 'ii', emscripten_webgl_enable_OES_vertex_array_object__sig: 'ii', emscripten_webgl_enable_WEBGL_draw_buffers__sig: 'ii', + emscripten_webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance__sig: 'ii', emscripten_webgl_enable_WEBGL_multi_draw__sig: 'ii', + emscripten_webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance__sig: 'ii', emscripten_webgl_enable_extension__sig: 'iip', emscripten_webgl_get_context_attributes__sig: 'iip', emscripten_webgl_get_current_context__sig: 'i', @@ -692,11 +694,17 @@ sigs = { glActiveTexture__sig: 'vi', glAttachShader__sig: 'vii', glBegin__sig: 'vi', + glBeginQuery__sig: 'vii', + glBeginTransformFeedback__sig: 'vi', glBindAttribLocation__sig: 'viip', glBindBuffer__sig: 'vii', + glBindBufferBase__sig: 'viii', + glBindBufferRange__sig: 'viiipp', glBindFramebuffer__sig: 'vii', glBindRenderbuffer__sig: 'vii', + glBindSampler__sig: 'vii', glBindTexture__sig: 'vii', + glBindTransformFeedback__sig: 'vii', glBindVertexArray__sig: 'vi', glBindVertexArrayOES__sig: 'vi', glBlendColor__sig: 'vffff', @@ -704,29 +712,43 @@ sigs = { glBlendEquationSeparate__sig: 'vii', glBlendFunc__sig: 'vii', glBlendFuncSeparate__sig: 'viiii', + glBlitFramebuffer__sig: 'viiiiiiiiii', glBufferData__sig: 'vippi', glBufferSubData__sig: 'vippp', glCheckFramebufferStatus__sig: 'ii', glClear__sig: 'vi', + glClearBufferfi__sig: 'viifi', + glClearBufferfv__sig: 'viip', + glClearBufferiv__sig: 'viip', + glClearBufferuiv__sig: 'viip', glClearColor__sig: 'vffff', glClearDepth__sig: 'vd', glClearDepthf__sig: 'vf', glClearStencil__sig: 'vi', + glClientWaitSync__sig: 'ipij', glColorMask__sig: 'viiii', glCompileShader__sig: 'vi', glCompressedTexImage2D__sig: 'viiiiiiip', + glCompressedTexImage3D__sig: 'viiiiiiiip', glCompressedTexSubImage2D__sig: 'viiiiiiiip', + glCompressedTexSubImage3D__sig: 'viiiiiiiiiip', + glCopyBufferSubData__sig: 'viippp', glCopyTexImage2D__sig: 'viiiiiiii', glCopyTexSubImage2D__sig: 'viiiiiiii', + glCopyTexSubImage3D__sig: 'viiiiiiiii', glCreateProgram__sig: 'i', glCreateShader__sig: 'ii', glCullFace__sig: 'vi', glDeleteBuffers__sig: 'vip', glDeleteFramebuffers__sig: 'vip', glDeleteProgram__sig: 'vi', + glDeleteQueries__sig: 'vip', glDeleteRenderbuffers__sig: 'vip', + glDeleteSamplers__sig: 'vip', glDeleteShader__sig: 'vi', + glDeleteSync__sig: 'vp', glDeleteTextures__sig: 'vip', + glDeleteTransformFeedbacks__sig: 'vip', glDeleteVertexArrays__sig: 'vip', glDeleteVertexArraysOES__sig: 'vip', glDepthFunc__sig: 'vi', @@ -738,59 +760,97 @@ sigs = { glDisableVertexAttribArray__sig: 'vi', glDrawArrays__sig: 'viii', glDrawArraysInstanced__sig: 'viiii', + glDrawArraysInstancedBaseInstance__sig: 'viiiii', glDrawBuffers__sig: 'vip', glDrawElements__sig: 'viiip', glDrawElementsInstanced__sig: 'viiipi', + glDrawRangeElements__sig: 'viiiiip', glEnable__sig: 'vi', glEnableVertexAttribArray__sig: 'vi', + glEndQuery__sig: 'vi', + glEndTransformFeedback__sig: 'v', + glFenceSync__sig: 'pii', glFinish__sig: 'v', glFlush__sig: 'v', glFlushMappedBufferRange__sig: 'vipp', glFramebufferRenderbuffer__sig: 'viiii', glFramebufferTexture2D__sig: 'viiiii', + glFramebufferTextureLayer__sig: 'viiiii', glFrontFace__sig: 'vi', glGenBuffers__sig: 'vip', glGenFramebuffers__sig: 'vip', + glGenQueries__sig: 'vip', glGenRenderbuffers__sig: 'vip', + glGenSamplers__sig: 'vip', glGenTextures__sig: 'vip', + glGenTransformFeedbacks__sig: 'vip', glGenVertexArrays__sig: 'vip', glGenVertexArraysOES__sig: 'vip', glGenerateMipmap__sig: 'vi', glGetActiveAttrib__sig: 'viiipppp', glGetActiveUniform__sig: 'viiipppp', + glGetActiveUniformBlockName__sig: 'viiipp', + glGetActiveUniformBlockiv__sig: 'viiip', + glGetActiveUniformsiv__sig: 'viipip', glGetAttachedShaders__sig: 'viipp', glGetAttribLocation__sig: 'iip', glGetBooleanv__sig: 'vip', + glGetBufferParameteri64v__sig: 'viip', glGetBufferParameteriv__sig: 'viip', glGetBufferPointerv__sig: 'viip', + glGetBufferSubData__sig: 'vippp', glGetError__sig: 'i', glGetFloatv__sig: 'vip', + glGetFragDataLocation__sig: 'iip', glGetFramebufferAttachmentParameteriv__sig: 'viiip', + glGetInteger64i_v__sig: 'viip', + glGetInteger64v__sig: 'vip', + glGetIntegeri_v__sig: 'viip', glGetIntegerv__sig: 'vip', + glGetInternalformativ__sig: 'viiiip', + glGetProgramBinary__sig: 'viippp', glGetProgramInfoLog__sig: 'viipp', glGetProgramiv__sig: 'viip', + glGetQueryObjectuiv__sig: 'viip', + glGetQueryiv__sig: 'viip', glGetRenderbufferParameteriv__sig: 'viip', + glGetSamplerParameterfv__sig: 'viip', + glGetSamplerParameteriv__sig: 'viip', glGetShaderInfoLog__sig: 'viipp', glGetShaderPrecisionFormat__sig: 'viipp', glGetShaderSource__sig: 'viipp', glGetShaderiv__sig: 'viip', glGetString__sig: 'pi', + glGetStringi__sig: 'pii', + glGetSynciv__sig: 'vpiipp', glGetTexParameterfv__sig: 'viip', glGetTexParameteriv__sig: 'viip', + glGetTransformFeedbackVarying__sig: 'viiipppp', + glGetUniformBlockIndex__sig: 'iip', + glGetUniformIndices__sig: 'viipp', glGetUniformLocation__sig: 'iip', glGetUniformfv__sig: 'viip', glGetUniformiv__sig: 'viip', + glGetUniformuiv__sig: 'viip', + glGetVertexAttribIiv__sig: 'viip', + glGetVertexAttribIuiv__sig: 'viip', glGetVertexAttribPointerv__sig: 'viip', glGetVertexAttribfv__sig: 'viip', glGetVertexAttribiv__sig: 'viip', glHint__sig: 'vii', + glInvalidateFramebuffer__sig: 'viip', + glInvalidateSubFramebuffer__sig: 'viipiiii', glIsBuffer__sig: 'ii', glIsEnabled__sig: 'ii', glIsFramebuffer__sig: 'ii', glIsProgram__sig: 'ii', + glIsQuery__sig: 'ii', glIsRenderbuffer__sig: 'ii', + glIsSampler__sig: 'ii', glIsShader__sig: 'ii', + glIsSync__sig: 'ip', glIsTexture__sig: 'ii', + glIsTransformFeedback__sig: 'ii', glIsVertexArray__sig: 'ii', glIsVertexArrayOES__sig: 'ii', glLineWidth__sig: 'vf', @@ -800,12 +860,22 @@ sigs = { glMatrixMode__sig: 'vi', glMultiDrawArrays__sig: 'vippi', glMultiDrawElements__sig: 'vipipi', + glPauseTransformFeedback__sig: 'v', glPixelStorei__sig: 'vii', glPolygonOffset__sig: 'vff', + glProgramBinary__sig: 'viipi', + glProgramParameteri__sig: 'viii', + glReadBuffer__sig: 'vi', glReadPixels__sig: 'viiiiiip', glReleaseShaderCompiler__sig: 'v', glRenderbufferStorage__sig: 'viiii', + glRenderbufferStorageMultisample__sig: 'viiiii', + glResumeTransformFeedback__sig: 'v', glSampleCoverage__sig: 'vfi', + glSamplerParameterf__sig: 'viif', + glSamplerParameterfv__sig: 'viip', + glSamplerParameteri__sig: 'viii', + glSamplerParameteriv__sig: 'viip', glScissor__sig: 'viiii', glShaderBinary__sig: 'vipipi', glShaderSource__sig: 'viipp', @@ -816,30 +886,50 @@ sigs = { glStencilOp__sig: 'viii', glStencilOpSeparate__sig: 'viiii', glTexImage2D__sig: 'viiiiiiiip', + glTexImage3D__sig: 'viiiiiiiiip', glTexParameterf__sig: 'viif', glTexParameterfv__sig: 'viip', glTexParameteri__sig: 'viii', glTexParameteriv__sig: 'viip', + glTexStorage2D__sig: 'viiiii', + glTexStorage3D__sig: 'viiiiii', glTexSubImage2D__sig: 'viiiiiiiip', + glTexSubImage3D__sig: 'viiiiiiiiiip', + glTransformFeedbackVaryings__sig: 'viipi', glUniform1f__sig: 'vif', glUniform1fv__sig: 'viip', glUniform1i__sig: 'vii', glUniform1iv__sig: 'viip', + glUniform1ui__sig: 'vii', + glUniform1uiv__sig: 'viip', glUniform2f__sig: 'viff', glUniform2fv__sig: 'viip', glUniform2i__sig: 'viii', glUniform2iv__sig: 'viip', + glUniform2ui__sig: 'viii', + glUniform2uiv__sig: 'viip', glUniform3f__sig: 'vifff', glUniform3fv__sig: 'viip', glUniform3i__sig: 'viiii', glUniform3iv__sig: 'viip', + glUniform3ui__sig: 'viiii', + glUniform3uiv__sig: 'viip', glUniform4f__sig: 'viffff', glUniform4fv__sig: 'viip', glUniform4i__sig: 'viiiii', glUniform4iv__sig: 'viip', + glUniform4ui__sig: 'viiiii', + glUniform4uiv__sig: 'viip', + glUniformBlockBinding__sig: 'viii', glUniformMatrix2fv__sig: 'viiip', + glUniformMatrix2x3fv__sig: 'viiip', + glUniformMatrix2x4fv__sig: 'viiip', glUniformMatrix3fv__sig: 'viiip', + glUniformMatrix3x2fv__sig: 'viiip', + glUniformMatrix3x4fv__sig: 'viiip', glUniformMatrix4fv__sig: 'viiip', + glUniformMatrix4x2fv__sig: 'viiip', + glUniformMatrix4x3fv__sig: 'viiip', glUnmapBuffer__sig: 'ii', glUseProgram__sig: 'vi', glValidateProgram__sig: 'vi', @@ -852,9 +942,15 @@ sigs = { glVertexAttrib4f__sig: 'viffff', glVertexAttrib4fv__sig: 'vip', glVertexAttribDivisor__sig: 'vii', + glVertexAttribI4i__sig: 'viiiii', + glVertexAttribI4iv__sig: 'vip', + glVertexAttribI4ui__sig: 'viiiii', + glVertexAttribI4uiv__sig: 'vip', + glVertexAttribIPointer__sig: 'viiiip', glVertexAttribPointer__sig: 'viiiiip', glVertexPointer__sig: 'viiip', glViewport__sig: 'viiii', + glWaitSync__sig: 'vpij', glewGetErrorString__sig: 'pi', glewGetExtension__sig: 'ip', glewGetString__sig: 'pi', diff --git a/src/library_webgl2.js b/src/library_webgl2.js index 644edf9d69fb2..ad97365dfb9b5 100644 --- a/src/library_webgl2.js +++ b/src/library_webgl2.js @@ -6,7 +6,6 @@ var LibraryWebGL2 = { glGetStringi__deps: ['$stringToNewUTF8'], - glGetStringi__sig: 'pii', glGetStringi: function(name, index) { if (GL.currentContext.version < 2) { GL.recordError(0x502 /* GL_INVALID_OPERATION */); // Calling GLES3/WebGL2 function with a GLES2/WebGL1 context @@ -49,13 +48,11 @@ var LibraryWebGL2 = { } }, - glGetInteger64v__sig: 'vip', glGetInteger64v__deps: ['$emscriptenWebGLGet'], glGetInteger64v: function(name_, p) { emscriptenWebGLGet(name_, p, {{{ cDefs.EM_FUNC_SIG_PARAM_I64 }}}); }, - glGetInternalformativ__sig: 'viiiip', glGetInternalformativ: function(target, internalformat, pname, bufSize, params) { #if GL_TRACK_ERRORS if (bufSize < 0) { @@ -82,7 +79,6 @@ var LibraryWebGL2 = { } }, - glCompressedTexImage3D__sig: 'viiiiiiiip', glCompressedTexImage3D: function(target, level, internalFormat, width, height, depth, border, imageSize, data) { if (GLctx.currentPixelUnpackBufferBinding) { GLctx['compressedTexImage3D'](target, level, internalFormat, width, height, depth, border, imageSize, data); @@ -91,7 +87,6 @@ var LibraryWebGL2 = { } }, - glCompressedTexSubImage3D__sig: 'viiiiiiiiiip', glCompressedTexSubImage3D: function(target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data) { if (GLctx.currentPixelUnpackBufferBinding) { GLctx['compressedTexSubImage3D'](target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data); @@ -100,7 +95,6 @@ var LibraryWebGL2 = { } }, - glGetBufferParameteri64v__sig: 'viip', glGetBufferParameteri64v__deps: ['$writeI53ToI64'], glGetBufferParameteri64v: function(target, value, data) { #if GL_TRACK_ERRORS @@ -133,7 +127,6 @@ var LibraryWebGL2 = { }, glInvalidateFramebuffer__deps: ['$tempFixedLengthArray'], - glInvalidateFramebuffer__sig: 'viip', glInvalidateFramebuffer: function(target, numAttachments, attachments) { #if GL_ASSERTIONS assert(numAttachments < tempFixedLengthArray.length, 'Invalid count of numAttachments=' + numAttachments + ' passed to glInvalidateFramebuffer (that many attachment points do not exist in GL)'); @@ -147,7 +140,6 @@ var LibraryWebGL2 = { }, glInvalidateSubFramebuffer__deps: ['$tempFixedLengthArray'], - glInvalidateSubFramebuffer__sig: 'viipiiii', glInvalidateSubFramebuffer: function(target, numAttachments, attachments, x, y, width, height) { #if GL_ASSERTIONS assert(numAttachments < tempFixedLengthArray.length, 'Invalid count of numAttachments=' + numAttachments + ' passed to glInvalidateSubFramebuffer (that many attachment points do not exist in GL)'); @@ -160,7 +152,6 @@ var LibraryWebGL2 = { GLctx['invalidateSubFramebuffer'](target, list, x, y, width, height); }, - glTexImage3D__sig: 'viiiiiiiiip', glTexImage3D__deps: ['$heapObjectForWebGLType', '$heapAccessShiftForWebGLHeap'], glTexImage3D: function(target, level, internalFormat, width, height, depth, border, format, type, pixels) { if (GLctx.currentPixelUnpackBufferBinding) { @@ -173,7 +164,6 @@ var LibraryWebGL2 = { } }, - glTexSubImage3D__sig: 'viiiiiiiiiip', glTexSubImage3D__deps: ['$heapObjectForWebGLType', '$heapAccessShiftForWebGLHeap'], glTexSubImage3D: function(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels) { if (GLctx.currentPixelUnpackBufferBinding) { @@ -187,7 +177,6 @@ var LibraryWebGL2 = { }, // Queries - glGenQueries__sig: 'vip', glGenQueries__deps: ['$__glGenObject'], glGenQueries: function(n, ids) { __glGenObject(n, ids, 'createQuery', GL.queries @@ -197,7 +186,6 @@ var LibraryWebGL2 = { ); }, - glDeleteQueries__sig: 'vip', glDeleteQueries: function(n, ids) { for (var i = 0; i < n; i++) { var id = {{{ makeGetValue('ids', 'i*4', 'i32') }}}; @@ -208,14 +196,12 @@ var LibraryWebGL2 = { } }, - glIsQuery__sig: 'ii', glIsQuery: function(id) { var query = GL.queries[id]; if (!query) return 0; return GLctx['isQuery'](query); }, - glBeginQuery__sig: 'vii', glBeginQuery: function(target, id) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.queries, id, 'glBeginQuery', 'id'); @@ -223,7 +209,6 @@ var LibraryWebGL2 = { GLctx['beginQuery'](target, GL.queries[id]); }, - glGetQueryiv__sig: 'viip', glGetQueryiv: function(target, pname, params) { #if GL_TRACK_ERRORS if (!params) { @@ -239,7 +224,6 @@ var LibraryWebGL2 = { {{{ makeSetValue('params', '0', 'GLctx[\'getQuery\'](target, pname)', 'i32') }}}; }, - glGetQueryObjectuiv__sig: 'viip', glGetQueryObjectuiv: function(id, pname, params) { #if GL_TRACK_ERRORS if (!params) { @@ -267,7 +251,6 @@ var LibraryWebGL2 = { }, // Sampler objects - glGenSamplers__sig: 'vip', glGenSamplers__deps: ['$__glGenObject'], glGenSamplers: function(n, samplers) { __glGenObject(n, samplers, 'createSampler', GL.samplers @@ -277,7 +260,6 @@ var LibraryWebGL2 = { ); }, - glDeleteSamplers__sig: 'vip', glDeleteSamplers: function(n, samplers) { for (var i = 0; i < n; i++) { var id = {{{ makeGetValue('samplers', 'i*4', 'i32') }}}; @@ -289,14 +271,12 @@ var LibraryWebGL2 = { } }, - glIsSampler__sig: 'ii', glIsSampler: function(id) { var sampler = GL.samplers[id]; if (!sampler) return 0; return GLctx['isSampler'](sampler); }, - glBindSampler__sig: 'vii', glBindSampler: function(unit, sampler) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.samplers, sampler, 'glBindSampler', 'sampler'); @@ -304,7 +284,6 @@ var LibraryWebGL2 = { GLctx['bindSampler'](unit, GL.samplers[sampler]); }, - glSamplerParameterf__sig: 'viif', glSamplerParameterf: function(sampler, pname, param) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.samplers, sampler, 'glBindSampler', 'sampler'); @@ -312,7 +291,6 @@ var LibraryWebGL2 = { GLctx['samplerParameterf'](GL.samplers[sampler], pname, param); }, - glSamplerParameteri__sig: 'viii', glSamplerParameteri: function(sampler, pname, param) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.samplers, sampler, 'glBindSampler', 'sampler'); @@ -320,7 +298,6 @@ var LibraryWebGL2 = { GLctx['samplerParameteri'](GL.samplers[sampler], pname, param); }, - glSamplerParameterfv__sig: 'viip', glSamplerParameterfv: function(sampler, pname, params) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.samplers, sampler, 'glBindSampler', 'sampler'); @@ -329,7 +306,6 @@ var LibraryWebGL2 = { GLctx['samplerParameterf'](GL.samplers[sampler], pname, param); }, - glSamplerParameteriv__sig: 'viip', glSamplerParameteriv: function(sampler, pname, params) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.samplers, sampler, 'glBindSampler', 'sampler'); @@ -338,7 +314,6 @@ var LibraryWebGL2 = { GLctx['samplerParameteri'](GL.samplers[sampler], pname, param); }, - glGetSamplerParameterfv__sig: 'viip', glGetSamplerParameterfv: function(sampler, pname, params) { #if GL_TRACK_ERRORS if (!params) { @@ -354,7 +329,6 @@ var LibraryWebGL2 = { {{{ makeSetValue('params', '0', 'GLctx[\'getSamplerParameter\'](GL.samplers[sampler], pname)', 'float') }}}; }, - glGetSamplerParameteriv__sig: 'viip', glGetSamplerParameteriv: function(sampler, pname, params) { #if GL_TRACK_ERRORS if (!params) { @@ -371,7 +345,6 @@ var LibraryWebGL2 = { }, // Transform Feedback - glGenTransformFeedbacks__sig: 'vip', glGenTransformFeedbacks__deps: ['$__glGenObject'], glGenTransformFeedbacks: function(n, ids) { __glGenObject(n, ids, 'createTransformFeedback', GL.transformFeedbacks @@ -381,7 +354,6 @@ var LibraryWebGL2 = { ); }, - glDeleteTransformFeedbacks__sig: 'vip', glDeleteTransformFeedbacks: function(n, ids) { for (var i = 0; i < n; i++) { var id = {{{ makeGetValue('ids', 'i*4', 'i32') }}}; @@ -393,12 +365,10 @@ var LibraryWebGL2 = { } }, - glIsTransformFeedback__sig: 'ii', glIsTransformFeedback: function(id) { return GLctx['isTransformFeedback'](GL.transformFeedbacks[id]); }, - glBindTransformFeedback__sig: 'vii', glBindTransformFeedback: function(target, id) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.transformFeedbacks, id, 'glBindTransformFeedback', 'id'); @@ -406,7 +376,6 @@ var LibraryWebGL2 = { GLctx['bindTransformFeedback'](target, GL.transformFeedbacks[id]); }, - glTransformFeedbackVaryings__sig: 'viipi', glTransformFeedbackVaryings: function(program, count, varyings, bufferMode) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.programs, program, 'glTransformFeedbackVaryings', 'program'); @@ -419,7 +388,6 @@ var LibraryWebGL2 = { GLctx['transformFeedbackVaryings'](program, vars, bufferMode); }, - glGetTransformFeedbackVarying__sig: 'viiipppp', glGetTransformFeedbackVarying: function(program, index, bufSize, length, size, type, name) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.programs, program, 'glGetTransformFeedbackVarying', 'program'); @@ -503,20 +471,17 @@ var LibraryWebGL2 = { } }, - glGetIntegeri_v__sig: 'viip', glGetIntegeri_v__deps: ['$emscriptenWebGLGetIndexed'], glGetIntegeri_v: function(target, index, data) { emscriptenWebGLGetIndexed(target, index, data, {{{ cDefs.EM_FUNC_SIG_PARAM_I }}}); }, - glGetInteger64i_v__sig: 'viip', glGetInteger64i_v__deps: ['$emscriptenWebGLGetIndexed'], glGetInteger64i_v: function(target, index, data) { emscriptenWebGLGetIndexed(target, index, data, {{{ cDefs.EM_FUNC_SIG_PARAM_I64 }}}); }, // Uniform Buffer objects - glBindBufferBase__sig: 'viii', glBindBufferBase: function(target, index, buffer) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.buffers, buffer, 'glBindBufferBase', 'buffer'); @@ -524,7 +489,6 @@ var LibraryWebGL2 = { GLctx['bindBufferBase'](target, index, GL.buffers[buffer]); }, - glBindBufferRange__sig: 'viiipp', glBindBufferRange: function(target, index, buffer, offset, ptrsize) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.buffers, buffer, 'glBindBufferRange', 'buffer'); @@ -532,7 +496,6 @@ var LibraryWebGL2 = { GLctx['bindBufferRange'](target, index, GL.buffers[buffer], offset, ptrsize); }, - glGetUniformIndices__sig: 'viipp', glGetUniformIndices: function(program, uniformCount, uniformNames, uniformIndices) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.programs, program, 'glGetUniformIndices', 'program'); @@ -566,7 +529,6 @@ var LibraryWebGL2 = { } }, - glGetActiveUniformsiv__sig: 'viipip', glGetActiveUniformsiv: function(program, uniformCount, uniformIndices, pname, params) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.programs, program, 'glGetActiveUniformsiv', 'program'); @@ -601,7 +563,6 @@ var LibraryWebGL2 = { } }, - glGetUniformBlockIndex__sig: 'iip', glGetUniformBlockIndex: function(program, uniformBlockName) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.programs, program, 'glGetUniformBlockIndex', 'program'); @@ -609,7 +570,6 @@ var LibraryWebGL2 = { return GLctx['getUniformBlockIndex'](GL.programs[program], UTF8ToString(uniformBlockName)); }, - glGetActiveUniformBlockiv__sig: 'viiip', glGetActiveUniformBlockiv: function(program, uniformBlockIndex, pname, params) { #if GL_TRACK_ERRORS if (!params) { @@ -644,7 +604,6 @@ var LibraryWebGL2 = { } }, - glGetActiveUniformBlockName__sig: 'viiipp', glGetActiveUniformBlockName: function(program, uniformBlockIndex, bufSize, length, uniformBlockName) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.programs, program, 'glGetActiveUniformBlockName', 'program'); @@ -661,7 +620,6 @@ var LibraryWebGL2 = { } }, - glUniformBlockBinding__sig: 'viii', glUniformBlockBinding: function(program, uniformBlockIndex, uniformBlockBinding) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.programs, program, 'glUniformBlockBinding', 'program'); @@ -671,7 +629,6 @@ var LibraryWebGL2 = { GLctx['uniformBlockBinding'](program, uniformBlockIndex, uniformBlockBinding); }, - glClearBufferiv__sig: 'viip', glClearBufferiv: function(buffer, drawbuffer, value) { #if GL_ASSERTIONS assert((value & 3) == 0, 'Pointer to integer data passed to glClearBufferiv must be aligned to four bytes!'); @@ -680,7 +637,6 @@ var LibraryWebGL2 = { GLctx['clearBufferiv'](buffer, drawbuffer, HEAP32, value>>2); }, - glClearBufferuiv__sig: 'viip', glClearBufferuiv: function(buffer, drawbuffer, value) { #if GL_ASSERTIONS assert((value & 3) == 0, 'Pointer to integer data passed to glClearBufferuiv must be aligned to four bytes!'); @@ -689,7 +645,6 @@ var LibraryWebGL2 = { GLctx['clearBufferuiv'](buffer, drawbuffer, HEAPU32, value>>2); }, - glClearBufferfv__sig: 'viip', glClearBufferfv: function(buffer, drawbuffer, value) { #if GL_ASSERTIONS assert((value & 3) == 0, 'Pointer to float data passed to glClearBufferfv must be aligned to four bytes!'); @@ -698,7 +653,6 @@ var LibraryWebGL2 = { GLctx['clearBufferfv'](buffer, drawbuffer, HEAPF32, value>>2); }, - glFenceSync__sig: 'pii', glFenceSync: function(condition, flags) { var sync = GLctx.fenceSync(condition, flags); if (sync) { @@ -710,7 +664,6 @@ var LibraryWebGL2 = { return 0; // Failed to create a sync object }, - glDeleteSync__sig: 'vp', glDeleteSync: function(id) { if (!id) return; var sync = GL.syncs[id]; @@ -723,7 +676,6 @@ var LibraryWebGL2 = { GL.syncs[id] = null; }, - glClientWaitSync__sig: 'ipij', #if !WASM_BIGINT glClientWaitSync__deps: ['$convertI32PairToI53'], #endif @@ -736,7 +688,6 @@ var LibraryWebGL2 = { return GLctx.clientWaitSync(GL.syncs[sync], flags, timeout); }, - glWaitSync__sig: 'vpij', #if !WASM_BIGINT glWaitSync__deps: ['$convertI32PairToI53'], #endif @@ -746,7 +697,6 @@ var LibraryWebGL2 = { GLctx.waitSync(GL.syncs[sync], flags, timeout); }, - glGetSynciv__sig: 'vpiipp', glGetSynciv: function(sync, pname, bufSize, length, values) { #if GL_TRACK_ERRORS if (bufSize < 0) { @@ -775,18 +725,15 @@ var LibraryWebGL2 = { } }, - glIsSync__sig: 'ip', glIsSync: function(sync) { return GLctx.isSync(GL.syncs[sync]); }, - glGetUniformuiv__sig: 'viip', glGetUniformuiv__deps: ['$emscriptenWebGLGetUniform'], glGetUniformuiv: function(program, location, params) { emscriptenWebGLGetUniform(program, location, params, {{{ cDefs.EM_FUNC_SIG_PARAM_I }}}); }, - glGetFragDataLocation__sig: 'iip', glGetFragDataLocation: function(program, name) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.programs, program, 'glGetFragDataLocation', 'program'); @@ -794,7 +741,6 @@ var LibraryWebGL2 = { return GLctx['getFragDataLocation'](GL.programs[program], UTF8ToString(name)); }, - glGetVertexAttribIiv__sig: 'viip', glGetVertexAttribIiv__deps: ['$emscriptenWebGLGetVertexAttrib'], glGetVertexAttribIiv: function(index, pname, params) { // N.B. This function may only be called if the vertex attribute was specified using the function glVertexAttribI4iv(), @@ -804,11 +750,9 @@ var LibraryWebGL2 = { // N.B. This function may only be called if the vertex attribute was specified using the function glVertexAttribI4uiv(), // otherwise the results are undefined. (GLES3 spec 6.1.12) - glGetVertexAttribIuiv__sig: 'viip', glGetVertexAttribIuiv__deps: ['$emscriptenWebGLGetVertexAttrib'], glGetVertexAttribIuiv: 'glGetVertexAttribIiv', - glUniform1ui__sig: 'vii', glUniform1ui__deps: ['$webglGetUniformLocation'], glUniform1ui: function(location, v0) { #if GL_ASSERTIONS @@ -817,7 +761,6 @@ var LibraryWebGL2 = { GLctx.uniform1ui(webglGetUniformLocation(location), v0); }, - glUniform2ui__sig: 'viii', glUniform2ui__deps: ['$webglGetUniformLocation'], glUniform2ui: function(location, v0, v1) { #if GL_ASSERTIONS @@ -826,7 +769,6 @@ var LibraryWebGL2 = { GLctx.uniform2ui(webglGetUniformLocation(location), v0, v1); }, - glUniform3ui__sig: 'viiii', glUniform3ui__deps: ['$webglGetUniformLocation'], glUniform3ui: function(location, v0, v1, v2) { #if GL_ASSERTIONS @@ -835,7 +777,6 @@ var LibraryWebGL2 = { GLctx.uniform3ui(webglGetUniformLocation(location), v0, v1, v2); }, - glUniform4ui__sig: 'viiiii', glUniform4ui__deps: ['$webglGetUniformLocation'], glUniform4ui: function(location, v0, v1, v2, v3) { #if GL_ASSERTIONS @@ -844,7 +785,6 @@ var LibraryWebGL2 = { GLctx.uniform4ui(webglGetUniformLocation(location), v0, v1, v2, v3); }, - glUniform1uiv__sig: 'viip', glUniform1uiv__deps: ['$webglGetUniformLocation'], glUniform1uiv: function(location, count, value) { #if GL_ASSERTIONS @@ -854,7 +794,6 @@ var LibraryWebGL2 = { count && GLctx.uniform1uiv(webglGetUniformLocation(location), HEAPU32, value>>2, count); }, - glUniform2uiv__sig: 'viip', glUniform2uiv__deps: ['$webglGetUniformLocation'], glUniform2uiv: function(location, count, value) { #if GL_ASSERTIONS @@ -864,7 +803,6 @@ var LibraryWebGL2 = { count && GLctx.uniform2uiv(webglGetUniformLocation(location), HEAPU32, value>>2, count*2); }, - glUniform3uiv__sig: 'viip', glUniform3uiv__deps: ['$webglGetUniformLocation'], glUniform3uiv: function(location, count, value) { #if GL_ASSERTIONS @@ -874,7 +812,6 @@ var LibraryWebGL2 = { count && GLctx.uniform3uiv(webglGetUniformLocation(location), HEAPU32, value>>2, count*3); }, - glUniform4uiv__sig: 'viip', glUniform4uiv__deps: ['$webglGetUniformLocation'], glUniform4uiv: function(location, count, value) { #if GL_ASSERTIONS @@ -884,7 +821,6 @@ var LibraryWebGL2 = { count && GLctx.uniform4uiv(webglGetUniformLocation(location), HEAPU32, value>>2, count*4); }, - glUniformMatrix2x3fv__sig: 'viiip', glUniformMatrix2x3fv__deps: ['$webglGetUniformLocation'], glUniformMatrix2x3fv: function(location, count, transpose, value) { #if GL_ASSERTIONS @@ -894,7 +830,6 @@ var LibraryWebGL2 = { count && GLctx.uniformMatrix2x3fv(webglGetUniformLocation(location), !!transpose, HEAPF32, value>>2, count*6); }, - glUniformMatrix3x2fv__sig: 'viiip', glUniformMatrix3x2fv__deps: ['$webglGetUniformLocation'], glUniformMatrix3x2fv: function(location, count, transpose, value) { #if GL_ASSERTIONS @@ -904,7 +839,6 @@ var LibraryWebGL2 = { count && GLctx.uniformMatrix3x2fv(webglGetUniformLocation(location), !!transpose, HEAPF32, value>>2, count*6); }, - glUniformMatrix2x4fv__sig: 'viiip', glUniformMatrix2x4fv__deps: ['$webglGetUniformLocation'], glUniformMatrix2x4fv: function(location, count, transpose, value) { #if GL_ASSERTIONS @@ -914,7 +848,6 @@ var LibraryWebGL2 = { count && GLctx.uniformMatrix2x4fv(webglGetUniformLocation(location), !!transpose, HEAPF32, value>>2, count*8); }, - glUniformMatrix4x2fv__sig: 'viiip', glUniformMatrix4x2fv__deps: ['$webglGetUniformLocation'], glUniformMatrix4x2fv: function(location, count, transpose, value) { #if GL_ASSERTIONS @@ -924,7 +857,6 @@ var LibraryWebGL2 = { count && GLctx.uniformMatrix4x2fv(webglGetUniformLocation(location), !!transpose, HEAPF32, value>>2, count*8); }, - glUniformMatrix3x4fv__sig: 'viiip', glUniformMatrix3x4fv__deps: ['$webglGetUniformLocation'], glUniformMatrix3x4fv: function(location, count, transpose, value) { #if GL_ASSERTIONS @@ -934,7 +866,6 @@ var LibraryWebGL2 = { count && GLctx.uniformMatrix3x4fv(webglGetUniformLocation(location), !!transpose, HEAPF32, value>>2, count*12); }, - glUniformMatrix4x3fv__sig: 'viiip', glUniformMatrix4x3fv__deps: ['$webglGetUniformLocation'], glUniformMatrix4x3fv: function(location, count, transpose, value) { #if GL_ASSERTIONS @@ -944,7 +875,6 @@ var LibraryWebGL2 = { count && GLctx.uniformMatrix4x3fv(webglGetUniformLocation(location), !!transpose, HEAPF32, value>>2, count*12); }, - glVertexAttribI4iv__sig: 'vip', glVertexAttribI4iv: function(index, v) { #if GL_ASSERTIONS assert((v & 3) == 0, 'Pointer to integer data passed to glVertexAttribI4iv must be aligned to four bytes!'); @@ -953,7 +883,6 @@ var LibraryWebGL2 = { GLctx.vertexAttribI4i(index, HEAP32[v>>2], HEAP32[v+4>>2], HEAP32[v+8>>2], HEAP32[v+12>>2]); }, - glVertexAttribI4uiv__sig: 'vip', glVertexAttribI4uiv: function(index, v) { #if GL_ASSERTIONS assert((v & 3) == 0, 'Pointer to integer data passed to glVertexAttribI4uiv must be aligned to four bytes!'); @@ -962,7 +891,6 @@ var LibraryWebGL2 = { GLctx.vertexAttribI4ui(index, HEAPU32[v>>2], HEAPU32[v+4>>2], HEAPU32[v+8>>2], HEAPU32[v+12>>2]); }, - glProgramParameteri__sig: 'viii', glProgramParameteri: function(program, pname, value) { GL.recordError(0x500/*GL_INVALID_ENUM*/); #if GL_ASSERTIONS @@ -970,7 +898,6 @@ var LibraryWebGL2 = { #endif }, - glGetProgramBinary__sig: 'viippp', glGetProgramBinary: function(program, bufSize, length, binaryFormat, binary) { GL.recordError(0x502/*GL_INVALID_OPERATION*/); #if GL_ASSERTIONS @@ -978,7 +905,6 @@ var LibraryWebGL2 = { #endif }, - glProgramBinary__sig: 'viipi', glProgramBinary: function(program, binaryFormat, binary, length) { GL.recordError(0x500/*GL_INVALID_ENUM*/); #if GL_ASSERTIONS @@ -986,7 +912,6 @@ var LibraryWebGL2 = { #endif }, - glFramebufferTextureLayer__sig: 'viiiii', glFramebufferTextureLayer: function(target, attachment, texture, level, layer) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.textures, texture, 'glFramebufferTextureLayer', 'texture'); @@ -994,7 +919,6 @@ var LibraryWebGL2 = { GLctx.framebufferTextureLayer(target, attachment, GL.textures[texture], level, layer); }, - glVertexAttribIPointer__sig: 'viiiip', glVertexAttribIPointer: function(index, size, type, stride, ptr) { #if FULL_ES3 var cb = GL.currentContext.clientBuffers[index]; @@ -1023,7 +947,6 @@ var LibraryWebGL2 = { #if !LEGACY_GL_EMULATION // Defined in library_glemu.js when LEGACY_GL_EMULATION is set - glDrawRangeElements__sig: 'viiiiip', glDrawRangeElements__deps: ['glDrawElements'], glDrawRangeElements: function(mode, start, end, count, type, indices) { // TODO: This should be a trivial pass-though function registered at the bottom of this page as @@ -1102,21 +1025,6 @@ var LibraryWebGL2 = { return webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance(GL.contexts[ctx].GLctx); }, - glVertexAttribI4i__sig: 'viiiii', - glVertexAttribI4ui__sig: 'viiiii', - glCopyBufferSubData__sig: 'viippp', - glTexStorage2D__sig: 'viiiii', - glTexStorage3D__sig: 'viiiiii', - glBeginTransformFeedback__sig: 'vi', - glEndTransformFeedback__sig: 'v', - glPauseTransformFeedback__sig: 'v', - glResumeTransformFeedback__sig: 'v', - glBlitFramebuffer__sig: 'viiiiiiiiii', - glReadBuffer__sig: 'vi', - glEndQuery__sig: 'vi', - glRenderbufferStorageMultisample__sig: 'viiiii', - glCopyTexSubImage3D__sig: 'viiiiiiiii', - glClearBufferfi__sig: 'viifi', }; #if MAX_WEBGL_VERSION >= 2 diff --git a/src/utility.js b/src/utility.js index 94a7b71897ebd..fea766f28b78f 100644 --- a/src/utility.js +++ b/src/utility.js @@ -146,7 +146,7 @@ function mergeInto(obj, other, options = null) { const oldsig = obj[key]; const newsig = other[key]; if (oldsig == newsig) { - warn(`signature redefinition for: ${key}. (old=${oldsig} vs new=${newsig})`); + warn(`signature redefinition for: ${key}`); } else { error(`signature redefinition for: ${key}. (old=${oldsig} vs new=${newsig})`); } diff --git a/test/test_other.py b/test/test_other.py index eb84278d0db00..d2ed532e1470b 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -3869,7 +3869,7 @@ def test_js_lib_sig_redefinition(self): } ''') err = self.run_process([EMCC, 'src.c', '--js-library', 'lib.js'], stderr=PIPE).stderr - self.assertContained('lib.js: signature redefinition for: jslibfunc__sig. (old=ii vs new=ii)', err) + self.assertContained('lib.js: signature redefinition for: jslibfunc__sig', err) # Add another redefinition, this time not matching create_file('lib2.js', r''' diff --git a/tools/gen_sig_info.py b/tools/gen_sig_info.py index 80344f59c6742..7ec20218e190c 100755 --- a/tools/gen_sig_info.py +++ b/tools/gen_sig_info.py @@ -227,6 +227,7 @@ def extract_sig_info(sig_info, extra_settings=None, extra_cflags=None): settings = { 'USE_PTHREADS': 1, 'STACK_OVERFLOW_CHECK': 1, + 'MAX_WEBGL_VERSION': 2, 'FULL_ES3': 1, 'USE_SDL': 1, 'FETCH': 1, From 5d5b14bafa26dce414eede8b7df5cf62700116e0 Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Fri, 31 Mar 2023 22:10:23 +0200 Subject: [PATCH 0088/1523] Reduce default thread stack size to 64KB (#19043) --- system/lib/libc/musl/src/internal/pthread_impl.h | 2 +- test/other/test_default_pthread_stack_size.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/system/lib/libc/musl/src/internal/pthread_impl.h b/system/lib/libc/musl/src/internal/pthread_impl.h index 3493ad88bf42e..740fe212dad73 100644 --- a/system/lib/libc/musl/src/internal/pthread_impl.h +++ b/system/lib/libc/musl/src/internal/pthread_impl.h @@ -251,7 +251,7 @@ extern hidden unsigned __default_guardsize; #ifdef __EMSCRIPTEN__ // Keep in sync with DEFAULT_PTHREAD_STACK_SIZE in settings.js -#define DEFAULT_STACK_SIZE (2*1024*1024) +#define DEFAULT_STACK_SIZE (64*1024) #else #define DEFAULT_STACK_SIZE 131072 #endif diff --git a/test/other/test_default_pthread_stack_size.c b/test/other/test_default_pthread_stack_size.c index 14670eeb5a397..b7af751db7760 100644 --- a/test/other/test_default_pthread_stack_size.c +++ b/test/other/test_default_pthread_stack_size.c @@ -8,7 +8,7 @@ int main() { size_t stacksize; pthread_attr_getstacksize(&attr, &stacksize); printf("%zu\n", stacksize); - // Should match DEFAULT_PTHREAD_STACK_SIZE = 2*1024*1024; - assert(stacksize == 2*1024*1024); + // Should match DEFAULT_PTHREAD_STACK_SIZE = 64*1024; + assert(stacksize == 64*1024); return 0; } From 41e404a030ea197d6ee6c84fc9dd0f84cf884e48 Mon Sep 17 00:00:00 2001 From: Pedro Nacht Date: Fri, 31 Mar 2023 17:22:43 -0300 Subject: [PATCH 0089/1523] [NFC] Add security policy (#19038) Closes #19037 --- SECURITY.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000000000..60079f1ecda6f --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,16 @@ +# Security Policy + +If you have discovered a security vulnerability in this project, please report it +privately. **Do not disclose it as a public issue.** This gives us time to work with you +to fix the issue before public exposure, reducing the chance that the exploit will be +used before a patch is released. + +Please submit the report as a [security bug on the Chromium tracker](https://bugs.chromium.org/p/chromium/issues/entry?template=Security%20Bug). + +Please provide the following information in your report: + +- A description of the vulnerability and its impact +- How to reproduce the issue +- Make it clear that it's an Emscripten bug. + +We ask that you give us 90 days to work on a fix before public exposure. From f18834086059f098f987b69efd712e14b16682bd Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 31 Mar 2023 14:15:42 -0700 Subject: [PATCH 0090/1523] Move runtime_strings.js code into library_strings.js (#19097) --- ChangeLog.md | 13 + src/embind/embind.js | 3 +- src/jsifier.js | 7 +- src/library.js | 15 +- src/library_dylink.js | 1 + src/library_fetch.js | 3 + src/library_fs.js | 5 +- src/library_html5.js | 9 +- src/library_legacy.js | 3 +- src/library_strings.js | 246 ++++++++++++++++++ src/library_syscall.js | 3 + src/library_uuid.js | 1 + src/library_wasi.js | 2 +- src/library_wasmfs.js | 1 + src/library_webgl.js | 2 + src/library_websocket.js | 8 +- src/modules.js | 5 - src/preamble.js | 2 - src/preamble_minimal.js | 2 - src/runtime_strings.js | 240 ----------------- test/code_size/hello_webgl2_wasm2js.json | 8 +- test/code_size/hello_webgl_wasm2js.json | 8 +- test/code_size/hello_world_wasm.js | 10 +- test/code_size/hello_world_wasm2js.js | 12 +- test/code_size/hello_world_wasm2js.json | 4 +- test/code_size/random_printf_wasm.json | 4 +- test/code_size/random_printf_wasm2js.json | 4 +- test/core/test_em_js.cpp | 2 + .../metadce/test_metadce_cxx_ctors1.jssize | 2 +- .../metadce/test_metadce_cxx_ctors2.jssize | 2 +- .../metadce/test_metadce_cxx_except.jssize | 2 +- .../test_metadce_cxx_except_wasm.jssize | 2 +- .../metadce/test_metadce_cxx_noexcept.jssize | 2 +- .../metadce/test_metadce_hello_O0.jssize | 2 +- .../metadce/test_metadce_hello_dylink.jssize | 2 +- .../test_metadce_libcxxabi_message_O3.jssize | 2 +- ...dce_libcxxabi_message_O3_standalone.jssize | 2 +- test/other/metadce/test_metadce_mem_O3.jssize | 2 +- .../metadce/test_metadce_mem_O3_grow.jssize | 2 +- ...test_metadce_mem_O3_grow_standalone.jssize | 2 +- .../test_metadce_mem_O3_standalone.jssize | 2 +- .../test_metadce_mem_O3_standalone_lib.jssize | 2 +- ...test_metadce_mem_O3_standalone_narg.jssize | 2 +- ...metadce_mem_O3_standalone_narg_flto.jssize | 2 +- .../metadce/test_metadce_minimal_O0.jssize | 2 +- .../metadce/test_metadce_minimal_O1.jssize | 2 +- .../metadce/test_metadce_minimal_O2.jssize | 2 +- .../test_metadce_minimal_pthreads.jssize | 2 +- test/other/test_unoptimized_code_size.js.size | 2 +- ...t_unoptimized_code_size_no_asserts.js.size | 2 +- .../test_unoptimized_code_size_strict.js.size | 2 +- test/pthread/test_pthread_utf8_funcs.cpp | 2 + 52 files changed, 358 insertions(+), 313 deletions(-) delete mode 100644 src/runtime_strings.js diff --git a/ChangeLog.md b/ChangeLog.md index 779ce8f629491..a22e65ebdd71d 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -20,6 +20,19 @@ See docs/process.md for more on how version tagging works. 3.1.35 (in development) ----------------------- +- The following JavaScript runtime functions were converted to JavaScript + library functions: + - UTF8ArrayToString + - UTF8ToString + - stringToUTF8Array + - stringToUTF8 + - lengthBytesUTF8 + If you use any of these functions in your JS code you will now need to include + them explictly in one of the following ways: + - Add them to a `__deps` entry in your JS library file (with leading $) + - Add them to `DEFAULT_LIBRARY_FUNCS_TO_INCLUDE` (with leading $) + - Add them to `EXPORTED_FUNCTIONS` (without leading $) + - Set `-sLEGACY_RUNTIME` to include all of them at once. - `FS.loadFilesFromDB` and `FS.saveFilesToDB` were removed. We think it's unlikly there were any users of these functions since there is now a separate IDBFS filesystem for folks that want persistence. (#19049) diff --git a/src/embind/embind.js b/src/embind/embind.js index 95eabef2f3cfe..85e71fd87a79c 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -656,7 +656,8 @@ var LibraryEmbind = { _embind_register_std_string__sig: 'vpp', _embind_register_std_string__deps: [ '$readLatin1String', '$registerType', - '$simpleReadValueFromPointer', '$throwBindingError'], + '$simpleReadValueFromPointer', '$throwBindingError', + '$stringToUTF8', '$lengthBytesUTF8'], _embind_register_std_string: function(rawType, name) { name = readLatin1String(name); var stdStringIsUTF8 diff --git a/src/jsifier.js b/src/jsifier.js index 7516f764b20d7..fa95d9e236e67 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -197,13 +197,16 @@ function ${name}(${args}) { function addImplicitDeps(snippet, deps) { // There are some common dependencies that we inject automatically by // conservatively scanning the input functions for their usage. - // Specifically, these are dependencies that are automatically generated by - // the {{{ makeDynCall }}}, and {{{ runtimeKeepalivePush/Pop }}} macros. + // Specifically, these are dependencies that are very common and would be + // burdensome to add manually to all functions. + // The first four are deps that are automatically/conditionally added + // by the {{{ makeDynCall }}}, and {{{ runtimeKeepalivePush/Pop }}} macros. const autoDeps = [ 'getDynCaller', 'getWasmTableEntry', 'runtimeKeepalivePush', 'runtimeKeepalivePop', + 'UTF8ToString', ]; for (const dep of autoDeps) { if (snippet.includes(dep + '(')) { diff --git a/src/library.js b/src/library.js index 9044c3687fd57..96fff5fd75f29 100644 --- a/src/library.js +++ b/src/library.js @@ -2027,7 +2027,7 @@ mergeInto(LibraryManager.library, { return 0; }, - getnameinfo__deps: ['$Sockets', '$DNS', '$readSockaddr'], + getnameinfo__deps: ['$Sockets', '$DNS', '$readSockaddr', '$stringToUTF8'], getnameinfo: function (sa, salen, node, nodelen, serv, servlen, flags) { var info = readSockaddr(sa, salen); if (info.errno) { @@ -2305,6 +2305,7 @@ mergeInto(LibraryManager.library, { // Mark as `noleakcheck` otherwise lsan will report the last returned string // as a leak. emscripten_run_script_string__noleakcheck: true, + emscripten_run_script_string__deps: ['$lengthBytesUTF8', '$stringToUTF8', 'malloc'], emscripten_run_script_string: function(ptr) { {{{ makeEval("var s = eval(UTF8ToString(ptr));") }}} if (s == null) { @@ -2565,7 +2566,7 @@ mergeInto(LibraryManager.library, { return callstack; }, - emscripten_get_callstack__deps: ['$getCallstack'], + emscripten_get_callstack__deps: ['$getCallstack', '$lengthBytesUTF8', '$stringToUTF8'], emscripten_get_callstack: function(flags, str, maxbytes) { // Use explicit calls to from64 rather then using the __sig // magic here. This is because the __sig wrapper uses arrow function @@ -2647,6 +2648,7 @@ mergeInto(LibraryManager.library, { debugger; }, + emscripten_print_double__deps: ['$stringToUTF8', '$lengthBytesUTF8'], emscripten_print_double: function(x, to, max) { var str = x + ''; if (to) return stringToUTF8(str, to, max); @@ -2887,6 +2889,7 @@ mergeInto(LibraryManager.library, { return result ? result.column || 0 : 0; }, + emscripten_get_module_name__deps: ['$stringToUTF8'], emscripten_get_module_name: function(buf, length) { #if MINIMAL_RUNTIME return stringToUTF8('{{{ TARGET_BASENAME }}}.wasm', buf, length); @@ -3363,6 +3366,9 @@ mergeInto(LibraryManager.library, { // Use program_invocation_short_name and program_invocation_name in compiled // programs. This function is for implementing them. +#if !MINIMAL_RUNTIME + _emscripten_get_progname__deps: ['$stringToUTF8'], +#endif _emscripten_get_progname: function(str, len) { #if !MINIMAL_RUNTIME #if ASSERTIONS @@ -3723,5 +3729,10 @@ DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.push( '$ccall', '$cwrap', '$ExitStatus', + '$UTF8ArrayToString', + '$UTF8ToString', + '$stringToUTF8Array', + '$stringToUTF8', + '$lengthBytesUTF8', ); #endif diff --git a/src/library_dylink.js b/src/library_dylink.js index 0b102e91742af..c440de7479227 100644 --- a/src/library_dylink.js +++ b/src/library_dylink.js @@ -370,6 +370,7 @@ var LibraryDylink = { // returns the side module metadata as an object // { memorySize, memoryAlign, tableSize, tableAlign, neededDynlibs} + $getDylinkMetadata__deps: ['$UTF8ArrayToString'], $getDylinkMetadata__internal: true, $getDylinkMetadata: function(binary) { var offset = 0; diff --git a/src/library_fetch.js b/src/library_fetch.js index 88497f99bae70..f2d470ff03f34 100644 --- a/src/library_fetch.js +++ b/src/library_fetch.js @@ -13,7 +13,9 @@ var LibraryFetch = { $Fetch__postset: 'Fetch.staticInit();', #endif $Fetch: Fetch, + _emscripten_fetch_get_response_headers_length__deps: ['$lengthBytesUTF8'], _emscripten_fetch_get_response_headers_length: fetchGetResponseHeadersLength, + _emscripten_fetch_get_response_headers__deps: ['$lengthBytesUTF8', '$stringToUTF8'], _emscripten_fetch_get_response_headers: fetchGetResponseHeaders, _emscripten_fetch_free: fetchFree, @@ -30,6 +32,7 @@ var LibraryFetch = { '$fetchXHR', '$callUserCallback', '$writeI53ToI64', + '$stringToUTF8', #if FETCH_SUPPORT_INDEXEDDB '$fetchCacheData', '$fetchLoadCachedData', diff --git a/src/library_fs.js b/src/library_fs.js index b47020340b7c4..5c7864e3f48f8 100644 --- a/src/library_fs.js +++ b/src/library_fs.js @@ -5,7 +5,10 @@ */ mergeInto(LibraryManager.library, { - $FS__deps: ['$randomFill', '$PATH', '$PATH_FS', '$TTY', '$MEMFS', '$asyncLoad', '$intArrayFromString', + $FS__deps: ['$randomFill', '$PATH', '$PATH_FS', '$TTY', '$MEMFS', '$asyncLoad', + '$intArrayFromString', + '$stringToUTF8Array', + '$lengthBytesUTF8', #if LibraryManager.has('library_idbfs.js') '$IDBFS', #endif diff --git a/src/library_html5.js b/src/library_html5.js index 4994e6919cc07..7ab09794a5595 100644 --- a/src/library_html5.js +++ b/src/library_html5.js @@ -235,7 +235,7 @@ var LibraryHTML5 = { }, }, - $registerKeyEventCallback__deps: ['$JSEvents', '$findEventTarget'], + $registerKeyEventCallback__deps: ['$JSEvents', '$findEventTarget', '$stringToUTF8'], $registerKeyEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) { #if PTHREADS targetThread = JSEvents.getTargetThreadForEventCallback(targetThread); @@ -768,7 +768,7 @@ var LibraryHTML5 = { return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, - $registerFocusEventCallback__deps: ['$JSEvents', '$findEventTarget'], + $registerFocusEventCallback__deps: ['$JSEvents', '$findEventTarget', '$stringToUTF8'], $registerFocusEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) { #if PTHREADS targetThread = JSEvents.getTargetThreadForEventCallback(targetThread); @@ -1073,7 +1073,7 @@ var LibraryHTML5 = { return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, - $fillFullscreenChangeEventData__deps: ['$JSEvents'], + $fillFullscreenChangeEventData__deps: ['$JSEvents', '$stringToUTF8'], $fillFullscreenChangeEventData: function(eventStruct) { var fullscreenElement = document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement; var isFullscreen = !!fullscreenElement; @@ -1662,7 +1662,7 @@ var LibraryHTML5 = { return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, - $fillPointerlockChangeEventData__deps: ['$JSEvents'], + $fillPointerlockChangeEventData__deps: ['$JSEvents', '$stringToUTF8'], $fillPointerlockChangeEventData: function(eventStruct) { var pointerLockElement = document.pointerLockElement || document.mozPointerLockElement || document.webkitPointerLockElement || document.msPointerLockElement; var isPointerlocked = !!pointerLockElement; @@ -2105,6 +2105,7 @@ var LibraryHTML5 = { return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, + $fillGamepadEventData__deps: ['$stringToUTF8'], $fillGamepadEventData: function(eventStruct, e) { {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenGamepadEvent.timestamp, 'e.timestamp', 'double') }}}; for (var i = 0; i < e.axes.length; ++i) { diff --git a/src/library_legacy.js b/src/library_legacy.js index dbbcf433431d8..a396573f86e11 100644 --- a/src/library_legacy.js +++ b/src/library_legacy.js @@ -44,12 +44,13 @@ mergeInto(LibraryManager.library, { // in a maximum length that can be used to be secure from out of bounds // writes. $writeStringToMemory__docs: '/** @deprecated @param {boolean=} dontAddNull */', + $writeStringToMemory__deps: ['$lengthBytesUTF8', '$stringToUTF8'], $writeStringToMemory: function(string, buffer, dontAddNull) { warnOnce('writeStringToMemory is deprecated and should not be called! Use stringToUTF8() instead!'); var /** @type {number} */ lastChar, /** @type {number} */ end; if (dontAddNull) { - // stringToUTF8Array always appends null. If we don't want to do that, remember the + // stringToUTF8 always appends null. If we don't want to do that, remember the // character that existed at the location where the null will be placed, and restore // that after the write (below). end = buffer + lengthBytesUTF8(string); diff --git a/src/library_strings.js b/src/library_strings.js index f72925a2f9ed1..eeefc039d823e 100644 --- a/src/library_strings.js +++ b/src/library_strings.js @@ -7,7 +7,251 @@ #include "arrayUtils.js" mergeInto(LibraryManager.library, { +#if TEXTDECODER == 2 + $UTF8Decoder: "new TextDecoder('utf8')", +#elif TEXTDECODER == 1 + $UTF8Decoder: "typeof TextDecoder != 'undefined' ? new TextDecoder('utf8') : undefined", +#endif + + $UTF8ArrayToString__docs: ` + /** + * Given a pointer 'idx' to a null-terminated UTF8-encoded string in the given + * array that contains uint8 values, returns a copy of that string as a + * Javascript String object. + * heapOrArray is either a regular array, or a JavaScript typed array view. + * @param {number} idx + * @param {number=} maxBytesToRead + * @return {string} + */`, +#if TEXTDECODER + $UTF8ArrayToString__deps: ['$UTF8Decoder'], +#endif + $UTF8ArrayToString: function(heapOrArray, idx, maxBytesToRead) { +#if CAN_ADDRESS_2GB + idx >>>= 0; +#endif + var endIdx = idx + maxBytesToRead; +#if TEXTDECODER + var endPtr = idx; + // TextDecoder needs to know the byte length in advance, it doesn't stop on + // null terminator by itself. Also, use the length info to avoid running tiny + // strings through TextDecoder, since .subarray() allocates garbage. + // (As a tiny code save trick, compare endPtr against endIdx using a negation, + // so that undefined means Infinity) + while (heapOrArray[endPtr] && !(endPtr >= endIdx)) ++endPtr; +#endif // TEXTDECODER + +#if TEXTDECODER == 2 + return UTF8Decoder.decode(heapOrArray.buffer ? {{{ getUnsharedTextDecoderView('heapOrArray', 'idx', 'endPtr') }}} : new Uint8Array(heapOrArray.slice(idx, endPtr))); +#else // TEXTDECODER == 2 +#if TEXTDECODER + if (endPtr - idx > 16 && heapOrArray.buffer && UTF8Decoder) { + return UTF8Decoder.decode({{{ getUnsharedTextDecoderView('heapOrArray', 'idx', 'endPtr') }}}); + } +#endif // TEXTDECODER + var str = ''; +#if TEXTDECODER + // If building with TextDecoder, we have already computed the string length + // above, so test loop end condition against that + while (idx < endPtr) { +#else + while (!(idx >= endIdx)) { +#endif + // For UTF8 byte structure, see: + // http://en.wikipedia.org/wiki/UTF-8#Description + // https://www.ietf.org/rfc/rfc2279.txt + // https://tools.ietf.org/html/rfc3629 + var u0 = heapOrArray[idx++]; +#if !TEXTDECODER + // If not building with TextDecoder enabled, we don't know the string + // length, so scan for \0 byte. + // If building with TextDecoder, we know exactly at what byte index the + // string ends, so checking for nulls here would be redundant. + if (!u0) return str; +#endif + if (!(u0 & 0x80)) { str += String.fromCharCode(u0); continue; } + var u1 = heapOrArray[idx++] & 63; + if ((u0 & 0xE0) == 0xC0) { str += String.fromCharCode(((u0 & 31) << 6) | u1); continue; } + var u2 = heapOrArray[idx++] & 63; + if ((u0 & 0xF0) == 0xE0) { + u0 = ((u0 & 15) << 12) | (u1 << 6) | u2; + } else { +#if ASSERTIONS + if ((u0 & 0xF8) != 0xF0) warnOnce('Invalid UTF-8 leading byte ' + ptrToString(u0) + ' encountered when deserializing a UTF-8 string in wasm memory to a JS string!'); +#endif + u0 = ((u0 & 7) << 18) | (u1 << 12) | (u2 << 6) | (heapOrArray[idx++] & 63); + } + + if (u0 < 0x10000) { + str += String.fromCharCode(u0); + } else { + var ch = u0 - 0x10000; + str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF)); + } + } + return str; +#endif // TEXTDECODER == 2 + }, + + $UTF8ToString__docs: ` + /** + * Given a pointer 'ptr' to a null-terminated UTF8-encoded string in the + * emscripten HEAP, returns a copy of that string as a Javascript String object. + * + * @param {number} ptr + * @param {number=} maxBytesToRead - An optional length that specifies the + * maximum number of bytes to read. You can omit this parameter to scan the + * string until the first \0 byte. If maxBytesToRead is passed, and the string + * at [ptr, ptr+maxBytesToReadr[ contains a null byte in the middle, then the + * string will cut short at that byte index (i.e. maxBytesToRead will not + * produce a string of exact length [ptr, ptr+maxBytesToRead[) N.B. mixing + * frequent uses of UTF8ToString() with and without maxBytesToRead may throw + * JS JIT optimizations off, so it is worth to consider consistently using one + * @return {string} + */`, +#if TEXTDECODER == 2 + $UTF8ToString__deps: ['$UTF8Decoder'], +#else + $UTF8ToString__deps: ['$UTF8ArrayToString'], +#endif + $UTF8ToString: function(ptr, maxBytesToRead) { +#if ASSERTIONS + assert(typeof ptr == 'number'); +#endif +#if CAN_ADDRESS_2GB + ptr >>>= 0; +#endif +#if TEXTDECODER == 2 + if (!ptr) return ''; + var maxPtr = ptr + maxBytesToRead; + for (var end = ptr; !(end >= maxPtr) && HEAPU8[end];) ++end; + return UTF8Decoder.decode({{{ getUnsharedTextDecoderView('HEAPU8', 'ptr', 'end') }}}); +#else + return ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead) : ''; +#endif + }, + + /** + * Copies the given Javascript String object 'str' to the given byte array at + * address 'outIdx', encoded in UTF8 form and null-terminated. The copy will + * require at most str.length*4+1 bytes of space in the HEAP. Use the function + * lengthBytesUTF8 to compute the exact number of bytes (excluding null + * terminator) that this function will write. + * + * @param {string} str - The Javascript string to copy. + * @param {ArrayBufferView|Array} heap - The array to copy to. Each + * index in this array is assumed + * to be one 8-byte element. + * @param {number} outIdx - The starting offset in the array to begin the copying. + * @param {number} maxBytesToWrite - The maximum number of bytes this function + * can write to the array. This count should + * include the null terminator, i.e. if + * maxBytesToWrite=1, only the null terminator + * will be written and nothing else. + * maxBytesToWrite=0 does not write any bytes + * to the output, not even the null + * terminator. + * @return {number} The number of bytes written, EXCLUDING the null terminator. + */ + $stringToUTF8Array: function(str, heap, outIdx, maxBytesToWrite) { +#if CAN_ADDRESS_2GB + outIdx >>>= 0; +#endif + // Parameter maxBytesToWrite is not optional. Negative values, 0, null, + // undefined and false each don't write out any bytes. + if (!(maxBytesToWrite > 0)) + return 0; + + var startIdx = outIdx; + var endIdx = outIdx + maxBytesToWrite - 1; // -1 for string null terminator. + for (var i = 0; i < str.length; ++i) { + // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code + // unit, not a Unicode code point of the character! So decode + // UTF16->UTF32->UTF8. + // See http://unicode.org/faq/utf_bom.html#utf16-3 + // For UTF8 byte structure, see http://en.wikipedia.org/wiki/UTF-8#Description + // and https://www.ietf.org/rfc/rfc2279.txt + // and https://tools.ietf.org/html/rfc3629 + var u = str.charCodeAt(i); // possibly a lead surrogate + if (u >= 0xD800 && u <= 0xDFFF) { + var u1 = str.charCodeAt(++i); + u = 0x10000 + ((u & 0x3FF) << 10) | (u1 & 0x3FF); + } + if (u <= 0x7F) { + if (outIdx >= endIdx) break; + heap[outIdx++] = u; + } else if (u <= 0x7FF) { + if (outIdx + 1 >= endIdx) break; + heap[outIdx++] = 0xC0 | (u >> 6); + heap[outIdx++] = 0x80 | (u & 63); + } else if (u <= 0xFFFF) { + if (outIdx + 2 >= endIdx) break; + heap[outIdx++] = 0xE0 | (u >> 12); + heap[outIdx++] = 0x80 | ((u >> 6) & 63); + heap[outIdx++] = 0x80 | (u & 63); + } else { + if (outIdx + 3 >= endIdx) break; +#if ASSERTIONS + if (u > 0x10FFFF) warnOnce('Invalid Unicode code point ' + ptrToString(u) + ' encountered when serializing a JS string to a UTF-8 string in wasm memory! (Valid unicode code points should be in range 0-0x10FFFF).'); +#endif + heap[outIdx++] = 0xF0 | (u >> 18); + heap[outIdx++] = 0x80 | ((u >> 12) & 63); + heap[outIdx++] = 0x80 | ((u >> 6) & 63); + heap[outIdx++] = 0x80 | (u & 63); + } + } + // Null-terminate the pointer to the buffer. + heap[outIdx] = 0; + return outIdx - startIdx; + }, + + /** + * Copies the given Javascript String object 'str' to the emscripten HEAP at + * address 'outPtr', null-terminated and encoded in UTF8 form. The copy will + * require at most str.length*4+1 bytes of space in the HEAP. + * Use the function lengthBytesUTF8 to compute the exact number of bytes + * (excluding null terminator) that this function will write. + * + * @return {number} The number of bytes written, EXCLUDING the null terminator. + */ + $stringToUTF8__deps: ['$stringToUTF8Array'], + $stringToUTF8: function(str, outPtr, maxBytesToWrite) { +#if ASSERTIONS + assert(typeof maxBytesToWrite == 'number', 'stringToUTF8(str, outPtr, maxBytesToWrite) is missing the third parameter that specifies the length of the output buffer!'); +#endif + return stringToUTF8Array(str, {{{ heapAndOffset('HEAPU8', 'outPtr') }}}, maxBytesToWrite); + }, + + /** + * Returns the number of bytes the given Javascript string takes if encoded as a + * UTF8 byte array, EXCLUDING the null terminator byte. + * + * @param {string} str - JavaScript string to operator on + * @return {number} Length, in bytes, of the UTF8 encoded string. + */ + $lengthBytesUTF8: function(str) { + var len = 0; + for (var i = 0; i < str.length; ++i) { + // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code + // unit, not a Unicode code point of the character! So decode + // UTF16->UTF32->UTF8. + // See http://unicode.org/faq/utf_bom.html#utf16-3 + var c = str.charCodeAt(i); // possibly a lead surrogate + if (c <= 0x7F) { + len++; + } else if (c <= 0x7FF) { + len += 2; + } else if (c >= 0xD800 && c <= 0xDFFF) { + len += 4; ++i; + } else { + len += 3; + } + } + return len; + }, + $intArrayFromString__docs: '/** @type {function(string, boolean=, number=)} */', + $intArrayFromString__deps: ['$lengthBytesUTF8', '$stringToUTF8Array'], $intArrayFromString: intArrayFromString, $intArrayToString: intArrayToString, @@ -232,6 +476,7 @@ mergeInto(LibraryManager.library, { // Allocate heap space for a JS string, and write it there. // It is the responsibility of the caller to free() that memory. + $stringToNewUTF8__deps: ['$lengthBytesUTF8', '$stringToUTF8'], $stringToNewUTF8: function(str) { var size = lengthBytesUTF8(str) + 1; var ret = {{{ makeMalloc('stringToNewUTF8', 'size') }}}; @@ -240,6 +485,7 @@ mergeInto(LibraryManager.library, { }, // Allocate stack space for a JS string, and write it there. + $stringToUTF8OnStack__deps: ['$lengthBytesUTF8', '$stringToUTF8'], $stringToUTF8OnStack: function(str) { var size = lengthBytesUTF8(str) + 1; var ret = stackAlloc(size); diff --git a/src/library_syscall.js b/src/library_syscall.js index bc08ecb93aa97..45fb3ca65dead 100644 --- a/src/library_syscall.js +++ b/src/library_syscall.js @@ -598,6 +598,7 @@ var SyscallsLibrary = { } return nonzero; }, + __syscall_getcwd__deps: ['$lengthBytesUTF8', '$stringToUTF8'], __syscall_getcwd: function(buf, size) { if (size === 0) return -{{{ cDefs.EINVAL }}}; var cwd = FS.cwd(); @@ -635,6 +636,7 @@ var SyscallsLibrary = { FS.fchown(fd, owner, group); return 0; }, + __syscall_getdents64__deps: ['$stringToUTF8'], __syscall_getdents64: function(fd, dirp, count) { var stream = SYSCALLS.getStreamFromFD(fd) if (!stream.getdents) { @@ -869,6 +871,7 @@ var SyscallsLibrary = { FS.symlink(target, linkpath); return 0; }, + __syscall_readlinkat__deps: ['$lengthBytesUTF8', '$stringToUTF8'], __syscall_readlinkat: function(dirfd, path, buf, bufsize) { path = SYSCALLS.getStr(path); path = SYSCALLS.calculateAt(dirfd, path); diff --git a/src/library_uuid.js b/src/library_uuid.js index f0f0e72219436..0e212e095d1af 100644 --- a/src/library_uuid.js +++ b/src/library_uuid.js @@ -111,6 +111,7 @@ mergeInto(LibraryManager.library, { // Convert a 'compact' form UUID to a string, if the upper parameter is supplied make the string upper case. uuid_unparse__docs: '/** @param {number|boolean=} upper */', + uuid_unparse__deps: ['$stringToUTF8'], uuid_unparse: function(uu, out, upper) { // void uuid_unparse(const uuid_t uu, char *out); var i = 0; diff --git a/src/library_wasi.js b/src/library_wasi.js index c9cca336316d5..1dbb9dbf692c3 100644 --- a/src/library_wasi.js +++ b/src/library_wasi.js @@ -226,7 +226,7 @@ var WasiLibrary = { $printCharBuffers: [null, [], []], // 1 => stdout, 2 => stderr $printCharBuffers__internal: true, $printChar__internal: true, - $printChar__deps: ['$printCharBuffers'], + $printChar__deps: ['$printCharBuffers', '$UTF8ArrayToString'], $printChar: function(stream, curr) { var buffer = printCharBuffers[stream]; #if ASSERTIONS diff --git a/src/library_wasmfs.js b/src/library_wasmfs.js index 2b6136a78a41e..ce489ab50db16 100644 --- a/src/library_wasmfs.js +++ b/src/library_wasmfs.js @@ -276,6 +276,7 @@ mergeInto(LibraryManager.library, { stringToUTF8(s, childNameBuffer, len); }, _wasmfs_get_preloaded_path_name__sig: 'vip', + _wasmfs_get_preloaded_path_name__deps: ['$lengthBytesUTF8', '$stringToUTF8'], _wasmfs_get_preloaded_path_name: function(index, fileNameBuffer) { var s = wasmFSPreloadedFiles[index].pathName; var len = lengthBytesUTF8(s) + 1; diff --git a/src/library_webgl.js b/src/library_webgl.js index c2e2066a2a17a..7455cf0317a0a 100644 --- a/src/library_webgl.js +++ b/src/library_webgl.js @@ -2916,6 +2916,7 @@ var LibraryGL = { return GLctx.getAttribLocation(GL.programs[program], UTF8ToString(name)); }, + $__glGetActiveAttribOrUniform__deps: ['$stringToUTF8'], $__glGetActiveAttribOrUniform: function(funcName, program, index, bufSize, length, size, type, name) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.programs, program, funcName, 'program'); @@ -3167,6 +3168,7 @@ var LibraryGL = { #endif }, + glGetShaderInfoLog__deps: ['$stringToUTF8'], glGetShaderInfoLog: function(shader, maxLength, length, infoLog) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.shaders, shader, 'glGetShaderInfoLog', 'shader'); diff --git a/src/library_websocket.js b/src/library_websocket.js index e6e7ad6ee50ea..06153eaf0a556 100644 --- a/src/library_websocket.js +++ b/src/library_websocket.js @@ -40,7 +40,7 @@ var LibraryWebSocket = { return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, - emscripten_websocket_get_extensions__deps: ['$WS'], + emscripten_websocket_get_extensions__deps: ['$WS', '$stringToUTF8'], emscripten_websocket_get_extensions__proxy: 'sync', emscripten_websocket_get_extensions: function(socketId, extensions, extensionsLength) { var socket = WS.sockets[socketId]; @@ -70,7 +70,7 @@ var LibraryWebSocket = { return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, - emscripten_websocket_get_protocol__deps: ['$WS'], + emscripten_websocket_get_protocol__deps: ['$WS', '$stringToUTF8'], emscripten_websocket_get_protocol__proxy: 'sync', emscripten_websocket_get_protocol: function(socketId, protocol, protocolLength) { var socket = WS.sockets[socketId]; @@ -100,7 +100,7 @@ var LibraryWebSocket = { return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, - emscripten_websocket_get_url__deps: ['$WS'], + emscripten_websocket_get_url__deps: ['$WS', '$stringToUTF8'], emscripten_websocket_get_url__proxy: 'sync', emscripten_websocket_get_url: function(socketId, url, urlLength) { var socket = WS.sockets[socketId]; @@ -186,7 +186,7 @@ var LibraryWebSocket = { return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, - emscripten_websocket_set_onclose_callback_on_thread__deps: ['$WS'], + emscripten_websocket_set_onclose_callback_on_thread__deps: ['$WS', '$stringToUTF8'], emscripten_websocket_set_onclose_callback_on_thread__proxy: 'sync', emscripten_websocket_set_onclose_callback_on_thread: function(socketId, userData, callbackFunc, thread) { if (!WS.socketEvent) WS.socketEvent = _malloc(1024); // TODO: sizeof(EmscriptenWebSocketCloseEvent), which is the largest event struct diff --git a/src/modules.js b/src/modules.js index 811ab7ddd8c57..613a836b0975a 100644 --- a/src/modules.js +++ b/src/modules.js @@ -355,11 +355,6 @@ function exportRuntime() { // All possible runtime elements that can be exported let runtimeElements = [ 'run', - 'UTF8ArrayToString', - 'UTF8ToString', - 'stringToUTF8Array', - 'stringToUTF8', - 'lengthBytesUTF8', 'addOnPreRun', 'addOnInit', 'addOnPreMain', diff --git a/src/preamble.js b/src/preamble.js index 5d1c9f5b610ef..1c3a74ac5744e 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -102,8 +102,6 @@ function _free() { #endif // free #endif // ASSERTIONS -#include "runtime_strings.js" - // Memory management var HEAP, diff --git a/src/preamble_minimal.js b/src/preamble_minimal.js index dc6ea52ad9e6b..dd67803067d5e 100644 --- a/src/preamble_minimal.js +++ b/src/preamble_minimal.js @@ -60,8 +60,6 @@ if (Module['doWasm2JS']) { Module['wasm'] = base64Decode('<<< WASM_BINARY_DATA >>>'); #endif -#include "runtime_strings.js" - var HEAP8, HEAP16, HEAP32, HEAPU8, HEAPU16, HEAPU32, HEAPF32, HEAPF64, #if WASM_BIGINT HEAP64, HEAPU64, diff --git a/src/runtime_strings.js b/src/runtime_strings.js deleted file mode 100644 index c412e5e310d7d..0000000000000 --- a/src/runtime_strings.js +++ /dev/null @@ -1,240 +0,0 @@ -/** - * @license - * Copyright 2019 The Emscripten Authors - * SPDX-License-Identifier: MIT - */ - -// runtime_strings.js: String related runtime functions that are part of both -// MINIMAL_RUNTIME and regular runtime. - -#if TEXTDECODER == 2 -var UTF8Decoder = new TextDecoder('utf8'); -#elif TEXTDECODER == 1 -var UTF8Decoder = typeof TextDecoder != 'undefined' ? new TextDecoder('utf8') : undefined; -#endif - -/** - * Given a pointer 'idx' to a null-terminated UTF8-encoded string in the given - * array that contains uint8 values, returns a copy of that string as a - * Javascript String object. - * heapOrArray is either a regular array, or a JavaScript typed array view. - * @param {number} idx - * @param {number=} maxBytesToRead - * @return {string} - */ -function UTF8ArrayToString(heapOrArray, idx, maxBytesToRead) { -#if CAN_ADDRESS_2GB - idx >>>= 0; -#endif - var endIdx = idx + maxBytesToRead; -#if TEXTDECODER - var endPtr = idx; - // TextDecoder needs to know the byte length in advance, it doesn't stop on - // null terminator by itself. Also, use the length info to avoid running tiny - // strings through TextDecoder, since .subarray() allocates garbage. - // (As a tiny code save trick, compare endPtr against endIdx using a negation, - // so that undefined means Infinity) - while (heapOrArray[endPtr] && !(endPtr >= endIdx)) ++endPtr; -#endif // TEXTDECODER - -#if TEXTDECODER == 2 - return UTF8Decoder.decode(heapOrArray.buffer ? {{{ getUnsharedTextDecoderView('heapOrArray', 'idx', 'endPtr') }}} : new Uint8Array(heapOrArray.slice(idx, endPtr))); -#else // TEXTDECODER == 2 -#if TEXTDECODER - if (endPtr - idx > 16 && heapOrArray.buffer && UTF8Decoder) { - return UTF8Decoder.decode({{{ getUnsharedTextDecoderView('heapOrArray', 'idx', 'endPtr') }}}); - } -#endif // TEXTDECODER - var str = ''; -#if TEXTDECODER - // If building with TextDecoder, we have already computed the string length - // above, so test loop end condition against that - while (idx < endPtr) { -#else - while (!(idx >= endIdx)) { -#endif - // For UTF8 byte structure, see: - // http://en.wikipedia.org/wiki/UTF-8#Description - // https://www.ietf.org/rfc/rfc2279.txt - // https://tools.ietf.org/html/rfc3629 - var u0 = heapOrArray[idx++]; -#if !TEXTDECODER - // If not building with TextDecoder enabled, we don't know the string - // length, so scan for \0 byte. - // If building with TextDecoder, we know exactly at what byte index the - // string ends, so checking for nulls here would be redundant. - if (!u0) return str; -#endif - if (!(u0 & 0x80)) { str += String.fromCharCode(u0); continue; } - var u1 = heapOrArray[idx++] & 63; - if ((u0 & 0xE0) == 0xC0) { str += String.fromCharCode(((u0 & 31) << 6) | u1); continue; } - var u2 = heapOrArray[idx++] & 63; - if ((u0 & 0xF0) == 0xE0) { - u0 = ((u0 & 15) << 12) | (u1 << 6) | u2; - } else { -#if ASSERTIONS - if ((u0 & 0xF8) != 0xF0) warnOnce('Invalid UTF-8 leading byte ' + ptrToString(u0) + ' encountered when deserializing a UTF-8 string in wasm memory to a JS string!'); -#endif - u0 = ((u0 & 7) << 18) | (u1 << 12) | (u2 << 6) | (heapOrArray[idx++] & 63); - } - - if (u0 < 0x10000) { - str += String.fromCharCode(u0); - } else { - var ch = u0 - 0x10000; - str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF)); - } - } - return str; -#endif // TEXTDECODER == 2 -} - -/** - * Given a pointer 'ptr' to a null-terminated UTF8-encoded string in the - * emscripten HEAP, returns a copy of that string as a Javascript String object. - * - * @param {number} ptr - * @param {number=} maxBytesToRead - An optional length that specifies the - * maximum number of bytes to read. You can omit this parameter to scan the - * string until the first \0 byte. If maxBytesToRead is passed, and the string - * at [ptr, ptr+maxBytesToReadr[ contains a null byte in the middle, then the - * string will cut short at that byte index (i.e. maxBytesToRead will not - * produce a string of exact length [ptr, ptr+maxBytesToRead[) N.B. mixing - * frequent uses of UTF8ToString() with and without maxBytesToRead may throw - * JS JIT optimizations off, so it is worth to consider consistently using one - * @return {string} - */ -function UTF8ToString(ptr, maxBytesToRead) { -#if ASSERTIONS - assert(typeof ptr == 'number'); -#endif -#if CAN_ADDRESS_2GB - ptr >>>= 0; -#endif -#if TEXTDECODER == 2 - if (!ptr) return ''; - var maxPtr = ptr + maxBytesToRead; - for (var end = ptr; !(end >= maxPtr) && HEAPU8[end];) ++end; - return UTF8Decoder.decode({{{ getUnsharedTextDecoderView('HEAPU8', 'ptr', 'end') }}}); -#else - return ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead) : ''; -#endif -} - -/** - * Copies the given Javascript String object 'str' to the given byte array at - * address 'outIdx', encoded in UTF8 form and null-terminated. The copy will - * require at most str.length*4+1 bytes of space in the HEAP. Use the function - * lengthBytesUTF8 to compute the exact number of bytes (excluding null - * terminator) that this function will write. - * - * @param {string} str - The Javascript string to copy. - * @param {ArrayBufferView|Array} heap - The array to copy to. Each - * index in this array is assumed - * to be one 8-byte element. - * @param {number} outIdx - The starting offset in the array to begin the copying. - * @param {number} maxBytesToWrite - The maximum number of bytes this function - * can write to the array. This count should - * include the null terminator, i.e. if - * maxBytesToWrite=1, only the null terminator - * will be written and nothing else. - * maxBytesToWrite=0 does not write any bytes - * to the output, not even the null - * terminator. - * @return {number} The number of bytes written, EXCLUDING the null terminator. - */ -function stringToUTF8Array(str, heap, outIdx, maxBytesToWrite) { -#if CAN_ADDRESS_2GB - outIdx >>>= 0; -#endif - // Parameter maxBytesToWrite is not optional. Negative values, 0, null, - // undefined and false each don't write out any bytes. - if (!(maxBytesToWrite > 0)) - return 0; - - var startIdx = outIdx; - var endIdx = outIdx + maxBytesToWrite - 1; // -1 for string null terminator. - for (var i = 0; i < str.length; ++i) { - // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code - // unit, not a Unicode code point of the character! So decode - // UTF16->UTF32->UTF8. - // See http://unicode.org/faq/utf_bom.html#utf16-3 - // For UTF8 byte structure, see http://en.wikipedia.org/wiki/UTF-8#Description - // and https://www.ietf.org/rfc/rfc2279.txt - // and https://tools.ietf.org/html/rfc3629 - var u = str.charCodeAt(i); // possibly a lead surrogate - if (u >= 0xD800 && u <= 0xDFFF) { - var u1 = str.charCodeAt(++i); - u = 0x10000 + ((u & 0x3FF) << 10) | (u1 & 0x3FF); - } - if (u <= 0x7F) { - if (outIdx >= endIdx) break; - heap[outIdx++] = u; - } else if (u <= 0x7FF) { - if (outIdx + 1 >= endIdx) break; - heap[outIdx++] = 0xC0 | (u >> 6); - heap[outIdx++] = 0x80 | (u & 63); - } else if (u <= 0xFFFF) { - if (outIdx + 2 >= endIdx) break; - heap[outIdx++] = 0xE0 | (u >> 12); - heap[outIdx++] = 0x80 | ((u >> 6) & 63); - heap[outIdx++] = 0x80 | (u & 63); - } else { - if (outIdx + 3 >= endIdx) break; -#if ASSERTIONS - if (u > 0x10FFFF) warnOnce('Invalid Unicode code point ' + ptrToString(u) + ' encountered when serializing a JS string to a UTF-8 string in wasm memory! (Valid unicode code points should be in range 0-0x10FFFF).'); -#endif - heap[outIdx++] = 0xF0 | (u >> 18); - heap[outIdx++] = 0x80 | ((u >> 12) & 63); - heap[outIdx++] = 0x80 | ((u >> 6) & 63); - heap[outIdx++] = 0x80 | (u & 63); - } - } - // Null-terminate the pointer to the buffer. - heap[outIdx] = 0; - return outIdx - startIdx; -} - -/** - * Copies the given Javascript String object 'str' to the emscripten HEAP at - * address 'outPtr', null-terminated and encoded in UTF8 form. The copy will - * require at most str.length*4+1 bytes of space in the HEAP. - * Use the function lengthBytesUTF8 to compute the exact number of bytes - * (excluding null terminator) that this function will write. - * - * @return {number} The number of bytes written, EXCLUDING the null terminator. - */ -function stringToUTF8(str, outPtr, maxBytesToWrite) { -#if ASSERTIONS - assert(typeof maxBytesToWrite == 'number', 'stringToUTF8(str, outPtr, maxBytesToWrite) is missing the third parameter that specifies the length of the output buffer!'); -#endif - return stringToUTF8Array(str, {{{ heapAndOffset('HEAPU8', 'outPtr') }}}, maxBytesToWrite); -} - -/** - * Returns the number of bytes the given Javascript string takes if encoded as a - * UTF8 byte array, EXCLUDING the null terminator byte. - * - * @param {string} str - JavaScript string to operator on - * @return {number} Length, in bytes, of the UTF8 encoded string. - */ -function lengthBytesUTF8(str) { - var len = 0; - for (var i = 0; i < str.length; ++i) { - // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code - // unit, not a Unicode code point of the character! So decode - // UTF16->UTF32->UTF8. - // See http://unicode.org/faq/utf_bom.html#utf16-3 - var c = str.charCodeAt(i); // possibly a lead surrogate - if (c <= 0x7F) { - len++; - } else if (c <= 0x7FF) { - len += 2; - } else if (c >= 0xD800 && c <= 0xDFFF) { - len += 4; ++i; - } else { - len += 3; - } - } - return len; -} diff --git a/test/code_size/hello_webgl2_wasm2js.json b/test/code_size/hello_webgl2_wasm2js.json index b57f45586eb05..82590513233fa 100644 --- a/test/code_size/hello_webgl2_wasm2js.json +++ b/test/code_size/hello_webgl2_wasm2js.json @@ -1,10 +1,10 @@ { "a.html": 567, "a.html.gz": 379, - "a.js": 18210, - "a.js.gz": 8068, + "a.js": 18201, + "a.js.gz": 8063, "a.mem": 3171, "a.mem.gz": 2714, - "total": 21948, - "total_gz": 11161 + "total": 21939, + "total_gz": 11156 } diff --git a/test/code_size/hello_webgl_wasm2js.json b/test/code_size/hello_webgl_wasm2js.json index 4f88747f65ba3..0bce64c31085a 100644 --- a/test/code_size/hello_webgl_wasm2js.json +++ b/test/code_size/hello_webgl_wasm2js.json @@ -1,10 +1,10 @@ { "a.html": 567, "a.html.gz": 379, - "a.js": 17681, - "a.js.gz": 7887, + "a.js": 17673, + "a.js.gz": 7885, "a.mem": 3171, "a.mem.gz": 2714, - "total": 21419, - "total_gz": 10980 + "total": 21411, + "total_gz": 10978 } diff --git a/test/code_size/hello_world_wasm.js b/test/code_size/hello_world_wasm.js index 1621dc2eecb62..39c7f8ea8fdd0 100644 --- a/test/code_size/hello_world_wasm.js +++ b/test/code_size/hello_world_wasm.js @@ -1,12 +1,12 @@ -var d = Module, e = new TextDecoder("utf8"), f, g, h; +var d = Module, e, f, g = new TextDecoder("utf8"), h; WebAssembly.instantiate(d.wasm, { a: { a: function(a) { var c = console, k = c.log; if (a) { - for (var l = a + void 0, b = a; !(b >= l) && f[b]; ) ++b; - a = e.decode(f.subarray(a, b)); + for (var l = a + void 0, b = a; !(b >= l) && e[b]; ) ++b; + a = g.decode(e.subarray(a, b)); } else a = ""; k.call(c, a); } @@ -14,8 +14,8 @@ WebAssembly.instantiate(d.wasm, { }).then((function(a) { a = a.instance.exports; h = a.d; - g = a.b; - f = new Uint8Array(g.buffer); + f = a.b; + e = new Uint8Array(f.buffer); a.c(); h(); })); \ No newline at end of file diff --git a/test/code_size/hello_world_wasm2js.js b/test/code_size/hello_world_wasm2js.js index a0f42eb284ab8..abf10cbbb704e 100644 --- a/test/code_size/hello_world_wasm2js.js +++ b/test/code_size/hello_world_wasm2js.js @@ -1,9 +1,9 @@ -var b = Module, d = new TextDecoder("utf8"), k = new function(a) { +var b = Module, g = new function(a) { this.buffer = new ArrayBuffer(65536 * a.initial); }({ initial: 256, maximum: 256 -}), l = k.buffer, g = new Uint8Array(l), m; +}), k = g.buffer, d = new Uint8Array(k), l = new TextDecoder("utf8"), m; function c(a) { this.exports = function(h) { @@ -43,17 +43,17 @@ function c(a) { a: function(a) { var h = console, n = h.log; if (a) { - for (var f = a + void 0, e = a; !(e >= f) && g[e]; ) ++e; - a = d.decode(g.subarray(a, e)); + for (var f = a + void 0, e = a; !(e >= f) && d[e]; ) ++e; + a = l.decode(d.subarray(a, e)); } else a = ""; n.call(h, a); }, - memory: k + memory: g } }).then((function(a) { a = a.instance.exports; m = a.c; - g.set(new Uint8Array(b.mem), 1024); + d.set(new Uint8Array(b.mem), 1024); a.b(); m(); })); \ No newline at end of file diff --git a/test/code_size/hello_world_wasm2js.json b/test/code_size/hello_world_wasm2js.json index 1c5bd3408e704..a3f3cbd9c3e90 100644 --- a/test/code_size/hello_world_wasm2js.json +++ b/test/code_size/hello_world_wasm2js.json @@ -2,9 +2,9 @@ "a.html": 671, "a.html.gz": 430, "a.js": 710, - "a.js.gz": 435, + "a.js.gz": 433, "a.mem": 6, "a.mem.gz": 32, "total": 1387, - "total_gz": 897 + "total_gz": 895 } diff --git a/test/code_size/random_printf_wasm.json b/test/code_size/random_printf_wasm.json index a01587ec0fdd8..61d36dd843d9f 100644 --- a/test/code_size/random_printf_wasm.json +++ b/test/code_size/random_printf_wasm.json @@ -1,6 +1,6 @@ { "a.html": 12778, - "a.html.gz": 6977, + "a.html.gz": 6975, "total": 12778, - "total_gz": 6977 + "total_gz": 6975 } diff --git a/test/code_size/random_printf_wasm2js.json b/test/code_size/random_printf_wasm2js.json index 940cac873a931..583d6d5870767 100644 --- a/test/code_size/random_printf_wasm2js.json +++ b/test/code_size/random_printf_wasm2js.json @@ -1,6 +1,6 @@ { "a.html": 17390, - "a.html.gz": 7551, + "a.html.gz": 7550, "total": 17390, - "total_gz": 7551 + "total_gz": 7550 } diff --git a/test/core/test_em_js.cpp b/test/core/test_em_js.cpp index ece7bc96c8ad3..1d50e6e55f97e 100644 --- a/test/core/test_em_js.cpp +++ b/test/core/test_em_js.cpp @@ -63,6 +63,8 @@ EM_JS(int, user_comma, (void), { return x[y][1]; }); +EM_JS_DEPS(deps, "$stringToUTF8,$lengthBytesUTF8"); + EM_JS(char*, return_utf8_str, (void), { var jsString = 'こんにちは'; var lengthBytes = lengthBytesUTF8(jsString)+1; diff --git a/test/other/metadce/test_metadce_cxx_ctors1.jssize b/test/other/metadce/test_metadce_cxx_ctors1.jssize index 11aaae0dc022f..e0d406ae03b87 100644 --- a/test/other/metadce/test_metadce_cxx_ctors1.jssize +++ b/test/other/metadce/test_metadce_cxx_ctors1.jssize @@ -1 +1 @@ -26183 +26178 diff --git a/test/other/metadce/test_metadce_cxx_ctors2.jssize b/test/other/metadce/test_metadce_cxx_ctors2.jssize index c87d967550f6a..56f822ab463b2 100644 --- a/test/other/metadce/test_metadce_cxx_ctors2.jssize +++ b/test/other/metadce/test_metadce_cxx_ctors2.jssize @@ -1 +1 @@ -26147 +26142 diff --git a/test/other/metadce/test_metadce_cxx_except.jssize b/test/other/metadce/test_metadce_cxx_except.jssize index f11164ae1afba..b96e97707e21e 100644 --- a/test/other/metadce/test_metadce_cxx_except.jssize +++ b/test/other/metadce/test_metadce_cxx_except.jssize @@ -1 +1 @@ -30720 +30715 diff --git a/test/other/metadce/test_metadce_cxx_except_wasm.jssize b/test/other/metadce/test_metadce_cxx_except_wasm.jssize index 79ad1614ad48f..d62e0edd7d545 100644 --- a/test/other/metadce/test_metadce_cxx_except_wasm.jssize +++ b/test/other/metadce/test_metadce_cxx_except_wasm.jssize @@ -1 +1 @@ -25862 +25857 diff --git a/test/other/metadce/test_metadce_cxx_noexcept.jssize b/test/other/metadce/test_metadce_cxx_noexcept.jssize index 11aaae0dc022f..e0d406ae03b87 100644 --- a/test/other/metadce/test_metadce_cxx_noexcept.jssize +++ b/test/other/metadce/test_metadce_cxx_noexcept.jssize @@ -1 +1 @@ -26183 +26178 diff --git a/test/other/metadce/test_metadce_hello_O0.jssize b/test/other/metadce/test_metadce_hello_O0.jssize index 198c1f4e0790b..62b8d754e9866 100644 --- a/test/other/metadce/test_metadce_hello_O0.jssize +++ b/test/other/metadce/test_metadce_hello_O0.jssize @@ -1 +1 @@ -23990 +24002 diff --git a/test/other/metadce/test_metadce_hello_dylink.jssize b/test/other/metadce/test_metadce_hello_dylink.jssize index 2ef6bbb56d062..e8f92ab1737aa 100644 --- a/test/other/metadce/test_metadce_hello_dylink.jssize +++ b/test/other/metadce/test_metadce_hello_dylink.jssize @@ -1 +1 @@ -27922 +27921 diff --git a/test/other/metadce/test_metadce_libcxxabi_message_O3.jssize b/test/other/metadce/test_metadce_libcxxabi_message_O3.jssize index e96a113a815ce..95494025b416c 100644 --- a/test/other/metadce/test_metadce_libcxxabi_message_O3.jssize +++ b/test/other/metadce/test_metadce_libcxxabi_message_O3.jssize @@ -1 +1 @@ -5170 +5166 diff --git a/test/other/metadce/test_metadce_libcxxabi_message_O3_standalone.jssize b/test/other/metadce/test_metadce_libcxxabi_message_O3_standalone.jssize index b399a63028457..2874bd57eeefd 100644 --- a/test/other/metadce/test_metadce_libcxxabi_message_O3_standalone.jssize +++ b/test/other/metadce/test_metadce_libcxxabi_message_O3_standalone.jssize @@ -1 +1 @@ -5238 +5234 diff --git a/test/other/metadce/test_metadce_mem_O3.jssize b/test/other/metadce/test_metadce_mem_O3.jssize index 1f10f1976c57e..a49b0bdb8b0d5 100644 --- a/test/other/metadce/test_metadce_mem_O3.jssize +++ b/test/other/metadce/test_metadce_mem_O3.jssize @@ -1 +1 @@ -6092 +6088 diff --git a/test/other/metadce/test_metadce_mem_O3_grow.jssize b/test/other/metadce/test_metadce_mem_O3_grow.jssize index 7b44e6c407b80..0a85a000114a0 100644 --- a/test/other/metadce/test_metadce_mem_O3_grow.jssize +++ b/test/other/metadce/test_metadce_mem_O3_grow.jssize @@ -1 +1 @@ -6429 +6425 diff --git a/test/other/metadce/test_metadce_mem_O3_grow_standalone.jssize b/test/other/metadce/test_metadce_mem_O3_grow_standalone.jssize index c9a4db7eba921..a734b82fb60ea 100644 --- a/test/other/metadce/test_metadce_mem_O3_grow_standalone.jssize +++ b/test/other/metadce/test_metadce_mem_O3_grow_standalone.jssize @@ -1 +1 @@ -5818 +5815 diff --git a/test/other/metadce/test_metadce_mem_O3_standalone.jssize b/test/other/metadce/test_metadce_mem_O3_standalone.jssize index bac191e478119..c689f62048150 100644 --- a/test/other/metadce/test_metadce_mem_O3_standalone.jssize +++ b/test/other/metadce/test_metadce_mem_O3_standalone.jssize @@ -1 +1 @@ -5741 +5737 diff --git a/test/other/metadce/test_metadce_mem_O3_standalone_lib.jssize b/test/other/metadce/test_metadce_mem_O3_standalone_lib.jssize index d57d96f601aca..7ac3c34e4749d 100644 --- a/test/other/metadce/test_metadce_mem_O3_standalone_lib.jssize +++ b/test/other/metadce/test_metadce_mem_O3_standalone_lib.jssize @@ -1 +1 @@ -5256 +5252 diff --git a/test/other/metadce/test_metadce_mem_O3_standalone_narg.jssize b/test/other/metadce/test_metadce_mem_O3_standalone_narg.jssize index b399a63028457..2874bd57eeefd 100644 --- a/test/other/metadce/test_metadce_mem_O3_standalone_narg.jssize +++ b/test/other/metadce/test_metadce_mem_O3_standalone_narg.jssize @@ -1 +1 @@ -5238 +5234 diff --git a/test/other/metadce/test_metadce_mem_O3_standalone_narg_flto.jssize b/test/other/metadce/test_metadce_mem_O3_standalone_narg_flto.jssize index b399a63028457..2874bd57eeefd 100644 --- a/test/other/metadce/test_metadce_mem_O3_standalone_narg_flto.jssize +++ b/test/other/metadce/test_metadce_mem_O3_standalone_narg_flto.jssize @@ -1 +1 @@ -5238 +5234 diff --git a/test/other/metadce/test_metadce_minimal_O0.jssize b/test/other/metadce/test_metadce_minimal_O0.jssize index fc4c8011f0552..ad846c4f1412f 100644 --- a/test/other/metadce/test_metadce_minimal_O0.jssize +++ b/test/other/metadce/test_metadce_minimal_O0.jssize @@ -1 +1 @@ -20298 +20248 diff --git a/test/other/metadce/test_metadce_minimal_O1.jssize b/test/other/metadce/test_metadce_minimal_O1.jssize index 5e91da113af69..d4c9c722de609 100644 --- a/test/other/metadce/test_metadce_minimal_O1.jssize +++ b/test/other/metadce/test_metadce_minimal_O1.jssize @@ -1 +1 @@ -4935 +4869 diff --git a/test/other/metadce/test_metadce_minimal_O2.jssize b/test/other/metadce/test_metadce_minimal_O2.jssize index e67b201f450e6..bb778e4e859fc 100644 --- a/test/other/metadce/test_metadce_minimal_O2.jssize +++ b/test/other/metadce/test_metadce_minimal_O2.jssize @@ -1 +1 @@ -3798 +3737 diff --git a/test/other/metadce/test_metadce_minimal_pthreads.jssize b/test/other/metadce/test_metadce_minimal_pthreads.jssize index 32f63fcc9dfdf..691c02c06b388 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.jssize +++ b/test/other/metadce/test_metadce_minimal_pthreads.jssize @@ -1 +1 @@ -15557 +15562 diff --git a/test/other/test_unoptimized_code_size.js.size b/test/other/test_unoptimized_code_size.js.size index c406ed12e1d78..5eaf22fbbe33c 100644 --- a/test/other/test_unoptimized_code_size.js.size +++ b/test/other/test_unoptimized_code_size.js.size @@ -1 +1 @@ -64444 +59608 diff --git a/test/other/test_unoptimized_code_size_no_asserts.js.size b/test/other/test_unoptimized_code_size_no_asserts.js.size index 5c9209553b59f..a1a4ad036cfb3 100644 --- a/test/other/test_unoptimized_code_size_no_asserts.js.size +++ b/test/other/test_unoptimized_code_size_no_asserts.js.size @@ -1 +1 @@ -37791 +33322 diff --git a/test/other/test_unoptimized_code_size_strict.js.size b/test/other/test_unoptimized_code_size_strict.js.size index 62df8c0b97d49..30bb88e98b13c 100644 --- a/test/other/test_unoptimized_code_size_strict.js.size +++ b/test/other/test_unoptimized_code_size_strict.js.size @@ -1 +1 @@ -63386 +58550 diff --git a/test/pthread/test_pthread_utf8_funcs.cpp b/test/pthread/test_pthread_utf8_funcs.cpp index ba596f37201c1..490a86e88abb3 100644 --- a/test/pthread/test_pthread_utf8_funcs.cpp +++ b/test/pthread/test_pthread_utf8_funcs.cpp @@ -13,6 +13,8 @@ char stringBuffer[1024]; #define TEST_STRING "something long so that it hits the TextDecoder path" +EM_JS_DEPS(deps, "$stringToUTF8"); + static void *thread1_start(void *arg) { EM_ASM({ var mystr = UTF8ToString($0); From 18e0fad3603135f68ca7e677a01387f4a8383bf1 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 31 Mar 2023 17:46:45 -0700 Subject: [PATCH 0091/1523] Auto-generate signatures for pthread-related functions. NFC (#19112) - Enable threading in tools/gen_sig_info.py - Ensure all thread-related JS functions are declared in header files - Prefix JS-only functions with `$` so that are not native accessible - Run `tools/gen_sig_info.py --remove` --- src/jsifier.js | 2 +- src/library.js | 8 ++++-- src/library_html5.js | 20 ++++++------- src/library_html5_webgl.js | 8 +++--- src/library_pthread.js | 31 ++++++++------------- src/library_sigs.js | 15 ++++++++++ system/lib/libc/dynlink.c | 15 ---------- system/lib/libc/emscripten_internal.h | 17 +++++++++++ system/lib/pthread/emscripten_thread_init.c | 2 -- system/lib/pthread/library_pthread.c | 4 +-- system/lib/pthread/pthread_create.c | 4 --- system/lib/pthread/pthread_kill.c | 2 -- system/lib/pthread/thread_mailbox.c | 7 ----- system/lib/pthread/thread_mailbox.h | 7 +++++ system/lib/pthread/threading_internal.h | 9 ++++-- tools/gen_sig_info.py | 18 ++++++++---- 16 files changed, 93 insertions(+), 76 deletions(-) diff --git a/src/jsifier.js b/src/jsifier.js index fa95d9e236e67..a966e7083cc05 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -168,7 +168,7 @@ function ${name}(${args}) { snippet = modifyFunction(snippet, (name, args, body) => ` function ${name}(${args}) { if (ENVIRONMENT_IS_PTHREAD) - return _emscripten_proxy_to_main_thread_js(${proxiedFunctionTable.length}, ${+sync}${args ? ', ' : ''}${args}); + return proxyToMainThread(${proxiedFunctionTable.length}, ${+sync}${args ? ', ' : ''}${args}); ${body} }\n`); } else if (WASM_WORKERS && ASSERTIONS) { diff --git a/src/library.js b/src/library.js index 96fff5fd75f29..df932af4e8a69 100644 --- a/src/library.js +++ b/src/library.js @@ -3001,7 +3001,11 @@ mergeInto(LibraryManager.library, { return runEmAsmFunction(code, sigPtr, argbuf); }, - $runMainThreadEmAsm__deps: ['$readEmAsmArgs'], + $runMainThreadEmAsm__deps: ['$readEmAsmArgs', +#if PTHREADS + '$proxyToMainThread' +#endif + ], $runMainThreadEmAsm: function(code, sigPtr, argbuf, sync) { var args = readEmAsmArgs(sigPtr, argbuf); #if PTHREADS @@ -3017,7 +3021,7 @@ mergeInto(LibraryManager.library, { // code paths as similar as possible on both sides.) // -1 - code is the encoding of a proxied EM_ASM, as a negative number // (positive numbers are non-EM_ASM calls). - return _emscripten_proxy_to_main_thread_js.apply(null, [-1 - code, sync].concat(args)); + return proxyToMainThread.apply(null, [-1 - code, sync].concat(args)); } #endif #if ASSERTIONS diff --git a/src/library_html5.js b/src/library_html5.js index 7ab09794a5595..9aa77eb98fb2b 100644 --- a/src/library_html5.js +++ b/src/library_html5.js @@ -2393,7 +2393,6 @@ var LibraryHTML5 = { return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, - _emscripten_set_offscreencanvas_size__sig: 'iiii', #if OFFSCREENCANVAS_SUPPORT _emscripten_set_offscreencanvas_size: 'emscripten_set_canvas_element_size', @@ -2479,8 +2478,8 @@ var LibraryHTML5 = { }, #if PTHREADS - emscripten_get_canvas_element_size_calling_thread__deps: ['$JSEvents', '$findCanvasEventTarget'], - emscripten_get_canvas_element_size_calling_thread: function(target, width, height) { + $getCanvasSizeCallingThread__deps: ['$JSEvents', '$findCanvasEventTarget'], + $getCanvasSizeCallingThread: function(target, width, height) { var canvas = findCanvasEventTarget(target); if (!canvas) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}}; @@ -2510,18 +2509,19 @@ var LibraryHTML5 = { return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, - emscripten_get_canvas_element_size_main_thread__proxy: 'sync', - emscripten_get_canvas_element_size_main_thread__sig: 'iiii', - emscripten_get_canvas_element_size_main_thread__deps: ['emscripten_get_canvas_element_size_calling_thread'], - emscripten_get_canvas_element_size_main_thread: function(target, width, height) { return _emscripten_get_canvas_element_size_calling_thread(target, width, height); }, + $getCanvasSizeMainThread__proxy: 'sync', + $getCanvasSizeMainThread__deps: ['$getCanvasSizeCallingThread'], + $getCanvasSizeMainThread: function(target, width, height) { + return getCanvasSizeCallingThread(target, width, height); + }, - emscripten_get_canvas_element_size__deps: ['$JSEvents', 'emscripten_get_canvas_element_size_calling_thread', 'emscripten_get_canvas_element_size_main_thread', '$findCanvasEventTarget'], + emscripten_get_canvas_element_size__deps: ['$JSEvents', '$getCanvasSizeCallingThread', '$getCanvasSizeMainThread', '$findCanvasEventTarget'], emscripten_get_canvas_element_size: function(target, width, height) { var canvas = findCanvasEventTarget(target); if (canvas) { - return _emscripten_get_canvas_element_size_calling_thread(target, width, height); + return getCanvasSizeCallingThread(target, width, height); } - return _emscripten_get_canvas_element_size_main_thread(target, width, height); + return getCanvasSizeMainThread(target, width, height); }, #else emscripten_get_canvas_element_size__deps: ['$JSEvents', '$findCanvasEventTarget'], diff --git a/src/library_html5_webgl.js b/src/library_html5_webgl.js index 8c36727abfc34..8921d24bbc6f9 100644 --- a/src/library_html5_webgl.js +++ b/src/library_html5_webgl.js @@ -321,8 +321,8 @@ var LibraryHtml5WebGL = { #if PTHREADS // Special function that will be invoked on the thread calling emscripten_webgl_destroy_context(), before routing // the call over to the target thread. - emscripten_webgl_destroy_context_before_on_calling_thread__deps: ['emscripten_webgl_get_current_context', 'emscripten_webgl_make_context_current'], - emscripten_webgl_destroy_context_before_on_calling_thread: function(contextHandle) { + $emscripten_webgl_destroy_context_before_on_calling_thread__deps: ['emscripten_webgl_get_current_context', 'emscripten_webgl_make_context_current'], + $emscripten_webgl_destroy_context_before_on_calling_thread: function(contextHandle) { if (_emscripten_webgl_get_current_context() == contextHandle) _emscripten_webgl_make_context_current(0); }, #endif @@ -592,8 +592,8 @@ function handleWebGLProxying(funcs) { var contextCheck = proxyContextHandle ? 'GL.contexts[p0]' : 'GLctx'; var funcBody = `${retStatement} ${contextCheck} ? _${i}_calling_thread(${funcArgsString}) : _${i}_main_thread(${funcArgsString});`; if (funcs[i + '_before_on_calling_thread']) { - funcs[i + '__deps'].push(i + '_before_on_calling_thread'); - funcBody = `_${i}_before_on_calling_thread(${funcArgsString}); ` + funcBody; + funcs[i + '__deps'].push('$' + i + '_before_on_calling_thread'); + funcBody = `${i}_before_on_calling_thread(${funcArgsString}); ` + funcBody; } funcArgs.push(funcBody); funcs[i] = new (Function.prototype.bind.apply(Function, [Function].concat(funcArgs))); diff --git a/src/library_pthread.js b/src/library_pthread.js index e36fede406edd..60b3320194622 100644 --- a/src/library_pthread.js +++ b/src/library_pthread.js @@ -562,7 +562,6 @@ var LibraryPThread = { worker.pthread_ptr = 0; }, - __emscripten_thread_cleanup__sig: 'vp', __emscripten_thread_cleanup: function(thread) { // Called when a thread needs to be cleaned up so it can be reused. // A thread is considered reusable when it either returns from its @@ -735,7 +734,6 @@ var LibraryPThread = { // allocations from __pthread_create_js we could also remove this. __pthread_create_js__noleakcheck: true, #endif - __pthread_create_js__sig: 'ipppp', __pthread_create_js__deps: ['$spawnThread', 'pthread_self', '$pthreadCreateProxied', #if OFFSCREENCANVAS_SUPPORT 'malloc', @@ -947,9 +945,9 @@ var LibraryPThread = { _exit(returnCode); }, - emscripten_proxy_to_main_thread_js__deps: ['$withStackSave', '_emscripten_run_in_main_runtime_thread_js'], - emscripten_proxy_to_main_thread_js__docs: '/** @type{function(number, (number|boolean), ...(number|boolean))} */', - emscripten_proxy_to_main_thread_js: function(index, sync) { + $proxyToMainThread__deps: ['$withStackSave', '_emscripten_run_in_main_runtime_thread_js'], + $proxyToMainThread__docs: '/** @type{function(number, (number|boolean), ...(number|boolean))} */', + $proxyToMainThread: function(index, sync) { // Additional arguments are passed after those two, which are the actual // function arguments. // The serialization buffer contains the number of call params, and then @@ -960,7 +958,7 @@ var LibraryPThread = { #if ASSERTIONS var maxArgs = {{{ cDefs.EM_QUEUED_JS_CALL_MAX_ARGS - 1 }}}; if (numCallArgs > maxArgs) { - throw 'emscripten_proxy_to_main_thread_js: Too many arguments ' + numCallArgs + ' to proxied function idx=' + index + ', maximum supported is ' + maxArgs; + throw 'proxyToMainThread: Too many arguments ' + numCallArgs + ' to proxied function idx=' + index + ', maximum supported is ' + maxArgs; } #endif // Allocate a buffer, which will be copied by the C code. @@ -994,29 +992,28 @@ var LibraryPThread = { }); }, - emscripten_receive_on_main_thread_js_callArgs: '=[]', + $emscripten_receive_on_main_thread_js_callArgs: '=[]', - emscripten_receive_on_main_thread_js__sig: 'diip', emscripten_receive_on_main_thread_js__deps: [ - 'emscripten_proxy_to_main_thread_js', - 'emscripten_receive_on_main_thread_js_callArgs'], + '$proxyToMainThread', + '$emscripten_receive_on_main_thread_js_callArgs'], emscripten_receive_on_main_thread_js: function(index, numCallArgs, args) { #if WASM_BIGINT numCallArgs /= 2; #endif - _emscripten_receive_on_main_thread_js_callArgs.length = numCallArgs; + emscripten_receive_on_main_thread_js_callArgs.length = numCallArgs; var b = args >> 3; for (var i = 0; i < numCallArgs; i++) { #if WASM_BIGINT if (HEAP64[b + 2*i]) { // It's a BigInt. - _emscripten_receive_on_main_thread_js_callArgs[i] = HEAP64[b + 2*i + 1]; + emscripten_receive_on_main_thread_js_callArgs[i] = HEAP64[b + 2*i + 1]; } else { // It's a Number. - _emscripten_receive_on_main_thread_js_callArgs[i] = HEAPF64[b + 2*i + 1]; + emscripten_receive_on_main_thread_js_callArgs[i] = HEAPF64[b + 2*i + 1]; } #else - _emscripten_receive_on_main_thread_js_callArgs[i] = HEAPF64[b + i]; + emscripten_receive_on_main_thread_js_callArgs[i] = HEAPF64[b + i]; #endif } // Proxied JS library funcs are encoded as positive values, and @@ -1030,7 +1027,7 @@ var LibraryPThread = { #if ASSERTIONS assert(func.length == numCallArgs, 'Call args mismatch in emscripten_receive_on_main_thread_js'); #endif - return func.apply(null, _emscripten_receive_on_main_thread_js_callArgs); + return func.apply(null, emscripten_receive_on_main_thread_js_callArgs); }, // TODO(sbc): Do we really need this to be dynamically settable from JS like this? @@ -1126,7 +1123,6 @@ var LibraryPThread = { }, #if MAIN_MODULE - _emscripten_thread_exit_joinable__sig: 'vp', _emscripten_thread_exit_joinable: function(thread) { // Called when a thread exits and is joinable. We mark these threads // as finished, which means that are in state where are no longer actually @@ -1152,7 +1148,6 @@ var LibraryPThread = { // TODO(sbc): Should we make a new form of __proxy attribute for JS library // function that run asynchronously like but blocks the caller until they are // done. Perhaps "sync_with_ctx"? - _emscripten_dlsync_threads_async__sig: 'vppp', _emscripten_dlsync_threads_async__deps: ['_emscripten_proxy_dlsync_async', 'emscripten_promise_create', '$getPromise'], _emscripten_dlsync_threads_async: function(caller, callback, ctx) { #if PTHREADS_DEBUG @@ -1234,7 +1229,6 @@ var LibraryPThread = { }, _emscripten_thread_mailbox_await__deps: ['$checkMailbox'], - _emscripten_thread_mailbox_await__sig: 'vp', _emscripten_thread_mailbox_await: function(pthread_ptr) { if (typeof Atomics.waitAsync === 'function') { // TODO: How to make this work with wasm64? @@ -1249,7 +1243,6 @@ var LibraryPThread = { }, _emscripten_notify_mailbox_postmessage__deps: ['$checkMailbox'], - _emscripten_notify_mailbox_postmessage__sig: 'vppp', _emscripten_notify_mailbox_postmessage: function(targetThreadId, currThreadId, mainThreadId) { diff --git a/src/library_sigs.js b/src/library_sigs.js index 3f5bb3b3e7428..3308b2a84cd14 100644 --- a/src/library_sigs.js +++ b/src/library_sigs.js @@ -212,7 +212,11 @@ sigs = { __assert_fail__sig: 'vppip', __call_sighandler__sig: 'vpi', __dlsym__sig: 'pppp', + __emscripten_init_main_thread_js__sig: 'vp', + __emscripten_thread_cleanup__sig: 'vp', __handle_stack_overflow__sig: 'vp', + __pthread_create_js__sig: 'ipppp', + __pthread_kill_js__sig: 'ipi', __syscall__newselect__sig: 'iipppp', __syscall_accept4__sig: 'iippiii', __syscall_bind__sig: 'iippiii', @@ -269,7 +273,10 @@ sigs = { _dlsym_catchup_js__sig: 'ppi', _dlsym_js__sig: 'pppp', _emscripten_dbg__sig: 'vp', + _emscripten_default_pthread_stack_size__sig: 'i', _emscripten_dlopen_js__sig: 'vpppp', + _emscripten_dlsync_threads__sig: 'v', + _emscripten_dlsync_threads_async__sig: 'vppp', _emscripten_err__sig: 'vp', _emscripten_fetch_free__sig: 'vi', _emscripten_fetch_get_response_headers__sig: 'pipp', @@ -277,9 +284,13 @@ sigs = { _emscripten_fs_load_embedded_files__sig: 'vp', _emscripten_get_now_is_monotonic__sig: 'i', _emscripten_get_progname__sig: 'vpi', + _emscripten_notify_mailbox_postmessage__sig: 'vppp', _emscripten_out__sig: 'vp', _emscripten_push_main_loop_blocker__sig: 'vppp', _emscripten_push_uncounted_main_loop_blocker__sig: 'vppp', + _emscripten_set_offscreencanvas_size__sig: 'ipii', + _emscripten_thread_exit_joinable__sig: 'vp', + _emscripten_thread_mailbox_await__sig: 'vp', _emscripten_throw_longjmp__sig: 'v', _gmtime_js__sig: 'vpp', _localtime_js__sig: 'vpp', @@ -419,6 +430,7 @@ sigs = { emscripten_call_worker__sig: 'vippipp', emscripten_cancel_animation_frame__sig: 'vi', emscripten_cancel_main_loop__sig: 'v', + emscripten_check_blocking_allowed__sig: 'v', emscripten_clear_immediate__sig: 'vi', emscripten_clear_interval__sig: 'vi', emscripten_clear_timeout__sig: 'vi', @@ -470,6 +482,7 @@ sigs = { emscripten_get_window_title__sig: 'p', emscripten_get_worker_queue_size__sig: 'ii', emscripten_has_asyncify__sig: 'i', + emscripten_has_threading_support__sig: 'i', emscripten_hide_mouse__sig: 'v', emscripten_html5_remove_all_event_listeners__sig: 'v', emscripten_idb_async_delete__sig: 'vppppp', @@ -512,6 +525,7 @@ sigs = { emscripten_math_tanh__sig: 'dd', emscripten_memcpy_big__sig: 'vppp', emscripten_notify_memory_growth__sig: 'vp', + emscripten_num_logical_cores__sig: 'i', emscripten_pause_main_loop__sig: 'v', emscripten_pc_get_column__sig: 'ip', emscripten_pc_get_file__sig: 'pp', @@ -525,6 +539,7 @@ sigs = { emscripten_promise_resolve__sig: 'vpip', emscripten_promise_then__sig: 'ppppp', emscripten_random__sig: 'f', + emscripten_receive_on_main_thread_js__sig: 'diip', emscripten_request_animation_frame__sig: 'ipp', emscripten_request_animation_frame_loop__sig: 'vpp', emscripten_request_fullscreen__sig: 'ipi', diff --git a/system/lib/libc/dynlink.c b/system/lib/libc/dynlink.c index 939aa8707942f..a5c19d977b738 100644 --- a/system/lib/libc/dynlink.c +++ b/system/lib/libc/dynlink.c @@ -179,21 +179,6 @@ static struct dso* load_library_start(const char* name, int flags) { // the module. #define ABORT_ON_SYNC_FAILURE 1 -// These functions are defined in JS. - -// Synchronous version of "dlsync_threads". Called only on the main thread. -// Runs _emscripten_dlsync_self on each of the threads that are running at -// the time of the call. -void _emscripten_dlsync_threads(); - -// Asynchronous version of "dlsync_threads". Called only on the main thread. -// Runs _emscripten_dlsync_self on each of the threads that are running at -// the time of the call. Once this is done the callback is called with the -// given em_proxying_ctx. -void _emscripten_dlsync_threads_async(pthread_t calling_thread, - void (*callback)(em_proxying_ctx*), - em_proxying_ctx* ctx); - static void dlsync_next(struct dlevent* dlevent, em_promise_t promise); static void sync_one_onsuccess(struct dso* dso, void* user_data) { diff --git a/system/lib/libc/emscripten_internal.h b/system/lib/libc/emscripten_internal.h index 811934040fdbf..92dbe29e43e75 100644 --- a/system/lib/libc/emscripten_internal.h +++ b/system/lib/libc/emscripten_internal.h @@ -12,6 +12,8 @@ */ #include +#include +#include #include // for `sighandler_t` #include // for `bool` @@ -93,6 +95,19 @@ void* _dlsym_catchup_js(struct dso* handle, int sym_index); int _setitimer_js(int which, double timeout); +// Synchronous version of "dlsync_threads". Called only on the main thread. +// Runs _emscripten_dlsync_self on each of the threads that are running at +// the time of the call. +void _emscripten_dlsync_threads(); + +// Asynchronous version of "dlsync_threads". Called only on the main thread. +// Runs _emscripten_dlsync_self on each of the threads that are running at +// the time of the call. Once this is done the callback is called with the +// given em_proxying_ctx. +void _emscripten_dlsync_threads_async(pthread_t calling_thread, + void (*callback)(em_proxying_ctx*), + em_proxying_ctx* ctx); + #ifdef _GNU_SOURCE void __call_sighandler(sighandler_t handler, int sig); #endif @@ -114,6 +129,8 @@ size_t _emscripten_fetch_get_response_headers_length(int32_t fetchID); size_t _emscripten_fetch_get_response_headers(int32_t fetchID, char *dst, size_t dstSizeBytes); void _emscripten_fetch_free(unsigned int); +EMSCRIPTEN_RESULT _emscripten_set_offscreencanvas_size(const char *target, int width, int height); + #ifdef __cplusplus } #endif diff --git a/system/lib/pthread/emscripten_thread_init.c b/system/lib/pthread/emscripten_thread_init.c index a4faf60d1e759..1c9933ba18cc9 100644 --- a/system/lib/pthread/emscripten_thread_init.c +++ b/system/lib/pthread/emscripten_thread_init.c @@ -8,8 +8,6 @@ #include "emscripten/threading.h" #include "threading_internal.h" -void __set_thread_state(pthread_t ptr, int is_main, int is_runtime, int can_block); - void _emscripten_thread_init(pthread_t ptr, int is_main, int is_runtime, diff --git a/system/lib/pthread/library_pthread.c b/system/lib/pthread/library_pthread.c index 02c52981f297e..3b9e1ed3b6846 100644 --- a/system/lib/pthread/library_pthread.c +++ b/system/lib/pthread/library_pthread.c @@ -36,6 +36,7 @@ #include #include "threading_internal.h" +#include "emscripten_internal.h" int emscripten_pthread_attr_gettransferredcanvases(const pthread_attr_t* a, const char** str) { *str = a->_a_transferredcanvases; @@ -176,9 +177,6 @@ void emscripten_async_waitable_close(em_queued_call* call) { em_queued_call_free(call); } -extern EMSCRIPTEN_RESULT _emscripten_set_offscreencanvas_size(const char *target, int width, int height); -extern double emscripten_receive_on_main_thread_js(int functionIndex, int numCallArgs, double* args); - static void _do_call(void* arg) { em_queued_call* q = (em_queued_call*)arg; // C function pointer diff --git a/system/lib/pthread/pthread_create.c b/system/lib/pthread/pthread_create.c index d434a8e98d2ec..d92d82cfc6f51 100644 --- a/system/lib/pthread/pthread_create.c +++ b/system/lib/pthread/pthread_create.c @@ -30,10 +30,6 @@ // See musl's pthread_create.c -int __pthread_create_js(struct pthread *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); -int _emscripten_default_pthread_stack_size(); -void __set_thread_state(pthread_t ptr, int is_main, int is_runtime, int can_block); - static void dummy_0() {} weak_alias(dummy_0, __pthread_tsd_run_dtors); diff --git a/system/lib/pthread/pthread_kill.c b/system/lib/pthread/pthread_kill.c index d1e4b0710e7a9..c068df51fe9b7 100644 --- a/system/lib/pthread/pthread_kill.c +++ b/system/lib/pthread/pthread_kill.c @@ -10,8 +10,6 @@ #include "pthread_impl.h" #include "lock.h" -int __pthread_kill_js(pthread_t t, int sig); - int pthread_kill(pthread_t t, int sig) { if (sig < 0 || sig >= _NSIG) { return EINVAL; diff --git a/system/lib/pthread/thread_mailbox.c b/system/lib/pthread/thread_mailbox.c index 9ac10a5f4074d..2ed156c27fe28 100644 --- a/system/lib/pthread/thread_mailbox.c +++ b/system/lib/pthread/thread_mailbox.c @@ -90,13 +90,6 @@ void _emscripten_check_mailbox() { &mailbox->notification, &expected, NOTIFICATION_NONE); } -// Send a postMessage notification telling the target thread to check its -// mailbox when it returns to its event loop. Pass in the current thread and -// main thread ids to minimize calls back into Wasm. -void _emscripten_notify_mailbox_postmessage(pthread_t target_thread, - pthread_t curr_thread, - pthread_t main_thread); - void emscripten_thread_mailbox_send(pthread_t thread, task t) { assert(thread->mailbox_refcount > 0); diff --git a/system/lib/pthread/thread_mailbox.h b/system/lib/pthread/thread_mailbox.h index 6747a489f99cb..92dab128cbf72 100644 --- a/system/lib/pthread/thread_mailbox.h +++ b/system/lib/pthread/thread_mailbox.h @@ -32,3 +32,10 @@ void _emscripten_thread_mailbox_await(pthread_t thread); // Close the mailbox and cancel any pending messages. void _emscripten_thread_mailbox_shutdown(pthread_t thread); + +// Send a postMessage notification telling the target thread to check its +// mailbox when it returns to its event loop. Pass in the current thread and +// main thread ids to minimize calls back into Wasm. +void _emscripten_notify_mailbox_postmessage(pthread_t target_thread, + pthread_t curr_thread, + pthread_t main_thread); diff --git a/system/lib/pthread/threading_internal.h b/system/lib/pthread/threading_internal.h index 3cf88e988d26c..fc5ab4bf947ca 100644 --- a/system/lib/pthread/threading_internal.h +++ b/system/lib/pthread/threading_internal.h @@ -124,10 +124,8 @@ hidden void _emscripten_tls_free(void); // we can pass more of the posixtest suite that vanilla musl. int _emscripten_thread_is_valid(pthread_t thread); -#ifdef __PIC__ void _emscripten_thread_exit_joinable(pthread_t thread); void _emscripten_process_dlopen_queue(void); -#endif #ifdef NDEBUG #define emscripten_set_current_thread_status(newStatus) @@ -150,3 +148,10 @@ void emscripten_set_current_thread_status(EM_THREAD_STATUS newStatus); // this is a no-op. void emscripten_conditional_set_current_thread_status(EM_THREAD_STATUS expectedStatus, EM_THREAD_STATUS newStatus); #endif + +int __pthread_kill_js(pthread_t t, int sig); +int __pthread_create_js(struct __pthread *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); +int _emscripten_default_pthread_stack_size(); +void __set_thread_state(pthread_t ptr, int is_main, int is_runtime, int can_block); + +double emscripten_receive_on_main_thread_js(int functionIndex, int numCallArgs, double* args); diff --git a/tools/gen_sig_info.py b/tools/gen_sig_info.py index 7ec20218e190c..172ffc7d3f48b 100755 --- a/tools/gen_sig_info.py +++ b/tools/gen_sig_info.py @@ -39,11 +39,15 @@ #include #include #include +#include +#include #include // Internal emscripten headers #include "emscripten_internal.h" +#include "threading_internal.h" #include "webgl_internal.h" +#include "thread_mailbox.h" // Internal musl headers #include "musl/include/assert.h" @@ -206,9 +210,10 @@ def strip_line(l): files = glob.glob('src/*.js') + glob.glob('src/**/*.js') for file in files: - lines = utils.read_file(file).splitlines() - lines = [l for l in lines if not strip_line(l)] - utils.write_file(file, '\n'.join(lines) + '\n') + if os.path.basename(file) != 'library_sigs.js': + lines = utils.read_file(file).splitlines() + lines = [l for l in lines if not strip_line(l)] + utils.write_file(file, '\n'.join(lines) + '\n') def extract_sigs(symbols, obj_file): @@ -225,12 +230,13 @@ def extract_sigs(symbols, obj_file): def extract_sig_info(sig_info, extra_settings=None, extra_cflags=None): tempfiles = shared.get_temp_files() settings = { - 'USE_PTHREADS': 1, 'STACK_OVERFLOW_CHECK': 1, 'MAX_WEBGL_VERSION': 2, 'FULL_ES3': 1, 'USE_SDL': 1, 'FETCH': 1, + 'PTHREADS': 1, + 'SHARED_MEMORY': 1, # Currently GLFW symbols have different sigs for the same symbol because the # signatures changed between v2 and v3, so for now we continue to maintain # them by hand. @@ -238,7 +244,8 @@ def extract_sig_info(sig_info, extra_settings=None, extra_cflags=None): 'JS_LIBRARIES': [ 'src/library_websocket.js', 'src/library_webaudio.js', - 'src/library_fetch.js' + 'src/library_fetch.js', + 'src/library_pthread.js', ], 'SUPPORT_LONGJMP': 'emscripten' } @@ -263,6 +270,7 @@ def extract_sig_info(sig_info, extra_settings=None, extra_cflags=None): '-Wno-deprecated-declarations', '-o', obj_file, '-I' + utils.path_from_root('system/lib/libc'), + '-I' + utils.path_from_root('system/lib/pthread'), '-I' + utils.path_from_root('system/lib/libc/musl/src/include'), '-I' + utils.path_from_root('system/lib/libc/musl/src/internal'), '-I' + utils.path_from_root('system/lib/gl'), From 574034b61200d2d3d76c46f63eddd0b0671a5667 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Sat, 1 Apr 2023 14:24:02 -0700 Subject: [PATCH 0092/1523] Implement some more of the wasi API (#12704) In order to test our WASI API implementation I've added `wasi-test-suite` as submodule. This submodule is only needed for testing. --- .gitmodules | 3 + emcc.py | 14 ++- emscripten.py | 3 +- src/generated_struct_info32.json | 61 ++++++++++- src/generated_struct_info64.json | 61 ++++++++++- src/library_sigs.js | 2 + src/library_syscall.js | 14 ++- src/library_wasi.js | 169 ++++++++++++++++++++++++++++--- src/shell.js | 2 +- src/struct_info.json | 58 ++++++++++- test/test_other.py | 79 +++++++++++++++ test/third_party/wasi-test-suite | 1 + tools/building.py | 1 + tools/gen_sig_info.py | 1 + 14 files changed, 445 insertions(+), 24 deletions(-) create mode 160000 test/third_party/wasi-test-suite diff --git a/.gitmodules b/.gitmodules index 391eaedc48e05..896f670b3caad 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "test/third_party/googletest"] path = test/third_party/googletest url = https://github.com/google/googletest +[submodule "test/third_party/wasi-test-suite"] + path = test/third_party/wasi-test-suite + url = https://github.com/khronosproject/wasi-test-suite diff --git a/emcc.py b/emcc.py index ac1091db62a3f..17c869565cbd6 100755 --- a/emcc.py +++ b/emcc.py @@ -1137,7 +1137,7 @@ def package_files(options, target): if options.preload_files: # Preloading files uses --pre-js code that runs before the module is loaded. file_code = shared.check_call(cmd, stdout=PIPE).stdout - js_manipulation.add_files_pre_js(options.pre_js, file_code) + js_manipulation.add_files_pre_js(settings.PRE_JS_FILES, file_code) else: # Otherwise, we are embedding files, which does not require --pre-js code, # and instead relies on a static constrcutor to populate the filesystem. @@ -1311,9 +1311,6 @@ def run(args): if len(options.preload_files) or len(options.embed_files): linker_arguments += package_files(options, target) - settings.PRE_JS_FILES = [os.path.abspath(f) for f in options.pre_js] - settings.POST_JS_FILES = [os.path.abspath(f) for f in options.post_js] - if options.oformat == OFormat.OBJECT: logger.debug(f'link_to_object: {linker_arguments} -> {target}') building.link_to_object(linker_arguments, target) @@ -1891,7 +1888,7 @@ def phase_linker_setup(options, state, newargs): # Requesting both Wasm and Wasm2JS support settings.WASM2JS = 1 - if (options.oformat == OFormat.WASM or settings.PURE_WASI) and not settings.SIDE_MODULE: + if options.oformat == OFormat.WASM and not settings.SIDE_MODULE: # if the output is just a wasm file, it will normally be a standalone one, # as there is no JS. an exception are side modules, as we can't tell at # compile time whether JS will be involved or not - the main module may @@ -1902,6 +1899,10 @@ def phase_linker_setup(options, state, newargs): if settings.LZ4: settings.EXPORTED_RUNTIME_METHODS += ['LZ4'] + if settings.PURE_WASI: + settings.STANDALONE_WASM = 1 + settings.WASM_BIGINT = 1 + if settings.WASM2C: # wasm2c only makes sense with standalone wasm - there will be no JS, # just wasm and then C @@ -2906,6 +2907,9 @@ def get_full_import_name(name): # in standalone mode, crt1 will call the constructors from inside the wasm settings.REQUIRED_EXPORTS.append('__wasm_call_ctors') + settings.PRE_JS_FILES = [os.path.abspath(f) for f in options.pre_js] + settings.POST_JS_FILES = [os.path.abspath(f) for f in options.post_js] + return target, wasm_target diff --git a/emscripten.py b/emscripten.py index d4109061e77f0..691da8e591c70 100644 --- a/emscripten.py +++ b/emscripten.py @@ -77,8 +77,9 @@ def optimize_syscalls(declares): # without filesystem support, it doesn't matter what syscalls need settings.SYSCALLS_REQUIRE_FILESYSTEM = 0 else: + # TODO(sbc): Find a better way to identify wasi syscalls syscall_prefixes = ('__syscall_', 'fd_') - syscalls = {d for d in declares if d.startswith(syscall_prefixes)} + syscalls = {d for d in declares if d.startswith(syscall_prefixes) or d in ['path_open']} # check if the only filesystem syscalls are in: close, ioctl, llseek, write # (without open, etc.. nothing substantial can be done, so we can disable # extra filesystem support in that case) diff --git a/src/generated_struct_info32.json b/src/generated_struct_info32.json index a2dbe9c3ee50d..96aedcd63bd59 100644 --- a/src/generated_struct_info32.json +++ b/src/generated_struct_info32.json @@ -394,10 +394,49 @@ "__WASI_CLOCKID_PROCESS_CPUTIME_ID": 2, "__WASI_CLOCKID_REALTIME": 0, "__WASI_CLOCKID_THREAD_CPUTIME_ID": 3, + "__WASI_FDFLAGS_APPEND": 1, + "__WASI_FDFLAGS_DSYNC": 2, + "__WASI_FDFLAGS_NONBLOCK": 4, + "__WASI_FDFLAGS_RSYNC": 8, + "__WASI_FDFLAGS_SYNC": 16, "__WASI_FILETYPE_CHARACTER_DEVICE": 2, "__WASI_FILETYPE_DIRECTORY": 3, "__WASI_FILETYPE_REGULAR_FILE": 4, - "__WASI_FILETYPE_SYMBOLIC_LINK": 7 + "__WASI_FILETYPE_SYMBOLIC_LINK": 7, + "__WASI_OFLAGS_CREAT": 1, + "__WASI_OFLAGS_DIRECTORY": 2, + "__WASI_OFLAGS_EXCL": 4, + "__WASI_OFLAGS_TRUNC": 8, + "__WASI_PREOPENTYPE_DIR": 0, + "__WASI_RIGHTS_FD_ADVISE": 128, + "__WASI_RIGHTS_FD_ALLOCATE": 256, + "__WASI_RIGHTS_FD_DATASYNC": 1, + "__WASI_RIGHTS_FD_FDSTAT_SET_FLAGS": 8, + "__WASI_RIGHTS_FD_FILESTAT_GET": 2097152, + "__WASI_RIGHTS_FD_FILESTAT_SET_SIZE": 4194304, + "__WASI_RIGHTS_FD_FILESTAT_SET_TIMES": 8388608, + "__WASI_RIGHTS_FD_READ": 2, + "__WASI_RIGHTS_FD_READDIR": 16384, + "__WASI_RIGHTS_FD_SEEK": 4, + "__WASI_RIGHTS_FD_SYNC": 16, + "__WASI_RIGHTS_FD_TELL": 32, + "__WASI_RIGHTS_FD_WRITE": 64, + "__WASI_RIGHTS_PATH_CREATE_DIRECTORY": 512, + "__WASI_RIGHTS_PATH_CREATE_FILE": 1024, + "__WASI_RIGHTS_PATH_FILESTAT_GET": 262144, + "__WASI_RIGHTS_PATH_FILESTAT_SET_SIZE": 524288, + "__WASI_RIGHTS_PATH_FILESTAT_SET_TIMES": 1048576, + "__WASI_RIGHTS_PATH_LINK_SOURCE": 2048, + "__WASI_RIGHTS_PATH_LINK_TARGET": 4096, + "__WASI_RIGHTS_PATH_OPEN": 8192, + "__WASI_RIGHTS_PATH_READLINK": 32768, + "__WASI_RIGHTS_PATH_REMOVE_DIRECTORY": 33554432, + "__WASI_RIGHTS_PATH_RENAME_SOURCE": 65536, + "__WASI_RIGHTS_PATH_RENAME_TARGET": 131072, + "__WASI_RIGHTS_PATH_SYMLINK": 16777216, + "__WASI_RIGHTS_PATH_UNLINK_FILE": 67108864, + "__WASI_RIGHTS_POLL_FD_READWRITE": 134217728, + "__WASI_RIGHTS_SOCK_SHUTDOWN": 268435456 }, "structs": { "EmscriptenBatteryEvent": { @@ -1236,6 +1275,26 @@ "fs_rights_base": 8, "fs_rights_inheriting": 16 }, + "__wasi_filestat_t": { + "__size__": 64, + "atim": 40, + "ctim": 56, + "dev": 0, + "filetype": 16, + "ino": 8, + "mtim": 48, + "nlink": 24, + "size": 32 + }, + "__wasi_prestat_dir_t": { + "__size__": 4, + "pr_name_len": 0 + }, + "__wasi_prestat_t": { + "__size__": 8, + "pr_type": 0, + "u": 4 + }, "addrinfo": { "__size__": 32, "ai_addr": 20, diff --git a/src/generated_struct_info64.json b/src/generated_struct_info64.json index d2265582696af..5946eabc8ff11 100644 --- a/src/generated_struct_info64.json +++ b/src/generated_struct_info64.json @@ -394,10 +394,49 @@ "__WASI_CLOCKID_PROCESS_CPUTIME_ID": 2, "__WASI_CLOCKID_REALTIME": 0, "__WASI_CLOCKID_THREAD_CPUTIME_ID": 3, + "__WASI_FDFLAGS_APPEND": 1, + "__WASI_FDFLAGS_DSYNC": 2, + "__WASI_FDFLAGS_NONBLOCK": 4, + "__WASI_FDFLAGS_RSYNC": 8, + "__WASI_FDFLAGS_SYNC": 16, "__WASI_FILETYPE_CHARACTER_DEVICE": 2, "__WASI_FILETYPE_DIRECTORY": 3, "__WASI_FILETYPE_REGULAR_FILE": 4, - "__WASI_FILETYPE_SYMBOLIC_LINK": 7 + "__WASI_FILETYPE_SYMBOLIC_LINK": 7, + "__WASI_OFLAGS_CREAT": 1, + "__WASI_OFLAGS_DIRECTORY": 2, + "__WASI_OFLAGS_EXCL": 4, + "__WASI_OFLAGS_TRUNC": 8, + "__WASI_PREOPENTYPE_DIR": 0, + "__WASI_RIGHTS_FD_ADVISE": 128, + "__WASI_RIGHTS_FD_ALLOCATE": 256, + "__WASI_RIGHTS_FD_DATASYNC": 1, + "__WASI_RIGHTS_FD_FDSTAT_SET_FLAGS": 8, + "__WASI_RIGHTS_FD_FILESTAT_GET": 2097152, + "__WASI_RIGHTS_FD_FILESTAT_SET_SIZE": 4194304, + "__WASI_RIGHTS_FD_FILESTAT_SET_TIMES": 8388608, + "__WASI_RIGHTS_FD_READ": 2, + "__WASI_RIGHTS_FD_READDIR": 16384, + "__WASI_RIGHTS_FD_SEEK": 4, + "__WASI_RIGHTS_FD_SYNC": 16, + "__WASI_RIGHTS_FD_TELL": 32, + "__WASI_RIGHTS_FD_WRITE": 64, + "__WASI_RIGHTS_PATH_CREATE_DIRECTORY": 512, + "__WASI_RIGHTS_PATH_CREATE_FILE": 1024, + "__WASI_RIGHTS_PATH_FILESTAT_GET": 262144, + "__WASI_RIGHTS_PATH_FILESTAT_SET_SIZE": 524288, + "__WASI_RIGHTS_PATH_FILESTAT_SET_TIMES": 1048576, + "__WASI_RIGHTS_PATH_LINK_SOURCE": 2048, + "__WASI_RIGHTS_PATH_LINK_TARGET": 4096, + "__WASI_RIGHTS_PATH_OPEN": 8192, + "__WASI_RIGHTS_PATH_READLINK": 32768, + "__WASI_RIGHTS_PATH_REMOVE_DIRECTORY": 33554432, + "__WASI_RIGHTS_PATH_RENAME_SOURCE": 65536, + "__WASI_RIGHTS_PATH_RENAME_TARGET": 131072, + "__WASI_RIGHTS_PATH_SYMLINK": 16777216, + "__WASI_RIGHTS_PATH_UNLINK_FILE": 67108864, + "__WASI_RIGHTS_POLL_FD_READWRITE": 134217728, + "__WASI_RIGHTS_SOCK_SHUTDOWN": 268435456 }, "structs": { "EmscriptenBatteryEvent": { @@ -1236,6 +1275,26 @@ "fs_rights_base": 8, "fs_rights_inheriting": 16 }, + "__wasi_filestat_t": { + "__size__": 64, + "atim": 40, + "ctim": 56, + "dev": 0, + "filetype": 16, + "ino": 8, + "mtim": 48, + "nlink": 24, + "size": 32 + }, + "__wasi_prestat_dir_t": { + "__size__": 8, + "pr_name_len": 0 + }, + "__wasi_prestat_t": { + "__size__": 16, + "pr_type": 0, + "u": 8 + }, "addrinfo": { "__size__": 48, "ai_addr": 24, diff --git a/src/library_sigs.js b/src/library_sigs.js index 3308b2a84cd14..dc99c670dc9f5 100644 --- a/src/library_sigs.js +++ b/src/library_sigs.js @@ -1001,9 +1001,11 @@ sigs = { lineRGBA__sig: 'ipiiiiiiii', pixelRGBA__sig: 'ipiiiiii', proc_exit__sig: 'vi', + random_get__sig: 'ipp', rectangleColor__sig: 'ipiiiii', rectangleRGBA__sig: 'ipiiiiiiii', rotozoomSurface__sig: 'ppddi', + sched_yield__sig: 'i', setprotoent__sig: 'vi', strftime__sig: 'ppppp', strftime_l__sig: 'pppppp', diff --git a/src/library_syscall.js b/src/library_syscall.js index 45fb3ca65dead..bc276d08c0a9f 100644 --- a/src/library_syscall.js +++ b/src/library_syscall.js @@ -994,7 +994,18 @@ function wrapSyscallFunction(x, library, isWasi) { var canThrow = library[x + '__nothrow'] !== true; #endif - var pre = '', post = ''; + if (!library[x + '__deps']) library[x + '__deps'] = []; + +#if PURE_WASI + // In PURE_WASI mode we can't assume the wasm binary was built by emscripten + // and politely notify us on memory growth. Instead we have to check for + // possible memory growth on each syscall. + var pre = '\nif (!HEAPU8.byteLength) _emscripten_notify_memory_growth(0);\n' + library[x + '__deps'].push('emscripten_notify_memory_growth'); +#else + var pre = ''; +#endif + var post = ''; if (isVariadic) { pre += 'SYSCALLS.varargs = varargs;\n'; } @@ -1047,7 +1058,6 @@ function wrapSyscallFunction(x, library, isWasi) { } library[x] = eval('(' + t + ')'); - if (!library[x + '__deps']) library[x + '__deps'] = []; library[x + '__deps'].push('$SYSCALLS'); #if PTHREADS // Most syscalls need to happen on the main JS thread (e.g. because the diff --git a/src/library_wasi.js b/src/library_wasi.js index 1dbb9dbf692c3..c506cbb289817 100644 --- a/src/library_wasi.js +++ b/src/library_wasi.js @@ -37,6 +37,17 @@ var WasiLibrary = { #endif // MINIMAL_RUNTIME }, + sched_yield__nothrow: true, + sched_yield: function() { + return 0; + }, + + random_get__deps: ['getentropy'], + random_get: function(buf, buf_len) { + _getentropy(buf, buf_len); + return 0; + }, + $getEnvStrings__deps: ['$ENV', '$getExecutableName'], $getEnvStrings: function() { if (!getEnvStrings.strings) { @@ -49,6 +60,7 @@ var WasiLibrary = { var lang = 'C.UTF-8'; #endif var env = { +#if !PURE_WASI 'USER': 'web_user', 'LOGNAME': 'web_user', 'PATH': '/', @@ -56,6 +68,7 @@ var WasiLibrary = { 'HOME': '/home/web_user', 'LANG': lang, '_': getExecutableName() +#endif }; // Apply the user-provided values, if any. for (var x in ENV) { @@ -368,23 +381,155 @@ var WasiLibrary = { #endif }, + $wasiRightsToMuslOFlags: function(rights) { +#if SYSCALL_DEBUG + err('wasiRightsToMuslOFlags: ' + rights); +#endif + if ((rights & {{{ cDefs.__WASI_RIGHTS_FD_READ }}}) && (rights & {{{ cDefs.__WASI_RIGHTS_FD_WRITE }}})) { + return {{{ cDefs.O_RDWR }}}; + } + if (rights & {{{ cDefs.__WASI_RIGHTS_FD_READ }}}) { + return {{{ cDefs.O_RDONLY }}}; + } + if (rights & {{{ cDefs.__WASI_RIGHTS_FD_WRITE }}}) { + return {{{ cDefs.O_WRONLY }}}; + } + throw new FS.ErrnoError({{{ cDefs.EINVAL }}}); + }, + + $wasiOFlagsToMuslOFlags: function(oflags) { + var musl_oflags = 0; + if (oflags & {{{ cDefs.__WASI_OFLAGS_CREAT }}}) { + musl_oflags |= {{{ cDefs.O_CREAT }}}; + } + if (oflags & {{{ cDefs.__WASI_OFLAGS_TRUNC }}}) { + musl_oflags |= {{{ cDefs.O_TRUNC }}}; + } + if (oflags & {{{ cDefs.__WASI_OFLAGS_DIRECTORY }}}) { + musl_oflags |= {{{ cDefs.O_DIRECTORY }}}; + } + if (oflags & {{{ cDefs.__WASI_OFLAGS_EXCL }}}) { + musl_oflags |= {{{ cDefs.O_EXCL }}}; + } + return musl_oflags; + }, + +#if PURE_WASI + // preopen maps open file descriptors to pathname. + // In emscripten we already have a VFS layer so (for now) we expose the entire + // VFS to the wasi API. + $preopens: "{3: '/'}", + + path_open__sig: 'iiiiiiiiii', + path_open__deps: ['$wasiRightsToMuslOFlags', '$wasiOFlagsToMuslOFlags', '$preopens'], + path_open: function(fd, dirflags, path, path_len, oflags, + fs_rights_base, fs_rights_inherting, + fdflags, opened_fd) { + if (!(fd in preopens)) { + return {{{ cDefs.EBADF }}}; + } + var pathname = UTF8ToString(path, path_len); + var musl_oflags = wasiRightsToMuslOFlags(Number(fs_rights_base)); +#if SYSCALL_DEBUG + err("oflags1: 0x" + musl_oflags.toString(16)); +#endif + musl_oflags |= wasiOFlagsToMuslOFlags(Number(oflags)); +#if SYSCALL_DEBUG + err("oflags2: 0x" + musl_oflags.toString(16)); +#endif + var stream = FS.open(pathname, musl_oflags); + {{{ makeSetValue('opened_fd', '0', 'stream.fd', 'i32') }}}; + return 0; + }, + + fd_prestat_dir_name__deps: ['$preopens'], + fd_prestat_dir_name__sig: 'iiii', + fd_prestat_dir_name__nothrow: true, + fd_prestat_dir_name: function(fd, path, path_len) { + if (!(fd in preopens)) { + return {{{ cDefs.EBADF }}}; + } + var preopen = preopens[fd]; + stringToUTF8Array(preopens, HEAP8, path, path_len) + return 0; + }, + + fd_prestat_get__deps: ['$preopens'], + fd_prestat_get__sig: 'iii', + fd_prestat_get__nothrow: true, + fd_prestat_get: function(fd, stat_buf) { + if (!(fd in preopens)) { + return {{{ cDefs.EBADF }}}; + } + var preopen = preopens[fd]; + {{{ makeSetValue('stat_buf', C_STRUCTS.__wasi_prestat_t.pr_type, cDefs.__WASI_PREOPENTYPE_DIR, 'i8') }}}; + {{{ makeSetValue('stat_buf', C_STRUCTS.__wasi_prestat_t.u + C_STRUCTS.__wasi_prestat_dir_t.pr_name_len, 'preopen.length', 'i64') }}}; + return 0; + }, + + fd_fdstat_set_flags__sig: 'iii', + fd_fdstat_set_flags: function(fd, flags) { + // TODO(sbc): implement + var stream = SYSCALLS.getStreamFromFD(fd); + return 0; + }, + + fd_filestat_get__sig: 'iii', + fd_filestat_get: function(fd, stat_buf) { + // TODO(sbc): implement + var stream = SYSCALLS.getStreamFromFD(fd); + {{{ makeSetValue('stat_buf', C_STRUCTS.__wasi_filestat_t.dev, '0', 'i64') }}}; + {{{ makeSetValue('stat_buf', C_STRUCTS.__wasi_filestat_t.ino, '0', 'i64') }}}; + {{{ makeSetValue('stat_buf', C_STRUCTS.__wasi_filestat_t.filetype, '0', 'i8') }}}; + {{{ makeSetValue('stat_buf', C_STRUCTS.__wasi_filestat_t.nlink, '0', 'i64') }}}; + {{{ makeSetValue('stat_buf', C_STRUCTS.__wasi_filestat_t.size, '0', 'i64') }}}; + {{{ makeSetValue('stat_buf', C_STRUCTS.__wasi_filestat_t.atim, '0', 'i64') }}}; + {{{ makeSetValue('stat_buf', C_STRUCTS.__wasi_filestat_t.mtim, '0', 'i64') }}}; + {{{ makeSetValue('stat_buf', C_STRUCTS.__wasi_filestat_t.ctim, '0', 'i64') }}}; + return 0; + }, +#endif + +#if PURE_WASI + fd_fdstat_get__deps: ['$preopens'], +#endif fd_fdstat_get: function(fd, pbuf) { + var rightsBase = 0; + var rightsInheriting = 0; + var flags = 0; +#if PURE_WASI + if (fd in preopens) { + var type = {{{ cDefs.__WASI_FILETYPE_DIRECTORY }}}; + rightsBase = {{{ cDefs.__WASI_RIGHTS_PATH_CREATE_FILE | + cDefs.__WASI_RIGHTS_PATH_OPEN }}}; + rightsInheriting = {{{ cDefs.__WASI_RIGHTS_FD_READ | + cDefs.__WASI_RIGHTS_FD_WRITE }}} + } else +#endif + { #if SYSCALLS_REQUIRE_FILESYSTEM - var stream = SYSCALLS.getStreamFromFD(fd); - // All character devices are terminals (other things a Linux system would - // assume is a character device, like the mouse, we have special APIs for). - var type = stream.tty ? {{{ cDefs.__WASI_FILETYPE_CHARACTER_DEVICE }}} : - FS.isDir(stream.mode) ? {{{ cDefs.__WASI_FILETYPE_DIRECTORY }}} : - FS.isLink(stream.mode) ? {{{ cDefs.__WASI_FILETYPE_SYMBOLIC_LINK }}} : - {{{ cDefs.__WASI_FILETYPE_REGULAR_FILE }}}; + var stream = SYSCALLS.getStreamFromFD(fd); + // All character devices are terminals (other things a Linux system would + // assume is a character device, like the mouse, we have special APIs for). + var type = stream.tty ? {{{ cDefs.__WASI_FILETYPE_CHARACTER_DEVICE }}} : + FS.isDir(stream.mode) ? {{{ cDefs.__WASI_FILETYPE_DIRECTORY }}} : + FS.isLink(stream.mode) ? {{{ cDefs.__WASI_FILETYPE_SYMBOLIC_LINK }}} : + {{{ cDefs.__WASI_FILETYPE_REGULAR_FILE }}}; #else - // hack to support printf in SYSCALLS_REQUIRE_FILESYSTEM=0 - var type = fd == 1 || fd == 2 ? {{{ cDefs.__WASI_FILETYPE_CHARACTER_DEVICE }}} : abort(); + // hack to support printf in SYSCALLS_REQUIRE_FILESYSTEM=0 + var type = fd == 0 || fd == 1 || fd == 2 ? {{{ cDefs.__WASI_FILETYPE_CHARACTER_DEVICE }}} : abort(); + if (fd == 0) { + rightsBase = {{{ cDefs.__WASI_RIGHTS_FD_READ }}}; + } else if (fd == 1 || fd == 2) { + rightsBase = {{{ cDefs.__WASI_RIGHTS_FD_WRITE }}}; + } + flags = {{{ cDefs.__WASI_FDFLAGS_APPEND }}}; #endif + } {{{ makeSetValue('pbuf', C_STRUCTS.__wasi_fdstat_t.fs_filetype, 'type', 'i8') }}}; - // TODO {{{ makeSetValue('pbuf', C_STRUCTS.__wasi_fdstat_t.fs_flags, '?', 'i16') }}}; - // TODO {{{ makeSetValue('pbuf', C_STRUCTS.__wasi_fdstat_t.fs_rights_base, '?', 'i64') }}}; - // TODO {{{ makeSetValue('pbuf', C_STRUCTS.__wasi_fdstat_t.fs_rights_inheriting, '?', 'i64') }}}; + {{{ makeSetValue('pbuf', C_STRUCTS.__wasi_fdstat_t.fs_flags, 'flags', 'i16') }}}; + {{{ makeSetValue('pbuf', C_STRUCTS.__wasi_fdstat_t.fs_rights_base, 'rightsBase', 'i64') }}}; + {{{ makeSetValue('pbuf', C_STRUCTS.__wasi_fdstat_t.fs_rights_inheriting, 'rightsInheriting', 'i64') }}}; return 0; }, diff --git a/src/shell.js b/src/shell.js index 0c21ed2b068dd..b007cce288047 100644 --- a/src/shell.js +++ b/src/shell.js @@ -218,7 +218,7 @@ if (ENVIRONMENT_IS_NODE) { #include "node_shell_read.js" - if (process.argv.length > 1) { + if (!Module['thisProgram'] && process.argv.length > 1) { thisProgram = process.argv[1].replace(/\\/g, '/'); } diff --git a/src/struct_info.json b/src/struct_info.json index 0466d2d93ee8d..f4c556e890c50 100644 --- a/src/struct_info.json +++ b/src/struct_info.json @@ -954,6 +954,23 @@ "fs_flags", "fs_rights_base", "fs_rights_inheriting" + ], + "__wasi_prestat_t": [ + "pr_type", + "u" + ], + "__wasi_prestat_dir_t": [ + "pr_name_len" + ], + "__wasi_filestat_t": [ + "dev", + "ino", + "filetype", + "nlink", + "size", + "atim", + "mtim", + "ctim" ] }, "defines": [ @@ -964,7 +981,46 @@ "__WASI_CLOCKID_REALTIME", "__WASI_CLOCKID_MONOTONIC", "__WASI_CLOCKID_PROCESS_CPUTIME_ID", - "__WASI_CLOCKID_THREAD_CPUTIME_ID" + "__WASI_CLOCKID_THREAD_CPUTIME_ID", + "__WASI_FDFLAGS_APPEND", + "__WASI_FDFLAGS_DSYNC", + "__WASI_FDFLAGS_NONBLOCK", + "__WASI_FDFLAGS_RSYNC", + "__WASI_FDFLAGS_SYNC", + "__WASI_OFLAGS_CREAT", + "__WASI_OFLAGS_DIRECTORY", + "__WASI_OFLAGS_EXCL", + "__WASI_OFLAGS_TRUNC", + "__WASI_RIGHTS_FD_DATASYNC", + "__WASI_RIGHTS_FD_READ", + "__WASI_RIGHTS_FD_SEEK", + "__WASI_RIGHTS_FD_FDSTAT_SET_FLAGS", + "__WASI_RIGHTS_FD_SYNC", + "__WASI_RIGHTS_FD_TELL", + "__WASI_RIGHTS_FD_WRITE", + "__WASI_RIGHTS_FD_ADVISE", + "__WASI_RIGHTS_FD_ALLOCATE", + "__WASI_RIGHTS_PATH_CREATE_DIRECTORY", + "__WASI_RIGHTS_PATH_CREATE_FILE", + "__WASI_RIGHTS_PATH_LINK_SOURCE", + "__WASI_RIGHTS_PATH_LINK_TARGET", + "__WASI_RIGHTS_PATH_OPEN", + "__WASI_RIGHTS_FD_READDIR", + "__WASI_RIGHTS_PATH_READLINK", + "__WASI_RIGHTS_PATH_RENAME_SOURCE", + "__WASI_RIGHTS_PATH_RENAME_TARGET", + "__WASI_RIGHTS_PATH_FILESTAT_GET", + "__WASI_RIGHTS_PATH_FILESTAT_SET_SIZE", + "__WASI_RIGHTS_PATH_FILESTAT_SET_TIMES", + "__WASI_RIGHTS_FD_FILESTAT_GET", + "__WASI_RIGHTS_FD_FILESTAT_SET_SIZE", + "__WASI_RIGHTS_FD_FILESTAT_SET_TIMES", + "__WASI_RIGHTS_PATH_SYMLINK", + "__WASI_RIGHTS_PATH_REMOVE_DIRECTORY", + "__WASI_RIGHTS_PATH_UNLINK_FILE", + "__WASI_RIGHTS_POLL_FD_READWRITE", + "__WASI_RIGHTS_SOCK_SHUTDOWN", + "__WASI_PREOPENTYPE_DIR" ] }, { diff --git a/test/test_other.py b/test/test_other.py index d2ed532e1470b..fb88902dcd359 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -13333,3 +13333,82 @@ def test_missing_struct_info(self): ''') err = self.expect_fail([EMCC, test_file('hello_world.c'), '--js-library=lib.js']) self.assertContained('Error: Missing C define Foo! If you just added it to struct_info.json, you need to run ./tools/gen_struct_info.py', err) + + def run_wasi_test_suite_test(self, name): + if not os.path.exists(path_from_root('test/third_party/wasi-test-suite')): + self.fail('wasi-testsuite not found; run `git submodule update --init`') + self.node_args += shared.node_bigint_flags() + wasm = path_from_root('test', 'third_party', 'wasi-test-suite', name + '.wasm') + with open(path_from_root('test', 'third_party', 'wasi-test-suite', name + '.json')) as f: + config = json.load(f) + exit_code = config.get('exitCode', 0) + args = config.get('args', []) + env = config.get('env', []) + if env: + env = [f'ENV["{key}"] = "{value}";' for key, value in env.items()] + env = '\n'.join(env) + create_file('env.js', 'Module.preRun = () => { %s };' % env) + self.emcc_args.append('--pre-js=env.js') + self.run_process([EMCC, '-Wno-experimental', '--post-link', '-g', + '-sPURE_WASI', '-lnodefs.js', '-lnoderawfs.js', + wasm, '-o', name + '.js'] + self.get_emcc_args(main_file=True)) + + output = self.run_js(name + '.js', args=args, assert_returncode=exit_code) + if 'stdout' in config: + self.assertContained(config['stdout'], output) + + @requires_node + def test_wasi_std_env_args(self): + create_file('pre.js', 'Module["thisProgram"] = "std_env_args.wasm"') + self.emcc_args += ['--pre-js', 'pre.js'] + self.run_wasi_test_suite_test('std_env_args') + + @requires_node + def test_wasi_std_env_vars(self): + self.run_wasi_test_suite_test('std_env_vars') + + @requires_node + def test_wasi_std_io_stdout(self): + self.run_wasi_test_suite_test('std_io_stdout') + + @requires_node + def test_wasi_std_io_stderr(self): + self.run_wasi_test_suite_test('std_io_stderr') + + @requires_node + def test_wasi_clock_res_get(self): + self.run_wasi_test_suite_test('wasi_clock_res_get') + + @requires_node + def test_wasi_clock_time_get(self): + self.run_wasi_test_suite_test('wasi_clock_time_get') + + @requires_node + def test_wasi_fd_fdstat_get(self): + self.run_wasi_test_suite_test('wasi_fd_fdstat_get') + + @requires_node + def test_wasi_wasi_fd_write_file(self): + self.run_wasi_test_suite_test('wasi_fd_write_file') + with open('new_file') as f: + self.assertEqual(f.read(), 'new_file') + + @requires_node + def test_wasi_wasi_fd_write_stdout(self): + self.run_wasi_test_suite_test('wasi_fd_write_stdout') + + @requires_node + def test_wasi_wasi_fd_write_stderr(self): + self.run_wasi_test_suite_test('wasi_fd_write_stderr') + + @requires_node + def test_wasi_proc_exit(self): + self.run_wasi_test_suite_test('wasi_proc_exit') + + @requires_node + def test_wasi_random_get(self): + self.run_wasi_test_suite_test('wasi_random_get') + + @requires_node + def test_wasi_sched_yield(self): + self.run_wasi_test_suite_test('wasi_sched_yield') diff --git a/test/third_party/wasi-test-suite b/test/third_party/wasi-test-suite new file mode 160000 index 0000000000000..ac9371207fc61 --- /dev/null +++ b/test/third_party/wasi-test-suite @@ -0,0 +1 @@ +Subproject commit ac9371207fc61972a21d7d086074ca690a99d14d diff --git a/tools/building.py b/tools/building.py index 8996f2cc9a9de..9125335950d0f 100644 --- a/tools/building.py +++ b/tools/building.py @@ -812,6 +812,7 @@ def metadce(js_file, wasm_file, minify_whitespace, debug_info): 'proc_exit', 'clock_res_get', 'clock_time_get', + 'path_open', } for item in graph: if 'import' in item and item['import'][1][1:] in WASI_IMPORTS: diff --git a/tools/gen_sig_info.py b/tools/gen_sig_info.py index 172ffc7d3f48b..b0a9e85c2da45 100755 --- a/tools/gen_sig_info.py +++ b/tools/gen_sig_info.py @@ -110,6 +110,7 @@ 'fd_fdstat_get', 'args_get', 'args_sizes_get', + 'random_get', } From 005489c8f378ffda97287b5b37cc41a199daf961 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Sat, 1 Apr 2023 14:33:06 -0700 Subject: [PATCH 0093/1523] Rebaseline codesize expectations. NFC --- test/other/metadce/test_metadce_cxx_ctors1.jssize | 2 +- test/other/metadce/test_metadce_cxx_ctors2.jssize | 2 +- test/other/metadce/test_metadce_cxx_except.jssize | 2 +- test/other/metadce/test_metadce_cxx_except_wasm.jssize | 2 +- test/other/metadce/test_metadce_cxx_mangle.jssize | 2 +- test/other/metadce/test_metadce_cxx_noexcept.jssize | 2 +- test/other/metadce/test_metadce_hello_O0.jssize | 2 +- test/other/metadce/test_metadce_hello_dylink.jssize | 2 +- test/other/metadce/test_metadce_mem_O3.jssize | 2 +- test/other/metadce/test_metadce_mem_O3_grow.jssize | 2 +- test/other/metadce/test_metadce_mem_O3_grow_standalone.jssize | 2 +- test/other/metadce/test_metadce_mem_O3_standalone.jssize | 2 +- test/other/metadce/test_metadce_minimal_O0.jssize | 2 +- test/other/test_unoptimized_code_size.js.size | 2 +- test/other/test_unoptimized_code_size_no_asserts.js.size | 2 +- test/other/test_unoptimized_code_size_strict.js.size | 2 +- 16 files changed, 16 insertions(+), 16 deletions(-) diff --git a/test/other/metadce/test_metadce_cxx_ctors1.jssize b/test/other/metadce/test_metadce_cxx_ctors1.jssize index e0d406ae03b87..5a83e94204ad0 100644 --- a/test/other/metadce/test_metadce_cxx_ctors1.jssize +++ b/test/other/metadce/test_metadce_cxx_ctors1.jssize @@ -1 +1 @@ -26178 +26205 diff --git a/test/other/metadce/test_metadce_cxx_ctors2.jssize b/test/other/metadce/test_metadce_cxx_ctors2.jssize index 56f822ab463b2..fbdf8f8114343 100644 --- a/test/other/metadce/test_metadce_cxx_ctors2.jssize +++ b/test/other/metadce/test_metadce_cxx_ctors2.jssize @@ -1 +1 @@ -26142 +26169 diff --git a/test/other/metadce/test_metadce_cxx_except.jssize b/test/other/metadce/test_metadce_cxx_except.jssize index b96e97707e21e..76cb23dce88c3 100644 --- a/test/other/metadce/test_metadce_cxx_except.jssize +++ b/test/other/metadce/test_metadce_cxx_except.jssize @@ -1 +1 @@ -30715 +30731 diff --git a/test/other/metadce/test_metadce_cxx_except_wasm.jssize b/test/other/metadce/test_metadce_cxx_except_wasm.jssize index d62e0edd7d545..4d5bbdb566ccb 100644 --- a/test/other/metadce/test_metadce_cxx_except_wasm.jssize +++ b/test/other/metadce/test_metadce_cxx_except_wasm.jssize @@ -1 +1 @@ -25857 +25873 diff --git a/test/other/metadce/test_metadce_cxx_mangle.jssize b/test/other/metadce/test_metadce_cxx_mangle.jssize index f11164ae1afba..f27a5fc2f515d 100644 --- a/test/other/metadce/test_metadce_cxx_mangle.jssize +++ b/test/other/metadce/test_metadce_cxx_mangle.jssize @@ -1 +1 @@ -30720 +30736 diff --git a/test/other/metadce/test_metadce_cxx_noexcept.jssize b/test/other/metadce/test_metadce_cxx_noexcept.jssize index e0d406ae03b87..5a83e94204ad0 100644 --- a/test/other/metadce/test_metadce_cxx_noexcept.jssize +++ b/test/other/metadce/test_metadce_cxx_noexcept.jssize @@ -1 +1 @@ -26178 +26205 diff --git a/test/other/metadce/test_metadce_hello_O0.jssize b/test/other/metadce/test_metadce_hello_O0.jssize index 62b8d754e9866..8cb9d5e400dfd 100644 --- a/test/other/metadce/test_metadce_hello_O0.jssize +++ b/test/other/metadce/test_metadce_hello_O0.jssize @@ -1 +1 @@ -24002 +24048 diff --git a/test/other/metadce/test_metadce_hello_dylink.jssize b/test/other/metadce/test_metadce_hello_dylink.jssize index e8f92ab1737aa..af1f987c7b7f8 100644 --- a/test/other/metadce/test_metadce_hello_dylink.jssize +++ b/test/other/metadce/test_metadce_hello_dylink.jssize @@ -1 +1 @@ -27921 +27937 diff --git a/test/other/metadce/test_metadce_mem_O3.jssize b/test/other/metadce/test_metadce_mem_O3.jssize index a49b0bdb8b0d5..b0f791df0f893 100644 --- a/test/other/metadce/test_metadce_mem_O3.jssize +++ b/test/other/metadce/test_metadce_mem_O3.jssize @@ -1 +1 @@ -6088 +6104 diff --git a/test/other/metadce/test_metadce_mem_O3_grow.jssize b/test/other/metadce/test_metadce_mem_O3_grow.jssize index 0a85a000114a0..f04ad2bec3f0a 100644 --- a/test/other/metadce/test_metadce_mem_O3_grow.jssize +++ b/test/other/metadce/test_metadce_mem_O3_grow.jssize @@ -1 +1 @@ -6425 +6441 diff --git a/test/other/metadce/test_metadce_mem_O3_grow_standalone.jssize b/test/other/metadce/test_metadce_mem_O3_grow_standalone.jssize index a734b82fb60ea..4d958ef476ea6 100644 --- a/test/other/metadce/test_metadce_mem_O3_grow_standalone.jssize +++ b/test/other/metadce/test_metadce_mem_O3_grow_standalone.jssize @@ -1 +1 @@ -5815 +5831 diff --git a/test/other/metadce/test_metadce_mem_O3_standalone.jssize b/test/other/metadce/test_metadce_mem_O3_standalone.jssize index c689f62048150..da710c1aba587 100644 --- a/test/other/metadce/test_metadce_mem_O3_standalone.jssize +++ b/test/other/metadce/test_metadce_mem_O3_standalone.jssize @@ -1 +1 @@ -5737 +5753 diff --git a/test/other/metadce/test_metadce_minimal_O0.jssize b/test/other/metadce/test_metadce_minimal_O0.jssize index ad846c4f1412f..4146d1bfbc386 100644 --- a/test/other/metadce/test_metadce_minimal_O0.jssize +++ b/test/other/metadce/test_metadce_minimal_O0.jssize @@ -1 +1 @@ -20248 +20294 diff --git a/test/other/test_unoptimized_code_size.js.size b/test/other/test_unoptimized_code_size.js.size index 5eaf22fbbe33c..bc594e72ee8f3 100644 --- a/test/other/test_unoptimized_code_size.js.size +++ b/test/other/test_unoptimized_code_size.js.size @@ -1 +1 @@ -59608 +59690 diff --git a/test/other/test_unoptimized_code_size_no_asserts.js.size b/test/other/test_unoptimized_code_size_no_asserts.js.size index a1a4ad036cfb3..6d8f14511f2ba 100644 --- a/test/other/test_unoptimized_code_size_no_asserts.js.size +++ b/test/other/test_unoptimized_code_size_no_asserts.js.size @@ -1 +1 @@ -33322 +33348 diff --git a/test/other/test_unoptimized_code_size_strict.js.size b/test/other/test_unoptimized_code_size_strict.js.size index 30bb88e98b13c..a569f0855e6da 100644 --- a/test/other/test_unoptimized_code_size_strict.js.size +++ b/test/other/test_unoptimized_code_size_strict.js.size @@ -1 +1 @@ -58550 +58632 From a90c5abb489c516f59c0d16864d953d4bedd37da Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Sun, 2 Apr 2023 20:52:51 -0700 Subject: [PATCH 0094/1523] Fix ubsan.test_fs_no_main_minimal_runtime (#19118) This test was broken by #19097 --- emcc.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/emcc.py b/emcc.py index 17c869565cbd6..023b24e52b27d 100755 --- a/emcc.py +++ b/emcc.py @@ -2645,8 +2645,10 @@ def check_memory_setting(setting): if settings.PTHREADS: settings.INITIAL_MEMORY += 50 * 1024 * 1024 - if settings.USE_OFFSET_CONVERTER and settings.WASM2JS: - exit_with_error('wasm2js is not compatible with USE_OFFSET_CONVERTER (see #14630)') + if settings.USE_OFFSET_CONVERTER: + if settings.WASM2JS: + exit_with_error('wasm2js is not compatible with USE_OFFSET_CONVERTER (see #14630)') + settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.append('$UTF8ArrayToString') if sanitize & UBSAN_SANITIZERS: if '-fsanitize-minimal-runtime' in newargs: From 94ae66a1e1102326847f24ea26558c0a141f496f Mon Sep 17 00:00:00 2001 From: Kshitij Rajgude Date: Tue, 4 Apr 2023 01:38:11 +0530 Subject: [PATCH 0095/1523] Implement FS.rmdir with WasmFS (#18952) --- emcc.py | 1 + emscripten.py | 2 ++ src/library_wasmfs.js | 6 +++++ system/lib/wasmfs/js_api.cpp | 2 ++ test/fs/test_dir.c | 49 ++++++++++++++++++++++++++++++++++++ test/test_core.py | 5 ++++ 6 files changed, 65 insertions(+) create mode 100644 test/fs/test_dir.c diff --git a/emcc.py b/emcc.py index 023b24e52b27d..6613e15bc5484 100755 --- a/emcc.py +++ b/emcc.py @@ -2325,6 +2325,7 @@ def phase_linker_setup(options, state, newargs): '_wasmfs_mkdir', '_wasmfs_unlink', '_wasmfs_chdir', + '_wasmfs_rmdir', '_wasmfs_symlink', '_wasmfs_chmod', '_wasmfs_identify', diff --git a/emscripten.py b/emscripten.py index 691da8e591c70..008d42ea9eaed 100644 --- a/emscripten.py +++ b/emscripten.py @@ -885,6 +885,8 @@ def create_wasm64_wrappers(metadata): '_emscripten_thread_free_data': '_p', '_emscripten_dlsync_self_async': '_p', '_emscripten_proxy_dlsync_async': '_pp', + '_wasmfs_rmdir': '_p', + '_wasmfs_unlink': '_p' } wasm64_wrappers = ''' diff --git a/src/library_wasmfs.js b/src/library_wasmfs.js index ce489ab50db16..84b4ee70c9138 100644 --- a/src/library_wasmfs.js +++ b/src/library_wasmfs.js @@ -140,6 +140,12 @@ mergeInto(LibraryManager.library, { }, // TODO: mkdirTree // TDOO: rmdir + rmdir: (path) => { + return withStackSave(() => { + var buffer = stringToUTF8OnStack(path); + return __wasmfs_rmdir(buffer); + }) + }, // TODO: open open: (path, flags, mode) => { flags = typeof flags == 'string' ? FS.modeStringToFlags(flags) : flags; diff --git a/system/lib/wasmfs/js_api.cpp b/system/lib/wasmfs/js_api.cpp index 7f85d1ed80fa5..fe33dd4ff6dd7 100644 --- a/system/lib/wasmfs/js_api.cpp +++ b/system/lib/wasmfs/js_api.cpp @@ -100,6 +100,8 @@ int _wasmfs_mkdir(char* path, int mode) { return __syscall_mkdirat(AT_FDCWD, (intptr_t)path, mode); } +int _wasmfs_rmdir(char* path){ return __syscall_unlinkat(AT_FDCWD, (intptr_t)path, AT_REMOVEDIR); } + int _wasmfs_open(char* path, int flags, mode_t mode) { return __syscall_openat(AT_FDCWD, (intptr_t)path, flags, mode); } diff --git a/test/fs/test_dir.c b/test/fs/test_dir.c new file mode 100644 index 0000000000000..6304b5a3b2337 --- /dev/null +++ b/test/fs/test_dir.c @@ -0,0 +1,49 @@ +/* + * Copyright 2023 The Emscripten Authors. All rights reserved. + * Emscripten is available under two separate licenses, the MIT license and the + * University of Illinois/NCSA Open Source License. Both these licenses can be + * found in the LICENSE file. + */ + +#include +#include +#include + +int main() { + EM_ASM( + // Create multiple directories + var err = FS.mkdir('/dir1'); + assert(!err); + err = FS.mkdir('/dir2'); + assert(!err); + + // Remove the multiple directories + err = FS.rmdir('/dir1'); + assert(!err); + err = FS.rmdir('/dir2'); + assert(!err); + + // Create a directory with a file inside it + var err = FS.mkdir('/test_dir'); + assert(!err); + err = FS.writeFile('/test_dir/file.txt', 'Hello World!'); + assert(!err); + + // Attempt to remove the directory (should fail) + err = FS.rmdir('/test_dir'); + assert(err); + + // Remove the file and then the directory + err = FS.unlink('/test_dir/file.txt'); + assert(!err); + err = FS.rmdir('/test_dir'); + assert(!err); + + // Attempt to remove a non-existent directory (should fail) + var err = FS.rmdir('/non_existent_dir'); + assert(err); + ); + puts("success"); + + return 0; +} diff --git a/test/test_core.py b/test/test_core.py index b9dbadf7ae087..594299cc458a0 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -5953,6 +5953,11 @@ def test_istream(self): self.set_setting('LINKABLE', linkable) self.do_core_test('test_istream.cpp') + def test_fs_dir_wasmfs(self): + self.emcc_args += ['-sWASMFS'] + self.emcc_args += ['-sFORCE_FILESYSTEM'] + self.do_runf(test_file('fs/test_dir.c'), 'success') + def test_fs_base(self): self.set_setting('DEFAULT_LIBRARY_FUNCS_TO_INCLUDE', ['$FS']) self.uses_es6 = True From f3c4c2ac0ab0630a18bd3c262b0692919d8f6da3 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 3 Apr 2023 13:27:34 -0700 Subject: [PATCH 0096/1523] [Wasm64] Get test_anisotropic with MEMORY64 (#18971) This required fixing some basic SDL and OpenGL operations. --- src/library_glemu.js | 4 ++-- test/{aniso.c => browser/test_anisotropic.c} | 0 test/{aniso.png => browser/test_anisotropic.png} | Bin test/{ => browser}/water.dds | Bin test/test_browser.py | 7 ++++--- 5 files changed, 6 insertions(+), 5 deletions(-) rename test/{aniso.c => browser/test_anisotropic.c} (100%) rename test/{aniso.png => browser/test_anisotropic.png} (100%) rename test/{ => browser}/water.dds (100%) diff --git a/src/library_glemu.js b/src/library_glemu.js index bf01ba6f531da..654ee7a130db8 100644 --- a/src/library_glemu.js +++ b/src/library_glemu.js @@ -417,8 +417,7 @@ var LibraryGLEmulation = { (GL.currentContext.compressionExt ? ' GL_ARB_texture_compression GL_EXT_texture_compression_s3tc' : '') + (GL.currentContext.anisotropicExt ? ' GL_EXT_texture_filter_anisotropic' : '') ); - GL.stringCache[name_] = ret; - return ret; + return GL.stringCache[name_] = {{{ to64('ret') }}}; } return glGetString(name_); }; @@ -3672,6 +3671,7 @@ var LibraryGLEmulation = { GLImmediate.matrixLib.mat4.set({{{ makeHEAPView('F64', 'matrix', 'matrix+' + (16*8)) }}}, GLImmediate.matrix[GLImmediate.currentMatrix]); }, + glLoadMatrixf__sig: 'vp', glLoadMatrixf: function(matrix) { #if GL_DEBUG if (GL.debug) dbg('glLoadMatrixf receiving: ' + Array.prototype.slice.call(HEAPF32.subarray(matrix >> 2, (matrix >> 2) + 16))); diff --git a/test/aniso.c b/test/browser/test_anisotropic.c similarity index 100% rename from test/aniso.c rename to test/browser/test_anisotropic.c diff --git a/test/aniso.png b/test/browser/test_anisotropic.png similarity index 100% rename from test/aniso.png rename to test/browser/test_anisotropic.png diff --git a/test/water.dds b/test/browser/water.dds similarity index 100% rename from test/water.dds rename to test/browser/water.dds diff --git a/test/test_browser.py b/test/test_browser.py index 8c031df58e385..4aa8dfaae6e06 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -2249,9 +2249,10 @@ def test_s3tc_ffp_only(self): self.btest('s3tc.c', reference='s3tc.png', args=['--preload-file', 'screenshot.dds', '-sLEGACY_GL_EMULATION', '-sGL_FFP_ONLY', '-lGL', '-lSDL']) @requires_graphics_hardware - def test_aniso(self): - shutil.copyfile(test_file('water.dds'), 'water.dds') - self.btest('aniso.c', reference='aniso.png', reference_slack=2, args=['--preload-file', 'water.dds', '-sLEGACY_GL_EMULATION', '-lGL', '-lSDL', '-Wno-incompatible-pointer-types']) + @also_with_wasm64 + def test_anisotropic(self): + shutil.copyfile(test_file('browser/water.dds'), 'water.dds') + self.btest('browser/test_anisotropic.c', reference='browser/test_anisotropic.png', reference_slack=2, args=['--preload-file', 'water.dds', '-sLEGACY_GL_EMULATION', '-lGL', '-lSDL', '-Wno-incompatible-pointer-types']) @requires_graphics_hardware def test_tex_nonbyte(self): From 578a13ad0d1b17d0cfda8d9b63022e8d3aac1fd8 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 3 Apr 2023 15:49:36 -0700 Subject: [PATCH 0097/1523] Use `dbg` over `err` for syscall debugging. NFC (#19126) Also, remove stray `err` logging from #13272. --- src/library_syscall.js | 1 - src/library_wasi.js | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/library_syscall.js b/src/library_syscall.js index bc276d08c0a9f..629e3edb96560 100644 --- a/src/library_syscall.js +++ b/src/library_syscall.js @@ -297,7 +297,6 @@ var SyscallsLibrary = { }, __syscall_getsockname__deps: ['$getSocketFromFD', '$writeSockaddr', '$DNS'], __syscall_getsockname: function(fd, addr, addrlen, d1, d2, d3) { - err("__syscall_getsockname " + fd); var sock = getSocketFromFD(fd); // TODO: sock.saddr should never be undefined, see TODO in websocket_sock_ops.getname var errno = writeSockaddr(addr, sock.family, DNS.lookup_name(sock.saddr || '0.0.0.0'), sock.sport, addrlen); diff --git a/src/library_wasi.js b/src/library_wasi.js index c506cbb289817..396c94577e8e6 100644 --- a/src/library_wasi.js +++ b/src/library_wasi.js @@ -383,7 +383,7 @@ var WasiLibrary = { $wasiRightsToMuslOFlags: function(rights) { #if SYSCALL_DEBUG - err('wasiRightsToMuslOFlags: ' + rights); + dbg('wasiRightsToMuslOFlags: ' + rights); #endif if ((rights & {{{ cDefs.__WASI_RIGHTS_FD_READ }}}) && (rights & {{{ cDefs.__WASI_RIGHTS_FD_WRITE }}})) { return {{{ cDefs.O_RDWR }}}; @@ -431,11 +431,11 @@ var WasiLibrary = { var pathname = UTF8ToString(path, path_len); var musl_oflags = wasiRightsToMuslOFlags(Number(fs_rights_base)); #if SYSCALL_DEBUG - err("oflags1: 0x" + musl_oflags.toString(16)); + dbg("oflags1: 0x" + musl_oflags.toString(16)); #endif musl_oflags |= wasiOFlagsToMuslOFlags(Number(oflags)); #if SYSCALL_DEBUG - err("oflags2: 0x" + musl_oflags.toString(16)); + dbg("oflags2: 0x" + musl_oflags.toString(16)); #endif var stream = FS.open(pathname, musl_oflags); {{{ makeSetValue('opened_fd', '0', 'stream.fd', 'i32') }}}; From 3a4035e41262548302b354a7d2ff67c83b2a03be Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 3 Apr 2023 17:46:11 -0700 Subject: [PATCH 0098/1523] Fix wasi_path_open and add assertion to stringToUTF8 (#19127) There were a few places where we were passing 0 instead of a string to `stringToUTF8`. --- src/library_strings.js | 3 +++ src/library_wasi.js | 7 +++++-- system/lib/compiler-rt/lib/asan/asan_flags.cpp | 2 +- system/lib/compiler-rt/lib/lsan/lsan.cpp | 2 +- system/lib/compiler-rt/lib/ubsan/ubsan_flags.cpp | 2 +- 5 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/library_strings.js b/src/library_strings.js index eeefc039d823e..1cbf2635036ed 100644 --- a/src/library_strings.js +++ b/src/library_strings.js @@ -156,6 +156,9 @@ mergeInto(LibraryManager.library, { $stringToUTF8Array: function(str, heap, outIdx, maxBytesToWrite) { #if CAN_ADDRESS_2GB outIdx >>>= 0; +#endif +#if ASSERTIONS + assert(typeof str === 'string'); #endif // Parameter maxBytesToWrite is not optional. Negative values, 0, null, // undefined and false each don't write out any bytes. diff --git a/src/library_wasi.js b/src/library_wasi.js index 396c94577e8e6..4d7d7c16271a0 100644 --- a/src/library_wasi.js +++ b/src/library_wasi.js @@ -449,8 +449,11 @@ var WasiLibrary = { if (!(fd in preopens)) { return {{{ cDefs.EBADF }}}; } - var preopen = preopens[fd]; - stringToUTF8Array(preopens, HEAP8, path, path_len) + var preopen_path = preopens[fd]; + stringToUTF8Array(preopen_path, HEAP8, path, path_len) +#if SYSCALL_DEBUG + dbg('fd_prestat_dir_name -> "' + preopen_path + '"'); +#endif return 0; }, diff --git a/system/lib/compiler-rt/lib/asan/asan_flags.cpp b/system/lib/compiler-rt/lib/asan/asan_flags.cpp index d4930dff5559f..6bad4c5763dbb 100644 --- a/system/lib/compiler-rt/lib/asan/asan_flags.cpp +++ b/system/lib/compiler-rt/lib/asan/asan_flags.cpp @@ -132,7 +132,7 @@ void InitializeFlags() { #define MAKE_OPTION_LOAD(parser, name) \ options = (char*)(long)EM_ASM_DOUBLE({ \ return withBuiltinMalloc(function () { \ - return stringToNewUTF8(Module[name] || 0); \ + return stringToNewUTF8(Module[name] || ""); \ }); \ }); \ parser.ParseString(options); \ diff --git a/system/lib/compiler-rt/lib/lsan/lsan.cpp b/system/lib/compiler-rt/lib/lsan/lsan.cpp index 78bc5b7241048..6f7576fcc7d25 100644 --- a/system/lib/compiler-rt/lib/lsan/lsan.cpp +++ b/system/lib/compiler-rt/lib/lsan/lsan.cpp @@ -84,7 +84,7 @@ static void InitializeFlags() { #if SANITIZER_EMSCRIPTEN char *options = (char*) EM_ASM_PTR({ return withBuiltinMalloc(function () { - return stringToNewUTF8(Module['LSAN_OPTIONS'] || 0); + return stringToNewUTF8(Module['LSAN_OPTIONS'] || ""); }); }); parser.ParseString(options); diff --git a/system/lib/compiler-rt/lib/ubsan/ubsan_flags.cpp b/system/lib/compiler-rt/lib/ubsan/ubsan_flags.cpp index 39aa638824df0..e18213cb769f4 100644 --- a/system/lib/compiler-rt/lib/ubsan/ubsan_flags.cpp +++ b/system/lib/compiler-rt/lib/ubsan/ubsan_flags.cpp @@ -79,7 +79,7 @@ void InitializeFlags() { #if SANITIZER_EMSCRIPTEN char *options = (char*) EM_ASM_PTR({ return withBuiltinMalloc(function () { - return stringToNewUTF8(Module['UBSAN_OPTIONS'] || 0); + return stringToNewUTF8(Module['UBSAN_OPTIONS'] || ""); }); }); parser.ParseString(options); From 574f4f449780f63ab97970d5d6b5625e124c7d79 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 3 Apr 2023 22:16:14 -0700 Subject: [PATCH 0099/1523] Don't memset/zero the stack region for new pthread. NFC (#19125) We had reports of slowdown when #17090 landed. Seems I overlooked that we were previously not memset'ing the stack region. This change should restore the previous performance. Fixes: #18628 --- system/lib/pthread/pthread_create.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/system/lib/pthread/pthread_create.c b/system/lib/pthread/pthread_create.c index d92d82cfc6f51..916368e634619 100644 --- a/system/lib/pthread/pthread_create.c +++ b/system/lib/pthread/pthread_create.c @@ -148,20 +148,22 @@ int __pthread_create(pthread_t* restrict res, // // 1. pthread struct (sizeof struct pthread) // 2. tls data (__builtin_wasm_tls_size()) - // 3. stack (_emscripten_default_pthread_stack_size()) - // 4. tsd pointers (__pthread_tsd_size) + // 3. tsd pointers (__pthread_tsd_size) + // 4. stack (_emscripten_default_pthread_stack_size()) size_t size = sizeof(struct pthread); if (__builtin_wasm_tls_size()) { size += __builtin_wasm_tls_size() + __builtin_wasm_tls_align() - 1; } + size += __pthread_tsd_size + TSD_ALIGN - 1; + size_t zero_size = size; if (!attr._a_stackaddr) { size += attr._a_stacksize + STACK_ALIGN - 1; } - size += __pthread_tsd_size + TSD_ALIGN - 1; - // Allocate all the data for the new thread and zero-initialize. + // Allocate all the data for the new thread and zero-initialize all parts + // except for the stack. unsigned char* block = emscripten_builtin_malloc(size); - memset(block, 0, size); + memset(block, 0, zero_size); uintptr_t offset = (uintptr_t)block; @@ -195,7 +197,14 @@ int __pthread_create(pthread_t* restrict res, offset += __builtin_wasm_tls_size(); } - // 3. stack data + // 3. tsd slots + if (__pthread_tsd_size) { + offset = ROUND_UP(offset, TSD_ALIGN); + new->tsd = (void*)offset; + offset += __pthread_tsd_size; + } + + // 4. stack data // musl stores top of the stack in pthread_t->stack (i.e. the high // end from which it grows down). if (attr._a_stackaddr) { @@ -205,13 +214,6 @@ int __pthread_create(pthread_t* restrict res, new->stack = (void*)offset; } - // 4. tsd slots - if (__pthread_tsd_size) { - offset = ROUND_UP(offset, TSD_ALIGN); - new->tsd = (void*)offset; - offset += __pthread_tsd_size; - } - // Check that we didn't use more data than we allocated. assert(offset < (uintptr_t)block + size); From 8d42854dde4a219c19f2fba2b9b6b50ac652d7a8 Mon Sep 17 00:00:00 2001 From: Derek Schuff Date: Tue, 4 Apr 2023 09:24:12 -0700 Subject: [PATCH 0100/1523] Mark 3.1.35 as released (#19129) --- ChangeLog.md | 5 ++++- emscripten-version.txt | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index a22e65ebdd71d..9f8ffe35ed5b0 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -18,8 +18,11 @@ to browse the changes between the tags. See docs/process.md for more on how version tagging works. -3.1.35 (in development) +3.1.36 (in development) ----------------------- + +3.1.35 - 04/03/23 +----------------- - The following JavaScript runtime functions were converted to JavaScript library functions: - UTF8ArrayToString diff --git a/emscripten-version.txt b/emscripten-version.txt index 95bd3806a33f8..d6c36e777536a 100644 --- a/emscripten-version.txt +++ b/emscripten-version.txt @@ -1 +1 @@ -3.1.35-git +3.1.36-git From b2f3b50b0291ed6b0e3058194b1b6db927ab4c33 Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Tue, 4 Apr 2023 10:34:43 -0700 Subject: [PATCH 0101/1523] Move proxying change to correct location in ChangeLog.md (#19132) PR #18776 updated the changelog for 3.1.32, but it should have updated the changelog for 3.1.33, which was in development at the time. --- ChangeLog.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 9f8ffe35ed5b0..e3abed28e258c 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -83,6 +83,9 @@ See docs/process.md for more on how version tagging works. - The WasmFS OPFS backend is now faster in browsers that implement [`Atomics.waitAsync`](https://caniuse.com/mdn-javascript_builtins_atomics_waitasync). (#18861) +- The `emscripten_proxy_async_with_callback` API was replaced with a simpler + `emscripten_proxy_callback` API that takes a second callback to be called if + the worker thread dies before completing the proxied work. 3.1.32 - 02/17/23 ----------------- @@ -101,9 +104,6 @@ See docs/process.md for more on how version tagging works. - Synchronous proxying functions in emscripten/proxying.h now return errors instead of hanging forever when the worker thread dies before the proxied work is finished. -- The `emscripten_proxy_async_with_callback` API was replaced with a simpler - `emscripten_proxy_callback` API that takes a second callback to be called if - the worker thread dies before completing the proxied work. 3.1.31 - 01/26/23 ----------------- From 6ba6f5ce9b65da7dd552eddefcde525007d5ab54 Mon Sep 17 00:00:00 2001 From: Brendan Dahl Date: Wed, 5 Apr 2023 11:35:17 -0700 Subject: [PATCH 0102/1523] Mark async imports in library files instead hardcoded list. (#19134) --- emcc.py | 8 +------- src/embind/emval.js | 1 + src/library_async.js | 5 +++++ src/library_dylink.js | 3 +++ src/library_idbstore.js | 6 ++++++ src/library_sdl.js | 1 + 6 files changed, 17 insertions(+), 7 deletions(-) diff --git a/emcc.py b/emcc.py index 6613e15bc5484..e80dd28430538 100755 --- a/emcc.py +++ b/emcc.py @@ -101,13 +101,7 @@ } DEFAULT_ASYNCIFY_IMPORTS = [ - 'emscripten_wget', 'emscripten_wget_data', 'emscripten_idb_load', - 'emscripten_idb_store', 'emscripten_idb_delete', 'emscripten_idb_exists', - 'emscripten_idb_load_blob', 'emscripten_idb_store_blob', 'SDL_Delay', - 'emscripten_scan_registers', 'emscripten_lazy_load_code', - 'emscripten_fiber_swap', '__load_secondary_module', - 'wasi_snapshot_preview1.fd_sync', '__wasi_fd_sync', '_emval_await', - '_dlopen_js', '__asyncjs__*' + 'wasi_snapshot_preview1.fd_sync', '__wasi_fd_sync', '__asyncjs__*' ] DEFAULT_ASYNCIFY_EXPORTS = [ diff --git a/src/embind/emval.js b/src/embind/emval.js index a3ae0862ea797..304de99360a1a 100644 --- a/src/embind/emval.js +++ b/src/embind/emval.js @@ -564,6 +564,7 @@ var LibraryEmVal = { #if ASYNCIFY _emval_await__deps: ['$Emval', '$Asyncify'], + _emval_await__async: true, _emval_await: function(promise) { return Asyncify.handleAsync(() => { promise = Emval.toValue(promise); diff --git a/src/library_async.js b/src/library_async.js index 6df67bed9acb6..8ee81652c4e5d 100644 --- a/src/library_async.js +++ b/src/library_async.js @@ -462,6 +462,7 @@ mergeInto(LibraryManager.library, { }, emscripten_wget__deps: ['$Browser', '$PATH_FS', '$FS'], + emscripten_wget__async: true, emscripten_wget: function(url, file) { return Asyncify.handleSleep((wakeUp) => { var _url = UTF8ToString(url); @@ -489,6 +490,7 @@ mergeInto(LibraryManager.library, { }, emscripten_wget_data__deps: ['$asyncLoad', 'malloc'], + emscripten_wget_data__async: true, emscripten_wget_data: function(url, pbuffer, pnum, perror) { return Asyncify.handleSleep((wakeUp) => { asyncLoad(UTF8ToString(url), (byteArray) => { @@ -507,6 +509,7 @@ mergeInto(LibraryManager.library, { }, emscripten_scan_registers__deps: ['$safeSetTimeout'], + emscripten_scan_registers__async: true, emscripten_scan_registers: function(func) { return Asyncify.handleSleep((wakeUp) => { // We must first unwind, so things are spilled to the stack. Then while @@ -523,6 +526,7 @@ mergeInto(LibraryManager.library, { }, emscripten_lazy_load_code__sig: 'v', + emscripten_lazy_load_code__async: true, emscripten_lazy_load_code: function() { return Asyncify.handleSleep((wakeUp) => { // Update the expected wasm binary file to be the lazy one. @@ -607,6 +611,7 @@ mergeInto(LibraryManager.library, { }, emscripten_fiber_swap__deps: ["$Asyncify", "$Fibers"], + emscripten_fiber_swap__async: true, emscripten_fiber_swap: function(oldFiber, newFiber) { if (ABORT) return; #if ASYNCIFY_DEBUG diff --git a/src/library_dylink.js b/src/library_dylink.js index c440de7479227..1ac61cb7192db 100644 --- a/src/library_dylink.js +++ b/src/library_dylink.js @@ -1088,6 +1088,9 @@ var LibraryDylink = { }, _dlopen_js__deps: ['$dlopenInternal'], +#if ASYNCIFY + _dlopen_js__async: true, +#endif _dlopen_js: function(handle) { #if ASYNCIFY return Asyncify.handleSleep(function(wakeUp) { diff --git a/src/library_idbstore.js b/src/library_idbstore.js index e6fe74f67ca02..4245866953e7d 100644 --- a/src/library_idbstore.js +++ b/src/library_idbstore.js @@ -55,6 +55,7 @@ var LibraryIDBStore = { }, #if ASYNCIFY + emscripten_idb_load__async: true, emscripten_idb_load: function(db, id, pbuffer, pnum, perror) { Asyncify.handleSleep(function(wakeUp) { IDBStore.getFile(UTF8ToString(db), UTF8ToString(id), function(error, byteArray) { @@ -72,6 +73,7 @@ var LibraryIDBStore = { }); }); }, + emscripten_idb_store__async: true, emscripten_idb_store: function(db, id, ptr, num, perror) { Asyncify.handleSleep(function(wakeUp) { IDBStore.setFile(UTF8ToString(db), UTF8ToString(id), new Uint8Array(HEAPU8.subarray(ptr, ptr+num)), function(error) { @@ -80,6 +82,7 @@ var LibraryIDBStore = { }); }); }, + emscripten_idb_delete__async: true, emscripten_idb_delete: function(db, id, perror) { Asyncify.handleSleep(function(wakeUp) { IDBStore.deleteFile(UTF8ToString(db), UTF8ToString(id), function(error) { @@ -88,6 +91,7 @@ var LibraryIDBStore = { }); }); }, + emscripten_idb_exists__async: true, emscripten_idb_exists: function(db, id, pexists, perror) { Asyncify.handleSleep(function(wakeUp) { IDBStore.existsFile(UTF8ToString(db), UTF8ToString(id), function(error, exists) { @@ -98,6 +102,7 @@ var LibraryIDBStore = { }); }, // extra worker methods - proxied + emscripten_idb_load_blob__async: true, emscripten_idb_load_blob: function(db, id, pblob, perror) { Asyncify.handleSleep(function(wakeUp) { assert(!IDBStore.pending); @@ -123,6 +128,7 @@ var LibraryIDBStore = { }); }); }, + emscripten_idb_store_blob__async: true, emscripten_idb_store_blob: function(db, id, ptr, num, perror) { Asyncify.handleSleep(function(wakeUp) { assert(!IDBStore.pending); diff --git a/src/library_sdl.js b/src/library_sdl.js index f449677e226ad..9154fb688b91e 100644 --- a/src/library_sdl.js +++ b/src/library_sdl.js @@ -1730,6 +1730,7 @@ var LibrarySDL = { }, #else SDL_Delay__deps: ['emscripten_sleep'], + SDL_Delay__async: true, SDL_Delay: function(delay) { _emscripten_sleep(delay); }, From dc15c7abe60a8d46ed8a758716b90b8368a18210 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 5 Apr 2023 15:05:02 -0700 Subject: [PATCH 0103/1523] Update a test for a binaryen text format change (#19137) --- test/test_other.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_other.py b/test/test_other.py index fb88902dcd359..394722d754b06 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -12894,7 +12894,7 @@ def test_extended_const(self): self.do_runf(test_file('hello_world.c'), emcc_args=['-sEXPORTED_FUNCTIONS=_main,___stdout_used', '-mextended-const', '-sMAIN_MODULE=2']) wat = self.get_wasm_text('hello_world.wasm') # Test that extended-const expressions are used in the data segments. - self.assertTrue(re.search(r'\(data \(i32.add\s+\(global.get \$\S+\)\s+\(i32.const \d+\)', wat)) + self.assertTrue(re.search(r'\(data (\$\S+ )?\(i32.add\s+\(global.get \$\S+\)\s+\(i32.const \d+\)', wat)) # Test that extended-const expressions are used in at least one global initializer. self.assertTrue(re.search(r'\(global \$\S+ i32 \(i32.add\s+\(global.get \$\S+\)\s+\(i32.const \d+\)', wat)) From 82e5f273c18356b0b68c44f710aa44a39bda341b Mon Sep 17 00:00:00 2001 From: walkingeyerobot Date: Wed, 5 Apr 2023 18:05:38 -0400 Subject: [PATCH 0104/1523] [Embind] Mark optional async argument (#19133) This avoids a closure compiler error. --- src/embind/embind.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 85e71fd87a79c..35f8b2d4e70ab 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -944,7 +944,7 @@ var LibraryEmbind = { '$Asyncify', #endif ], - $craftInvokerFunction: function(humanName, argTypes, classType, cppInvokerFunc, cppTargetFunc, isAsync) { + $craftInvokerFunction: function(humanName, argTypes, classType, cppInvokerFunc, cppTargetFunc, /** boolean= */ isAsync) { // humanName: a human-readable string name for the function to be generated. // argTypes: An array that contains the embind type objects for all types in the function signature. // argTypes[0] is the type object for the function return value. @@ -953,6 +953,7 @@ var LibraryEmbind = { // classType: The embind type object for the class to be bound, or null if this is not a method of a class. // cppInvokerFunc: JS Function object to the C++-side function that interops into C++ code. // cppTargetFunc: Function pointer (an integer to FUNCTION_TABLE) to the target C++ function the cppInvokerFunc will end up calling. + // isAsync: Optional. If true, returns an async function. Async bindings are only supported with JSPI. var argCount = argTypes.length; if (argCount < 2) { From 117af3408d9c0ad4f74858c1e3ab3397ea49fb46 Mon Sep 17 00:00:00 2001 From: Brendan Dahl Date: Wed, 5 Apr 2023 15:35:23 -0700 Subject: [PATCH 0105/1523] Support multiple arguments for dbg(). (#19094) This seems to be already be used with multiple arguments and the debug output was getting cut off. --- src/runtime_debug.js | 4 ++-- test/test_other.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/runtime_debug.js b/src/runtime_debug.js index 96663a21659d9..5a627a2634561 100644 --- a/src/runtime_debug.js +++ b/src/runtime_debug.js @@ -133,11 +133,11 @@ function dbg(text) { // Avoid using the console for debugging in multi-threaded node applications // See https://github.com/emscripten-core/emscripten/issues/14804 if (ENVIRONMENT_IS_NODE) { - fs.writeSync(2, text + '\n'); + fs.writeSync(2, Array.from(arguments).join(' ') + '\n'); } else #endif // TODO(sbc): Make this configurable somehow. Its not always convenient for // logging to show up as errors. - console.error(text); + console.error.apply(console, arguments); } #endif diff --git a/test/test_other.py b/test/test_other.py index 394722d754b06..90f80c5309eb7 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -11786,7 +11786,7 @@ def test_split_module(self, customLoader, jspi): if jspi: self.require_v8() self.v8_args.append('--experimental-wasm-stack-switching') - self.emcc_args += ['-g', '-sASYNCIFY_DEBUG', '-sASYNCIFY=2', '-sASYNCIFY_EXPORTS=[\'say_hello\']'] + self.emcc_args += ['-g', '-sASYNCIFY=2', '-sASYNCIFY_EXPORTS=[\'say_hello\']'] self.emcc_args += ['-sEXPORTED_FUNCTIONS=_malloc,_free'] output = self.do_other_test('test_split_module.c') if jspi: From 12e2c964a03f023a62db1b4593f2488e5e214da1 Mon Sep 17 00:00:00 2001 From: Brendan Dahl Date: Wed, 5 Apr 2023 16:13:36 -0700 Subject: [PATCH 0106/1523] Support OPFS on the main thread with JSPI. (#19063) The OPFS backend will now use async reaad/writes when used on the main thread. The ProxyWorker is stubbed out and calls are directly dispatched into JS. The JS side uses a new FileSystemAsyncAccessHandle class that matches the sync version of the class, but has async read/writes. Hopefully, we can one day replace that with something from the platform. --- src/library_wasmfs_opfs.js | 155 +++++++++++++++----- src/parseTools.js | 8 + system/lib/wasmfs/backends/opfs_backend.cpp | 45 ++++-- test/test_browser.py | 10 +- 4 files changed, 170 insertions(+), 48 deletions(-) diff --git a/src/library_wasmfs_opfs.js b/src/library_wasmfs_opfs.js index 9aeb35d1ebe45..b1e1b39844ece 100644 --- a/src/library_wasmfs_opfs.js +++ b/src/library_wasmfs_opfs.js @@ -14,14 +14,68 @@ mergeInto(LibraryManager.library, { $wasmfsOPFSBlobs__deps: ["$HandleAllocator"], $wasmfsOPFSBlobs: "new HandleAllocator()", - _wasmfs_opfs_init_root_directory__deps: ['$wasmfsOPFSDirectoryHandles'], +#if !USE_PTHREADS + // OPFS will only be used on modern browsers that supports JS classes. + $FileSystemAsyncAccessHandle: class FileSystemAsyncAccessHandle { + // This class implements the same interface as the sync version, but has + // async reads and writes. Hopefully this will one day be implemented by the + // platform so we can remove it. + constructor(handle) { + this.handle = handle; + } + async close() {} + async flush() {} + async getSize() { + let file = await this.handle.getFile(); + return file.size; + } + async read(buffer, options = { at: 0 }) { + let file = await this.handle.getFile(); + // The end position may be past the end of the file, but slice truncates + // it. + let slice = await file.slice(options.at, options.at + buffer.length); + let fileBuffer = await slice.arrayBuffer(); + let array = new Uint8Array(fileBuffer); + buffer.set(array); + return array.length; + } + async write(buffer, options = { at: 0 }) { + let writable = await this.handle.createWritable({keepExistingData: true}); + await writable.write({ type: 'write', position: options.at, data: buffer }); + await writable.close(); + return buffer.length; + } + async truncate(size) { + let writable = await this.handle.createWritable({keepExistingData: true}); + await writable.truncate(size); + await writable.close(); + } + }, + + $wasmfsOPFSCreateAsyncAccessHandle__deps: ['$FileSystemAsyncAccessHandle'], + $wasmfsOPFSCreateAsyncAccessHandle: function(fileHandle) { + return new FileSystemAsyncAccessHandle(fileHandle); + }, +#endif + + $wasmfsOPFSProxyFinish: function(ctx) { + // When using pthreads the proxy needs to know when the work is finished. + // When used with JSPI the work will be executed in an async block so there + // is no need to notify when done. +#if USE_PTHREADS + _emscripten_proxy_finish(ctx); +#endif + }, + + _wasmfs_opfs_init_root_directory__sig: 'vp', + _wasmfs_opfs_init_root_directory__deps: ['$wasmfsOPFSDirectoryHandles', '$wasmfsOPFSProxyFinish'], _wasmfs_opfs_init_root_directory: async function(ctx) { // allocated.length starts off as 1 since 0 is a reserved handle if (wasmfsOPFSDirectoryHandles.allocated.length == 1) { let root = await navigator.storage.getDirectory(); wasmfsOPFSDirectoryHandles.allocated.push(root); } - _emscripten_proxy_finish(ctx); + wasmfsOPFSProxyFinish(ctx); }, // Return the file ID for the file with `name` under `parent`, creating it if @@ -74,8 +128,9 @@ mergeInto(LibraryManager.library, { return wasmfsOPFSDirectoryHandles.allocate(childHandle); }, + _wasmfs_opfs_get_child__sig: 'vpippp', _wasmfs_opfs_get_child__deps: ['$wasmfsOPFSGetOrCreateFile', - '$wasmfsOPFSGetOrCreateDir'], + '$wasmfsOPFSGetOrCreateDir', '$wasmfsOPFSProxyFinish'], _wasmfs_opfs_get_child: async function(ctx, parent, namePtr, childTypePtr, childIDPtr) { let name = UTF8ToString(namePtr); @@ -87,10 +142,11 @@ mergeInto(LibraryManager.library, { } {{{ makeSetValue('childTypePtr', 0, 'childType', 'i32') }}}; {{{ makeSetValue('childIDPtr', 0, 'childID', 'i32') }}}; - _emscripten_proxy_finish(ctx); + wasmfsOPFSProxyFinish(ctx); }, - _wasmfs_opfs_get_entries__deps: [], + _wasmfs_opfs_get_entries__sig: 'vpipp', + _wasmfs_opfs_get_entries__deps: ['$wasmfsOPFSProxyFinish'], _wasmfs_opfs_get_entries: async function(ctx, dirID, entriesPtr, errPtr) { let dirHandle = wasmfsOPFSDirectoryHandles.get(dirID); @@ -111,28 +167,31 @@ mergeInto(LibraryManager.library, { let err = -{{{ cDefs.EIO }}}; {{{ makeSetValue('errPtr', 0, 'err', 'i32') }}}; } - _emscripten_proxy_finish(ctx); + wasmfsOPFSProxyFinish(ctx); }, - _wasmfs_opfs_insert_file__deps: ['$wasmfsOPFSGetOrCreateFile'], + _wasmfs_opfs_insert_file__sig: 'vpipp', + _wasmfs_opfs_insert_file__deps: ['$wasmfsOPFSGetOrCreateFile', '$wasmfsOPFSProxyFinish'], _wasmfs_opfs_insert_file: async function(ctx, parent, namePtr, childIDPtr) { let name = UTF8ToString(namePtr); let childID = await wasmfsOPFSGetOrCreateFile(parent, name, true); {{{ makeSetValue('childIDPtr', 0, 'childID', 'i32') }}}; - _emscripten_proxy_finish(ctx); + wasmfsOPFSProxyFinish(ctx); }, - _wasmfs_opfs_insert_directory__deps: ['$wasmfsOPFSGetOrCreateDir'], + _wasmfs_opfs_insert_directory__sig: 'vpipp', + _wasmfs_opfs_insert_directory__deps: ['$wasmfsOPFSGetOrCreateDir', '$wasmfsOPFSProxyFinish'], _wasmfs_opfs_insert_directory: async function(ctx, parent, namePtr, childIDPtr) { let name = UTF8ToString(namePtr); let childID = await wasmfsOPFSGetOrCreateDir(parent, name, true); {{{ makeSetValue('childIDPtr', 0, 'childID', 'i32') }}}; - _emscripten_proxy_finish(ctx); + wasmfsOPFSProxyFinish(ctx); }, + _wasmfs_opfs_move__sig: 'vpiipp', _wasmfs_opfs_move__deps: ['$wasmfsOPFSFileHandles', - '$wasmfsOPFSDirectoryHandles'], + '$wasmfsOPFSDirectoryHandles', '$wasmfsOPFSProxyFinish'], _wasmfs_opfs_move: async function(ctx, fileID, newDirID, namePtr, errPtr) { let name = UTF8ToString(namePtr); let fileHandle = wasmfsOPFSFileHandles.get(fileID); @@ -143,10 +202,11 @@ mergeInto(LibraryManager.library, { let err = -{{{ cDefs.EIO }}}; {{{ makeSetValue('errPtr', 0, 'err', 'i32') }}}; } - _emscripten_proxy_finish(ctx); + wasmfsOPFSProxyFinish(ctx); }, - _wasmfs_opfs_remove_child__deps: ['$wasmfsOPFSDirectoryHandles'], + _wasmfs_opfs_remove_child__sig: 'vpipp', + _wasmfs_opfs_remove_child__deps: ['$wasmfsOPFSDirectoryHandles', '$wasmfsOPFSProxyFinish'], _wasmfs_opfs_remove_child: async function(ctx, dirID, namePtr, errPtr) { let name = UTF8ToString(namePtr); let dirHandle = wasmfsOPFSDirectoryHandles.get(dirID); @@ -156,26 +216,34 @@ mergeInto(LibraryManager.library, { let err = -{{{ cDefs.EIO }}}; {{{ makeSetValue('errPtr', 0, 'err', 'i32') }}}; } - _emscripten_proxy_finish(ctx); + wasmfsOPFSProxyFinish(ctx); }, + _wasmfs_opfs_free_file__sig: 'vi', _wasmfs_opfs_free_file__deps: ['$wasmfsOPFSFileHandles'], _wasmfs_opfs_free_file: function(fileID) { wasmfsOPFSFileHandles.free(fileID); }, + _wasmfs_opfs_free_directory__sig: 'vi', _wasmfs_opfs_free_directory__deps: ['$wasmfsOPFSDirectoryHandles'], _wasmfs_opfs_free_directory: function(dirID) { wasmfsOPFSDirectoryHandles.free(dirID); }, + _wasmfs_opfs_open_access__sig: 'vpip', _wasmfs_opfs_open_access__deps: ['$wasmfsOPFSFileHandles', - '$wasmfsOPFSAccessHandles'], + '$wasmfsOPFSAccessHandles', '$wasmfsOPFSProxyFinish', +#if !USE_PTHREADS + '$wasmfsOPFSCreateAsyncAccessHandle' +#endif + ], _wasmfs_opfs_open_access: async function(ctx, fileID, accessIDPtr) { let fileHandle = wasmfsOPFSFileHandles.get(fileID); let accessID; try { let accessHandle; +#if USE_PTHREADS // TODO: Remove this once the Access Handles API has settled. if (FileSystemFileHandle.prototype.createSyncAccessHandle.length == 0) { accessHandle = await fileHandle.createSyncAccessHandle(); @@ -183,6 +251,9 @@ mergeInto(LibraryManager.library, { accessHandle = await fileHandle.createSyncAccessHandle( {mode: "in-place"}); } +#else + accessHandle = await wasmfsOPFSCreateAsyncAccessHandle(fileHandle); +#endif accessID = wasmfsOPFSAccessHandles.allocate(accessHandle); } catch (e) { // TODO: Presumably only one of these will appear in the final API? @@ -197,11 +268,12 @@ mergeInto(LibraryManager.library, { } } {{{ makeSetValue('accessIDPtr', 0, 'accessID', 'i32') }}}; - _emscripten_proxy_finish(ctx); + wasmfsOPFSProxyFinish(ctx); }, + _wasmfs_opfs_open_blob__sig: 'vpip', _wasmfs_opfs_open_blob__deps: ['$wasmfsOPFSFileHandles', - '$wasmfsOPFSBlobs'], + '$wasmfsOPFSBlobs', '$wasmfsOPFSProxyFinish'], _wasmfs_opfs_open_blob: async function(ctx, fileID, blobIDPtr) { let fileHandle = wasmfsOPFSFileHandles.get(fileID); let blobID; @@ -219,10 +291,11 @@ mergeInto(LibraryManager.library, { } } {{{ makeSetValue('blobIDPtr', 0, 'blobID', 'i32') }}}; - _emscripten_proxy_finish(ctx); + wasmfsOPFSProxyFinish(ctx); }, - _wasmfs_opfs_close_access__deps: ['$wasmfsOPFSAccessHandles'], + _wasmfs_opfs_close_access__sig: 'vpip', + _wasmfs_opfs_close_access__deps: ['$wasmfsOPFSAccessHandles', '$wasmfsOPFSProxyFinish'], _wasmfs_opfs_close_access: async function(ctx, accessID, errPtr) { let accessHandle = wasmfsOPFSAccessHandles.get(accessID); try { @@ -232,20 +305,22 @@ mergeInto(LibraryManager.library, { {{{ makeSetValue('errPtr', 0, 'err', 'i32') }}}; } wasmfsOPFSAccessHandles.free(accessID); - _emscripten_proxy_finish(ctx); + wasmfsOPFSProxyFinish(ctx); }, + _wasmfs_opfs_close_blob__sig: 'vi', _wasmfs_opfs_close_blob__deps: ['$wasmfsOPFSBlobs'], _wasmfs_opfs_close_blob: function(blobID) { wasmfsOPFSBlobs.free(blobID); }, + _wasmfs_opfs_read_access__sig: 'iipii', _wasmfs_opfs_read_access__deps: ['$wasmfsOPFSAccessHandles'], - _wasmfs_opfs_read_access: function(accessID, bufPtr, len, pos) { + _wasmfs_opfs_read_access: {{{ asyncIf(!USE_PTHREADS) }}} function(accessID, bufPtr, len, pos) { let accessHandle = wasmfsOPFSAccessHandles.get(accessID); let data = HEAPU8.subarray(bufPtr, bufPtr + len); try { - return accessHandle.read(data, {at: pos}); + return {{{ awaitIf(!USE_PTHREADS) }}} accessHandle.read(data, {at: pos}); } catch (e) { if (e.name == "TypeError") { return -{{{ cDefs.EINVAL }}}; @@ -257,7 +332,8 @@ mergeInto(LibraryManager.library, { } }, - _wasmfs_opfs_read_blob__deps: ['$wasmfsOPFSBlobs'], + _wasmfs_opfs_read_blob__sig: 'ipipiip', + _wasmfs_opfs_read_blob__deps: ['$wasmfsOPFSBlobs', '$wasmfsOPFSProxyFinish'], _wasmfs_opfs_read_blob: async function(ctx, blobID, bufPtr, len, pos, nreadPtr) { let blob = wasmfsOPFSBlobs.get(blobID); let slice = blob.slice(pos, pos + len); @@ -283,15 +359,16 @@ mergeInto(LibraryManager.library, { } {{{ makeSetValue('nreadPtr', 0, 'nread', 'i32') }}}; - _emscripten_proxy_finish(ctx); + wasmfsOPFSProxyFinish(ctx); }, + _wasmfs_opfs_write_access__sig: 'iipii', _wasmfs_opfs_write_access__deps: ['$wasmfsOPFSAccessHandles'], - _wasmfs_opfs_write_access: function(accessID, bufPtr, len, pos) { + _wasmfs_opfs_write_access: {{{ asyncIf(!USE_PTHREADS) }}} function(accessID, bufPtr, len, pos) { let accessHandle = wasmfsOPFSAccessHandles.get(accessID); let data = HEAPU8.subarray(bufPtr, bufPtr + len); try { - return accessHandle.write(data, {at: pos}); + return {{{ awaitIf(!USE_PTHREADS) }}} accessHandle.write(data, {at: pos}); } catch (e) { if (e.name == "TypeError") { return -{{{ cDefs.EINVAL }}}; @@ -303,7 +380,8 @@ mergeInto(LibraryManager.library, { } }, - _wasmfs_opfs_get_size_access__deps: ['$wasmfsOPFSAccessHandles'], + _wasmfs_opfs_get_size_access__sig: 'vpip', + _wasmfs_opfs_get_size_access__deps: ['$wasmfsOPFSAccessHandles', '$wasmfsOPFSProxyFinish'], _wasmfs_opfs_get_size_access: async function(ctx, accessID, sizePtr) { let accessHandle = wasmfsOPFSAccessHandles.get(accessID); let size; @@ -313,16 +391,18 @@ mergeInto(LibraryManager.library, { size = -{{{ cDefs.EIO }}}; } {{{ makeSetValue('sizePtr', 0, 'size', 'i64') }}}; - _emscripten_proxy_finish(ctx); + wasmfsOPFSProxyFinish(ctx); }, + _wasmfs_opfs_get_size_blob__sig: 'ii', _wasmfs_opfs_get_size_blob__deps: ['$wasmfsOPFSBlobs'], _wasmfs_opfs_get_size_blob: function(blobID) { // This cannot fail. return wasmfsOPFSBlobs.get(blobID).size; }, - _wasmfs_opfs_get_size_file__deps: ['$wasmfsOPFSFileHandles'], + _wasmfs_opfs_get_size_file__sig: 'vpip', + _wasmfs_opfs_get_size_file__deps: ['$wasmfsOPFSFileHandles', '$wasmfsOPFSProxyFinish'], _wasmfs_opfs_get_size_file: async function(ctx, fileID, sizePtr) { let fileHandle = wasmfsOPFSFileHandles.get(fileID); let size; @@ -332,10 +412,11 @@ mergeInto(LibraryManager.library, { size = -{{{ cDefs.EIO }}}; } {{{ makeSetValue('sizePtr', 0, 'size', 'i64') }}}; - _emscripten_proxy_finish(ctx); + wasmfsOPFSProxyFinish(ctx); }, - _wasmfs_opfs_set_size_access__deps: ['$wasmfsOPFSAccessHandles'], + _wasmfs_opfs_set_size_access__sig: 'vpijp', + _wasmfs_opfs_set_size_access__deps: ['$wasmfsOPFSAccessHandles', '$wasmfsOPFSProxyFinish'], _wasmfs_opfs_set_size_access: async function(ctx, accessID, {{{ defineI64Param('size') }}}, errPtr) { @@ -347,10 +428,11 @@ mergeInto(LibraryManager.library, { let err = -{{{ cDefs.EIO }}}; {{{ makeSetValue('errPtr', 0, 'err', 'i32') }}}; } - _emscripten_proxy_finish(ctx); + wasmfsOPFSProxyFinish(ctx); }, - _wasmfs_opfs_set_size_file__deps: ['$wasmfsOPFSFileHandles'], + _wasmfs_opfs_set_size_file__sig: 'vpijp', + _wasmfs_opfs_set_size_file__deps: ['$wasmfsOPFSFileHandles', '$wasmfsOPFSProxyFinish'], _wasmfs_opfs_set_size_file: async function(ctx, fileID, {{{ defineI64Param('size') }}}, errPtr) { @@ -364,10 +446,11 @@ mergeInto(LibraryManager.library, { let err = -{{{ cDefs.EIO }}}; {{{ makeSetValue('errPtr', 0, 'err', 'i32') }}}; } - _emscripten_proxy_finish(ctx); + wasmfsOPFSProxyFinish(ctx); }, - _wasmfs_opfs_flush_access__deps: ['$wasmfsOPFSAccessHandles'], + _wasmfs_opfs_flush_access__sig: 'vpip', + _wasmfs_opfs_flush_access__deps: ['$wasmfsOPFSAccessHandles', '$wasmfsOPFSProxyFinish'], _wasmfs_opfs_flush_access: async function(ctx, accessID, errPtr) { let accessHandle = wasmfsOPFSAccessHandles.get(accessID); try { @@ -376,6 +459,6 @@ mergeInto(LibraryManager.library, { let err = -{{{ cDefs.EIO }}}; {{{ makeSetValue('errPtr', 0, 'err', 'i32') }}}; } - _emscripten_proxy_finish(ctx); + wasmfsOPFSProxyFinish(ctx); } }); diff --git a/src/parseTools.js b/src/parseTools.js index b8a16c34b5411..02b70dc394d80 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -917,6 +917,14 @@ function addReadyPromiseAssertions(promise) { });`; } +function asyncIf(condition) { + return condition ? 'async' : ''; +} + +function awaitIf(condition) { + return condition ? 'await' : ''; +} + function makeMalloc(source, param) { if (hasExportedSymbol('malloc')) { return `_malloc(${param})`; diff --git a/system/lib/wasmfs/backends/opfs_backend.cpp b/system/lib/wasmfs/backends/opfs_backend.cpp index d77d5b1de50ea..f089520a4f877 100644 --- a/system/lib/wasmfs/backends/opfs_backend.cpp +++ b/system/lib/wasmfs/backends/opfs_backend.cpp @@ -118,6 +118,32 @@ void _wasmfs_opfs_flush_access(em_proxying_ctx* ctx, int access_id, int* err); namespace { using ProxyWorker = emscripten::ProxyWorker; +using ProxyingQueue = emscripten::ProxyingQueue; + +class Worker { +public: +#ifdef __EMSCRIPTEN_PTHREADS__ + ProxyWorker proxy; + + template + void operator()(T func) { + proxy(func); + } +#else + // When used with JSPI on the main thread the various wasmfs_opfs_* functions + // can be directly executed since they are all async. + template + void operator()(T func) { + if constexpr (std::is_invocable_v) { + // TODO: Find a way to remove this, since it's unused. + ProxyingQueue::ProxyingCtx p; + func(p); + } else { + func(); + } + } +#endif +}; class OpenState { public: @@ -131,7 +157,7 @@ class OpenState { public: Kind getKind() { return kind; } - int open(ProxyWorker& proxy, int fileID, oflags_t flags) { + int open(Worker& proxy, int fileID, oflags_t flags) { if (kind == None) { assert(openCount == 0); switch (flags) { @@ -175,7 +201,7 @@ class OpenState { return 0; } - int close(ProxyWorker& proxy) { + int close(Worker& proxy) { // TODO: Downgrade to Blob access once the last writable file descriptor has // been closed. int err = 0; @@ -214,11 +240,11 @@ class OpenState { class OPFSFile : public DataFile { public: - ProxyWorker& proxy; + Worker& proxy; int fileID; OpenState state; - OPFSFile(mode_t mode, backend_t backend, int fileID, ProxyWorker& proxy) + OPFSFile(mode_t mode, backend_t backend, int fileID, Worker& proxy) : DataFile(mode, backend), proxy(proxy), fileID(fileID) {} ~OPFSFile() override { @@ -335,12 +361,12 @@ class OPFSFile : public DataFile { class OPFSDirectory : public Directory { public: - ProxyWorker& proxy; + Worker& proxy; // The ID of this directory in the JS library. int dirID = 0; - OPFSDirectory(mode_t mode, backend_t backend, int dirID, ProxyWorker& proxy) + OPFSDirectory(mode_t mode, backend_t backend, int dirID, Worker& proxy) : Directory(mode, backend), proxy(proxy), dirID(dirID) {} ~OPFSDirectory() override { @@ -445,7 +471,7 @@ class OPFSDirectory : public Directory { class OPFSBackend : public Backend { public: - ProxyWorker proxy; + Worker proxy; std::shared_ptr createFile(mode_t mode) override { // No way to support a raw file without a parent directory. @@ -472,8 +498,9 @@ extern "C" { backend_t wasmfs_create_opfs_backend() { // ProxyWorker cannot safely be synchronously spawned from the main browser // thread. See comment in thread_utils.h for more details. - assert(!emscripten_is_main_browser_thread() && - "Cannot safely create OPFS backend on main browser thread"); + assert(!emscripten_is_main_browser_thread() || emscripten_has_asyncify() == 2 && + "Cannot safely create OPFS backend on main browser thread without JSPI"); + return wasmFS.addBackend(std::make_unique()); } diff --git a/test/test_browser.py b/test/test_browser.py index 4aa8dfaae6e06..36e2e38825569 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -5397,11 +5397,15 @@ def test_wasmfs_fetch_backend(self, args): args=['-sWASMFS', '-pthread', '-sPROXY_TO_PTHREAD', '-sINITIAL_MEMORY=32MB', '--js-library', test_file('wasmfs/wasmfs_fetch.js')] + args) - @requires_threads @no_firefox('no OPFS support yet') - def test_wasmfs_opfs(self): + @parameterized({ + '': (['-pthread', '-sPROXY_TO_PTHREAD'],), + 'jspi': (['-Wno-experimental', '-sASYNCIFY=2'],), + }) + @requires_threads + def test_wasmfs_opfs(self, args): test = test_file('wasmfs/wasmfs_opfs.c') - args = ['-sWASMFS', '-pthread', '-sPROXY_TO_PTHREAD', '-O3'] + args = ['-sWASMFS', '-O3'] + args self.btest_exit(test, args=args + ['-DWASMFS_SETUP']) self.btest_exit(test, args=args + ['-DWASMFS_RESUME']) From 7d8c940ad0afd6d67ecb732a633ce0813bda1c53 Mon Sep 17 00:00:00 2001 From: Brendan Dahl Date: Fri, 7 Apr 2023 08:47:37 -0700 Subject: [PATCH 0107/1523] Remove unneeded asyncify imports/exports for JSPI mode. (#19136) --- emcc.py | 2 +- emscripten.py | 4 ++-- src/library.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/emcc.py b/emcc.py index e80dd28430538..ccfb59bc4f3a2 100755 --- a/emcc.py +++ b/emcc.py @@ -2110,7 +2110,7 @@ def phase_linker_setup(options, state, newargs): '__stack_pointer', ] - if settings.ASYNCIFY: + if settings.ASYNCIFY == 1: settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += [ '__asyncify_state', '__asyncify_data' diff --git a/emscripten.py b/emscripten.py index 008d42ea9eaed..935d8212e11d8 100644 --- a/emscripten.py +++ b/emscripten.py @@ -314,7 +314,7 @@ def emscript(in_wasm, out_wasm, outfile_js, memfile): if settings.RELOCATABLE and settings.MEMORY64 == 2: metadata.imports += ['__memory_base32'] - if settings.ASYNCIFY: + if settings.ASYNCIFY == 1: metadata.exports += ['asyncify_start_unwind', 'asyncify_stop_unwind', 'asyncify_start_rewind', 'asyncify_stop_rewind'] update_settings_glue(out_wasm, metadata) @@ -365,7 +365,7 @@ def emscript(in_wasm, out_wasm, outfile_js, memfile): if settings.INITIAL_TABLE == -1: settings.INITIAL_TABLE = dylink_sec.table_size + 1 - if settings.ASYNCIFY: + if settings.ASYNCIFY == 1: metadata.imports += ['__asyncify_state', '__asyncify_data'] if metadata.invokeFuncs: diff --git a/src/library.js b/src/library.js index df932af4e8a69..f38c244d972f2 100644 --- a/src/library.js +++ b/src/library.js @@ -3623,7 +3623,7 @@ mergeInto(LibraryManager.library, { #if SUPPORT_LONGJMP == 'wasm' __c_longjmp: "new WebAssembly.Tag({'parameters': ['{{{ POINTER_WASM_TYPE }}}']})", #endif -#if ASYNCIFY +#if ASYNCIFY == 1 __asyncify_state: "new WebAssembly.Global({'value': 'i32', 'mutable': true}, 0)", __asyncify_data: "new WebAssembly.Global({'value': 'i32', 'mutable': true}, 0)", #endif From cc5a988c703405bc7f67149585178084a12a6713 Mon Sep 17 00:00:00 2001 From: Jesse Wright <63333554+jeswr@users.noreply.github.com> Date: Sat, 8 Apr 2023 02:02:51 +1000 Subject: [PATCH 0108/1523] Use direct link for Dynamic Linking in compiler errors (#19146) --- src/library_dylink.js | 2 +- test/test_other.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/library_dylink.js b/src/library_dylink.js index 1ac61cb7192db..d19669c1dfaeb 100644 --- a/src/library_dylink.js +++ b/src/library_dylink.js @@ -6,7 +6,7 @@ * Dynamic library loading */ -var dlopenMissingError = "'To use dlopen, you need enable dynamic linking, see https://github.com/emscripten-core/emscripten/wiki/Linking'" +var dlopenMissingError = "'To use dlopen, you need enable dynamic linking, see https://emscripten.org/docs/compiling/Dynamic-Linking.html'" var LibraryDylink = { #if RELOCATABLE diff --git a/test/test_other.py b/test/test_other.py index 90f80c5309eb7..9ca7e4efe0289 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -12297,13 +12297,13 @@ def test_unimplemented_syscalls_dlopen(self): cmd = [EMCC, test_file('other/test_dlopen_blocking.c')] self.run_process(cmd) err = self.run_js('a.out.js', assert_returncode=NON_ZERO) - self.assertContained('Aborted(To use dlopen, you need enable dynamic linking, see https://github.com/emscripten-core/emscripten/wiki/Linking)', err) + self.assertContained('Aborted(To use dlopen, you need enable dynamic linking, see https://emscripten.org/docs/compiling/Dynamic-Linking.html)', err) # If we build the same thing with ALLOW_UNIMPLEMENTED_SYSCALLS=0 we # expect a link-time failure rather than a runtime one. cmd += ['-sALLOW_UNIMPLEMENTED_SYSCALLS=0'] err = self.expect_fail(cmd) - self.assertContained('To use dlopen, you need enable dynamic linking, see https://github.com/emscripten-core/emscripten/wiki/Linking', err) + self.assertContained('To use dlopen, you need enable dynamic linking, see https://emscripten.org/docs/compiling/Dynamic-Linking.html', err) def test_unimplemented_syscalls_dladdr(self): create_file('main.c', ''' @@ -12317,7 +12317,7 @@ def test_unimplemented_syscalls_dladdr(self): self.run_process([EMCC, 'main.c']) err = self.run_js('a.out.js', assert_returncode=NON_ZERO) - self.assertContained('Aborted(To use dlopen, you need enable dynamic linking, see https://github.com/emscripten-core/emscripten/wiki/Linking)', err) + self.assertContained('Aborted(To use dlopen, you need enable dynamic linking, see https://emscripten.org/docs/compiling/Dynamic-Linking.html)', err) @requires_v8 def test_missing_shell_support(self): From 38eedc630f17094b3202fd48ac0c2c585dbea31e Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 7 Apr 2023 11:34:42 -0700 Subject: [PATCH 0109/1523] Rebaseline codesize expectations. NFC --- test/other/metadce/test_metadce_minimal_pthreads.size | 2 +- test/other/test_unoptimized_code_size.js.size | 2 +- test/other/test_unoptimized_code_size_strict.js.size | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/other/metadce/test_metadce_minimal_pthreads.size b/test/other/metadce/test_metadce_minimal_pthreads.size index 686ddd583747b..ef216c038b7ad 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.size +++ b/test/other/metadce/test_metadce_minimal_pthreads.size @@ -1 +1 @@ -18965 +18968 diff --git a/test/other/test_unoptimized_code_size.js.size b/test/other/test_unoptimized_code_size.js.size index bc594e72ee8f3..42f4f5feb52f1 100644 --- a/test/other/test_unoptimized_code_size.js.size +++ b/test/other/test_unoptimized_code_size.js.size @@ -1 +1 @@ -59690 +59710 diff --git a/test/other/test_unoptimized_code_size_strict.js.size b/test/other/test_unoptimized_code_size_strict.js.size index a569f0855e6da..b4386945c4b88 100644 --- a/test/other/test_unoptimized_code_size_strict.js.size +++ b/test/other/test_unoptimized_code_size_strict.js.size @@ -1 +1 @@ -58632 +58652 From 6f3cfe3b534af4551f9d3ccf296f92c76589c465 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 10 Apr 2023 21:51:55 -0700 Subject: [PATCH 0110/1523] Add implementation of emscripten_memcpy_big based on bulk memory. (#19128) These new functions live in `libbulkmemory` which only gets included if bulk memory is enabled (either via `-mbulk-memory` directly or indirectly via `-pthread). benchmark results for benchmark.test_memcpy_1mb: ``` v8: mean: 1.666 v8-bulkmemory: mean: 1.598 v8-standalone-bulkmemory: mean: 1.576 v8-standalone: mean: 3.197 ``` Here we can see the that when bulk memory is enabled its at least as fast if not faster than the JS version. v8-standalone doesn't have emscripten_memcpy_big at all is is much slower, as expected. By adding `-mbulk-memory` the standalone version becomes just as fast as the non-standalone. --- embuilder.py | 1 + emcc.py | 9 +++++ src/library.js | 4 +- src/settings_internal.js | 2 + system/lib/libc/emscripten_internal.h | 1 + system/lib/libc/emscripten_memcpy.c | 2 +- system/lib/libc/emscripten_memcpy_big.S | 14 +++++++ system/lib/libc/emscripten_memset.c | 37 +++++++++++++++---- system/lib/libc/emscripten_memset_big.S | 14 +++++++ system/lib/standalone/standalone.c | 2 +- .../other/metadce/test_metadce_hello_O0.funcs | 2 +- .../test_metadce_minimal_pthreads.funcs | 2 +- test/other/test_memops_bulk_memory.c | 13 +++++++ test/test_other.py | 29 ++++++++++++++- tools/settings.py | 1 + tools/system_libs.py | 16 +++++++- 16 files changed, 133 insertions(+), 16 deletions(-) create mode 100644 system/lib/libc/emscripten_memcpy_big.S create mode 100644 system/lib/libc/emscripten_memset_big.S create mode 100644 test/other/test_memops_bulk_memory.c diff --git a/embuilder.py b/embuilder.py index c6b01b677ee42..bc6b0d4828858 100755 --- a/embuilder.py +++ b/embuilder.py @@ -28,6 +28,7 @@ # Minimal subset of targets used by CI systems to build enough to useful MINIMAL_TASKS = [ + 'libbulkmemory', 'libcompiler_rt', 'libcompiler_rt-wasm-sjlj', 'libc', diff --git a/emcc.py b/emcc.py index ccfb59bc4f3a2..cbfeba26cd522 100755 --- a/emcc.py +++ b/emcc.py @@ -1599,6 +1599,9 @@ def phase_setup(options, state, newargs): if '-mbulk-memory' not in newargs: newargs += ['-mbulk-memory'] + if settings.SHARED_MEMORY: + settings.BULK_MEMORY = 1 + if 'DISABLE_EXCEPTION_CATCHING' in user_settings and 'EXCEPTION_CATCHING_ALLOWED' in user_settings: # If we get here then the user specified both DISABLE_EXCEPTION_CATCHING and EXCEPTION_CATCHING_ALLOWED # on the command line. This is no longer valid so report either an error or a warning (for @@ -2434,6 +2437,8 @@ def phase_linker_setup(options, state, newargs): settings.JS_LIBRARIES.append((0, shared.path_from_root('src', 'library_wasm_worker.js'))) settings.SUPPORTS_GLOBALTHIS = feature_matrix.caniuse(feature_matrix.Feature.GLOBALTHIS) + if not settings.BULK_MEMORY: + settings.BULK_MEMORY = feature_matrix.caniuse(feature_matrix.Feature.BULK_MEMORY) if settings.AUDIO_WORKLET: if not settings.SUPPORTS_GLOBALTHIS: @@ -3565,6 +3570,10 @@ def consume_arg_file(): settings.DISABLE_EXCEPTION_CATCHING = 1 settings.DISABLE_EXCEPTION_THROWING = 1 settings.WASM_EXCEPTIONS = 0 + elif arg == '-mbulk-memory': + settings.BULK_MEMORY = 1 + elif arg == '-mno-bulk-memory': + settings.BULK_MEMORY = 0 elif arg == '-fexceptions': # TODO Currently -fexceptions only means Emscripten EH. Switch to wasm # exception handling by default when -fexceptions is given when wasm diff --git a/src/library.js b/src/library.js index f38c244d972f2..f2afff44362cd 100644 --- a/src/library.js +++ b/src/library.js @@ -389,9 +389,11 @@ mergeInto(LibraryManager.library, { // variant, so we should never emit emscripten_memcpy_big() in the build. // In STANDALONE_WASM we avoid the emscripten_memcpy_big dependency so keep // the wasm file standalone. + // In BULK_MEMORY mode we include native versions of these functions based + // on memory.fill and memory.copy. // In MAIN_MODULE=1 or EMCC_FORCE_STDLIBS mode all of libc is force included // so we cannot override parts of it, and therefore cannot use libc_optz. -#if (SHRINK_LEVEL < 2 || LINKABLE || process.env.EMCC_FORCE_STDLIBS) && !STANDALONE_WASM +#if (SHRINK_LEVEL < 2 || LINKABLE || process.env.EMCC_FORCE_STDLIBS) && !STANDALONE_WASM && !BULK_MEMORY #if MIN_CHROME_VERSION < 45 || MIN_EDGE_VERSION < 14 || MIN_FIREFOX_VERSION < 34 || MIN_IE_VERSION != TARGET_NOT_SUPPORTED || MIN_SAFARI_VERSION < 100101 // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/copyWithin lists browsers that support TypedArray.prototype.copyWithin, but it diff --git a/src/settings_internal.js b/src/settings_internal.js index 040cb40d8e7c1..cc4f7506ecd90 100644 --- a/src/settings_internal.js +++ b/src/settings_internal.js @@ -256,3 +256,5 @@ var POST_JS_FILES = []; // Set when -pthread / -sPTHREADS is passed var PTHREADS = false; + +var BULK_MEMORY = false; diff --git a/system/lib/libc/emscripten_internal.h b/system/lib/libc/emscripten_internal.h index 92dbe29e43e75..4aff06e6b1a35 100644 --- a/system/lib/libc/emscripten_internal.h +++ b/system/lib/libc/emscripten_internal.h @@ -30,6 +30,7 @@ extern "C" { void emscripten_memcpy_big(void* __restrict__ dest, const void* __restrict__ src, size_t n) EM_IMPORT(emscripten_memcpy_big); +void emscripten_memset_big(void* ptr, char value, size_t n); void emscripten_notify_memory_growth(size_t memory_index); diff --git a/system/lib/libc/emscripten_memcpy.c b/system/lib/libc/emscripten_memcpy.c index 3a3f091a5def6..d226b3eebad51 100644 --- a/system/lib/libc/emscripten_memcpy.c +++ b/system/lib/libc/emscripten_memcpy.c @@ -29,7 +29,7 @@ static void *__memcpy(void *restrict dest, const void *restrict src, size_t n) { unsigned char *block_aligned_d_end; unsigned char *d_end; -#ifndef EMSCRIPTEN_STANDALONE_WASM +#if !defined(EMSCRIPTEN_STANDALONE_WASM) || defined(__wasm_bulk_memory__) if (n >= 512) { emscripten_memcpy_big(dest, src, n); return dest; diff --git a/system/lib/libc/emscripten_memcpy_big.S b/system/lib/libc/emscripten_memcpy_big.S new file mode 100644 index 0000000000000..2c3bdfbe674d6 --- /dev/null +++ b/system/lib/libc/emscripten_memcpy_big.S @@ -0,0 +1,14 @@ +#ifdef __wasm64__ +#define PTR i64 +#else +#define PTR i32 +#endif + +.globl emscripten_memcpy_big +emscripten_memcpy_big: + .functype emscripten_memcpy_big (PTR, PTR, PTR) -> () + local.get 0 + local.get 1 + local.get 2 + memory.copy 0, 0 + end_function diff --git a/system/lib/libc/emscripten_memset.c b/system/lib/libc/emscripten_memset.c index 048390e4fc3cb..6109d52eddf35 100644 --- a/system/lib/libc/emscripten_memset.c +++ b/system/lib/libc/emscripten_memset.c @@ -1,23 +1,44 @@ -// XXX EMSCRIPTEN ASAN: build an uninstrumented version of memset -#if defined(__EMSCRIPTEN__) && defined(__has_feature) -#if __has_feature(address_sanitizer) -#define memset __attribute__((no_sanitize("address"))) emscripten_builtin_memset -#endif +#include "emscripten_internal.h" // for emscripten_memset_big + +#if defined(__has_feature) && __has_feature(address_sanitizer) +// build an uninstrumented version of memset +__attribute__((no_sanitize("address"))) void *__musl_memset(void *str, int c, size_t n); +__attribute__((no_sanitize("address"))) void *__memset(void *str, int c, size_t n); #endif -#ifdef EMSCRIPTEN_OPTIMIZE_FOR_OZ +__attribute__((__weak__)) void *__musl_memset(void *str, int c, size_t n); +__attribute__((__weak__)) void *__memset(void *str, int c, size_t n); -#include +#ifdef EMSCRIPTEN_OPTIMIZE_FOR_OZ -void *memset(void *str, int c, size_t n) { +void *__memset(void *str, int c, size_t n) { unsigned char *s = (unsigned char *)str; #pragma clang loop unroll(disable) while(n--) *s++ = c; return str; } +#elif defined(__wasm_bulk_memory__) + +#define memset __musl_memset +#include "musl/src/string/memset.c" +#undef memset + +void *__memset(void *str, int c, size_t n) { + if (n >= 512) { + emscripten_memset_big(str, c, n); + return str; + } + return __musl_memset(str, c, n); +} + #else +#define memset __memset #include "musl/src/string/memset.c" +#undef memset #endif + +weak_alias(__memset, emscripten_builtin_memset); +weak_alias(__memset, memset); diff --git a/system/lib/libc/emscripten_memset_big.S b/system/lib/libc/emscripten_memset_big.S new file mode 100644 index 0000000000000..ed765c3190d2c --- /dev/null +++ b/system/lib/libc/emscripten_memset_big.S @@ -0,0 +1,14 @@ +#ifdef __wasm64__ +#define PTR i64 +#else +#define PTR i32 +#endif + +.globl emscripten_memset_big +emscripten_memset_big: + .functype emscripten_memset_big (PTR, i32, PTR) -> () + local.get 0 + local.get 1 + local.get 2 + memory.fill 0 + end_function diff --git a/system/lib/standalone/standalone.c b/system/lib/standalone/standalone.c index 200002dce1e1b..7f2185e8da8da 100644 --- a/system/lib/standalone/standalone.c +++ b/system/lib/standalone/standalone.c @@ -152,7 +152,7 @@ int emscripten_resize_heap(size_t size) { } double emscripten_get_now(void) { - return (1000 * clock()) / (double)CLOCKS_PER_SEC; + return (1000ll * clock()) / (double)CLOCKS_PER_SEC; } // C++ ABI diff --git a/test/other/metadce/test_metadce_hello_O0.funcs b/test/other/metadce/test_metadce_hello_O0.funcs index b12d0bc6b6c73..684921992a5f7 100644 --- a/test/other/metadce/test_metadce_hello_O0.funcs +++ b/test/other/metadce/test_metadce_hello_O0.funcs @@ -9,6 +9,7 @@ $__lock $__lockfile $__lshrti3 $__memcpy +$__memset $__ofl_lock $__ofl_unlock $__original_main @@ -41,7 +42,6 @@ $isdigit $legalstub$dynCall_jiji $main $memchr -$memset $out $pad $pop_arg diff --git a/test/other/metadce/test_metadce_minimal_pthreads.funcs b/test/other/metadce/test_metadce_minimal_pthreads.funcs index 86cf4f2716c41..b73e40caf9df9 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.funcs +++ b/test/other/metadce/test_metadce_minimal_pthreads.funcs @@ -1,6 +1,7 @@ $__emscripten_stdout_seek $__errno_location $__memcpy +$__memset $__pthread_mutex_lock $__pthread_mutex_trylock $__pthread_mutex_unlock @@ -63,7 +64,6 @@ $get_tasks_for_thread $init_file_lock $init_mparams $main -$memset $nodtor $pthread_attr_destroy $receive_notification diff --git a/test/other/test_memops_bulk_memory.c b/test/other/test_memops_bulk_memory.c new file mode 100644 index 0000000000000..5f6dc0b6874c3 --- /dev/null +++ b/test/other/test_memops_bulk_memory.c @@ -0,0 +1,13 @@ +#include +#include + +const char *hello = "hello"; +const char *world = "world"; + +int main() { + char buffer[100]; + memset(buffer, 'a', 100); + memcpy(buffer, hello, strlen(hello) + 1); + assert(strcmp(buffer, hello) == 0); + return 0; +} diff --git a/test/test_other.py b/test/test_other.py index 9ca7e4efe0289..7d70fb9c13768 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -12219,7 +12219,7 @@ def test_standard_library_mapping(self): # Test the `-l` flags on the command line get mapped the correct libraries variant self.run_process([EMBUILDER, 'build', 'libc-mt-debug', 'libcompiler_rt-mt', 'libdlmalloc-mt']) - libs = ['-lc', '-lcompiler_rt', '-lmalloc'] + libs = ['-lc', '-lbulkmemory', '-lcompiler_rt', '-lmalloc'] err = self.run_process([EMCC, test_file('hello_world.c'), '-pthread', '-nodefaultlibs', '-v'] + libs, stderr=PIPE).stderr # Check that the linker was run with `-mt` variants because `-pthread` was passed. @@ -13412,3 +13412,30 @@ def test_wasi_random_get(self): @requires_node def test_wasi_sched_yield(self): self.run_wasi_test_suite_test('wasi_sched_yield') + + def test_memops_bulk_memory(self): + self.emcc_args += ['--profiling-funcs', '-fno-builtin'] + + def run(args, expect_bulk_mem): + self.do_runf(test_file('other/test_memops_bulk_memory.c'), emcc_args=args) + funcs = self.parse_wasm('test_memops_bulk_memory.wasm')[2] + js = read_file('test_memops_bulk_memory.js') + if expect_bulk_mem: + self.assertNotContained('_emscripten_memcpy_big', js) + self.assertIn('$emscripten_memcpy_big', funcs) + else: + self.assertContained('_emscripten_memcpy_big', js) + self.assertNotIn('$emscripten_memcpy_big', funcs) + + # By default we expect to find _emscripten_memcpy_big in the generaed JS and not in the + # native code. + run([], expect_bulk_mem=False) + + # With bulk memory enabled we expect *not* to find it. + run(['-mbulk-memory'], expect_bulk_mem=True) + + run(['-mbulk-memory', '-mno-bulk-memory'], expect_bulk_mem=False) + + # -pthread implicitly enables bulk memory too. + self.setup_node_pthreads() + run(['-pthread'], expect_bulk_mem=True) diff --git a/tools/settings.py b/tools/settings.py index 429020bf12dbd..10d6ca06ebff6 100644 --- a/tools/settings.py +++ b/tools/settings.py @@ -71,6 +71,7 @@ 'DEFAULT_TO_CXX', 'WASM_OBJECT_FILES', 'WASM_WORKERS', + 'BULK_MEMORY', # Internal settings used during compilation 'EXCEPTION_CATCHING_ALLOWED', diff --git a/tools/system_libs.py b/tools/system_libs.py index 7bebfb22b6bbc..b0cca903a4963 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -1274,6 +1274,17 @@ def can_use(self): not settings.LINKABLE and not os.environ.get('EMCC_FORCE_STDLIBS') +class libbulkmemory(MuslInternalLibrary, AsanInstrumentedLibrary): + name = 'libbulkmemory' + src_dir = 'system/lib/libc' + src_files = ['emscripten_memcpy.c', 'emscripten_memset.c', + 'emscripten_memcpy_big.S', 'emscripten_memset_big.S'] + cflags = ['-mbulk-memory'] + + def can_use(self): + return super(libbulkmemory, self).can_use() and settings.BULK_MEMORY + + class libprintf_long_double(libc): name = 'libprintf_long_double' cflags = ['-DEMSCRIPTEN_PRINTF_LONG_DOUBLE'] @@ -1945,7 +1956,7 @@ def get_files(self): '__main_void.c']) files += files_in_path( path='system/lib/libc', - filenames=['emscripten_memcpy.c']) + filenames=['emscripten_memcpy.c', 'emscripten_memset.c']) # It is more efficient to use JS methods for time, normally. files += files_in_path( path='system/lib/libc/musl/src/time', @@ -2154,7 +2165,8 @@ def add_sanitizer_libs(): if settings.SHRINK_LEVEL >= 2 and not settings.LINKABLE and \ not os.environ.get('EMCC_FORCE_STDLIBS'): add_library('libc_optz') - + if settings.BULK_MEMORY: + add_library('libbulkmemory') if settings.STANDALONE_WASM: add_library('libstandalonewasm') if settings.ALLOW_UNIMPLEMENTED_SYSCALLS: From dfbf6a805bc185b1c837590a4e2d11a432d8024c Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Tue, 11 Apr 2023 07:52:23 -0700 Subject: [PATCH 0111/1523] Implement `emscripten_promise_all_settled` in promise.h (#19152) This is like `emscripten_promise_all`, but always fulfills and separately reports whether each input promise is fulfilled or rejected. --- src/generated_struct_info32.json | 5 ++ src/generated_struct_info64.json | 5 ++ src/library_promise.js | 55 +++++++++++++-- src/library_sigs.js | 1 + src/struct_info.json | 10 ++- system/include/emscripten/promise.h | 28 +++++--- test/core/test_promise.c | 101 +++++++++++++++++++++++++++- test/core/test_promise.out | 6 ++ 8 files changed, 194 insertions(+), 17 deletions(-) diff --git a/src/generated_struct_info32.json b/src/generated_struct_info32.json index 96aedcd63bd59..1a160f0d19462 100644 --- a/src/generated_struct_info32.json +++ b/src/generated_struct_info32.json @@ -1330,6 +1330,11 @@ "table_addr": 20, "table_size": 24 }, + "em_settled_result_t": { + "__size__": 8, + "result": 0, + "value": 4 + }, "emscripten_fetch_attr_t": { "__size__": 92, "attributes": 52, diff --git a/src/generated_struct_info64.json b/src/generated_struct_info64.json index 5946eabc8ff11..cc1d801fe6355 100644 --- a/src/generated_struct_info64.json +++ b/src/generated_struct_info64.json @@ -1330,6 +1330,11 @@ "table_addr": 32, "table_size": 40 }, + "em_settled_result_t": { + "__size__": 16, + "result": 0, + "value": 8 + }, "emscripten_fetch_attr_t": { "__size__": 152, "attributes": 72, diff --git a/src/library_promise.js b/src/library_promise.js index 1ee467c88efb2..7d62c584ccf06 100644 --- a/src/library_promise.js +++ b/src/library_promise.js @@ -27,6 +27,16 @@ mergeInto(LibraryManager.library, { return promiseInfo; }, + $idsToPromises__deps: ['$promiseMap', '$getPromise'], + $idsToPromises: function(idBuf, size) { + var promises = []; + for (var i = 0; i < size; i++) { + var id = {{{ makeGetValue('idBuf', `i*${POINTER_SIZE}`, 'i32') }}}; + promises[i] = getPromise(id); + } + return promises; + }, + emscripten_promise_create__deps: ['$makePromise'], emscripten_promise_create: function() { return makePromise().id; @@ -146,13 +156,9 @@ mergeInto(LibraryManager.library, { return newId; }, - emscripten_promise_all__deps: ['$promiseMap', '$getPromise'], + emscripten_promise_all__deps: ['$promiseMap', '$idsToPromises'], emscripten_promise_all: function(idBuf, resultBuf, size) { - var promises = []; - for (var i = 0; i < size; i++) { - var id = {{{ makeGetValue('idBuf', `i*${POINTER_SIZE}`, 'i32') }}}; - promises[i] = getPromise(id); - } + var promises = idsToPromises(idBuf, size); #if RUNTIME_DEBUG dbg('emscripten_promise_all: ' + promises); #endif @@ -169,6 +175,43 @@ mergeInto(LibraryManager.library, { }); #if RUNTIME_DEBUG dbg('create: ' + id); +#endif + return id; + }, + + emscripten_promise_all_settled__deps: ['$promiseMap', '$idsToPromises'], + emscripten_promise_all_settled: function(idBuf, resultBuf, size) { + var promises = idsToPromises(idBuf, size); +#if RUNTIME_DEBUG + dbg('emscripten_promise_all_settled: ' + promises); +#endif + var id = promiseMap.allocate({ + promise: Promise.allSettled(promises).then((results) => { + if (resultBuf) { + for (var i = 0; i < size; i++) { + var baseOffset = i * {{{ C_STRUCTS.em_settled_result_t.__size__ }}}; + var resultOffset = + baseOffset + {{{ C_STRUCTS.em_settled_result_t.result }}}; + var valueOffset = + baseOffset + {{{ C_STRUCTS.em_settled_result_t.value }}}; + if (results[i].status === 'fulfilled') { + var fulfill = {{{ cDefs.EM_PROMISE_FULFILL }}}; + {{{ makeSetValue('resultBuf', 'resultOffset', 'fulfill', 'i32') }}}; + {{{ makeSetValue('resultBuf', 'valueOffset', 'results[i].value', '*') }}}; + } else { + var reject = {{{ cDefs.EM_PROMISE_REJECT }}}; + {{{ makeSetValue('resultBuf', 'resultOffset', 'reject', 'i32') }}}; + // Closure can't type `reason` in some contexts. + var reason = /** @type {number} */ (results[i].reason); + {{{ makeSetValue('resultBuf', 'valueOffset', 'reason', '*') }}}; + } + } + } + return resultBuf; + }) + }); +#if RUNTIME_DEBUG + dbg('create: ' + id); #endif return id; }, diff --git a/src/library_sigs.js b/src/library_sigs.js index dc99c670dc9f5..9fdbf18790fe1 100644 --- a/src/library_sigs.js +++ b/src/library_sigs.js @@ -534,6 +534,7 @@ sigs = { emscripten_performance_now__sig: 'd', emscripten_print_double__sig: 'idpi', emscripten_promise_all__sig: 'pppp', + emscripten_promise_all_settled__sig: 'pppp', emscripten_promise_create__sig: 'p', emscripten_promise_destroy__sig: 'vp', emscripten_promise_resolve__sig: 'vpip', diff --git a/src/struct_info.json b/src/struct_info.json index f4c556e890c50..534d4c4ca575d 100644 --- a/src/struct_info.json +++ b/src/struct_info.json @@ -262,7 +262,7 @@ "O_PATH", "O_NONBLOCK", "O_CLOEXEC", - "F_GETOWN", + "F_GETOWN", "F_GETOWN_EX", "F_SETFD", "O_EXCL", @@ -1095,7 +1095,13 @@ "EM_PROMISE_MATCH", "EM_PROMISE_MATCH_RELEASE", "EM_PROMISE_REJECT" - ] + ], + "structs": { + "em_settled_result_t": [ + "result", + "value" + ] + } }, { "file": "AL/al.h", diff --git a/system/include/emscripten/promise.h b/system/include/emscripten/promise.h index ad89c22781aaa..d0b4906b52715 100644 --- a/system/include/emscripten/promise.h +++ b/system/include/emscripten/promise.h @@ -92,17 +92,29 @@ emscripten_promise_then(em_promise_t promise, void* data); // Call Promise.all to create and return a new promise that is either fulfilled -// once the `num_promises` input promises in the `promises` have been fulfilled -// or is rejected once any of the input promises has been rejected. When the -// returned promise is fulfilled, the values each of the input promises were -// resolved with will be written to the `results` array and the returned promise -// will be fulfilled with the address of that array as well. +// once the `num_promises` input promises passed in `promises` have been +// fulfilled or is rejected once any of the input promises has been rejected. +// When the returned promise is fulfilled, the values each of the input promises +// were resolved with will be written to the `results` array if it is non-null +// and the returned promise will be fulfilled with the address of that array as +// well. __attribute__((warn_unused_result)) em_promise_t emscripten_promise_all( em_promise_t* promises, void** results, size_t num_promises); -// TODO: emscripten_promise_all_settled -// TODO: emscripten_promise_race -// TODO: emscripten_promise_any +typedef struct em_settled_result_t { + em_promise_result_t result; + void* value; +} em_settled_result_t; + +// Call Promise.allSettled to create and return a new promise that is fulfilled +// once the `num_promises` input promises passed in `promises` have been +// settled. When the returned promise is fulfilled, the `results` buffer will be +// filled with the result comprising of either EM_PROMISE_FULFILL and the +// fulfilled value or EM_PROMISE_REJECT and the rejection reason for each of the +// input promises if `results` is non-null. The returned promise will be +// fulfilled with the value of `results` as well. +__attribute__((warn_unused_result)) em_promise_t emscripten_promise_all_settled( + em_promise_t* promises, em_settled_result_t* results, size_t num_promises); #ifdef __cplusplus } diff --git a/test/core/test_promise.c b/test/core/test_promise.c index 48d13a00dba66..53e9427889afd 100644 --- a/test/core/test_promise.c +++ b/test/core/test_promise.c @@ -248,6 +248,102 @@ static em_promise_result_t test_all(void** result, void* data, void* value) { return EM_PROMISE_MATCH_RELEASE; } +typedef struct promise_all_settled_state { + size_t size; + em_promise_t in[3]; + em_settled_result_t out[3]; + em_settled_result_t expected[3]; +} promise_all_settled_state; + +static em_promise_result_t +check_promise_all_settled_results(void** result, void* data, void* value) { + promise_all_settled_state* state = (promise_all_settled_state*)data; + assert(value == state->out); + emscripten_console_log("promise_all_settled results:"); + for (size_t i = 0; i < state->size; ++i) { + emscripten_console_logf( + "%s %ld", + state->out[i].result == EM_PROMISE_FULFILL ? "fulfill" : "reject", + (uintptr_t)state->out[i].value); + assert(state->out[i].result == state->expected[i].result); + assert(state->out[i].value == state->expected[i].value); + } + free(state); + return EM_PROMISE_FULFILL; +} + +static em_promise_result_t check_null(void** result, void* data, void* value) { + assert(value == NULL); + return EM_PROMISE_FULFILL; +} + +static em_promise_result_t +test_all_settled(void** result, void* data, void* value) { + emscripten_console_log("test_all_settled"); + assert(data == (void*)5); + + // No input should be handled ok. + promise_all_settled_state* state = malloc(sizeof(promise_all_settled_state)); + *state = + (promise_all_settled_state){.size = 0, .in = {}, .out = {}, .expected = {}}; + em_promise_t empty = + emscripten_promise_all_settled(state->in, state->out, state->size); + em_promise_t empty_checked = emscripten_promise_then( + empty, check_promise_all_settled_results, fail, state); + emscripten_promise_destroy(empty); + + // Fulfilled and rejected inputs should be reported. + state = malloc(sizeof(promise_all_settled_state)); + *state = (promise_all_settled_state){.size = 3, + .in = {emscripten_promise_create(), + emscripten_promise_create(), + emscripten_promise_create()}, + .out = {}, + .expected = { + {EM_PROMISE_FULFILL, (void*)42}, + {EM_PROMISE_REJECT, (void*)43}, + {EM_PROMISE_FULFILL, (void*)44}, + }}; + em_promise_t full = + emscripten_promise_all_settled(state->in, state->out, state->size); + em_promise_t full_checked = emscripten_promise_then( + full, check_promise_all_settled_results, fail, state); + emscripten_promise_destroy(full); + emscripten_promise_resolve(state->in[0], EM_PROMISE_FULFILL, (void*)42); + emscripten_promise_resolve(state->in[1], EM_PROMISE_REJECT, (void*)43); + emscripten_promise_resolve(state->in[2], EM_PROMISE_FULFILL, (void*)44); + emscripten_promise_destroy(state->in[0]); + emscripten_promise_destroy(state->in[1]); + emscripten_promise_destroy(state->in[2]); + + // Null buffer should be ok. + em_promise_t null_in[3] = { + emscripten_promise_create(), + emscripten_promise_create(), + emscripten_promise_create(), + }; + em_promise_t null = emscripten_promise_all_settled(null_in, NULL, 3); + em_promise_t null_checked = + emscripten_promise_then(null, check_null, fail, NULL); + emscripten_promise_destroy(null); + emscripten_promise_resolve(null_in[0], EM_PROMISE_REJECT, (void*)42); + emscripten_promise_resolve(null_in[1], EM_PROMISE_FULFILL, (void*)43); + emscripten_promise_resolve(null_in[2], EM_PROMISE_REJECT, (void*)44); + emscripten_promise_destroy(null_in[0]); + emscripten_promise_destroy(null_in[1]); + emscripten_promise_destroy(null_in[2]); + + em_promise_t to_finish[3] = {empty_checked, full_checked, null_checked}; + em_promise_t finish_test_all = emscripten_promise_all(to_finish, NULL, 3); + + emscripten_promise_destroy(empty_checked); + emscripten_promise_destroy(full_checked); + emscripten_promise_destroy(null_checked); + + *result = finish_test_all; + return EM_PROMISE_MATCH_RELEASE; +} + static em_promise_result_t finish(void** result, void* data, void* value) { emscripten_console_logf("finish"); @@ -292,8 +388,10 @@ int main() { em_promise_t test3 = emscripten_promise_then(test2, test_rejection, fail, (void*)3); em_promise_t test4 = emscripten_promise_then(test3, test_all, fail, (void*)4); + em_promise_t test5 = + emscripten_promise_then(test4, test_all_settled, fail, (void*)5); em_promise_t assert_stack = - emscripten_promise_then(test4, check_stack, fail, NULL); + emscripten_promise_then(test5, check_stack, fail, NULL); em_promise_t end = emscripten_promise_then(assert_stack, finish, fail, NULL); emscripten_promise_resolve(start, EM_PROMISE_FULFILL, NULL); @@ -304,6 +402,7 @@ int main() { emscripten_promise_destroy(test2); emscripten_promise_destroy(test3); emscripten_promise_destroy(test4); + emscripten_promise_destroy(test5); emscripten_promise_destroy(assert_stack); emscripten_promise_destroy(end); diff --git a/test/core/test_promise.out b/test/core/test_promise.out index 2df7acbc0edc7..8bf244c6fb421 100644 --- a/test/core/test_promise.out +++ b/test/core/test_promise.out @@ -15,4 +15,10 @@ promise_all results: 1337 0 promise_all error: 1337 +test_all_settled +promise_all_settled results: +promise_all_settled results: +fulfill 42 +reject 43 +fulfill 44 finish From e92f01f877c69d7f12f085760f7d9524c7addf20 Mon Sep 17 00:00:00 2001 From: juj Date: Tue, 11 Apr 2023 20:40:26 +0300 Subject: [PATCH 0112/1523] Fix function name of WebGL 2 extension EXT_disjoint_timer_query_webgl2 (#19158) --- system/include/webgl/webgl2_ext.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/include/webgl/webgl2_ext.h b/system/include/webgl/webgl2_ext.h index 4ecfd1aa9e00b..9f24cb39ac439 100644 --- a/system/include/webgl/webgl2_ext.h +++ b/system/include/webgl/webgl2_ext.h @@ -9,7 +9,7 @@ #define GL_TIME_ELAPSED_EXT 0x88BF #define GL_TIMESTAMP_EXT 0x8E28 #define GL_GPU_DISJOINT_EXT 0x8FBB -WEBGL_APICALL void GL_APIENTRY emscripten_webgl2_queryCounterEXT(GLuint query, GLenum target); +WEBGL_APICALL void GL_APIENTRY glQueryCounterEXT(GLuint query, GLenum target); #endif /* EMSCRIPTEN_GL_EXT_disjoint_timer_query_webgl2 */ // 46. https://www.khronos.org/registry/webgl/extensions/WEBGL_draw_instanced_base_vertex_base_instance/ From 90958d92d499afb264292f2ab1937d978f388017 Mon Sep 17 00:00:00 2001 From: Derek Schuff Date: Tue, 11 Apr 2023 10:56:02 -0700 Subject: [PATCH 0113/1523] Update documentation and remove unneeded warning for --source-map base (#19155) The behavior of the --source-map-base and -gsource-map flags has changed since their introduction but the documentation and link-time warning did not. The current behavior is what we want, so keep it and update the docs. --- docs/emcc.txt | 17 ++++++++++------- emcc.py | 2 -- site/source/docs/tools_reference/emcc.rst | 11 +++++++++-- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/docs/emcc.txt b/docs/emcc.txt index 37b5347a4cba4..7f9ea7a1d1d0d 100644 --- a/docs/emcc.txt +++ b/docs/emcc.txt @@ -174,9 +174,14 @@ Options that are modified or new in *emcc* are listed below: different server, for example). "-gsource-map" - When linking, generate a source map using LLVM debug information - (which must be present in object files, i.e., they should have been - compiled with "-g"). + [link] Generate a source map using LLVM debug information (which + must be present in object files, i.e., they should have been + compiled with "-g"). When this option is provided, the **.wasm** + file is updated to have a "sourceMappingURL" section. The resulting + URL will have format: "" + "" + ".map". + "" defaults to being empty (which means the source map is + served from the same directory as the wasm file). It can be changed + using --source-map-base. "-g" [compile+link] Controls the level of debuggability. Each level @@ -375,10 +380,8 @@ Options that are modified or new in *emcc* are listed below: specified using the "-o" option. "--source-map-base " - [link] The URL for the location where WebAssembly source maps will - be published. When this option is provided, the **.wasm** file is - updated to have a "sourceMappingURL" section. The resulting URL - will have format: "" + "" + ".map". + [link] The base URL for the location where WebAssembly source maps + will be published. Must be used with -gsource-map. "--minify 0" [same as -g1 if passed at compile time, otherwise applies at link] diff --git a/emcc.py b/emcc.py index cbfeba26cd522..a1ad29b7228cd 100755 --- a/emcc.py +++ b/emcc.py @@ -3648,8 +3648,6 @@ def consume_arg_file(): def phase_binaryen(target, options, wasm_target): global final_js logger.debug('using binaryen') - if settings.GENERATE_SOURCE_MAP and not settings.SOURCE_MAP_BASE: - logger.warning("Wasm source map won't be usable in a browser without --source-map-base") # whether we need to emit -g (function name debug info) in the final wasm debug_info = settings.DEBUG_LEVEL >= 2 or settings.EMIT_NAME_SECTION # whether we need to emit -g in the intermediate binaryen invocations (but not diff --git a/site/source/docs/tools_reference/emcc.rst b/site/source/docs/tools_reference/emcc.rst index 31d7b6bc988a9..be3a7ecbc0635 100644 --- a/site/source/docs/tools_reference/emcc.rst +++ b/site/source/docs/tools_reference/emcc.rst @@ -162,8 +162,14 @@ Options that are modified or new in *emcc* are listed below: .. _emcc-gsource-map: ``-gsource-map`` - When linking, generate a source map using LLVM debug information (which must + [link] + Generate a source map using LLVM debug information (which must be present in object files, i.e., they should have been compiled with ``-g``). + When this option is provided, the **.wasm** file is updated to have a + ``sourceMappingURL`` section. The resulting URL will have format: + ```` + ```` + ``.map``. ```` defaults + to being empty (which means the source map is served from the same directory + as the wasm file). It can be changed using :ref:`--source-map-base `. .. _emcc-gN: @@ -352,7 +358,8 @@ Options that are modified or new in *emcc* are listed below: ``--source-map-base `` [link] - The URL for the location where WebAssembly source maps will be published. When this option is provided, the **.wasm** file is updated to have a ``sourceMappingURL`` section. The resulting URL will have format: ```` + ```` + ``.map``. + The base URL for the location where WebAssembly source maps will be published. Must be used + with :ref:`-gsource-map `. .. _emcc-minify: From df3a308e7c54462a99c9e6946be4d5d4b9dbae39 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 11 Apr 2023 14:05:59 -0700 Subject: [PATCH 0114/1523] Move parts of emscripten exception handling to native code. NFC (#16627) Co-authored-by: Ingvar Stepanyan --- emcc.py | 7 + src/library_exceptions.js | 98 +------- src/library_exceptions_stub.js | 4 - .../src/cxa_exception_emscripten.cpp | 216 +++++++++--------- .../libcxxabi/src/cxa_exception_js_utils.cpp | 105 +++++++++ system/lib/libcxxabi/src/cxa_noexception.cpp | 11 + system/lib/standalone/standalone.c | 5 - test/core/test_exceptions_primary.cpp | 3 +- test/no_this_in_dyncall.out | 2 +- .../metadce/test_metadce_cxx_ctors1.exports | 1 + .../metadce/test_metadce_cxx_ctors2.exports | 1 + .../metadce/test_metadce_cxx_except.exports | 2 + .../metadce/test_metadce_cxx_except.jssize | 2 +- .../metadce/test_metadce_cxx_except.size | 2 +- .../metadce/test_metadce_cxx_mangle.exports | 2 + .../metadce/test_metadce_cxx_mangle.jssize | 2 +- .../metadce/test_metadce_cxx_mangle.size | 2 +- .../metadce/test_metadce_cxx_noexcept.exports | 1 + .../metadce/test_metadce_cxx_noexcept.jssize | 2 +- .../metadce/test_metadce_cxx_noexcept.size | 2 +- .../metadce/test_metadce_minimal_O0.jssize | 2 +- test/test_core.py | 2 +- test/test_other.py | 2 +- tools/deps_info.py | 22 +- tools/system_libs.py | 6 +- 25 files changed, 278 insertions(+), 226 deletions(-) create mode 100644 system/lib/libcxxabi/src/cxa_exception_js_utils.cpp diff --git a/emcc.py b/emcc.py index a1ad29b7228cd..32bdda680fe01 100755 --- a/emcc.py +++ b/emcc.py @@ -2785,6 +2785,13 @@ def check_memory_setting(setting): '__cxa_is_pointer_type', '__cxa_can_catch', + # __cxa_begin_catch depends on this but we can't use deps info in this + # case because that only works for user-level code, and __cxa_begin_catch + # can be used by the standard library. + '__cxa_increment_exception_refcount', + # Same for __cxa_end_catch + '__cxa_decrement_exception_refcount', + # Emscripten exception handling can generate invoke calls, and they call # setThrew(). We cannot handle this using deps_info as the invokes are not # emitted because of library function usage, but by codegen itself. diff --git a/src/library_exceptions.js b/src/library_exceptions.js index bb3281330a3ea..d64e217cf1aa5 100644 --- a/src/library_exceptions.js +++ b/src/library_exceptions.js @@ -23,11 +23,9 @@ var LibraryExceptions = { // // excPtr - Thrown object pointer to wrap. Metadata pointer is calculated from it. $ExceptionInfo__docs: '/** @constructor */', - $ExceptionInfo__deps: ['__cxa_is_pointer_type', #if EXCEPTION_DEBUG - '$ptrToString', + $ExceptionInfo__deps: ['$ptrToString'], #endif - ], $ExceptionInfo: function(excPtr) { this.excPtr = excPtr; this.ptr = excPtr - {{{ C_STRUCTS.__cxa_exception.__size__ }}}; @@ -48,10 +46,6 @@ var LibraryExceptions = { return {{{ makeGetValue('this.ptr', C_STRUCTS.__cxa_exception.exceptionDestructor, '*') }}}; }; - this.set_refcount = function(refcount) { - {{{ makeSetValue('this.ptr', C_STRUCTS.__cxa_exception.referenceCount, 'refcount', 'i32') }}}; - }; - this.set_caught = function (caught) { caught = caught ? 1 : 0; {{{ makeSetValue('this.ptr', C_STRUCTS.__cxa_exception.caught, 'caught', 'i8') }}}; @@ -78,34 +72,8 @@ var LibraryExceptions = { this.set_adjusted_ptr(0); this.set_type(type); this.set_destructor(destructor); - this.set_refcount(0); - this.set_caught(false); - this.set_rethrown(false); } - this.add_ref = function() { -#if SHARED_MEMORY - Atomics.add(HEAP32, (this.ptr + {{{ C_STRUCTS.__cxa_exception.referenceCount }}}) >> 2, 1); -#else - var value = {{{ makeGetValue('this.ptr', C_STRUCTS.__cxa_exception.referenceCount, 'i32') }}}; - {{{ makeSetValue('this.ptr', C_STRUCTS.__cxa_exception.referenceCount, 'value + 1', 'i32') }}}; -#endif - }; - - // Returns true if last reference released. - this.release_ref = function() { -#if SHARED_MEMORY - var prev = Atomics.sub(HEAP32, (this.ptr + {{{ C_STRUCTS.__cxa_exception.referenceCount }}}) >> 2, 1); -#else - var prev = {{{ makeGetValue('this.ptr', C_STRUCTS.__cxa_exception.referenceCount, 'i32') }}}; - {{{ makeSetValue('this.ptr', C_STRUCTS.__cxa_exception.referenceCount, 'prev - 1', 'i32') }}}; -#endif -#if ASSERTIONS - assert(prev > 0); -#endif - return prev === 1; - }; - this.set_adjusted_ptr = function(adjustedPtr) { {{{ makeSetValue('this.ptr', C_STRUCTS.__cxa_exception.adjustedPtr, 'adjustedPtr', '*') }}}; }; @@ -131,52 +99,6 @@ var LibraryExceptions = { }; }, - $exception_addRef: function (info) { -#if EXCEPTION_DEBUG - dbg('exception_addRef ' + ptrToString(info.excPtr)); -#endif - info.add_ref(); - }, - - $exception_decRef__deps: ['__cxa_free_exception' -#if EXCEPTION_DEBUG - , '$exceptionLast', '$exceptionCaught' -#endif - ], - $exception_decRef: function(info) { -#if EXCEPTION_DEBUG - dbg('exception_decRef ' + ptrToString(info.excPtr)); -#endif - // A rethrown exception can reach refcount 0; it must not be discarded - // Its next handler will clear the rethrown flag and addRef it, prior to - // final decRef and destruction here - if (info.release_ref() && !info.get_rethrown()) { - var destructor = info.get_destructor(); - if (destructor) { - // In Wasm, destructors return 'this' as in ARM - {{{ makeDynCall('pp', 'destructor') }}}(info.excPtr); - } - ___cxa_free_exception(info.excPtr); -#if EXCEPTION_DEBUG - dbg('decref freeing exception ' + [ptrToString(info.excPtr), exceptionLast, 'stack', exceptionCaught]); -#endif - } - }, - - __cxa_increment_exception_refcount__deps: ['$exception_addRef', '$ExceptionInfo'], - __cxa_increment_exception_refcount__sig: 'vp', - __cxa_increment_exception_refcount: function(ptr) { - if (!ptr) return; - exception_addRef(new ExceptionInfo(ptr)); - }, - - __cxa_decrement_exception_refcount__deps: ['$exception_decRef', '$ExceptionInfo'], - __cxa_decrement_exception_refcount__sig: 'vp', - __cxa_decrement_exception_refcount: function(ptr) { - if (!ptr) return; - exception_decRef(new ExceptionInfo(ptr)); - }, - // Here, we throw an exception after recording a couple of values that we need to remember // We also remember that it was the last exception thrown as we need to know that later. __cxa_throw__sig: 'vppp', @@ -224,7 +146,8 @@ var LibraryExceptions = { return type; }, - __cxa_begin_catch__deps: ['$exceptionCaught', '$exception_addRef', '$uncaughtExceptionCount'], + __cxa_begin_catch__deps: ['$exceptionCaught', '__cxa_increment_exception_refcount', + '$uncaughtExceptionCount'], __cxa_begin_catch__sig: 'pp', __cxa_begin_catch: function(ptr) { var info = new ExceptionInfo(ptr); @@ -237,7 +160,7 @@ var LibraryExceptions = { #if EXCEPTION_DEBUG dbg('__cxa_begin_catch ' + [ptrToString(ptr), 'stack', exceptionCaught]); #endif - exception_addRef(info); + ___cxa_increment_exception_refcount(info.excPtr); return info.get_exception_ptr(); }, @@ -245,7 +168,7 @@ var LibraryExceptions = { // and free the exception. Note that if the dynCall on the destructor fails // due to calling apply on undefined, that means that the destructor is // an invalid index into the FUNCTION_TABLE, so something has gone wrong. - __cxa_end_catch__deps: ['$exceptionCaught', '$exceptionLast', '$exception_decRef'], + __cxa_end_catch__deps: ['$exceptionCaught', '$exceptionLast', '__cxa_decrement_exception_refcount', 'setThrew'], __cxa_end_catch__sig: 'v', __cxa_end_catch: function() { // Clear state flag. @@ -259,17 +182,18 @@ var LibraryExceptions = { #if EXCEPTION_DEBUG dbg('__cxa_end_catch popped ' + [info, exceptionLast, 'stack', exceptionCaught]); #endif - exception_decRef(info); + ___cxa_decrement_exception_refcount(info.excPtr); exceptionLast = 0; // XXX in decRef? }, __cxa_get_exception_ptr__deps: ['$ExceptionInfo'], __cxa_get_exception_ptr__sig: 'pp', __cxa_get_exception_ptr: function(ptr) { + var rtn = new ExceptionInfo(ptr).get_exception_ptr(); #if EXCEPTION_DEBUG - dbg('__cxa_get_exception_ptr ' + ptrToString(ptr)); + err('__cxa_get_exception_ptr ' + ptrToString(ptr) + ' -> ' + ptrToString(rtn)); #endif - return new ExceptionInfo(ptr).get_exception_ptr(); + return rtn; }, __cxa_uncaught_exceptions__deps: ['$uncaughtExceptionCount'], @@ -285,13 +209,13 @@ var LibraryExceptions = { throw exception; }, - __cxa_current_primary_exception__deps: ['$exceptionCaught', '$exception_addRef'], + __cxa_current_primary_exception__deps: ['$exceptionCaught', '__cxa_increment_exception_refcount'], __cxa_current_primary_exception: function() { if (!exceptionCaught.length) { return 0; } var info = exceptionCaught[exceptionCaught.length - 1]; - exception_addRef(info); + ___cxa_increment_exception_refcount(info.excPtr); return info.excPtr; }, diff --git a/src/library_exceptions_stub.js b/src/library_exceptions_stub.js index e0a10712498db..16c7e532644c4 100644 --- a/src/library_exceptions_stub.js +++ b/src/library_exceptions_stub.js @@ -7,10 +7,6 @@ var LibraryExceptions = {}; [ - '__cxa_allocate_exception', - '__cxa_free_exception', - '__cxa_increment_exception_refcount', - '__cxa_decrement_exception_refcount', '__cxa_throw', '__cxa_rethrow', 'llvm_eh_typeid_for', diff --git a/system/lib/libcxxabi/src/cxa_exception_emscripten.cpp b/system/lib/libcxxabi/src/cxa_exception_emscripten.cpp index 0e408898c32fc..af7ec0c0452f0 100644 --- a/system/lib/libcxxabi/src/cxa_exception_emscripten.cpp +++ b/system/lib/libcxxabi/src/cxa_exception_emscripten.cpp @@ -1,21 +1,30 @@ -//===------------------- cxa_exception_emscripten.cpp ---------------------===// +//===-------------------- cxa_exception_emscripten.cpp --------------------===// // -// This code contains Emscripten specific code for exception handling. -// Emscripten has two modes of exception handling: Emscripten EH, which uses JS -// glue code, and Wasm EH, which uses the new Wasm exception handling proposal -// and meant to be faster. Code for different modes is demarcated with -// '__USING_EMSCRIPTEN_EXCEPTIONS__' and '__USING_WASM_EXCEPTIONS__'. +// Most code in the file is directly copied from cxa_exception.cpp. +// TODO(sbc): consider merging them +// +// Notable changes: + // __cxa_allocate_exception doesn't add get_cxa_exception_offset +// __cxa_decrement_exception_refcount dosn't call the destructor if rethrown +// Both of these changes are mirrored from the historical JS implemenation of +// thse functions. // //===----------------------------------------------------------------------===// +#include "cxxabi.h" #include "cxa_exception.h" -#include "private_typeinfo.h" -#include -#include -#include -#include +#include "include/atomic_support.h" +#include "fallback_malloc.h" +#include "stdio.h" +#include "assert.h" + +// Define to enable extra debugging on stderr. +#if EXCEPTIONS_DEBUG +#define DEBUG printf +#else +#define DEBUG(...) +#endif -#if !defined(__USING_WASM_EXCEPTIONS__) // Until recently, Rust's `rust_eh_personality` for emscripten referred to this // symbol. If Emscripten doesn't provide it, there will be errors when linking // rust. The rust personality function is never called so we can just abort. @@ -30,121 +39,116 @@ __gxx_personality_v0(int version, _Unwind_Context* context) { abort(); } -#endif // !defined(__USING_WASM_EXCEPTIONS__) -using namespace __cxxabiv1; +namespace __cxxabiv1 { -// Some utility routines are copied from cxa_exception.cpp -static inline __cxa_exception* -cxa_exception_from_thrown_object(void* thrown_object) { - return static_cast<__cxa_exception*>(thrown_object) - 1; +// Utility routines +static +inline +__cxa_exception* +cxa_exception_from_thrown_object(void* thrown_object) +{ + DEBUG("cxa_exception_from_thrown_object %p -> %p\n", + thrown_object, static_cast<__cxa_exception*>(thrown_object) - 1); + return static_cast<__cxa_exception*>(thrown_object) - 1; } // Note: This is never called when exception_header is masquerading as a // __cxa_dependent_exception. -static inline void* -thrown_object_from_cxa_exception(__cxa_exception* exception_header) { - return static_cast(exception_header + 1); +static +inline +void* +thrown_object_from_cxa_exception(__cxa_exception* exception_header) +{ + DEBUG("thrown_object_from_cxa_exception %p -> %p\n", + exception_header, static_cast(exception_header + 1)); + return static_cast(exception_header + 1); } -#if defined(__USING_EMSCRIPTEN_EXCEPTIONS__) || \ - defined(__USING_WASM_EXCEPTIONS__) - -// Get the exception object from the unwind pointer. -// Relies on the structure layout, where the unwind pointer is right in -// front of the user's exception object -static inline __cxa_exception* cxa_exception_from_unwind_exception( - _Unwind_Exception* unwind_exception) { - return cxa_exception_from_thrown_object(unwind_exception + 1); +// Round s up to next multiple of a. +static inline +size_t aligned_allocation_size(size_t s, size_t a) { + return (s + a - 1) & ~(a - 1); } -static inline void* thrown_object_from_unwind_exception( - _Unwind_Exception* unwind_exception) { - __cxa_exception* exception_header = - cxa_exception_from_unwind_exception(unwind_exception); - return thrown_object_from_cxa_exception(exception_header); +static inline +size_t cxa_exception_size_from_exception_thrown_size(size_t size) { + return aligned_allocation_size(size + sizeof (__cxa_exception), + alignof(__cxa_exception)); } extern "C" { -void* __thrown_object_from_unwind_exception( - _Unwind_Exception* unwind_exception) { - return thrown_object_from_unwind_exception(unwind_exception); +// Allocate a __cxa_exception object, and zero-fill it. +// Reserve "thrown_size" bytes on the end for the user's exception +// object. Zero-fill the object. If memory can't be allocated, call +// std::terminate. Return a pointer to the memory to be used for the +// user's exception object. +void *__cxa_allocate_exception(size_t thrown_size) _NOEXCEPT { + size_t actual_size = cxa_exception_size_from_exception_thrown_size(thrown_size); + + char *raw_buffer = + (char *)__aligned_malloc_with_fallback(actual_size); + if (NULL == raw_buffer) + std::terminate(); + __cxa_exception *exception_header = + static_cast<__cxa_exception *>((void *)(raw_buffer)); + ::memset(exception_header, 0, actual_size); + return thrown_object_from_cxa_exception(exception_header); } -// Given a thrown_object, puts the information about its type and message into -// 'type' and 'message' output parameters. 'type' will contain the string -// representation of the type of the exception, e.g., 'int'. 'message' will -// contain the result of 'std::exception::what()' method if the type of the -// exception is a subclass of std::exception; otherwise it will be NULL. The -// caller is responsible for freeing 'type' buffer and also 'message' buffer, if -// it is not NULL. -void __get_exception_message(void* thrown_object, char** type, char** message) { - __cxa_exception* exception_header = - cxa_exception_from_thrown_object(thrown_object); - const __shim_type_info* thrown_type = - static_cast(exception_header->exceptionType); - const char* type_name = thrown_type->name(); - - int status = 0; - char* demangled_buf = __cxa_demangle(type_name, 0, 0, &status); - if (status == 0 && demangled_buf) { - *type = demangled_buf; - } else { - if (demangled_buf) { - free(demangled_buf); - } - *type = (char*)malloc(strlen(type_name) + 1); - strcpy(*type, type_name); - } - - *message = NULL; - const __shim_type_info* catch_type = - static_cast(&typeid(std::exception)); - int can_catch = catch_type->can_catch(thrown_type, thrown_object); - if (can_catch) { - const char* what = - static_cast(thrown_object)->what(); - *message = (char*)malloc(strlen(what) + 1); - strcpy(*message, what); - } -} -// Returns a message saying that execution was terminated due to an exception. -// This message is freshly malloc'd and should be freed. -char* __get_exception_terminate_message(void* thrown_object) { - char* type; - char* message; - __get_exception_message(thrown_object, &type, &message); - char* result; - if (message != NULL) { - asprintf( - &result, "terminating with uncaught exception %s: %s", type, message); - free(message); - } else { - asprintf(&result, "terminating with uncaught exception of type %s", type); - } - free(type); - return result; -} +// Free a __cxa_exception object allocated with __cxa_allocate_exception. +void __cxa_free_exception(void *thrown_object) _NOEXCEPT { + // Compute the size of the padding before the header. + char *raw_buffer = + ((char *)cxa_exception_from_thrown_object(thrown_object)); + __aligned_free_with_fallback((void *)raw_buffer); } -#endif // __USING_EMSCRIPTEN_EXCEPTIONS__ || __USING_WASM_EXCEPTIONS__ - -#ifndef __USING_WASM_EXCEPTIONS__ - -namespace __cxxabiv1 { - -void* __cxa_allocate_exception(size_t size) _NOEXCEPT { - // Thrown object is prepended by exception metadata block - __cxa_exception* ex = (__cxa_exception*)malloc(size + sizeof(__cxa_exception)); - return thrown_object_from_cxa_exception(ex); +/* + If thrown_object is not null, atomically increment the referenceCount field + of the __cxa_exception header associated with the thrown object referred to + by thrown_object. + + Requires: If thrown_object is not NULL, it is a native exception. +*/ +void +__cxa_increment_exception_refcount(void *thrown_object) _NOEXCEPT { + if (thrown_object != NULL ) + { + __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); + DEBUG("INC: %p refcnt=%zu\n", thrown_object, exception_header->referenceCount); + std::__libcpp_atomic_add(&exception_header->referenceCount, size_t(1)); + } } -void __cxa_free_exception(void *thrown_object) _NOEXCEPT { - free(cxa_exception_from_thrown_object(thrown_object)); +/* + If thrown_object is not null, atomically decrement the referenceCount field + of the __cxa_exception header associated with the thrown object referred to + by thrown_object. If the referenceCount drops to zero, destroy and + deallocate the exception. + + Requires: If thrown_object is not NULL, it is a native exception. +*/ +_LIBCXXABI_NO_CFI +void __cxa_decrement_exception_refcount(void *thrown_object) _NOEXCEPT { + if (thrown_object != NULL ) + { + __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); + DEBUG("DEC: %p refcnt=%zu rethrown=%d\n", thrown_object, + exception_header->referenceCount, exception_header->rethrown); + assert(exception_header->referenceCount > 0); + if (std::__libcpp_atomic_add(&exception_header->referenceCount, size_t(-1)) == 0 && !exception_header->rethrown) + { + DEBUG("DEL: %p\n", thrown_object); + if (NULL != exception_header->exceptionDestructor) + exception_header->exceptionDestructor(thrown_object); + __cxa_free_exception(thrown_object); + } + } } -} +} // extern "C" -#endif // !__USING_WASM_EXCEPTIONS__ +} // abi diff --git a/system/lib/libcxxabi/src/cxa_exception_js_utils.cpp b/system/lib/libcxxabi/src/cxa_exception_js_utils.cpp new file mode 100644 index 0000000000000..e2c61aa0967e5 --- /dev/null +++ b/system/lib/libcxxabi/src/cxa_exception_js_utils.cpp @@ -0,0 +1,105 @@ +#include "cxxabi.h" + +#include "cxa_exception.h" +#include "private_typeinfo.h" +#include +// #include +// #include +#include + +namespace __cxxabiv1 { + +// Utility routines +static +inline +__cxa_exception* +cxa_exception_from_thrown_object(void* thrown_object) +{ + return static_cast<__cxa_exception*>(thrown_object) - 1; +} + +// Note: This is never called when exception_header is masquerading as a +// __cxa_dependent_exception. +static +inline +void* +thrown_object_from_cxa_exception(__cxa_exception* exception_header) +{ + return static_cast(exception_header + 1); +} + +// Get the exception object from the unwind pointer. +// Relies on the structure layout, where the unwind pointer is right in +// front of the user's exception object +static inline __cxa_exception* cxa_exception_from_unwind_exception( + _Unwind_Exception* unwind_exception) { + return cxa_exception_from_thrown_object(unwind_exception + 1); +} + +extern "C" { + +void* __thrown_object_from_unwind_exception( + _Unwind_Exception* unwind_exception) { + __cxa_exception* exception_header = + cxa_exception_from_unwind_exception(unwind_exception); + return thrown_object_from_cxa_exception(exception_header); +} + +// Given a thrown_object, puts the information about its type and message into +// 'type' and 'message' output parameters. 'type' will contain the string +// representation of the type of the exception, e.g., 'int'. 'message' will +// contain the result of 'std::exception::what()' method if the type of the +// exception is a subclass of std::exception; otherwise it will be NULL. The +// caller is responsible for freeing 'type' buffer and also 'message' buffer, if +// it is not NULL. +void __get_exception_message(void* thrown_object, char** type, char** message) { + __cxa_exception* exception_header = + cxa_exception_from_thrown_object(thrown_object); + const __shim_type_info* thrown_type = + static_cast(exception_header->exceptionType); + const char* type_name = thrown_type->name(); + + int status = 0; + char* demangled_buf = __cxa_demangle(type_name, 0, 0, &status); + if (status == 0 && demangled_buf) { + *type = demangled_buf; + } else { + if (demangled_buf) { + free(demangled_buf); + } + *type = (char*)malloc(strlen(type_name) + 1); + strcpy(*type, type_name); + } + + *message = NULL; + const __shim_type_info* catch_type = + static_cast(&typeid(std::exception)); + int can_catch = catch_type->can_catch(thrown_type, thrown_object); + if (can_catch) { + const char* what = + static_cast(thrown_object)->what(); + *message = (char*)malloc(strlen(what) + 1); + strcpy(*message, what); + } +} + +// Returns a message saying that execution was terminated due to an exception. +// This message is freshly malloc'd and should be freed. +char* __get_exception_terminate_message(void* thrown_object) { + char* type; + char* message; + __get_exception_message(thrown_object, &type, &message); + char* result; + if (message != NULL) { + asprintf( + &result, "terminating with uncaught exception %s: %s", type, message); + free(message); + } else { + asprintf(&result, "terminating with uncaught exception of type %s", type); + } + free(type); + return result; +} +} // extern "C" + +} // namespace __cxxabiv1 diff --git a/system/lib/libcxxabi/src/cxa_noexception.cpp b/system/lib/libcxxabi/src/cxa_noexception.cpp index 4a803f72e193e..1097f75866983 100644 --- a/system/lib/libcxxabi/src/cxa_noexception.cpp +++ b/system/lib/libcxxabi/src/cxa_noexception.cpp @@ -49,6 +49,17 @@ __cxa_uncaught_exception() throw() { return false; } unsigned int __cxa_uncaught_exceptions() throw() { return 0; } +#if __EMSCRIPTEN__ +// Under emscripten this code is also linked when building when +// DISABLE_EXCEPTION_CATCHING is set but DISABLE_EXCEPTION_THROWING is not. +// TODO(sbc): Perhaps just call std::terminate here. It could +// just be some test code that needs updating. +void *__cxa_allocate_exception(size_t thrown_size) _NOEXCEPT { + char* allocation = (char*)malloc(thrown_size + sizeof(__cxa_exception)); + return allocation + sizeof(__cxa_exception); +} +#endif + } // extern "C" // provide dummy implementations for the 'no exceptions' case. diff --git a/system/lib/standalone/standalone.c b/system/lib/standalone/standalone.c index 7f2185e8da8da..43a446e14fd78 100644 --- a/system/lib/standalone/standalone.c +++ b/system/lib/standalone/standalone.c @@ -171,11 +171,6 @@ void __cxa_throw(void* ptr, void* type, void* destructor) { abort(); } -__attribute__((__weak__)) -void* __cxa_allocate_exception(size_t thrown_size) { - abort(); -} - // WasmFS integration. We stub out file preloading and such, that are not // expected to work anyhow. diff --git a/test/core/test_exceptions_primary.cpp b/test/core/test_exceptions_primary.cpp index 511b7eafa357d..70c35edbd6826 100644 --- a/test/core/test_exceptions_primary.cpp +++ b/test/core/test_exceptions_primary.cpp @@ -9,6 +9,7 @@ #include // std::logic_error int main () { + std::cout << "in main\n"; std::exception_ptr p; try { throw std::logic_error("some logic_error exception"); // throws @@ -20,7 +21,7 @@ int main () { std::cout << "(after exception)\n"; try { - std::rethrow_exception (p); + std::rethrow_exception(p); } catch (const std::exception& e) { std::cout << "exception caught: " << e.what() << '\n'; } diff --git a/test/no_this_in_dyncall.out b/test/no_this_in_dyncall.out index f70d7bba4ae1f..d81cc0710eb6c 100644 --- a/test/no_this_in_dyncall.out +++ b/test/no_this_in_dyncall.out @@ -1 +1 @@ -42 \ No newline at end of file +42 diff --git a/test/other/metadce/test_metadce_cxx_ctors1.exports b/test/other/metadce/test_metadce_cxx_ctors1.exports index 7590b6e0dd3f1..f4dc65925fb0b 100644 --- a/test/other/metadce/test_metadce_cxx_ctors1.exports +++ b/test/other/metadce/test_metadce_cxx_ctors1.exports @@ -1,3 +1,4 @@ +__cxa_increment_exception_refcount __cxa_is_pointer_type __errno_location __indirect_function_table diff --git a/test/other/metadce/test_metadce_cxx_ctors2.exports b/test/other/metadce/test_metadce_cxx_ctors2.exports index 0605207136d30..183246153c0dd 100644 --- a/test/other/metadce/test_metadce_cxx_ctors2.exports +++ b/test/other/metadce/test_metadce_cxx_ctors2.exports @@ -1,3 +1,4 @@ +__cxa_increment_exception_refcount __cxa_is_pointer_type __errno_location __indirect_function_table diff --git a/test/other/metadce/test_metadce_cxx_except.exports b/test/other/metadce/test_metadce_cxx_except.exports index 3f04dd4390620..0697b34554a59 100644 --- a/test/other/metadce/test_metadce_cxx_except.exports +++ b/test/other/metadce/test_metadce_cxx_except.exports @@ -1,5 +1,7 @@ __cxa_can_catch +__cxa_decrement_exception_refcount __cxa_free_exception +__cxa_increment_exception_refcount __cxa_is_pointer_type __errno_location __indirect_function_table diff --git a/test/other/metadce/test_metadce_cxx_except.jssize b/test/other/metadce/test_metadce_cxx_except.jssize index 76cb23dce88c3..556009c26d005 100644 --- a/test/other/metadce/test_metadce_cxx_except.jssize +++ b/test/other/metadce/test_metadce_cxx_except.jssize @@ -1 +1 @@ -30731 +30647 diff --git a/test/other/metadce/test_metadce_cxx_except.size b/test/other/metadce/test_metadce_cxx_except.size index 1dabda97be1a0..e002babd75bc5 100644 --- a/test/other/metadce/test_metadce_cxx_except.size +++ b/test/other/metadce/test_metadce_cxx_except.size @@ -1 +1 @@ -165312 +166229 diff --git a/test/other/metadce/test_metadce_cxx_mangle.exports b/test/other/metadce/test_metadce_cxx_mangle.exports index d517a701b28ff..2a14e2cb1fbda 100644 --- a/test/other/metadce/test_metadce_cxx_mangle.exports +++ b/test/other/metadce/test_metadce_cxx_mangle.exports @@ -1,6 +1,8 @@ __cxa_can_catch +__cxa_decrement_exception_refcount __cxa_demangle __cxa_free_exception +__cxa_increment_exception_refcount __cxa_is_pointer_type __errno_location __indirect_function_table diff --git a/test/other/metadce/test_metadce_cxx_mangle.jssize b/test/other/metadce/test_metadce_cxx_mangle.jssize index f27a5fc2f515d..0f8b4a91ce346 100644 --- a/test/other/metadce/test_metadce_cxx_mangle.jssize +++ b/test/other/metadce/test_metadce_cxx_mangle.jssize @@ -1 +1 @@ -30736 +30651 diff --git a/test/other/metadce/test_metadce_cxx_mangle.size b/test/other/metadce/test_metadce_cxx_mangle.size index 66fd4fb1993fd..50931b6ce6811 100644 --- a/test/other/metadce/test_metadce_cxx_mangle.size +++ b/test/other/metadce/test_metadce_cxx_mangle.size @@ -1 +1 @@ -220408 +221325 diff --git a/test/other/metadce/test_metadce_cxx_noexcept.exports b/test/other/metadce/test_metadce_cxx_noexcept.exports index 7590b6e0dd3f1..f4dc65925fb0b 100644 --- a/test/other/metadce/test_metadce_cxx_noexcept.exports +++ b/test/other/metadce/test_metadce_cxx_noexcept.exports @@ -1,3 +1,4 @@ +__cxa_increment_exception_refcount __cxa_is_pointer_type __errno_location __indirect_function_table diff --git a/test/other/metadce/test_metadce_cxx_noexcept.jssize b/test/other/metadce/test_metadce_cxx_noexcept.jssize index 5a83e94204ad0..a17c777bce2e8 100644 --- a/test/other/metadce/test_metadce_cxx_noexcept.jssize +++ b/test/other/metadce/test_metadce_cxx_noexcept.jssize @@ -1 +1 @@ -26205 +26122 diff --git a/test/other/metadce/test_metadce_cxx_noexcept.size b/test/other/metadce/test_metadce_cxx_noexcept.size index f4b7350835a3f..79e609efbb1cd 100644 --- a/test/other/metadce/test_metadce_cxx_noexcept.size +++ b/test/other/metadce/test_metadce_cxx_noexcept.size @@ -1 +1 @@ -126251 +126371 diff --git a/test/other/metadce/test_metadce_minimal_O0.jssize b/test/other/metadce/test_metadce_minimal_O0.jssize index 4146d1bfbc386..6121d7203d2bf 100644 --- a/test/other/metadce/test_metadce_minimal_O0.jssize +++ b/test/other/metadce/test_metadce_minimal_O0.jssize @@ -1 +1 @@ -20294 +20694 diff --git a/test/test_core.py b/test/test_core.py index 594299cc458a0..dec35b9f46535 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -1262,7 +1262,6 @@ def test_exceptions_off(self): @no_asan('TODO: ASan support in minimal runtime') @no_wasm64('MEMORY64 does not yet support exceptions') def test_exceptions_minimal_runtime(self): - self.set_setting('EXCEPTION_DEBUG') self.set_setting('EXIT_RUNTIME') self.maybe_closure() self.set_setting('MINIMAL_RUNTIME') @@ -1273,6 +1272,7 @@ def test_exceptions_minimal_runtime(self): self.set_setting('DISABLE_EXCEPTION_CATCHING', 0) self.do_run_from_file(test_file('core/test_exceptions.cpp'), test_file('core/test_exceptions_caught.out')) + self.set_setting('EXCEPTION_DEBUG') self.set_setting('DISABLE_EXCEPTION_CATCHING') self.do_run_from_file(test_file('core/test_exceptions.cpp'), test_file('core/test_exceptions_uncaught.out'), assert_returncode=NON_ZERO) diff --git a/test/test_other.py b/test/test_other.py index 7d70fb9c13768..e40d929cdb118 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -13011,7 +13011,7 @@ def test_rust_gxx_personality_v0(self): return 0; } } - ''', assert_returncode=NON_ZERO) + ''', assert_returncode=NON_ZERO, emcc_args=['-fexceptions']) def test_bigint64array_polyfill(self): bigint64array = read_file(path_from_root('src/polyfill/bigint64array.js')) diff --git a/tools/deps_info.py b/tools/deps_info.py index 4d5f9a557019b..1bc56aa76a819 100644 --- a/tools/deps_info.py +++ b/tools/deps_info.py @@ -185,18 +185,16 @@ def append_deps_info(js_symbol_deps): def get_deps_info(): if not settings.WASM_EXCEPTIONS and settings.LINK_AS_CXX: - _deps_info['__cxa_begin_catch'] = ['__cxa_is_pointer_type', '__cxa_free_exception'] - _deps_info['__cxa_throw'] = ['__cxa_is_pointer_type'] - _deps_info['__cxa_find_matching_catch'] = ['__cxa_can_catch', 'setTempRet0'] - _deps_info['__cxa_find_matching_catch_1'] = ['__cxa_can_catch', 'setTempRet0'] - _deps_info['__cxa_find_matching_catch_2'] = ['__cxa_can_catch', 'setTempRet0'] - _deps_info['__cxa_find_matching_catch_3'] = ['__cxa_can_catch', 'setTempRet0'] - _deps_info['__cxa_find_matching_catch_4'] = ['__cxa_can_catch', 'setTempRet0'] - _deps_info['__cxa_find_matching_catch_5'] = ['__cxa_can_catch', 'setTempRet0'] - _deps_info['__cxa_find_matching_catch_6'] = ['__cxa_can_catch', 'setTempRet0'] - _deps_info['__cxa_find_matching_catch_7'] = ['__cxa_can_catch', 'setTempRet0'] - _deps_info['__cxa_find_matching_catch_8'] = ['__cxa_can_catch', 'setTempRet0'] - _deps_info['__cxa_find_matching_catch_9'] = ['__cxa_can_catch', 'setTempRet0'] + _deps_info['__cxa_end_catch'] = ['setThrew', '__cxa_decrement_exception_refcount'] + base_js_exception_deps = [ + '__cxa_is_pointer_type', + '__cxa_increment_exception_refcount', + ] + _deps_info['__cxa_throw'] = base_js_exception_deps + _deps_info['__cxa_begin_catch'] = base_js_exception_deps + _deps_info['__cxa_find_matching_catch'] = base_js_exception_deps + ['__cxa_can_catch', 'setTempRet0'] + for i in range(1, 10): + _deps_info['__cxa_find_matching_catch_%d' % i] = _deps_info['__cxa_find_matching_catch'] if settings.PTHREADS and settings.OFFSCREENCANVAS_SUPPORT: _deps_info['pthread_create'] = ['malloc'] if settings.FILESYSTEM and settings.SYSCALLS_REQUIRE_FILESYSTEM: diff --git a/tools/system_libs.py b/tools/system_libs.py index b0cca903a4963..8098052fbbba8 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -1476,16 +1476,20 @@ def get_files(self): 'stdlib_stdexcept.cpp', 'stdlib_typeinfo.cpp', 'private_typeinfo.cpp', - 'cxa_exception_emscripten.cpp', + 'cxa_exception_js_utils.cpp', ] if self.eh_mode == Exceptions.NONE: filenames += ['cxa_noexception.cpp'] + elif self.eh_mode == Exceptions.EMSCRIPTEN: + filenames += ['cxa_exception_emscripten.cpp'] elif self.eh_mode == Exceptions.WASM: filenames += [ 'cxa_exception_storage.cpp', 'cxa_exception.cpp', 'cxa_personality.cpp' ] + else: + assert False return files_in_path( path='system/lib/libcxxabi/src', From 2c07fa650624de0915cec36b382f7f83167593e3 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 11 Apr 2023 14:08:59 -0700 Subject: [PATCH 0115/1523] [GLFW] Add missing checks before GLFW callbacks (#19148) Also convert them all to if (..) { .. } notation (diff without whitespace is smaller). A few were left in the old format if the code benefited from that due to other reasons in the surrounding logic. Fixes #19145 --- src/library_glfw.js | 72 +++++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 35 deletions(-) diff --git a/src/library_glfw.js b/src/library_glfw.js index 944fc70474cb0..7de00ae98a03d 100644 --- a/src/library_glfw.js +++ b/src/library_glfw.js @@ -370,7 +370,6 @@ var LibraryGLFW = { #if USE_GLFW == 2 {{{ makeDynCall('vii', 'GLFW.active.charFunc') }}}(charCode, 1); #endif - #if USE_GLFW == 3 {{{ makeDynCall('vii', 'GLFW.active.charFunc') }}}(GLFW.active.id, charCode); #endif @@ -387,16 +386,16 @@ var LibraryGLFW = { #endif GLFW.active.keys[key] = status; GLFW.active.domKeys[keyCode] = status; - if (!GLFW.active.keyFunc) return; + if (GLFW.active.keyFunc) { #if USE_GLFW == 2 - {{{ makeDynCall('vii', 'GLFW.active.keyFunc') }}}(key, status); + {{{ makeDynCall('vii', 'GLFW.active.keyFunc') }}}(key, status); #endif - #if USE_GLFW == 3 - if (repeat) status = 2; // GLFW_REPEAT - {{{ makeDynCall('viiiii', 'GLFW.active.keyFunc') }}}(GLFW.active.id, key, keyCode, status, GLFW.getModBits(GLFW.active)); + if (repeat) status = 2; // GLFW_REPEAT + {{{ makeDynCall('viiiii', 'GLFW.active.keyFunc') }}}(GLFW.active.id, key, keyCode, status, GLFW.getModBits(GLFW.active)); #endif + } }, onGamepadConnected: function(event) { @@ -439,13 +438,14 @@ var LibraryGLFW = { if (event.target != Module["canvas"] || !GLFW.active.cursorPosFunc) return; + if (GLFW.active.cursorPosFunc) { #if USE_GLFW == 2 - {{{ makeDynCall('vii', 'GLFW.active.cursorPosFunc') }}}(Browser.mouseX, Browser.mouseY); + {{{ makeDynCall('vii', 'GLFW.active.cursorPosFunc') }}}(Browser.mouseX, Browser.mouseY); #endif - #if USE_GLFW == 3 - {{{ makeDynCall('vidd', 'GLFW.active.cursorPosFunc') }}}(GLFW.active.id, Browser.mouseX, Browser.mouseY); + {{{ makeDynCall('vidd', 'GLFW.active.cursorPosFunc') }}}(GLFW.active.id, Browser.mouseX, Browser.mouseY); #endif + } }, DOMToGLFWMouseButton: function(event) { @@ -465,20 +465,24 @@ var LibraryGLFW = { onMouseenter: function(event) { if (!GLFW.active) return; - if (event.target != Module["canvas"] || !GLFW.active.cursorEnterFunc) return; + if (event.target != Module["canvas"]) return; #if USE_GLFW == 3 - {{{ makeDynCall('vii', 'GLFW.active.cursorEnterFunc') }}}(GLFW.active.id, 1); + if (GLFW.active.cursorEnterFunc) { + {{{ makeDynCall('vii', 'GLFW.active.cursorEnterFunc') }}}(GLFW.active.id, 1); + } #endif }, onMouseleave: function(event) { if (!GLFW.active) return; - if (event.target != Module["canvas"] || !GLFW.active.cursorEnterFunc) return; + if (event.target != Module["canvas"]) return; #if USE_GLFW == 3 - {{{ makeDynCall('vii', 'GLFW.active.cursorEnterFunc') }}}(GLFW.active.id, 0); + if (GLFW.active.cursorEnterFunc) { + {{{ makeDynCall('vii', 'GLFW.active.cursorEnterFunc') }}}(GLFW.active.id, 0); + } #endif }, @@ -500,15 +504,14 @@ var LibraryGLFW = { GLFW.active.buttons &= ~(1 << eventButton); } - if (!GLFW.active.mouseButtonFunc) return; - + if (GLFW.active.mouseButtonFunc) { #if USE_GLFW == 2 - {{{ makeDynCall('vii', 'GLFW.active.mouseButtonFunc') }}}(eventButton, status); + {{{ makeDynCall('vii', 'GLFW.active.mouseButtonFunc') }}}(eventButton, status); #endif - #if USE_GLFW == 3 - {{{ makeDynCall('viiii', 'GLFW.active.mouseButtonFunc') }}}(GLFW.active.id, eventButton, status, GLFW.getModBits(GLFW.active)); + {{{ makeDynCall('viiii', 'GLFW.active.mouseButtonFunc') }}}(GLFW.active.id, eventButton, status, GLFW.getModBits(GLFW.active)); #endif + } }, onMouseButtonDown: function(event) { @@ -528,11 +531,9 @@ var LibraryGLFW = { GLFW.wheelPos += delta; if (!GLFW.active || !GLFW.active.scrollFunc || event.target != Module['canvas']) return; - #if USE_GLFW == 2 {{{ makeDynCall('vi', 'GLFW.active.scrollFunc') }}}(GLFW.wheelPos); #endif - #if USE_GLFW == 3 var sx = 0; var sy = delta; @@ -594,24 +595,23 @@ var LibraryGLFW = { onWindowSizeChanged: function() { if (!GLFW.active) return; - if (!GLFW.active.windowSizeFunc) return; - + if (GLFW.active.windowSizeFunc) { #if USE_GLFW == 2 - {{{ makeDynCall('vii', 'GLFW.active.windowSizeFunc') }}}(GLFW.active.width, GLFW.active.height); + {{{ makeDynCall('vii', 'GLFW.active.windowSizeFunc') }}}(GLFW.active.width, GLFW.active.height); #endif - #if USE_GLFW == 3 - {{{ makeDynCall('viii', 'GLFW.active.windowSizeFunc') }}}(GLFW.active.id, GLFW.active.width, GLFW.active.height); + {{{ makeDynCall('viii', 'GLFW.active.windowSizeFunc') }}}(GLFW.active.id, GLFW.active.width, GLFW.active.height); #endif + } }, onFramebufferSizeChanged: function() { if (!GLFW.active) return; - if (!GLFW.active.framebufferSizeFunc) return; - #if USE_GLFW == 3 - {{{ makeDynCall('viii', 'GLFW.active.framebufferSizeFunc') }}}(GLFW.active.id, GLFW.active.width, GLFW.active.height); + if (GLFW.active.framebufferSizeFunc) { + {{{ makeDynCall('viii', 'GLFW.active.framebufferSizeFunc') }}}(GLFW.active.id, GLFW.active.width, GLFW.active.height); + } #endif }, @@ -620,7 +620,9 @@ var LibraryGLFW = { if (!GLFW.active) return; #if USE_GLFW == 3 - {{{ makeDynCall('viff', 'GLFW.active.windowContentScaleFunc') }}}(GLFW.active.id, GLFW.scale, GLFW.scale); + if (GLFW.active.windowContentScaleFunc) { + {{{ makeDynCall('viff', 'GLFW.active.windowContentScaleFunc') }}}(GLFW.active.id, GLFW.scale, GLFW.scale); + } #endif }, @@ -988,15 +990,14 @@ var LibraryGLFW = { } } - if (!win.windowSizeFunc) return; - + if (win.windowSizeFunc) { #if USE_GLFW == 2 - {{{ makeDynCall('vii', 'win.windowSizeFunc') }}}(width, height); + {{{ makeDynCall('vii', 'win.windowSizeFunc') }}}(width, height); #endif - #if USE_GLFW == 3 - {{{ makeDynCall('viii', 'win.windowSizeFunc') }}}(win.id, width, height); + {{{ makeDynCall('viii', 'win.windowSizeFunc') }}}(win.id, width, height); #endif + } }, createWindow: function(width, height, title, monitor, share) { @@ -1063,8 +1064,9 @@ var LibraryGLFW = { if (!win) return; #if USE_GLFW == 3 - if (win.windowCloseFunc) + if (win.windowCloseFunc) { {{{ makeDynCall('vi', 'win.windowCloseFunc') }}}(win.id); + } #endif GLFW.windows[win.id - 1] = null; From 7d2ca622bd6fe2c7f280312cdf569b3f9c0519d2 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 11 Apr 2023 14:20:49 -0700 Subject: [PATCH 0116/1523] Rebaseline codesize expectations. NFC --- test/other/metadce/test_metadce_cxx_ctors1.jssize | 2 +- test/other/metadce/test_metadce_cxx_ctors1.size | 2 +- test/other/metadce/test_metadce_cxx_ctors2.jssize | 2 +- test/other/metadce/test_metadce_cxx_ctors2.size | 2 +- test/other/metadce/test_metadce_cxx_except.jssize | 2 +- test/other/metadce/test_metadce_cxx_mangle.jssize | 2 +- test/other/metadce/test_metadce_cxx_noexcept.jssize | 2 +- test/other/metadce/test_metadce_hello_O0.jssize | 2 +- test/other/metadce/test_metadce_minimal_O0.jssize | 2 +- test/other/test_unoptimized_code_size.js.size | 2 +- test/other/test_unoptimized_code_size_strict.js.size | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/test/other/metadce/test_metadce_cxx_ctors1.jssize b/test/other/metadce/test_metadce_cxx_ctors1.jssize index 5a83e94204ad0..eaa1bce3a3169 100644 --- a/test/other/metadce/test_metadce_cxx_ctors1.jssize +++ b/test/other/metadce/test_metadce_cxx_ctors1.jssize @@ -1 +1 @@ -26205 +26064 diff --git a/test/other/metadce/test_metadce_cxx_ctors1.size b/test/other/metadce/test_metadce_cxx_ctors1.size index fba69b18f9001..912d2488a2a9c 100644 --- a/test/other/metadce/test_metadce_cxx_ctors1.size +++ b/test/other/metadce/test_metadce_cxx_ctors1.size @@ -1 +1 @@ -123454 +123573 diff --git a/test/other/metadce/test_metadce_cxx_ctors2.jssize b/test/other/metadce/test_metadce_cxx_ctors2.jssize index fbdf8f8114343..de572e787d4bc 100644 --- a/test/other/metadce/test_metadce_cxx_ctors2.jssize +++ b/test/other/metadce/test_metadce_cxx_ctors2.jssize @@ -1 +1 @@ -26169 +26028 diff --git a/test/other/metadce/test_metadce_cxx_ctors2.size b/test/other/metadce/test_metadce_cxx_ctors2.size index 96fcfdd147414..c05b9543c7300 100644 --- a/test/other/metadce/test_metadce_cxx_ctors2.size +++ b/test/other/metadce/test_metadce_cxx_ctors2.size @@ -1 +1 @@ -123359 +123478 diff --git a/test/other/metadce/test_metadce_cxx_except.jssize b/test/other/metadce/test_metadce_cxx_except.jssize index 556009c26d005..907b6f9c52048 100644 --- a/test/other/metadce/test_metadce_cxx_except.jssize +++ b/test/other/metadce/test_metadce_cxx_except.jssize @@ -1 +1 @@ -30647 +30578 diff --git a/test/other/metadce/test_metadce_cxx_mangle.jssize b/test/other/metadce/test_metadce_cxx_mangle.jssize index 0f8b4a91ce346..1c6ad02b459b4 100644 --- a/test/other/metadce/test_metadce_cxx_mangle.jssize +++ b/test/other/metadce/test_metadce_cxx_mangle.jssize @@ -1 +1 @@ -30651 +30582 diff --git a/test/other/metadce/test_metadce_cxx_noexcept.jssize b/test/other/metadce/test_metadce_cxx_noexcept.jssize index a17c777bce2e8..eaa1bce3a3169 100644 --- a/test/other/metadce/test_metadce_cxx_noexcept.jssize +++ b/test/other/metadce/test_metadce_cxx_noexcept.jssize @@ -1 +1 @@ -26122 +26064 diff --git a/test/other/metadce/test_metadce_hello_O0.jssize b/test/other/metadce/test_metadce_hello_O0.jssize index 8cb9d5e400dfd..e8bcc8a6af475 100644 --- a/test/other/metadce/test_metadce_hello_O0.jssize +++ b/test/other/metadce/test_metadce_hello_O0.jssize @@ -1 +1 @@ -24048 +24028 diff --git a/test/other/metadce/test_metadce_minimal_O0.jssize b/test/other/metadce/test_metadce_minimal_O0.jssize index 6121d7203d2bf..ee659efaeef94 100644 --- a/test/other/metadce/test_metadce_minimal_O0.jssize +++ b/test/other/metadce/test_metadce_minimal_O0.jssize @@ -1 +1 @@ -20694 +20274 diff --git a/test/other/test_unoptimized_code_size.js.size b/test/other/test_unoptimized_code_size.js.size index 42f4f5feb52f1..945c40bdcfd9f 100644 --- a/test/other/test_unoptimized_code_size.js.size +++ b/test/other/test_unoptimized_code_size.js.size @@ -1 +1 @@ -59710 +59729 diff --git a/test/other/test_unoptimized_code_size_strict.js.size b/test/other/test_unoptimized_code_size_strict.js.size index b4386945c4b88..504971565a78a 100644 --- a/test/other/test_unoptimized_code_size_strict.js.size +++ b/test/other/test_unoptimized_code_size_strict.js.size @@ -1 +1 @@ -58652 +58671 From c4c0ecd6e78db5d9068c5631761e01eb03916c5c Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 11 Apr 2023 19:52:54 -0700 Subject: [PATCH 0117/1523] Remove `makeMalloc` utility function. NFC (#19160) It seems much safer/cleaner to simply use explicit dependencies on `malloc`. The one function where an optional dependency might be useful is `allocate` since it can operator both with and without `malloc`, but that function is deprecated/legacy. See #19159 --- src/library_glfw.js | 3 ++- src/library_legacy.js | 4 ++-- src/library_strings.js | 4 ++-- src/parseTools.js | 15 --------------- src/parseTools_legacy.js | 4 ++++ test/test_other.py | 19 ------------------- tools/deps_info.py | 2 +- 7 files changed, 11 insertions(+), 40 deletions(-) diff --git a/src/library_glfw.js b/src/library_glfw.js index 7de00ae98a03d..63c66f5b34e98 100644 --- a/src/library_glfw.js +++ b/src/library_glfw.js @@ -1272,10 +1272,11 @@ var LibraryGLFW = { glfwPostEmptyEvent: function() {}, glfwGetMonitors__sig: 'ii', + glfwGetMonitors__deps: ['malloc'], glfwGetMonitors: function(count) { {{{ makeSetValue('count', '0', '1', 'i32') }}}; if (!GLFW.monitors) { - GLFW.monitors = {{{ makeMalloc('glfwGetMonitors', POINTER_SIZE) }}}; + GLFW.monitors = _malloc({{{ POINTER_SIZE }}}); {{{ makeSetValue('GLFW.monitors', '0', '1', 'i32') }}}; } return GLFW.monitors; diff --git a/src/library_legacy.js b/src/library_legacy.js index a396573f86e11..6a7362b627afa 100644 --- a/src/library_legacy.js +++ b/src/library_legacy.js @@ -17,7 +17,7 @@ mergeInto(LibraryManager.library, { * @param {(Uint8Array|Array)} slab: An array of data. * @param {number=} allocator : How to allocate memory, see ALLOC_* */ - $allocate__deps: ['$ALLOC_NORMAL', '$ALLOC_STACK'], + $allocate__deps: ['$ALLOC_NORMAL', '$ALLOC_STACK', 'malloc'], $allocate: function(slab, allocator) { var ret; #if ASSERTIONS @@ -28,7 +28,7 @@ mergeInto(LibraryManager.library, { if (allocator == ALLOC_STACK) { ret = stackAlloc(slab.length); } else { - ret = {{{ makeMalloc('allocate', 'slab.length') }}}; + ret = _malloc(slab.length); } if (!slab.subarray && !slab.slice) { diff --git a/src/library_strings.js b/src/library_strings.js index 1cbf2635036ed..a7da5dec1af7f 100644 --- a/src/library_strings.js +++ b/src/library_strings.js @@ -479,10 +479,10 @@ mergeInto(LibraryManager.library, { // Allocate heap space for a JS string, and write it there. // It is the responsibility of the caller to free() that memory. - $stringToNewUTF8__deps: ['$lengthBytesUTF8', '$stringToUTF8'], + $stringToNewUTF8__deps: ['$lengthBytesUTF8', '$stringToUTF8', 'malloc'], $stringToNewUTF8: function(str) { var size = lengthBytesUTF8(str) + 1; - var ret = {{{ makeMalloc('stringToNewUTF8', 'size') }}}; + var ret = _malloc(size); if (ret) stringToUTF8(str, ret, size); return ret; }, diff --git a/src/parseTools.js b/src/parseTools.js index 02b70dc394d80..66e6bd8946fff 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -925,21 +925,6 @@ function awaitIf(condition) { return condition ? 'await' : ''; } -function makeMalloc(source, param) { - if (hasExportedSymbol('malloc')) { - return `_malloc(${param})`; - } - // It should be impossible to call some functions without malloc being - // included, unless we have a deps_info.json bug. To let closure not error - // on `_malloc` not being present, they don't call malloc and instead abort - // with an error at runtime. - // TODO: A more comprehensive deps system could catch this at compile time. - if (!ASSERTIONS) { - return 'abort();'; - } - return `abort('malloc was not included, but is needed in ${source}. Adding "_malloc" to EXPORTED_FUNCTIONS should fix that. This may be a bug in the compiler, please file an issue.');`; -} - // Adds a call to runtimeKeepalivePush, if needed by the current build // configuration. // We skip this completely in MINIMAL_RUNTIME and also in builds that diff --git a/src/parseTools_legacy.js b/src/parseTools_legacy.js index 3e6bd7b07dd3f..c3adeb7930295 100644 --- a/src/parseTools_legacy.js +++ b/src/parseTools_legacy.js @@ -85,6 +85,10 @@ function makeCopyValues(dest, src, num, type, modifier, align, sep = ';') { return ret.join(sep); } +function makeMalloc(source, param) { + return `_malloc(${param})`; +} + global.Runtime = { getNativeTypeSize: getNativeTypeSize, getNativeFieldSize: getNativeFieldSize, diff --git a/test/test_other.py b/test/test_other.py index e40d929cdb118..4e575609453f3 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -11519,25 +11519,6 @@ def test_missing_malloc_export(self): "malloc() called but not included in the build - add '_malloc' to EXPORTED_FUNCTIONS", "free() called but not included in the build - add '_free' to EXPORTED_FUNCTIONS")) - def test_missing_malloc_export_indirect(self): - # we used to include malloc by default. show a clear error in builds with - # ASSERTIONS to help with any confusion when the user calls a JS API that - # requires malloc - create_file('unincluded_malloc.c', r''' - #include - EM_JS_DEPS(main, "$stringToNewUTF8"); - int main() { - EM_ASM({ - try { - stringToNewUTF8("foo"); - } catch(e) { - console.log('exception:', e); - } - }); - } - ''') - self.do_runf('unincluded_malloc.c', 'malloc was not included, but is needed in stringToNewUTF8. Adding "_malloc" to EXPORTED_FUNCTIONS should fix that. This may be a bug in the compiler, please file an issue.') - def test_getrusage(self): self.do_runf(test_file('other/test_getrusage.c')) diff --git a/tools/deps_info.py b/tools/deps_info.py index 1bc56aa76a819..2d7460fe1886c 100644 --- a/tools/deps_info.py +++ b/tools/deps_info.py @@ -150,7 +150,7 @@ 'glewInit': ['malloc'], 'glfwGetProcAddress': ['malloc'], 'glfwInit': ['malloc', 'free'], - 'glfwSleep': ['sleep'], + 'glfwSleep': ['sleep', 'malloc'], 'glfwGetMonitors': ['malloc'], 'localtime': ['malloc'], 'localtime_r': ['malloc'], From 2bf300089d9ae12a1275076f2e54b3e47b160949 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 11 Apr 2023 19:56:18 -0700 Subject: [PATCH 0118/1523] [Wasm64] Changes to make AUDIO_WORKLET work with MEMORY64 (#18972) --- emscripten.py | 3 ++- src/library_sigs.js | 3 +++ src/library_webaudio.js | 5 +---- test/test_browser.py | 9 ++++++--- tools/gen_sig_info.py | 4 ++++ 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/emscripten.py b/emscripten.py index 935d8212e11d8..274975c50dafe 100644 --- a/emscripten.py +++ b/emscripten.py @@ -886,7 +886,8 @@ def create_wasm64_wrappers(metadata): '_emscripten_dlsync_self_async': '_p', '_emscripten_proxy_dlsync_async': '_pp', '_wasmfs_rmdir': '_p', - '_wasmfs_unlink': '_p' + '_wasmfs_unlink': '_p', + 'emscripten_wasm_worker_initialize': '_p_', } wasm64_wrappers = ''' diff --git a/src/library_sigs.js b/src/library_sigs.js index 9fdbf18790fe1..8e69e8e218458 100644 --- a/src/library_sigs.js +++ b/src/library_sigs.js @@ -438,6 +438,8 @@ sigs = { emscripten_console_log__sig: 'vp', emscripten_console_warn__sig: 'vp', emscripten_create_audio_context__sig: 'ip', + emscripten_create_wasm_audio_worklet_node__sig: 'iipppp', + emscripten_create_wasm_audio_worklet_processor_async__sig: 'vippp', emscripten_create_worker__sig: 'ip', emscripten_current_thread_is_audio_worklet__sig: 'i', emscripten_date_now__sig: 'd', @@ -621,6 +623,7 @@ sigs = { emscripten_stack_snapshot__sig: 'p', emscripten_stack_unwind_buffer__sig: 'ippi', emscripten_start_fetch__sig: 'vp', + emscripten_start_wasm_audio_worklet_thread_async__sig: 'vipipp', emscripten_supports_offscreencanvas__sig: 'i', emscripten_throw_number__sig: 'vd', emscripten_throw_string__sig: 'vp', diff --git a/src/library_webaudio.js b/src/library_webaudio.js index d0e6da3075404..9b4942f0aa472 100644 --- a/src/library_webaudio.js +++ b/src/library_webaudio.js @@ -126,9 +126,6 @@ let LibraryWebAudio = { 'wasm_workers_id', '$_EmAudioDispatchProcessorCallback'], emscripten_start_wasm_audio_worklet_thread_async: function(contextHandle, stackLowestAddress, stackSize, callback, userData) { -#if !AUDIO_WORKLET - abort('emscripten_create_wasm_audio_worklet() requires building with -s AUDIO_WORKLET=1 enabled!'); -#endif #if ASSERTIONS assert(contextHandle, `Called emscripten_start_wasm_audio_worklet_thread_async() with a null Web Audio Context handle!`); @@ -156,7 +153,7 @@ let LibraryWebAudio = { #if WEBAUDIO_DEBUG console.error(`emscripten_start_wasm_audio_worklet_thread_async() addModule() failed!`); #endif - {{{ makeDynCall('viii', 'callback') }}}(contextHandle, 0/*EM_FALSE*/, userData); + {{{ makeDynCall('viip', 'callback') }}}(contextHandle, 0/*EM_FALSE*/, userData); }; // Does browser not support AudioWorklets? diff --git a/test/test_browser.py b/test/test_browser.py index 36e2e38825569..3cb8a2ff790c9 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -418,7 +418,7 @@ def make_main_two_files(path1, path2, nonexistingpath): # Tests that user .html shell files can manually download .data files created with --preload-file cmdline. @parameterized({ - 'default': ([],), + '': ([],), 'pthreads': (['-pthread', '-sPROXY_TO_PTHREAD', '-sEXIT_RUNTIME'],), }) @requires_threads @@ -5502,7 +5502,8 @@ def test_full_js_library_strict(self): # Tests the AudioWorklet demo @parameterized({ - 'default': ([],), + '': ([],), + 'memory64': (['-sMEMORY64', '-Wno-experimental'],), 'with_fs': (['--preload-file', test_file('hello_world.c') + '@/'],), 'closure': (['--closure', '1', '-Oz'],), 'asyncify': (['-sASYNCIFY'],), @@ -5512,11 +5513,13 @@ def test_full_js_library_strict(self): 'minimal_runtime_pthreads_and_closure': (['-sMINIMAL_RUNTIME', '-pthread', '--closure', '1', '-Oz'],), }) def test_audio_worklet(self, args): + if '-sMEMORY64' in args and is_firefox(): + self.skipTest('https://github.com/emscripten-core/emscripten/issues/19161') self.btest_exit(test_file('webaudio/audioworklet.c'), args=['-sAUDIO_WORKLET', '-sWASM_WORKERS'] + args) # Tests that posting functions between the main thread and the audioworklet thread works @parameterized({ - 'default': ([],), + '': ([],), 'closure': (['--closure', '1', '-Oz'],), }) def test_audio_worklet_post_function(self, args): diff --git a/tools/gen_sig_info.py b/tools/gen_sig_info.py index b0a9e85c2da45..e1a653c333dd1 100755 --- a/tools/gen_sig_info.py +++ b/tools/gen_sig_info.py @@ -231,6 +231,8 @@ def extract_sigs(symbols, obj_file): def extract_sig_info(sig_info, extra_settings=None, extra_cflags=None): tempfiles = shared.get_temp_files() settings = { + # Enable as many settings as we can here to ensure the maximum number + # of JS symbols are included. 'STACK_OVERFLOW_CHECK': 1, 'MAX_WEBGL_VERSION': 2, 'FULL_ES3': 1, @@ -238,6 +240,8 @@ def extract_sig_info(sig_info, extra_settings=None, extra_cflags=None): 'FETCH': 1, 'PTHREADS': 1, 'SHARED_MEMORY': 1, + 'AUDIO_WORKLET': 1, + 'WASM_WORKERS': 1, # Currently GLFW symbols have different sigs for the same symbol because the # signatures changed between v2 and v3, so for now we continue to maintain # them by hand. From 3c5bac99f8d3070113d4e9af64dbbbceea4b51b0 Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Tue, 11 Apr 2023 20:31:54 -0700 Subject: [PATCH 0119/1523] Implement `emscripten_promise_any` in promise.h (#19153) Similar to `emscripten_promise_all` and `emscripten_promise_all_settled`, this function propagates the first of its input promises to be fulfilled or is rejected with a list of reasons if its inputs are rejected. --- src/library_promise.js | 25 ++++++ src/library_sigs.js | 1 + system/include/emscripten/promise.h | 11 +++ test/core/test_promise.c | 126 +++++++++++++++++++++++++++- test/core/test_promise.out | 7 ++ 5 files changed, 167 insertions(+), 3 deletions(-) diff --git a/src/library_promise.js b/src/library_promise.js index 7d62c584ccf06..b2d6aa757d49b 100644 --- a/src/library_promise.js +++ b/src/library_promise.js @@ -215,4 +215,29 @@ mergeInto(LibraryManager.library, { #endif return id; }, + + emscripten_promise_any__deps: ['$promiseMap', '$idsToPromises'], + emscripten_promise_any: function(idBuf, errorBuf, size) { + var promises = idsToPromises(idBuf, size); +#if RUNTIME_DEBUG + dbg('emscripten_promise_any: ' + promises); +#endif +#if ASSERTIONS + assert(typeof Promise.any !== 'undefined', "Promise.any does not exist"); +#endif + var id = promiseMap.allocate({ + promise: Promise.any(promises).catch((err) => { + if (errorBuf) { + for (var i = 0; i < size; i++) { + {{{ makeSetValue('errorBuf', `i*${POINTER_SIZE}`, 'err.errors[i]', '*') }}}; + } + } + throw errorBuf; + }) + }); +#if RUNTIME_DEBUG + dbg('create: ' + id); +#endif + return id; + } }); diff --git a/src/library_sigs.js b/src/library_sigs.js index 8e69e8e218458..d46b1c3d1e406 100644 --- a/src/library_sigs.js +++ b/src/library_sigs.js @@ -537,6 +537,7 @@ sigs = { emscripten_print_double__sig: 'idpi', emscripten_promise_all__sig: 'pppp', emscripten_promise_all_settled__sig: 'pppp', + emscripten_promise_any__sig: 'pppp', emscripten_promise_create__sig: 'p', emscripten_promise_destroy__sig: 'vp', emscripten_promise_resolve__sig: 'vpip', diff --git a/system/include/emscripten/promise.h b/system/include/emscripten/promise.h index d0b4906b52715..5168126e5079b 100644 --- a/system/include/emscripten/promise.h +++ b/system/include/emscripten/promise.h @@ -116,6 +116,17 @@ typedef struct em_settled_result_t { __attribute__((warn_unused_result)) em_promise_t emscripten_promise_all_settled( em_promise_t* promises, em_settled_result_t* results, size_t num_promises); +// Call Promise.any to create and return a new promise that is fulfilled once +// any of the `num_promises` input promises passed in `promises` has been +// fulfilled or is rejected once all of the input promises have been rejected. +// If the returned promise is fulfilled, it will be fulfilled with the same +// value as the first fulfilled input promise. Otherwise, if the returned +// promise is rejected, the rejection reasons for each input promise will be +// written to the `errors` buffer if it is non-null. The rejection reason for +// the returned promise will also be the address of the `errors` buffer. +__attribute__((warn_unused_result)) em_promise_t emscripten_promise_any( + em_promise_t* promises, void** errors, size_t num_promises); + #ifdef __cplusplus } #endif diff --git a/test/core/test_promise.c b/test/core/test_promise.c index 53e9427889afd..dabe918f7a11c 100644 --- a/test/core/test_promise.c +++ b/test/core/test_promise.c @@ -334,13 +334,131 @@ test_all_settled(void** result, void* data, void* value) { emscripten_promise_destroy(null_in[2]); em_promise_t to_finish[3] = {empty_checked, full_checked, null_checked}; - em_promise_t finish_test_all = emscripten_promise_all(to_finish, NULL, 3); + em_promise_t finish_test_all_settled = + emscripten_promise_all(to_finish, NULL, 3); emscripten_promise_destroy(empty_checked); emscripten_promise_destroy(full_checked); emscripten_promise_destroy(null_checked); - *result = finish_test_all; + *result = finish_test_all_settled; + return EM_PROMISE_MATCH_RELEASE; +} + +typedef struct promise_any_state { + size_t size; + em_promise_t in[3]; + void* expected; + void* err[3]; + void* expected_err[3]; +} promise_any_state; + +static em_promise_result_t +check_promise_any_result(void** result, void* data, void* value) { + promise_any_state* state = (promise_any_state*)data; + emscripten_console_logf("promise_any result: %ld", (uintptr_t)value); + assert(value == state->expected); + free(state); + return EM_PROMISE_FULFILL; +} + +static em_promise_result_t +check_promise_any_err(void** result, void* data, void* value) { + promise_any_state* state = (promise_any_state*)data; + assert(value == state->err); + emscripten_console_log("promise_any reasons:"); + for (size_t i = 0; i < state->size; ++i) { + emscripten_console_logf("%ld", (uintptr_t)state->err[i]); + assert(state->err[i] == state->expected_err[i]); + } + free(state); + return EM_PROMISE_FULFILL; +} + +static em_promise_result_t test_any(void** result, void* data, void* value) { + emscripten_console_log("test_any"); + assert(data == (void*)6); + + // No input should be handled ok and be rejected. + promise_any_state* state = malloc(sizeof(promise_any_state)); + *state = (promise_any_state){ + .size = 0, .in = {}, .expected = NULL, .err = {}, .expected_err = {}}; + em_promise_t empty = + emscripten_promise_any(state->in, state->err, state->size); + em_promise_t empty_checked = + emscripten_promise_then(empty, fail, check_promise_any_err, state); + emscripten_promise_destroy(empty); + + // The first fulfilled promise should be propagated. + state = malloc(sizeof(promise_any_state)); + *state = (promise_any_state){.size = 3, + .in = {emscripten_promise_create(), + emscripten_promise_create(), + emscripten_promise_create()}, + .expected = (void*)42, + .err = {}, + .expected_err = {}}; + em_promise_t full = + emscripten_promise_any(state->in, state->err, state->size); + em_promise_t full_checked = + emscripten_promise_then(full, check_promise_any_result, fail, state); + emscripten_promise_destroy(full); + emscripten_promise_resolve(state->in[0], EM_PROMISE_REJECT, (void*)41); + emscripten_promise_resolve(state->in[1], EM_PROMISE_FULFILL, (void*)42); + emscripten_promise_resolve(state->in[2], EM_PROMISE_FULFILL, (void*)43); + emscripten_promise_destroy(state->in[0]); + emscripten_promise_destroy(state->in[1]); + emscripten_promise_destroy(state->in[2]); + + // If all promises are rejected, the result will be rejected with the reasons. + state = malloc(sizeof(promise_any_state)); + *state = + (promise_any_state){.size = 3, + .in = {emscripten_promise_create(), + emscripten_promise_create(), + emscripten_promise_create()}, + .expected = NULL, + .err = {}, + .expected_err = {(void*)42, (void*)43, (void*)44}}; + em_promise_t rejected = + emscripten_promise_any(state->in, state->err, state->size); + em_promise_t rejected_checked = + emscripten_promise_then(rejected, fail, check_promise_any_err, state); + emscripten_promise_destroy(rejected); + emscripten_promise_resolve(state->in[0], EM_PROMISE_REJECT, (void*)42); + emscripten_promise_resolve(state->in[1], EM_PROMISE_REJECT, (void*)43); + emscripten_promise_resolve(state->in[2], EM_PROMISE_REJECT, (void*)44); + emscripten_promise_destroy(state->in[0]); + emscripten_promise_destroy(state->in[1]); + emscripten_promise_destroy(state->in[2]); + + // Same, but now the error reason buffer is null. + em_promise_t null_in[3] = { + emscripten_promise_create(), + emscripten_promise_create(), + emscripten_promise_create(), + }; + em_promise_t null = emscripten_promise_any(null_in, NULL, 3); + em_promise_t null_checked = + emscripten_promise_then(null, fail, check_null, NULL); + emscripten_promise_destroy(null); + emscripten_promise_resolve(null_in[0], EM_PROMISE_REJECT, (void*)42); + emscripten_promise_resolve(null_in[1], EM_PROMISE_REJECT, (void*)43); + emscripten_promise_resolve(null_in[2], EM_PROMISE_REJECT, (void*)44); + emscripten_promise_destroy(null_in[0]); + emscripten_promise_destroy(null_in[1]); + emscripten_promise_destroy(null_in[2]); + + em_promise_t to_finish[4] = { + empty_checked, full_checked, rejected_checked, null_checked}; + em_promise_t finish_test_any = emscripten_promise_all(to_finish, NULL, 4); + + emscripten_promise_destroy(empty_checked); + emscripten_promise_destroy(full_checked); + emscripten_promise_destroy(rejected_checked); + emscripten_promise_destroy(null_checked); + + *result = finish_test_any; return EM_PROMISE_MATCH_RELEASE; } @@ -390,8 +508,9 @@ int main() { em_promise_t test4 = emscripten_promise_then(test3, test_all, fail, (void*)4); em_promise_t test5 = emscripten_promise_then(test4, test_all_settled, fail, (void*)5); + em_promise_t test6 = emscripten_promise_then(test5, test_any, fail, (void*)6); em_promise_t assert_stack = - emscripten_promise_then(test5, check_stack, fail, NULL); + emscripten_promise_then(test6, check_stack, fail, NULL); em_promise_t end = emscripten_promise_then(assert_stack, finish, fail, NULL); emscripten_promise_resolve(start, EM_PROMISE_FULFILL, NULL); @@ -403,6 +522,7 @@ int main() { emscripten_promise_destroy(test3); emscripten_promise_destroy(test4); emscripten_promise_destroy(test5); + emscripten_promise_destroy(test6); emscripten_promise_destroy(assert_stack); emscripten_promise_destroy(end); diff --git a/test/core/test_promise.out b/test/core/test_promise.out index 8bf244c6fb421..f9db8cc4f22e1 100644 --- a/test/core/test_promise.out +++ b/test/core/test_promise.out @@ -21,4 +21,11 @@ promise_all_settled results: fulfill 42 reject 43 fulfill 44 +test_any +promise_any reasons: +promise_any result: 42 +promise_any reasons: +42 +43 +44 finish From 47cb9c6b4e905033a3ed8240609ef96df36e5780 Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Wed, 12 Apr 2023 11:41:37 -0700 Subject: [PATCH 0120/1523] Implement `emscripten_promise_race` in promise.h (#19154) This function propagates the result of its first input promise to settle, whether it is fulfilled or rejected. --- src/library_promise.js | 15 +++++++++++ src/library_sigs.js | 1 + system/include/emscripten/promise.h | 8 ++++++ test/core/test_promise.c | 41 ++++++++++++++++++++++++++++- test/core/test_promise.out | 3 +++ 5 files changed, 67 insertions(+), 1 deletion(-) diff --git a/src/library_promise.js b/src/library_promise.js index b2d6aa757d49b..340948b2e43d1 100644 --- a/src/library_promise.js +++ b/src/library_promise.js @@ -237,6 +237,21 @@ mergeInto(LibraryManager.library, { }); #if RUNTIME_DEBUG dbg('create: ' + id); +#endif + return id; + }, + + emscripten_promise_race__deps: ['$promiseMap', '$idsToPromises'], + emscripten_promise_race: function(idBuf, size) { + var promises = idsToPromises(idBuf, size); +#if RUNTIME_DEBUG + dbg('emscripten_promise_race: ' + promises); +#endif + var id = promiseMap.allocate({ + promise: Promise.race(promises) + }); +#if RUNTIME_DEBUG + dbg('create: ' + id); #endif return id; } diff --git a/src/library_sigs.js b/src/library_sigs.js index d46b1c3d1e406..593db24837ccf 100644 --- a/src/library_sigs.js +++ b/src/library_sigs.js @@ -540,6 +540,7 @@ sigs = { emscripten_promise_any__sig: 'pppp', emscripten_promise_create__sig: 'p', emscripten_promise_destroy__sig: 'vp', + emscripten_promise_race__sig: 'ppp', emscripten_promise_resolve__sig: 'vpip', emscripten_promise_then__sig: 'ppppp', emscripten_random__sig: 'f', diff --git a/system/include/emscripten/promise.h b/system/include/emscripten/promise.h index 5168126e5079b..d132455cf3f12 100644 --- a/system/include/emscripten/promise.h +++ b/system/include/emscripten/promise.h @@ -127,6 +127,14 @@ __attribute__((warn_unused_result)) em_promise_t emscripten_promise_all_settled( __attribute__((warn_unused_result)) em_promise_t emscripten_promise_any( em_promise_t* promises, void** errors, size_t num_promises); +// Call Promise.race to create and return a new promise that settles once any of +// the `num_promises` input promises passed in `promises` has been settled. If +// the first input promise to settle is fulfilled, the resulting promise is +// fulfilled with the same value. Otherwise, if the first input promise to +// settle is rejected, the resulting promise is rejected with the same reason. +__attribute__((warn_unused_result)) em_promise_t +emscripten_promise_race(em_promise_t* promises, size_t num_promises); + #ifdef __cplusplus } #endif diff --git a/test/core/test_promise.c b/test/core/test_promise.c index dabe918f7a11c..3a19875acb052 100644 --- a/test/core/test_promise.c +++ b/test/core/test_promise.c @@ -462,6 +462,42 @@ static em_promise_result_t test_any(void** result, void* data, void* value) { return EM_PROMISE_MATCH_RELEASE; } +static em_promise_result_t test_race(void** result, void* data, void* value) { + emscripten_console_log("test_race"); + assert(data == (void*)7); + + em_promise_t in[2] = {emscripten_promise_create(), + emscripten_promise_create()}; + em_promise_t fulfill = emscripten_promise_race(in, 2); + em_promise_t fulfill_checked = + emscripten_promise_then(fulfill, expect_success, fail, NULL); + emscripten_promise_destroy(fulfill); + emscripten_promise_resolve(in[1], EM_PROMISE_FULFILL, (void*)42); + emscripten_promise_resolve(in[0], EM_PROMISE_REJECT, NULL); + emscripten_promise_destroy(in[0]); + emscripten_promise_destroy(in[1]); + + in[0] = emscripten_promise_create(); + in[1] = emscripten_promise_create(); + em_promise_t reject = emscripten_promise_race(in, 2); + em_promise_t reject_checked = + emscripten_promise_then(reject, fail, expect_error, NULL); + emscripten_promise_destroy(reject); + emscripten_promise_resolve(in[0], EM_PROMISE_REJECT, (void*)42); + emscripten_promise_resolve(in[1], EM_PROMISE_FULFILL, NULL); + emscripten_promise_destroy(in[0]); + emscripten_promise_destroy(in[1]); + + em_promise_t to_finish[2] = {fulfill_checked, reject_checked}; + em_promise_t finish_test_race = emscripten_promise_all(to_finish, NULL, 0); + + emscripten_promise_destroy(fulfill_checked); + emscripten_promise_destroy(reject_checked); + + *result = finish_test_race; + return EM_PROMISE_MATCH_RELEASE; +} + static em_promise_result_t finish(void** result, void* data, void* value) { emscripten_console_logf("finish"); @@ -509,8 +545,10 @@ int main() { em_promise_t test5 = emscripten_promise_then(test4, test_all_settled, fail, (void*)5); em_promise_t test6 = emscripten_promise_then(test5, test_any, fail, (void*)6); + em_promise_t test7 = + emscripten_promise_then(test6, test_race, fail, (void*)7); em_promise_t assert_stack = - emscripten_promise_then(test6, check_stack, fail, NULL); + emscripten_promise_then(test7, check_stack, fail, NULL); em_promise_t end = emscripten_promise_then(assert_stack, finish, fail, NULL); emscripten_promise_resolve(start, EM_PROMISE_FULFILL, NULL); @@ -523,6 +561,7 @@ int main() { emscripten_promise_destroy(test4); emscripten_promise_destroy(test5); emscripten_promise_destroy(test6); + emscripten_promise_destroy(test7); emscripten_promise_destroy(assert_stack); emscripten_promise_destroy(end); diff --git a/test/core/test_promise.out b/test/core/test_promise.out index f9db8cc4f22e1..84f57b62633e2 100644 --- a/test/core/test_promise.out +++ b/test/core/test_promise.out @@ -28,4 +28,7 @@ promise_any reasons: 42 43 44 +test_race +expected success: 42 +expected error: 42 finish From e64f644859c3c25461a472cca6feb9bd71efbe0b Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 12 Apr 2023 14:08:30 -0700 Subject: [PATCH 0121/1523] Deprecate the USES_DYNAMIC_ALLOC setting (#19164) All this setting was doing was setting MALLOC=none so it doesn't seem like it needs to exist as a separate setting. I think it used to do more, for example, prior to #12790 it used was used in some JS library code. Another PR that removed a lot of usage of this settings was #12057. Simply removing it simplifies another change I'm working on: #18905. Also, the docs were incorrect in stating it was ignored except under MINIMAL_RUNTIME, but we had no testing for it. --- ChangeLog.md | 2 ++ emcc.py | 4 ---- src/settings.js | 8 +------- test/test_other.py | 6 +++--- 4 files changed, 6 insertions(+), 14 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index e3abed28e258c..fc808b2e829e9 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -20,6 +20,8 @@ See docs/process.md for more on how version tagging works. 3.1.36 (in development) ----------------------- +- The `USES_DYNAMIC_ALLOC` setting has been deprecated. You can get the same + effect from `-sMALLOC=none`. (#19164) 3.1.35 - 04/03/23 ----------------- diff --git a/emcc.py b/emcc.py index 32bdda680fe01..77e796a7733aa 100755 --- a/emcc.py +++ b/emcc.py @@ -2331,10 +2331,6 @@ def phase_linker_setup(options, state, newargs): '_wasmfs_readdir_finish', ] - # Explicitly drop linking in a malloc implementation if program is not using any dynamic allocation calls. - if not settings.USES_DYNAMIC_ALLOC: - settings.MALLOC = 'none' - if settings.FETCH and final_suffix in EXECUTABLE_ENDINGS: state.forced_stdlibs.append('libfetch') settings.JS_LIBRARIES.append((0, 'library_fetch.js')) diff --git a/src/settings.js b/src/settings.js index e839bf2a78fd0..af20a52f8ebff 100644 --- a/src/settings.js +++ b/src/settings.js @@ -1851,13 +1851,6 @@ var MINIMAL_RUNTIME_STREAMING_WASM_COMPILATION = false; // [link] var MINIMAL_RUNTIME_STREAMING_WASM_INSTANTIATION = false; -// If building with MINIMAL_RUNTIME=1 and application uses sbrk()/malloc(), -// enable this. If you are not using dynamic allocations, can set this to 0 to -// save code size. This setting is ignored when building with -s -// MINIMAL_RUNTIME=0. -// [link] -var USES_DYNAMIC_ALLOC = true; - // If set to 'emscripten' or 'wasm', compiler supports setjmp() and longjmp(). // If set to 0, these APIs are not available. If you are using C++ exceptions, // but do not need setjmp()+longjmp() API, then you can set this to 0 to save a @@ -2175,4 +2168,5 @@ var LEGACY_SETTINGS = [ ['LLD_REPORT_UNDEFINED', [1], 'Disabling is no longer supported'], ['MEM_INIT_METHOD', [0], 'No longer supported'], ['USE_PTHREADS', [0, 1], 'No longer needed. Use -pthread instead'], + ['USES_DYNAMIC_ALLOC', [1], 'No longer supported. Use -sMALLOC=none'], ]; diff --git a/test/test_other.py b/test/test_other.py index 4e575609453f3..09e43f8648f3a 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -9993,14 +9993,14 @@ def test_minimal_runtime_code_size(self, test_name, js, compare_js_output=False) math_sources = [test_file('code_size/math.c')] hello_world_sources = [test_file('small_hello_world.c'), - '-sUSES_DYNAMIC_ALLOC=0'] + '-sMALLOC=none'] random_printf_sources = [test_file('hello_random_printf.c'), - '-sUSES_DYNAMIC_ALLOC=0', + '-sMALLOC=none', '-sSINGLE_FILE'] hello_webgl_sources = [test_file('minimal_webgl/main.cpp'), test_file('minimal_webgl/webgl.c'), '--js-library', test_file('minimal_webgl/library_js.js'), - '-sUSES_DYNAMIC_ALLOC', '-lwebgl.js', + '-lwebgl.js', '-sMODULARIZE'] hello_webgl2_sources = hello_webgl_sources + ['-sMAX_WEBGL_VERSION=2'] hello_wasm_worker_sources = [test_file('wasm_worker/wasm_worker_code_size.c'), '-sWASM_WORKERS', '-sENVIRONMENT=web,worker'] From aa860ca2e5d5eb5c7210e6261b60af568f949aa6 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 12 Apr 2023 15:39:54 -0700 Subject: [PATCH 0122/1523] Fix lto0.test_exceptions_allowed_uncaught failure (#19165) This test started failing after #16627. Prior to that change the exceptions destructors were called via the following code in JS: ``` // In Wasm, destructors return 'this' as in ARM {{{ makeDynCall('pp', 'destructor') }}}(info.excPtr); ``` For some reason the LTO build produces the following for for the call to `exception_header->exceptionDestructor(thrown_object)` in `__cxa_decrement_exception_refcount`: ``` call_indirect 0 (type 0) ``` Where as the normal non-LTO build produces: ``` call 13 ``` Because invoke_ii goes via JS it uses the sloppy type checking and doesn't trap, but `call_indirect` has strict type checking and so does trap. --- .circleci/config.yml | 1 + system/lib/libcxxabi/src/cxa_exception.h | 3 ++- .../lib/libcxxabi/src/cxa_exception_emscripten.cpp | 13 +++++++------ 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index f964b520d2973..ffd8a4ce41e27 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -492,6 +492,7 @@ jobs: title: "core3+extras" test_targets: " lto2.test_dylink_syslibs_all + lto0.test_exceptions_allowed_uncaught core3 core2g.test_externref corez.test_dylink_iostream diff --git a/system/lib/libcxxabi/src/cxa_exception.h b/system/lib/libcxxabi/src/cxa_exception.h index dd20ba1e8891a..96f828d003239 100644 --- a/system/lib/libcxxabi/src/cxa_exception.h +++ b/system/lib/libcxxabi/src/cxa_exception.h @@ -24,7 +24,8 @@ namespace __cxxabiv1 { struct _LIBCXXABI_HIDDEN __cxa_exception { size_t referenceCount; std::type_info *exceptionType; - void (*exceptionDestructor)(void *); + // In wasm, destructors return 'this' as in ARM + void* (*exceptionDestructor)(void *); uint8_t caught; uint8_t rethrown; void *adjustedPtr; diff --git a/system/lib/libcxxabi/src/cxa_exception_emscripten.cpp b/system/lib/libcxxabi/src/cxa_exception_emscripten.cpp index af7ec0c0452f0..195dcdae8ac23 100644 --- a/system/lib/libcxxabi/src/cxa_exception_emscripten.cpp +++ b/system/lib/libcxxabi/src/cxa_exception_emscripten.cpp @@ -20,7 +20,8 @@ // Define to enable extra debugging on stderr. #if EXCEPTIONS_DEBUG -#define DEBUG printf +#include "emscripten/console.h" +#define DEBUG _emscripten_errf #else #define DEBUG(...) #endif @@ -48,7 +49,7 @@ inline __cxa_exception* cxa_exception_from_thrown_object(void* thrown_object) { - DEBUG("cxa_exception_from_thrown_object %p -> %p\n", + DEBUG("cxa_exception_from_thrown_object %p -> %p", thrown_object, static_cast<__cxa_exception*>(thrown_object) - 1); return static_cast<__cxa_exception*>(thrown_object) - 1; } @@ -60,7 +61,7 @@ inline void* thrown_object_from_cxa_exception(__cxa_exception* exception_header) { - DEBUG("thrown_object_from_cxa_exception %p -> %p\n", + DEBUG("thrown_object_from_cxa_exception %p -> %p", exception_header, static_cast(exception_header + 1)); return static_cast(exception_header + 1); } @@ -118,7 +119,7 @@ __cxa_increment_exception_refcount(void *thrown_object) _NOEXCEPT { if (thrown_object != NULL ) { __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); - DEBUG("INC: %p refcnt=%zu\n", thrown_object, exception_header->referenceCount); + DEBUG("INC: %p refcnt=%zu", thrown_object, exception_header->referenceCount); std::__libcpp_atomic_add(&exception_header->referenceCount, size_t(1)); } } @@ -136,12 +137,12 @@ void __cxa_decrement_exception_refcount(void *thrown_object) _NOEXCEPT { if (thrown_object != NULL ) { __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); - DEBUG("DEC: %p refcnt=%zu rethrown=%d\n", thrown_object, + DEBUG("DEC: %p refcnt=%zu rethrown=%d", thrown_object, exception_header->referenceCount, exception_header->rethrown); assert(exception_header->referenceCount > 0); if (std::__libcpp_atomic_add(&exception_header->referenceCount, size_t(-1)) == 0 && !exception_header->rethrown) { - DEBUG("DEL: %p\n", thrown_object); + DEBUG("DEL: %p (dtor=%p)", thrown_object, exception_header->exceptionDestructor); if (NULL != exception_header->exceptionDestructor) exception_header->exceptionDestructor(thrown_object); __cxa_free_exception(thrown_object); From 2e9314ec4e44da4ca98b9715d4b4f2575a88257c Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 12 Apr 2023 17:54:27 -0700 Subject: [PATCH 0123/1523] Rebaseline codesize expectations. NFC --- test/other/metadce/test_metadce_cxx_except.size | 2 +- test/other/metadce/test_metadce_cxx_mangle.size | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/other/metadce/test_metadce_cxx_except.size b/test/other/metadce/test_metadce_cxx_except.size index e002babd75bc5..2cab05e0ebf11 100644 --- a/test/other/metadce/test_metadce_cxx_except.size +++ b/test/other/metadce/test_metadce_cxx_except.size @@ -1 +1 @@ -166229 +166230 diff --git a/test/other/metadce/test_metadce_cxx_mangle.size b/test/other/metadce/test_metadce_cxx_mangle.size index 50931b6ce6811..264492efef7b6 100644 --- a/test/other/metadce/test_metadce_cxx_mangle.size +++ b/test/other/metadce/test_metadce_cxx_mangle.size @@ -1 +1 @@ -221325 +221326 From 53948389b6e17f170113602f9bd95335ea59decb Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 13 Apr 2023 09:34:24 -0700 Subject: [PATCH 0124/1523] Remove unnecessary dependency from deps_info.py. NFC (#19166) This was recently introduced in #16627 but when to a different deps system in #18905 I noticed it is not necessary. --- test/other/metadce/test_metadce_cxx_ctors1.exports | 1 - test/other/metadce/test_metadce_cxx_ctors1.size | 2 +- test/other/metadce/test_metadce_cxx_ctors2.exports | 1 - test/other/metadce/test_metadce_cxx_ctors2.size | 2 +- test/other/metadce/test_metadce_cxx_noexcept.exports | 1 - test/other/metadce/test_metadce_cxx_noexcept.size | 2 +- tools/deps_info.py | 7 ++----- 7 files changed, 5 insertions(+), 11 deletions(-) diff --git a/test/other/metadce/test_metadce_cxx_ctors1.exports b/test/other/metadce/test_metadce_cxx_ctors1.exports index f4dc65925fb0b..7590b6e0dd3f1 100644 --- a/test/other/metadce/test_metadce_cxx_ctors1.exports +++ b/test/other/metadce/test_metadce_cxx_ctors1.exports @@ -1,4 +1,3 @@ -__cxa_increment_exception_refcount __cxa_is_pointer_type __errno_location __indirect_function_table diff --git a/test/other/metadce/test_metadce_cxx_ctors1.size b/test/other/metadce/test_metadce_cxx_ctors1.size index 912d2488a2a9c..fba69b18f9001 100644 --- a/test/other/metadce/test_metadce_cxx_ctors1.size +++ b/test/other/metadce/test_metadce_cxx_ctors1.size @@ -1 +1 @@ -123573 +123454 diff --git a/test/other/metadce/test_metadce_cxx_ctors2.exports b/test/other/metadce/test_metadce_cxx_ctors2.exports index 183246153c0dd..0605207136d30 100644 --- a/test/other/metadce/test_metadce_cxx_ctors2.exports +++ b/test/other/metadce/test_metadce_cxx_ctors2.exports @@ -1,4 +1,3 @@ -__cxa_increment_exception_refcount __cxa_is_pointer_type __errno_location __indirect_function_table diff --git a/test/other/metadce/test_metadce_cxx_ctors2.size b/test/other/metadce/test_metadce_cxx_ctors2.size index c05b9543c7300..96fcfdd147414 100644 --- a/test/other/metadce/test_metadce_cxx_ctors2.size +++ b/test/other/metadce/test_metadce_cxx_ctors2.size @@ -1 +1 @@ -123478 +123359 diff --git a/test/other/metadce/test_metadce_cxx_noexcept.exports b/test/other/metadce/test_metadce_cxx_noexcept.exports index f4dc65925fb0b..7590b6e0dd3f1 100644 --- a/test/other/metadce/test_metadce_cxx_noexcept.exports +++ b/test/other/metadce/test_metadce_cxx_noexcept.exports @@ -1,4 +1,3 @@ -__cxa_increment_exception_refcount __cxa_is_pointer_type __errno_location __indirect_function_table diff --git a/test/other/metadce/test_metadce_cxx_noexcept.size b/test/other/metadce/test_metadce_cxx_noexcept.size index 79e609efbb1cd..f4b7350835a3f 100644 --- a/test/other/metadce/test_metadce_cxx_noexcept.size +++ b/test/other/metadce/test_metadce_cxx_noexcept.size @@ -1 +1 @@ -126371 +126251 diff --git a/tools/deps_info.py b/tools/deps_info.py index 2d7460fe1886c..b05890878d923 100644 --- a/tools/deps_info.py +++ b/tools/deps_info.py @@ -186,12 +186,9 @@ def append_deps_info(js_symbol_deps): def get_deps_info(): if not settings.WASM_EXCEPTIONS and settings.LINK_AS_CXX: _deps_info['__cxa_end_catch'] = ['setThrew', '__cxa_decrement_exception_refcount'] - base_js_exception_deps = [ - '__cxa_is_pointer_type', - '__cxa_increment_exception_refcount', - ] + base_js_exception_deps = ['__cxa_is_pointer_type'] _deps_info['__cxa_throw'] = base_js_exception_deps - _deps_info['__cxa_begin_catch'] = base_js_exception_deps + _deps_info['__cxa_begin_catch'] = base_js_exception_deps + ['__cxa_increment_exception_refcount'] _deps_info['__cxa_find_matching_catch'] = base_js_exception_deps + ['__cxa_can_catch', 'setTempRet0'] for i in range(1, 10): _deps_info['__cxa_find_matching_catch_%d' % i] = _deps_info['__cxa_find_matching_catch'] From 6d61e5dea2a5e093c19eb2d488e81df0a423b7e5 Mon Sep 17 00:00:00 2001 From: JeromeDesfieux <45177748+JeromeDesfieux@users.noreply.github.com> Date: Thu, 13 Apr 2023 21:42:11 +0200 Subject: [PATCH 0125/1523] Add LOCALAPPDATA to the path list to search from for the browers for Windows (#19171) On Windows, when applications are installed without admin priviledges then they are installed in `LOCALAPPDATA` (= C:\Users\my.name\AppData\Local\) --- emrun.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emrun.py b/emrun.py index 41254e5be05e8..0f90d1bf84bb3 100644 --- a/emrun.py +++ b/emrun.py @@ -1224,7 +1224,7 @@ def find_browser(name): ('chrome', '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'), ('chrome_canary', '/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary')] elif WINDOWS: - pf_locations = ['ProgramFiles(x86)', 'ProgramFiles', 'ProgramW6432'] + pf_locations = ['ProgramFiles(x86)', 'ProgramFiles', 'ProgramW6432', 'LOCALAPPDATA'] for pf_env in pf_locations: if pf_env not in os.environ: From 309581e433f114e47ce61d619fbdc00136e9de90 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 13 Apr 2023 18:19:46 -0700 Subject: [PATCH 0126/1523] Exclude malloc dependencies from LTO. NFC (#19174) IIUC `sbrk.c` was implicitly being excluded from LTO by being added to `libmalloc` instead of `libc`, even though it makes more sense in `libc`. sbrk depends on `emscripten_get_heap_size`, so an alternative to this change would be to move `emscripten_get_heap_size` into libmalloc, but since neither of those two files depends on the malloc type I think this approach makes more sense. Split out from #18905 --- system/lib/{ => libc}/sbrk.c | 6 ++++++ test/code_size/hello_wasm_worker_wasm.json | 8 ++++---- test/code_size/hello_webgl2_wasm.json | 8 ++++---- test/code_size/hello_webgl2_wasm2js.json | 10 +++++----- test/code_size/hello_webgl_wasm.json | 8 ++++---- test/code_size/hello_webgl_wasm2js.json | 10 +++++----- test/other/metadce/test_metadce_hello_dylink.size | 2 +- test/test_core.py | 2 +- tools/system_libs.py | 13 ++++++++++--- 9 files changed, 40 insertions(+), 27 deletions(-) rename system/lib/{ => libc}/sbrk.c (96%) diff --git a/system/lib/sbrk.c b/system/lib/libc/sbrk.c similarity index 96% rename from system/lib/sbrk.c rename to system/lib/libc/sbrk.c index 21f2d570956eb..aa1410518bfd7 100644 --- a/system/lib/sbrk.c +++ b/system/lib/libc/sbrk.c @@ -6,6 +6,12 @@ * */ +// libc files are compiled as -std=c99 which doesn't normally declare +// max_align_t. +#if __STDC_VERSION__ < 201112L +#define __NEED_max_align_t +#endif + #ifndef EMSCRIPTEN_NO_ERRNO #include #endif diff --git a/test/code_size/hello_wasm_worker_wasm.json b/test/code_size/hello_wasm_worker_wasm.json index fd3c7cade8ae8..1c477feb0bcd4 100644 --- a/test/code_size/hello_wasm_worker_wasm.json +++ b/test/code_size/hello_wasm_worker_wasm.json @@ -3,8 +3,8 @@ "a.html.gz": 433, "a.js": 733, "a.js.gz": 463, - "a.wasm": 1854, - "a.wasm.gz": 1034, - "total": 3324, - "total_gz": 1930 + "a.wasm": 1859, + "a.wasm.gz": 1033, + "total": 3329, + "total_gz": 1929 } diff --git a/test/code_size/hello_webgl2_wasm.json b/test/code_size/hello_webgl2_wasm.json index 8f2a7cbe7bf44..69df7d2928d07 100644 --- a/test/code_size/hello_webgl2_wasm.json +++ b/test/code_size/hello_webgl2_wasm.json @@ -3,8 +3,8 @@ "a.html.gz": 379, "a.js": 4971, "a.js.gz": 2430, - "a.wasm": 10451, - "a.wasm.gz": 6680, - "total": 15991, - "total_gz": 9489 + "a.wasm": 10459, + "a.wasm.gz": 6689, + "total": 15999, + "total_gz": 9498 } diff --git a/test/code_size/hello_webgl2_wasm2js.json b/test/code_size/hello_webgl2_wasm2js.json index 82590513233fa..17ddaf74b7b1d 100644 --- a/test/code_size/hello_webgl2_wasm2js.json +++ b/test/code_size/hello_webgl2_wasm2js.json @@ -1,10 +1,10 @@ { "a.html": 567, "a.html.gz": 379, - "a.js": 18201, - "a.js.gz": 8063, + "a.js": 18219, + "a.js.gz": 8059, "a.mem": 3171, - "a.mem.gz": 2714, - "total": 21939, - "total_gz": 11156 + "a.mem.gz": 2713, + "total": 21957, + "total_gz": 11151 } diff --git a/test/code_size/hello_webgl_wasm.json b/test/code_size/hello_webgl_wasm.json index 2e5c5d3487a3e..71d230beea6b4 100644 --- a/test/code_size/hello_webgl_wasm.json +++ b/test/code_size/hello_webgl_wasm.json @@ -3,8 +3,8 @@ "a.html.gz": 379, "a.js": 4450, "a.js.gz": 2250, - "a.wasm": 10451, - "a.wasm.gz": 6680, - "total": 15470, - "total_gz": 9309 + "a.wasm": 10459, + "a.wasm.gz": 6689, + "total": 15478, + "total_gz": 9318 } diff --git a/test/code_size/hello_webgl_wasm2js.json b/test/code_size/hello_webgl_wasm2js.json index 0bce64c31085a..f67f4f18bae42 100644 --- a/test/code_size/hello_webgl_wasm2js.json +++ b/test/code_size/hello_webgl_wasm2js.json @@ -1,10 +1,10 @@ { "a.html": 567, "a.html.gz": 379, - "a.js": 17673, - "a.js.gz": 7885, + "a.js": 17691, + "a.js.gz": 7882, "a.mem": 3171, - "a.mem.gz": 2714, - "total": 21411, - "total_gz": 10978 + "a.mem.gz": 2713, + "total": 21429, + "total_gz": 10974 } diff --git a/test/other/metadce/test_metadce_hello_dylink.size b/test/other/metadce/test_metadce_hello_dylink.size index 748b6c86252a0..22e75887797fe 100644 --- a/test/other/metadce/test_metadce_hello_dylink.size +++ b/test/other/metadce/test_metadce_hello_dylink.size @@ -1 +1 @@ -9486 +9488 diff --git a/test/test_core.py b/test/test_core.py index dec35b9f46535..327f3b9b42746 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -1017,7 +1017,7 @@ def test_emmalloc(self, *args): self.set_setting('MALLOC', 'none') self.emcc_args += [ '-fno-builtin', - path_from_root('system/lib/sbrk.c'), + path_from_root('system/lib/libc/sbrk.c'), path_from_root('system/lib/emmalloc.c') ] self.emcc_args += args diff --git a/tools/system_libs.py b/tools/system_libs.py index 8098052fbbba8..88f533d758c29 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -955,6 +955,8 @@ def get_libcall_files(self): path='system/lib/libc', filenames=['emscripten_memcpy.c', 'emscripten_memset.c', 'emscripten_scan_stack.c', + 'emscripten_get_heap_size.c', # needed by malloc + 'sbrk.c', # needed by malloc 'emscripten_memmove.c']) # Calls to iprintf can be generated during codegen. Ideally we wouldn't # compile these with -O2 like we do the rest of compiler-rt since its @@ -973,7 +975,12 @@ def get_libcall_files(self): iprintf_files += files_in_path( path='system/lib/libc/musl/src/string', filenames=['strlen.c']) - return math_files + exit_files + other_files + iprintf_files + + errno_files = files_in_path( + path='system/lib/libc/musl/src/errno', + filenames=['__errno_location.c']) + + return math_files + exit_files + other_files + iprintf_files + errno_files def get_files(self): libc_files = [] @@ -1185,6 +1192,7 @@ def get_files(self): 'sigaction.c', 'sigtimedwait.c', 'wasi-helpers.c', + 'sbrk.c', ]) if settings.RELOCATABLE: @@ -1587,8 +1595,7 @@ def get_files(self): malloc = utils.path_from_root('system/lib', { 'dlmalloc': 'dlmalloc.c', 'emmalloc': 'emmalloc.c', }[malloc_base]) - sbrk = utils.path_from_root('system/lib/sbrk.c') - return [malloc, sbrk] + return [malloc] def get_cflags(self): cflags = super().get_cflags() From 97c22d48eb1575c5065bb3b4124b732a9f59e7f9 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 14 Apr 2023 00:48:31 -0700 Subject: [PATCH 0127/1523] Build-time error on use of emscripten_promise_any if Promise.any is not available (#19172) --- emcc.py | 28 ++++++++++++++++------------ src/library_promise.js | 8 +++++++- src/settings_internal.js | 3 +++ test/test_core.py | 8 ++++++++ tools/feature_matrix.py | 24 +++++++++++++++++++++++- 5 files changed, 57 insertions(+), 14 deletions(-) diff --git a/emcc.py b/emcc.py index 77e796a7733aa..81dc0d968a8b8 100755 --- a/emcc.py +++ b/emcc.py @@ -2420,6 +2420,14 @@ def phase_linker_setup(options, state, newargs): if settings.INCLUDE_FULL_LIBRARY and not settings.DISABLE_EXCEPTION_CATCHING: settings.EXPORTED_FUNCTIONS += ['___get_exception_message', '_free'] + if settings.MEMORY64: + if settings.ASYNCIFY and settings.MEMORY64 == 1: + exit_with_error('MEMORY64=1 is not compatible with ASYNCIFY') + if not settings.DISABLE_EXCEPTION_CATCHING: + exit_with_error('MEMORY64 is not compatible with DISABLE_EXCEPTION_CATCHING=0') + # Any "pointers" passed to JS will now be i64's, in both modes. + settings.WASM_BIGINT = 1 + if settings.WASM_WORKERS: # TODO: After #15982 is resolved, these dependencies can be declared in library_wasm_worker.js # instead of having to record them here. @@ -2432,13 +2440,19 @@ def phase_linker_setup(options, state, newargs): settings.WASM_WORKER_FILE = unsuffixed(os.path.basename(target)) + '.ww.js' settings.JS_LIBRARIES.append((0, shared.path_from_root('src', 'library_wasm_worker.js'))) + # Set min browser versions based on certain settings such as WASM_BIGINT, + # PTHREADS, AUDIO_WORKLET + # Such setting must be set before this point + feature_matrix.apply_min_browser_versions() + + # TODO(sbc): Find make a generic way to expose the feature matrix to JS + # compiler rather then adding them all ad-hoc as internal settings settings.SUPPORTS_GLOBALTHIS = feature_matrix.caniuse(feature_matrix.Feature.GLOBALTHIS) + settings.SUPPORTS_PROMISE_ANY = feature_matrix.caniuse(feature_matrix.Feature.PROMISE_ANY) if not settings.BULK_MEMORY: settings.BULK_MEMORY = feature_matrix.caniuse(feature_matrix.Feature.BULK_MEMORY) if settings.AUDIO_WORKLET: - if not settings.SUPPORTS_GLOBALTHIS: - exit_with_error('Must target recent enough browser versions that will support globalThis in order to target Wasm Audio Worklets!') if settings.AUDIO_WORKLET == 1: settings.AUDIO_WORKLET_FILE = unsuffixed(os.path.basename(target)) + '.aw.js' settings.JS_LIBRARIES.append((0, shared.path_from_root('src', 'library_webaudio.js'))) @@ -2552,14 +2566,6 @@ def check_memory_setting(setting): if settings.SHARED_MEMORY or settings.RELOCATABLE or settings.ASYNCIFY_LAZY_LOAD_CODE or settings.WASM2JS: settings.IMPORTED_MEMORY = 1 - if settings.MEMORY64: - if settings.ASYNCIFY and settings.MEMORY64 == 1: - exit_with_error('MEMORY64=1 is not compatible with ASYNCIFY') - if not settings.DISABLE_EXCEPTION_CATCHING: - exit_with_error('MEMORY64 is not compatible with DISABLE_EXCEPTION_CATCHING=0') - # Any "pointers" passed to JS will now be i64's, in both modes. - settings.WASM_BIGINT = 1 - if settings.WASM_BIGINT: settings.LEGALIZE_JS_FFI = 0 @@ -2900,8 +2906,6 @@ def get_full_import_name(name): if settings.WASM_EXCEPTIONS: settings.EXPORTED_FUNCTIONS += ['___cpp_exception', '___cxa_increment_exception_refcount', '___cxa_decrement_exception_refcount', '___thrown_object_from_unwind_exception'] - feature_matrix.apply_min_browser_versions() - if settings.SIDE_MODULE: # For side modules, we ignore all REQUIRED_EXPORTS that might have been added above. # They all come from either libc or compiler-rt. The exception is __wasm_call_ctors diff --git a/src/library_promise.js b/src/library_promise.js index 340948b2e43d1..8d9b5eb0efe1d 100644 --- a/src/library_promise.js +++ b/src/library_promise.js @@ -216,7 +216,13 @@ mergeInto(LibraryManager.library, { return id; }, - emscripten_promise_any__deps: ['$promiseMap', '$idsToPromises'], + + emscripten_promise_any__deps: [ + '$promiseMap', '$idsToPromises', +#if !SUPPORTS_PROMISE_ANY && !INCLUDE_FULL_LIBRARY + () => error("emscripten_promise_any used, but Promise.any is not supported by the current runtime configuration (run with EMCC_DEBUG=1 in the env for more details)"), +#endif + ], emscripten_promise_any: function(idBuf, errorBuf, size) { var promises = idsToPromises(idBuf, size); #if RUNTIME_DEBUG diff --git a/src/settings_internal.js b/src/settings_internal.js index cc4f7506ecd90..b9cb0ea0fc404 100644 --- a/src/settings_internal.js +++ b/src/settings_internal.js @@ -175,6 +175,9 @@ var TARGET_NOT_SUPPORTED = 0x7FFFFFFF; // Used to track whether target environment supports the 'globalThis' attribute. var SUPPORTS_GLOBALTHIS = false; +// Used to track whether target environment supports the 'Promise.any'. +var SUPPORTS_PROMISE_ANY = false; + // Wasm backend symbols that are considered system symbols and don't // have the normal C symbol name mangled applied (== prefix with an underscore) // (Also implicily on this list is any function that starts with string "dynCall_") diff --git a/test/test_core.py b/test/test_core.py index 327f3b9b42746..2a995f3fdd7f0 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -9761,6 +9761,14 @@ def test_main_reads_args(self): @requires_node def test_promise(self): + # This test depends on Promise.any, which in turn requires a modern target. Check that it + # fails to even build without bumping the min versions: + err = self.expect_fail([EMCC, test_file('core/test_promise.c')]) + self.assertContained('error: emscripten_promise_any used, but Promise.any is not supported by the current runtime configuration', err) + self.set_setting('MIN_NODE_VERSION', '150000') + self.set_setting('MIN_SAFARI_VERSION', '150000') + self.set_setting('MIN_FIREFOX_VERSION', '79') + self.set_setting('MIN_CHROME_VERSION', '85') self.do_core_test('test_promise.c') diff --git a/tools/feature_matrix.py b/tools/feature_matrix.py index a20086d21ea4b..7aebf78c53081 100644 --- a/tools/feature_matrix.py +++ b/tools/feature_matrix.py @@ -22,6 +22,7 @@ class Feature(IntEnum): JS_BIGINT_INTEGRATION = auto() THREADS = auto() GLOBALTHIS = auto() + PROMISE_ANY = auto() default_features = {Feature.SIGN_EXT, Feature.MUTABLE_GLOBALS} @@ -62,25 +63,44 @@ class Feature(IntEnum): 'edge': 79, 'firefox': 65, 'safari': 120100, - # 'node': 120000 + 'node': 120000, + }, + Feature.PROMISE_ANY: { + 'chrome': 85, + 'firefox': 79, + 'safari': 140000, + 'node': 150000, }, } def caniuse(feature): min_versions = min_browser_versions[feature] + + def report_missing(setting_name): + setting_value = getattr(settings, setting_name) + logger.debug(f'cannot use {feature.name} because {setting_name} is too old: {setting_value}') + if settings.MIN_CHROME_VERSION < min_versions['chrome']: + report_missing('MIN_CHROME_VERSION') return False # For edge we just use the same version requirements as chrome since, # at least for modern versions of edge, they share version numbers. if settings.MIN_EDGE_VERSION < min_versions['chrome']: + report_missing('MIN_EDGE_VERSION') return False if settings.MIN_FIREFOX_VERSION < min_versions['firefox']: + report_missing('MIN_FIREFOX_VERSION') return False if settings.MIN_SAFARI_VERSION < min_versions['safari']: + report_missing('MIN_SAFARI_VERSION') return False # IE don't support any non-MVP features if settings.MIN_IE_VERSION != 0x7FFFFFFF: + report_missing('MIN_IE_VERSION') + return False + if 'node' in min_versions and settings.MIN_NODE_VERSION < min_versions['node']: + report_missing('MIN_NODE_VERSION') return False return True @@ -112,3 +132,5 @@ def apply_min_browser_versions(): if settings.PTHREADS: enable_feature(Feature.THREADS, 'pthreads') enable_feature(Feature.BULK_MEMORY, 'pthreads') + if settings.AUDIO_WORKLET: + enable_feature(Feature.GLOBALTHIS, 'AUDIO_WORKLET') From ef15cbbda47ba41e6421821a2cdd787fa5361420 Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Fri, 14 Apr 2023 18:26:06 +0200 Subject: [PATCH 0128/1523] Remove redundant Node worker listener. NFC (#19178) The corresponding TODO-item is no longer relevant after PR #18305 has landed. Resolves: #9763. --- src/library_pthread.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/library_pthread.js b/src/library_pthread.js index 60b3320194622..170d9f5f0ed71 100644 --- a/src/library_pthread.js +++ b/src/library_pthread.js @@ -336,10 +336,6 @@ var LibraryPThread = { worker.on('error', function(e) { worker.onerror(e); }); - worker.on('detachedExit', function() { - // TODO: update the worker queue? - // See: https://github.com/emscripten-core/emscripten/issues/9763 - }); } #endif From b921f76d4a7e90f3022095593df6ec3a38552555 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 14 Apr 2023 15:33:29 -0700 Subject: [PATCH 0129/1523] Fix for EMCC_USE_NINJA + embuilder --force. NFC (#19181) Since --force set `do_clear` we cannot use that as a sign not do run the build. --- embuilder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embuilder.py b/embuilder.py index bc6b0d4828858..4a4bd933623ee 100755 --- a/embuilder.py +++ b/embuilder.py @@ -268,7 +268,7 @@ def main(): time_taken = time.time() - start_time logger.info('...success. Took %s(%.2fs)' % (('%02d:%02d mins ' % (time_taken // 60, time_taken % 60) if time_taken >= 60 else ''), time_taken)) - if USE_NINJA and not do_clear: + if USE_NINJA and args.operation != 'clear': system_libs.build_deferred() if len(tasks) > 1 or USE_NINJA: From 518d9fea335f7cd2b5771e43df76e0535c6df5dd Mon Sep 17 00:00:00 2001 From: Derek Schuff Date: Fri, 14 Apr 2023 17:03:14 -0700 Subject: [PATCH 0130/1523] Add a stub cxa_free_exception cxa_noexception.cpp (#19183) In some cases cxa_free_exception can be called by compiler-generated code, which may cause linkage failure in emscripten's default mode which allows throwing but not catching. This PR adds a "stub" __cxa_free_exception to go along with __cxa_allocate_exception. --- system/lib/libcxxabi/src/cxa_noexception.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/system/lib/libcxxabi/src/cxa_noexception.cpp b/system/lib/libcxxabi/src/cxa_noexception.cpp index 1097f75866983..1ef53bf79f243 100644 --- a/system/lib/libcxxabi/src/cxa_noexception.cpp +++ b/system/lib/libcxxabi/src/cxa_noexception.cpp @@ -58,6 +58,22 @@ void *__cxa_allocate_exception(size_t thrown_size) _NOEXCEPT { char* allocation = (char*)malloc(thrown_size + sizeof(__cxa_exception)); return allocation + sizeof(__cxa_exception); } + +static +inline +__cxa_exception* +cxa_exception_from_thrown_object(void* thrown_object) +{ + return static_cast<__cxa_exception*>(thrown_object) - 1; +} + +// Free a __cxa_exception object allocated with __cxa_allocate_exception. +void __cxa_free_exception(void *thrown_object) _NOEXCEPT { + // Compute the size of the padding before the header. + char *raw_buffer = + ((char *)cxa_exception_from_thrown_object(thrown_object)); + free((void *)raw_buffer); +} #endif } // extern "C" From 354e03c7d3c69ea1eda78be33140820c1e807f30 Mon Sep 17 00:00:00 2001 From: Eduard Trushnikov Date: Mon, 17 Apr 2023 19:52:11 +0300 Subject: [PATCH 0131/1523] Fix library_websocket after pull request 19064 (len is undefined) (#19190) --- src/library_websocket.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/library_websocket.js b/src/library_websocket.js index 06153eaf0a556..88d0d2b05fd37 100644 --- a/src/library_websocket.js +++ b/src/library_websocket.js @@ -238,8 +238,8 @@ var LibraryWebSocket = { HEAPU32[WS.socketEvent>>2] = socketId; if (typeof e.data == 'string') { var buf = stringToNewUTF8(e.data); -#if WEBSOCKET_DEBUG var len = lengthBytesUTF8(e.data)+1; +#if WEBSOCKET_DEBUG var s = (e.data.length < 256) ? e.data : (e.data.substr(0, 256) + ' (' + (e.data.length-256) + ' more characters)'); dbg('WebSocket onmessage, received data: "' + e.data + '", ' + e.data.length + ' chars, ' + len + ' bytes encoded as UTF-8: "' + s + '"'); #endif From e8ee82b0cb97891e6d208611595ca5804593f2f7 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 17 Apr 2023 12:06:08 -0700 Subject: [PATCH 0132/1523] Mark 3.1.36 as released (#19187) --- ChangeLog.md | 5 ++++- emscripten-version.txt | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index fc808b2e829e9..e08545a9fa59b 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -18,8 +18,11 @@ to browse the changes between the tags. See docs/process.md for more on how version tagging works. -3.1.36 (in development) +3.1.37 (in development) ----------------------- + +3.1.36 - 04/16/23 +----------------- - The `USES_DYNAMIC_ALLOC` setting has been deprecated. You can get the same effect from `-sMALLOC=none`. (#19164) diff --git a/emscripten-version.txt b/emscripten-version.txt index d6c36e777536a..bdba3ba8dcca1 100644 --- a/emscripten-version.txt +++ b/emscripten-version.txt @@ -1 +1 @@ -3.1.36-git +3.1.37-git From a831c41a82cb32131ce5ec52b4882ad59d3b7116 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 17 Apr 2023 13:56:02 -0700 Subject: [PATCH 0133/1523] Report setitimer as unsupported in standalone mode (#19194) Without this, we can get a link error on not finding _setitimer_js. We can't really support timers in standalone mode so reporting an error if setitimer is called seems best. --- system/lib/standalone/standalone.c | 7 +++++++ test/other/test_itimer_standalone.c | 27 +++++++++++++++++++++++++++ test/other/test_itimer_standalone.out | 1 + test/test_other.py | 7 +++++++ 4 files changed, 42 insertions(+) create mode 100644 test/other/test_itimer_standalone.c create mode 100644 test/other/test_itimer_standalone.out diff --git a/system/lib/standalone/standalone.c b/system/lib/standalone/standalone.c index 43a446e14fd78..366e60d76fd54 100644 --- a/system/lib/standalone/standalone.c +++ b/system/lib/standalone/standalone.c @@ -223,3 +223,10 @@ void _emscripten_err(const char* text) { wasi_writeln(2, text); } void __call_sighandler(sighandler_t handler, int sig) { handler(sig); } + +int _setitimer_js(int which, double timeout) { + // There is no API to let us set timers in standalone mode atm. Return an + // error. + errno = ENOTSUP; + return -1; +} diff --git a/test/other/test_itimer_standalone.c b/test/other/test_itimer_standalone.c new file mode 100644 index 0000000000000..75037f8dec9ec --- /dev/null +++ b/test/other/test_itimer_standalone.c @@ -0,0 +1,27 @@ +// Copyright 2023 The Emscripten Authors. All rights reserved. +// Emscripten is available under two separate licenses, the MIT license and the +// University of Illinois/NCSA Open Source License. Both these licenses can be +// found in the LICENSE file. + +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +int main() { + int rtn; + struct itimerval val; + memset(&val, 0, sizeof(val)); + + val.it_value.tv_sec = 1; + rtn = setitimer(ITIMER_REAL, &val, NULL); + + // In standalone mode we cannot use timers, and error. + assert(rtn == -1); + assert(errno == ENOTSUP); + + printf("done\n"); + return 0; +} diff --git a/test/other/test_itimer_standalone.out b/test/other/test_itimer_standalone.out new file mode 100644 index 0000000000000..19f86f493ab11 --- /dev/null +++ b/test/other/test_itimer_standalone.out @@ -0,0 +1 @@ +done diff --git a/test/test_other.py b/test/test_other.py index 09e43f8648f3a..5588fe353b9ce 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -13189,6 +13189,13 @@ def test_itimer(self): def test_itimer_pthread(self): self.do_other_test('test_itimer.c') + def test_itimer_standlone(self): + self.emcc_args += ['-sSTANDALONE_WASM'] + self.do_other_test('test_itimer_standalone.c') + for engine in config.WASM_ENGINES: + print('wasm engine', engine) + self.assertContained('done', self.run_js('test_itimer_standalone.wasm', engine)) + @node_pthreads @no_mac("Our Mac CI currently has too much contention to run this reliably") def test_itimer_proxy_to_pthread(self): From 5f84e88f82191911f95326eace67b93480e078ca Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 17 Apr 2023 14:12:42 -0700 Subject: [PATCH 0134/1523] Don't ignore errors in `compiler.js --symbols-only` (#19184) Previously we would report the error but then exit with 0. --- src/jsifier.js | 11 ++++++++--- src/parseTools.js | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/jsifier.js b/src/jsifier.js index a966e7083cc05..69176e3b21aef 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -520,7 +520,9 @@ function ${name}(${args}) { includeFile('base64Utils.js'); } - if (abortExecution) throw Error('Aborting compilation due to previous errors'); + if (abortExecution) { + throw Error('Aborting compilation due to previous errors'); + } // This is the main 'post' pass. Print out the generated code that we have here, together with the // rest of the output that we started to print out earlier (see comment on the @@ -569,8 +571,11 @@ function ${name}(${args}) { deps: symbolDeps, asyncFuncs })); - return; + } else { + finalCombiner(); } - finalCombiner(); + if (abortExecution) { + throw Error('Aborting compilation due to previous errors'); + } } diff --git a/src/parseTools.js b/src/parseTools.js index 66e6bd8946fff..b11f046982430 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -133,7 +133,7 @@ function preprocess(filename) { error(`${filename}:${i + 1}: #error ${trimmed.substring(trimmed.indexOf(' ')).trim()}`); } } else { - throw new Error(`${filename}:${i + 1}: Unknown preprocessor directive ${first}`); + error(`${filename}:${i + 1}: Unknown preprocessor directive ${first}`); } } else { if (showCurrentLine()) { From 8fc85aaa921834553b19005035b80a9837b29fd9 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 17 Apr 2023 18:03:17 -0700 Subject: [PATCH 0135/1523] Don't include __cxa_find_matching_catch helpers with WASM_EXCEPTIONS. NFC (#19195) Split out from #18905 --- src/jsifier.js | 2 +- src/library_exceptions.js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/jsifier.js b/src/jsifier.js index 69176e3b21aef..7302ea0dd6c93 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -221,7 +221,7 @@ function ${name}(${args}) { // the number specifies the number of arguments. In Emscripten, route all // these to a single function '__cxa_find_matching_catch' that variadically // processes all of these functions using JS 'arguments' object. - if (symbol.startsWith('__cxa_find_matching_catch_')) { + if (!WASM_EXCEPTIONS && symbol.startsWith('__cxa_find_matching_catch_')) { if (DISABLE_EXCEPTION_THROWING) { error('DISABLE_EXCEPTION_THROWING was set (likely due to -fno-exceptions), which means no C++ exception throwing support code is linked in, but exception catching code appears. Either do not set DISABLE_EXCEPTION_THROWING (if you do want exception throwing) or compile all source files with -fno-except (so that no exceptions support code is required); also make sure DISABLE_EXCEPTION_CATCHING is set to the right value - if you want exceptions, it should be off, and vice versa.'); return; diff --git a/src/library_exceptions.js b/src/library_exceptions.js index d64e217cf1aa5..61ad2568e36a2 100644 --- a/src/library_exceptions.js +++ b/src/library_exceptions.js @@ -238,7 +238,6 @@ var LibraryExceptions = { // functionality boils down to picking a suitable 'catch' block. // We'll do that here, instead, to keep things simpler. __cxa_find_matching_catch__deps: ['$exceptionLast', '$ExceptionInfo', '__resumeException', '__cxa_can_catch', 'setTempRet0'], - //__cxa_find_matching_catch__sig: 'p', __cxa_find_matching_catch: function() { var thrown = #if EXCEPTION_STACK_TRACES @@ -408,6 +407,7 @@ var LibraryExceptions = { #endif }; +#if !WASM_EXCEPTIONS // In LLVM, exceptions generate a set of functions of form // __cxa_find_matching_catch_1(), __cxa_find_matching_catch_2(), etc. where the // number specifies the number of arguments. In Emscripten, route all these to @@ -416,5 +416,6 @@ var LibraryExceptions = { addCxaCatch = function(n) { LibraryManager.library['__cxa_find_matching_catch_' + n] = '__cxa_find_matching_catch'; }; +#endif mergeInto(LibraryManager.library, LibraryExceptions); From 1e7b78fe45cee0b96b64938f9742368923cd0713 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 17 Apr 2023 18:42:19 -0700 Subject: [PATCH 0136/1523] Remove deps_info system and the running of llvm-nm on input file. NFC (#18905) This uses a new "stub object" construct to tell the linker (wasm-ld) not only about the existence of the JS library symbols but the native symbols on which they depend (a.k.a reverse dependencies). This allows us to completely remove deps_info.py in favor of just using normal `__deps` entries in the library files. It also means we no longer need to run `llvm-nm` on the linker inputs to discover the symbols they use. Depends on: https://reviews.llvm.org/D145308 Fixes: #18875 --- ChangeLog.md | 7 + emcc.py | 32 ++- emscripten.py | 24 +- .../Interacting-with-code.rst | 4 - src/jsifier.js | 30 ++- src/library.js | 11 +- src/library_async.js | 6 +- src/library_browser.js | 2 + src/library_exceptions.js | 12 +- src/library_exceptions_stub.js | 2 +- src/library_glew.js | 2 +- src/library_glfw.js | 2 +- src/library_html5.js | 28 +-- src/library_html5_webgl.js | 4 + src/library_idbstore.js | 2 + src/library_syscall.js | 7 + src/library_websocket.js | 2 +- src/settings.js | 17 +- test/test_core.py | 16 -- test/test_other.py | 99 +-------- tools/building.py | 128 ++++------- tools/deps_info.py | 208 ------------------ tools/shared.py | 2 +- tools/system_libs.py | 105 +++------ 24 files changed, 205 insertions(+), 547 deletions(-) delete mode 100644 tools/deps_info.py diff --git a/ChangeLog.md b/ChangeLog.md index e08545a9fa59b..d3aebb21461ff 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -20,6 +20,13 @@ See docs/process.md for more on how version tagging works. 3.1.37 (in development) ----------------------- +- The old reverse dependency system based on `tools/deps_info.py` has been + removed and the existing `__deps` entries in JS library files can now be used + to express JS-to-native dependencies. As well being more precise, and + extensible via user-supplied JS libraries, this also speeds up link times + since we no longer need scan linker inputs using `llvm-nm`. It also + completely removes the need for the `REVERSE_DEPS` settings which has now + been deprecated. (#18905) 3.1.36 - 04/16/23 ----------------- diff --git a/emcc.py b/emcc.py index 81dc0d968a8b8..4f1ee56a94cfc 100755 --- a/emcc.py +++ b/emcc.py @@ -50,7 +50,6 @@ from tools.minimal_runtime_shell import generate_minimal_runtime_html import tools.line_endings from tools import feature_matrix -from tools import deps_info from tools import js_manipulation from tools import wasm2c from tools import webassembly @@ -1275,7 +1274,7 @@ def run(args): process_libraries(state, []) if len(input_files) != 1: exit_with_error('--post-link requires a single input file') - phase_post_link(options, state, input_files[0][1], wasm_target, target) + phase_post_link(options, state, input_files[0][1], wasm_target, target, {}) return 0 ## Compile source code to object files @@ -1316,11 +1315,10 @@ def run(args): js_info = get_js_sym_info() if not settings.SIDE_MODULE: js_syms = js_info['deps'] - deps_info.append_deps_info(js_syms) if settings.ASYNCIFY: settings.ASYNCIFY_IMPORTS += ['env.' + x for x in js_info['asyncFuncs']] - phase_calculate_system_libraries(state, linker_arguments, linker_inputs, newargs) + phase_calculate_system_libraries(state, linker_arguments, newargs) phase_link(linker_arguments, wasm_target, js_syms) @@ -1336,7 +1334,7 @@ def run(args): # Perform post-link steps (unless we are running bare mode) if options.oformat != OFormat.BARE: - phase_post_link(options, state, wasm_target, wasm_target, target) + phase_post_link(options, state, wasm_target, wasm_target, target, js_syms) return 0 @@ -1952,6 +1950,12 @@ def phase_linker_setup(options, state, newargs): if '_main' in settings.EXPORTED_FUNCTIONS: settings.EXPORT_IF_DEFINED.append('__main_argc_argv') + elif settings.ASSERTIONS: + # In debug builds when `main` is not explictly requested as an + # export we still add it to EXPORT_IF_DEFINED so that we can warn + # users who forget to explicitly export `main`. + # See other.test_warn_unexported_main. + settings.EXPORT_IF_DEFINED.append('main') if settings.ASSERTIONS: # Exceptions are thrown with a stack trace by default when ASSERTIONS is @@ -2082,11 +2086,6 @@ def phase_linker_setup(options, state, newargs): settings.INCLUDE_FULL_LIBRARY = 1 settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['$loadDylibs'] - # If we are including the entire JS library then we know for sure we will, by definition, - # require all the reverse dependencies. - if settings.INCLUDE_FULL_LIBRARY: - default_setting('REVERSE_DEPS', 'all') - if settings.MAIN_MODULE == 1 or settings.SIDE_MODULE == 1: settings.LINKABLE = 1 @@ -3086,14 +3085,13 @@ def compile_source_file(i, input_file): @ToolchainProfiler.profile_block('calculate system libraries') -def phase_calculate_system_libraries(state, linker_arguments, linker_inputs, newargs): +def phase_calculate_system_libraries(state, linker_arguments, newargs): extra_files_to_link = [] # Link in ports and system libraries, if necessary if not settings.SIDE_MODULE: # Ports are always linked into the main module, never the side module. extra_files_to_link += ports.get_libs(settings) - all_linker_inputs = [f for _, f in sorted(linker_inputs)] + extra_files_to_link - extra_files_to_link += system_libs.calculate(all_linker_inputs, newargs, forced=state.forced_stdlibs) + extra_files_to_link += system_libs.calculate(newargs, forced=state.forced_stdlibs) linker_arguments.extend(extra_files_to_link) @@ -3112,7 +3110,7 @@ def phase_link(linker_arguments, wasm_target, js_syms): @ToolchainProfiler.profile_block('post_link') -def phase_post_link(options, state, in_wasm, wasm_target, target): +def phase_post_link(options, state, in_wasm, wasm_target, target, js_syms): global final_js target_basename = unsuffixed_basename(target) @@ -3134,7 +3132,7 @@ def phase_post_link(options, state, in_wasm, wasm_target, target): else: memfile = shared.replace_or_append_suffix(target, '.mem') - phase_emscript(options, in_wasm, wasm_target, memfile) + phase_emscript(options, in_wasm, wasm_target, memfile, js_syms) if options.js_transform: phase_source_transforms(options) @@ -3152,7 +3150,7 @@ def phase_post_link(options, state, in_wasm, wasm_target, target): @ToolchainProfiler.profile_block('emscript') -def phase_emscript(options, in_wasm, wasm_target, memfile): +def phase_emscript(options, in_wasm, wasm_target, memfile, js_syms): # Emscripten logger.debug('emscript') @@ -3161,7 +3159,7 @@ def phase_emscript(options, in_wasm, wasm_target, memfile): # _read in shell.js depends on intArrayToString when SUPPORT_BASE64_EMBEDDING is set settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.append('$intArrayToString') - emscripten.run(in_wasm, wasm_target, final_js, memfile) + emscripten.run(in_wasm, wasm_target, final_js, memfile, js_syms) save_intermediate('original') diff --git a/emscripten.py b/emscripten.py index 274975c50dafe..aff41acd2ed3a 100644 --- a/emscripten.py +++ b/emscripten.py @@ -296,7 +296,7 @@ def create_named_globals(metadata): return '\n'.join(named_globals) -def emscript(in_wasm, out_wasm, outfile_js, memfile): +def emscript(in_wasm, out_wasm, outfile_js, memfile, js_syms): # Overview: # * Run wasm-emscripten-finalize to extract metadata and modify the binary # to use emscripten's wasm<->JS ABI @@ -309,7 +309,7 @@ def emscript(in_wasm, out_wasm, outfile_js, memfile): # set file locations, so that JS glue can find what it needs settings.WASM_BINARY_FILE = js_manipulation.escape_for_js_string(os.path.basename(out_wasm)) - metadata = finalize_wasm(in_wasm, out_wasm, memfile) + metadata = finalize_wasm(in_wasm, out_wasm, memfile, js_syms) if settings.RELOCATABLE and settings.MEMORY64 == 2: metadata.imports += ['__memory_base32'] @@ -461,7 +461,7 @@ def get_metadata(infile, outfile, modify_wasm, args): return metadata -def finalize_wasm(infile, outfile, memfile): +def finalize_wasm(infile, outfile, memfile, js_syms): building.save_intermediate(infile, 'base.wasm') args = [] @@ -536,13 +536,23 @@ def finalize_wasm(infile, outfile, memfile): expected_exports = set(settings.EXPORTED_FUNCTIONS) expected_exports.update(asmjs_mangle(s) for s in settings.REQUIRED_EXPORTS) - - # Calculate the subset of exports that were explicitly marked with llvm.used. + # Assume that when JS symbol dependencies are exported it is because they + # are needed by by a JS symbol and are not being explicitly exported due + # to EMSCRIPTEN_KEEPALIVE (llvm.used). + for deps in js_syms.values(): + expected_exports.update(asmjs_mangle(s) for s in deps) + + # Calculate the subset of exports that were explicitly marked as + # EMSCRIPTEN_KEEPALIVE (llvm.used). # These are any exports that were not requested on the command line and are # not known auto-generated system functions. unexpected_exports = [e for e in metadata.exports if treat_as_user_function(e)] unexpected_exports = [asmjs_mangle(e) for e in unexpected_exports] unexpected_exports = [e for e in unexpected_exports if e not in expected_exports] + if '_main' in unexpected_exports: + logger.warning('main() is in the input files, but "_main" is not in EXPORTED_FUNCTIONS, which means it may be eliminated as dead code. Export it if you want main() to run.') + unexpected_exports.remove('_main') + building.user_requested_exports.update(unexpected_exports) settings.EXPORTED_FUNCTIONS.extend(unexpected_exports) @@ -922,5 +932,5 @@ def normalize_line_endings(text): return text -def run(in_wasm, out_wasm, outfile_js, memfile): - emscript(in_wasm, out_wasm, outfile_js, memfile) +def run(in_wasm, out_wasm, outfile_js, memfile, js_syms): + emscript(in_wasm, out_wasm, outfile_js, memfile, js_syms) diff --git a/site/source/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.rst b/site/source/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.rst index eed087f3f90d5..b7096e81623af 100644 --- a/site/source/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.rst +++ b/site/source/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.rst @@ -596,9 +596,6 @@ See the `library_*.js`_ files for other examples. This is useful when all the implemented methods use a JavaScript singleton containing helper methods. See ``library_webgl.js`` for an example. - - If a JavaScript library depends on a compiled C library (like most - of *libc*), you must edit `src/deps_info.json`_. Search for - "deps_info" in `tools/system_libs.py`_. - The keys passed into `mergeInto` generate functions that are prefixed by ``_``. In other words ``my_func: function() {},`` becomes ``function _my_func() {}``, as all C methods in emscripten have a ``_`` prefix. Keys starting with ``$`` have the ``$`` @@ -810,7 +807,6 @@ you can give it a try. See `Emnapi documentation`_ for more details. .. _library.js: https://github.com/emscripten-core/emscripten/blob/main/src/library.js .. _test_js_libraries: https://github.com/emscripten-core/emscripten/blob/1.29.12/tests/test_core.py#L5043 -.. _src/deps_info.json: https://github.com/emscripten-core/emscripten/blob/main/src/deps_info.json .. _tools/system_libs.py: https://github.com/emscripten-core/emscripten/blob/main/tools/system_libs.py .. _library_\*.js: https://github.com/emscripten-core/emscripten/tree/main/src .. _test_add_function in test/test_core.py: https://github.com/emscripten-core/emscripten/blob/1.29.12/tests/test_core.py#L6237 diff --git a/src/jsifier.js b/src/jsifier.js index 7302ea0dd6c93..bd6c5607d3755 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -66,6 +66,26 @@ function isDefined(symName) { return false; } +function getTransitiveDeps(symbol) { + // TODO(sbc): Use some kind of cache to avoid quadratic behaviour here. + const transitiveDeps = new Set(); + const seen = new Set(); + const toVisit = [symbol]; + while (toVisit.length) { + const sym = toVisit.pop(); + if (!seen.has(sym)) { + let directDeps = LibraryManager.library[sym + '__deps'] || []; + directDeps = directDeps.filter((d) => typeof d === 'string'); + if (directDeps.length) { + directDeps.forEach(transitiveDeps.add, transitiveDeps); + toVisit.push(...directDeps); + } + seen.add(sym); + } + } + return Array.from(transitiveDeps); +} + function runJSify() { const libraryItems = []; const symbolDeps = {}; @@ -260,8 +280,14 @@ function ${name}(${args}) { if (symbolsOnly) { if (!isJsOnlySymbol(symbol) && LibraryManager.library.hasOwnProperty(symbol)) { - externalDeps = deps.filter((d) => !isJsOnlySymbol(d) && !(d in LibraryManager.library) && typeof d === 'string'); - symbolDeps[symbol] = externalDeps; + var value = LibraryManager.library[symbol]; + var resolvedSymbol = symbol; + // Resolve aliases before looking up deps + if (typeof value == 'string' && value[0] != '=' && LibraryManager.library.hasOwnProperty(value)) { + resolvedSymbol = value; + } + var transtiveDeps = getTransitiveDeps(resolvedSymbol); + symbolDeps[symbol] = transtiveDeps.filter((d) => !isJsOnlySymbol(d) && !(d in LibraryManager.library)); } return; } diff --git a/src/library.js b/src/library.js index f2afff44362cd..6c1dab396ffa4 100644 --- a/src/library.js +++ b/src/library.js @@ -1212,6 +1212,13 @@ mergeInto(LibraryManager.library, { // ========================================================================== #if SUPPORT_LONGJMP == 'emscripten' + // In WebAssemblyLowerEmscriptenEHSjLj pass in the LLVM backend, function + // calls that exist in the same function with setjmp are converted to a code + // sequence that includes invokes, malloc, free, saveSetjmp, and + // emscripten_longjmp. setThrew is called from invokes, but we don't have + // any way to express that dependency so we use emscripten_throw_longjmp as + // a proxy and declare the dependency here. + _emscripten_throw_longjmp__deps: ['setThrew'], _emscripten_throw_longjmp: function() { #if EXCEPTION_STACK_TRACES throw new EmscriptenSjLj; @@ -1721,7 +1728,7 @@ mergeInto(LibraryManager.library, { return { family: family, addr: addr, port: port }; }, $writeSockaddr__docs: '/** @param {number=} addrlen */', - $writeSockaddr__deps: ['$Sockets', '$inetPton4', '$inetPton6', '$zeroMemory'], + $writeSockaddr__deps: ['$Sockets', '$inetPton4', '$inetPton6', '$zeroMemory', 'htons'], $writeSockaddr: function (sa, family, addr, port, addrlen) { switch (family) { case {{{ cDefs.AF_INET }}}: @@ -1858,7 +1865,7 @@ mergeInto(LibraryManager.library, { return 0; }, - getaddrinfo__deps: ['$Sockets', '$DNS', '$inetPton4', '$inetNtop4', '$inetPton6', '$inetNtop6', '$writeSockaddr'], + getaddrinfo__deps: ['$Sockets', '$DNS', '$inetPton4', '$inetNtop4', '$inetPton6', '$inetNtop6', '$writeSockaddr', 'malloc', 'htonl'], getaddrinfo__proxy: 'sync', getaddrinfo: function(node, service, hint, out) { // Note getaddrinfo currently only returns a single addrinfo with ai_next defaulting to NULL. When NULL diff --git a/src/library_async.js b/src/library_async.js index 8ee81652c4e5d..d808eecc19997 100644 --- a/src/library_async.js +++ b/src/library_async.js @@ -22,7 +22,11 @@ mergeInto(LibraryManager.library, { #if ASYNCIFY $Asyncify__deps: ['$runAndAbortIfError', '$callUserCallback', '$sigToWasmTypes', #if !MINIMAL_RUNTIME - '$runtimeKeepalivePush', '$runtimeKeepalivePop' + '$runtimeKeepalivePush', '$runtimeKeepalivePop', +#endif +#if ASYNCIFY == 1 + // Needed by allocateData and handleSleep respectively + 'malloc', 'free', #endif ], diff --git a/src/library_browser.js b/src/library_browser.js index 07cc2d96b8d4c..821e2d83defe3 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -1212,6 +1212,7 @@ var LibraryBrowser = { // To avoid creating worker parent->child chains, always proxies to execute on the main thread. emscripten_create_worker__proxy: 'sync', + emscripten_create_worker__deps: ['$UTF8ToString', 'malloc', 'free'], emscripten_create_worker: function(url) { url = UTF8ToString(url); var id = Browser.workers.length; @@ -1253,6 +1254,7 @@ var LibraryBrowser = { return id; }, + emscripten_destroy_worker__deps: ['free'], emscripten_destroy_worker__proxy: 'sync', emscripten_destroy_worker: function(id) { var info = Browser.workers[id]; diff --git a/src/library_exceptions.js b/src/library_exceptions.js index 61ad2568e36a2..0672aca7b018b 100644 --- a/src/library_exceptions.js +++ b/src/library_exceptions.js @@ -23,9 +23,12 @@ var LibraryExceptions = { // // excPtr - Thrown object pointer to wrap. Metadata pointer is calculated from it. $ExceptionInfo__docs: '/** @constructor */', + $ExceptionInfo__deps: [ + '__cxa_is_pointer_type', #if EXCEPTION_DEBUG - $ExceptionInfo__deps: ['$ptrToString'], + '$ptrToString' #endif + ], $ExceptionInfo: function(excPtr) { this.excPtr = excPtr; this.ptr = excPtr - {{{ C_STRUCTS.__cxa_exception.__size__ }}}; @@ -416,6 +419,13 @@ var LibraryExceptions = { addCxaCatch = function(n) { LibraryManager.library['__cxa_find_matching_catch_' + n] = '__cxa_find_matching_catch'; }; + +// Add the first 10 catch handlers premptively. Others get added on demand in +// jsifier. This is done here primarily so that these symbols end up with the +// correct deps in the stub library that we pass to wasm-ld. +for (let i = 1; i < 10; i++) { + addCxaCatch(i) +} #endif mergeInto(LibraryManager.library, LibraryExceptions); diff --git a/src/library_exceptions_stub.js b/src/library_exceptions_stub.js index 16c7e532644c4..4be6c2a715bab 100644 --- a/src/library_exceptions_stub.js +++ b/src/library_exceptions_stub.js @@ -24,7 +24,7 @@ var LibraryExceptions = {}; #if !INCLUDE_FULL_LIBRARY // This method of link-time error genertation is not compatible with INCLUDE_FULL_LIBRARY LibraryExceptions[name + '__deps'] = [function() { - error('DISABLE_EXCEPTION_THROWING was set (likely due to -fno-exceptions), which means no C++ exception throwing support code is linked in, but such support is required by symbol ' + name + '. Either do not set DISABLE_EXCEPTION_THROWING (if you do want exception throwing) or compile all source files with -fno-except (so that no exceptions support code is required); also make sure DISABLE_EXCEPTION_CATCHING is set to the right value - if you want exceptions, it should be off, and vice versa.'); + error(`DISABLE_EXCEPTION_THROWING was set (likely due to -fno-exceptions), which means no C++ exception throwing support code is linked in, but such support is required by symbol '${name}'. Either do not set DISABLE_EXCEPTION_THROWING (if you do want exception throwing) or compile all source files with -fno-except (so that no exceptions support code is required); also make sure DISABLE_EXCEPTION_CATCHING is set to the right value - if you want exceptions, it should be off, and vice versa.`); }]; #endif }); diff --git a/src/library_glew.js b/src/library_glew.js index 817cc2e0f09cf..e8f9e9885141c 100644 --- a/src/library_glew.js +++ b/src/library_glew.js @@ -20,7 +20,7 @@ */ var LibraryGLEW = { - $GLEW__deps: ['glGetString', '$stringToNewUTF8'], + $GLEW__deps: ['glGetString', '$stringToNewUTF8', '$UTF8ToString'], $GLEW: { isLinaroFork: 1, extensions: null, diff --git a/src/library_glfw.js b/src/library_glfw.js index 63c66f5b34e98..7c5b742d00223 100644 --- a/src/library_glfw.js +++ b/src/library_glfw.js @@ -1123,7 +1123,7 @@ var LibraryGLFW = { /******************************************************************************* * GLFW FUNCTIONS ******************************************************************************/ - glfwInit__deps: ['emscripten_get_device_pixel_ratio'], + glfwInit__deps: ['emscripten_get_device_pixel_ratio', 'malloc', 'free'], glfwInit__sig: 'i', glfwInit: function() { if (GLFW.windows) return 1; // GL_TRUE diff --git a/src/library_html5.js b/src/library_html5.js index 9aa77eb98fb2b..ed6887011566d 100644 --- a/src/library_html5.js +++ b/src/library_html5.js @@ -235,7 +235,7 @@ var LibraryHTML5 = { }, }, - $registerKeyEventCallback__deps: ['$JSEvents', '$findEventTarget', '$stringToUTF8'], + $registerKeyEventCallback__deps: ['$JSEvents', '$findEventTarget', '$stringToUTF8', 'malloc'], $registerKeyEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) { #if PTHREADS targetThread = JSEvents.getTargetThreadForEventCallback(targetThread); @@ -503,7 +503,7 @@ var LibraryHTML5 = { #endif }, - $registerMouseEventCallback__deps: ['$JSEvents', '$fillMouseEventData', '$findEventTarget'], + $registerMouseEventCallback__deps: ['$JSEvents', '$fillMouseEventData', '$findEventTarget', 'malloc'], $registerMouseEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) { #if PTHREADS targetThread = JSEvents.getTargetThreadForEventCallback(targetThread); @@ -616,7 +616,7 @@ var LibraryHTML5 = { return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, - $registerWheelEventCallback__deps: ['$JSEvents', '$fillMouseEventData', '$findEventTarget'], + $registerWheelEventCallback__deps: ['$JSEvents', '$fillMouseEventData', '$findEventTarget', 'malloc'], $registerWheelEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) { #if PTHREADS targetThread = JSEvents.getTargetThreadForEventCallback(targetThread); @@ -692,7 +692,7 @@ var LibraryHTML5 = { } }, - $registerUiEventCallback__deps: ['$JSEvents', '$findEventTarget'], + $registerUiEventCallback__deps: ['$JSEvents', '$findEventTarget', 'malloc'], $registerUiEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) { #if PTHREADS targetThread = JSEvents.getTargetThreadForEventCallback(targetThread); @@ -768,7 +768,7 @@ var LibraryHTML5 = { return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, - $registerFocusEventCallback__deps: ['$JSEvents', '$findEventTarget', '$stringToUTF8'], + $registerFocusEventCallback__deps: ['$JSEvents', '$findEventTarget', 'malloc', '$stringToUTF8'], $registerFocusEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) { #if PTHREADS targetThread = JSEvents.getTargetThreadForEventCallback(targetThread); @@ -911,7 +911,7 @@ var LibraryHTML5 = { {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenDeviceMotionEvent.rotationRateGamma, 'rr["gamma"]', 'double') }}}; }, - $registerDeviceMotionEventCallback__deps: ['$JSEvents', '$fillDeviceMotionEventData', '$findEventTarget'], + $registerDeviceMotionEventCallback__deps: ['$JSEvents', '$fillDeviceMotionEventData', '$findEventTarget', 'malloc'], $registerDeviceMotionEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) { #if PTHREADS targetThread = JSEvents.getTargetThreadForEventCallback(targetThread); @@ -979,7 +979,7 @@ var LibraryHTML5 = { {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenOrientationChangeEvent.orientationAngle, 'orientation', 'i32') }}}; }, - $registerOrientationChangeEventCallback__deps: ['$JSEvents', '$fillOrientationChangeEventData', '$findEventTarget'], + $registerOrientationChangeEventCallback__deps: ['$JSEvents', '$fillOrientationChangeEventData', '$findEventTarget', 'malloc'], $registerOrientationChangeEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) { #if PTHREADS targetThread = JSEvents.getTargetThreadForEventCallback(targetThread); @@ -1099,7 +1099,7 @@ var LibraryHTML5 = { } }, - $registerFullscreenChangeEventCallback__deps: ['$JSEvents', '$fillFullscreenChangeEventData', '$findEventTarget'], + $registerFullscreenChangeEventCallback__deps: ['$JSEvents', '$fillFullscreenChangeEventData', '$findEventTarget', 'malloc'], $registerFullscreenChangeEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) { #if PTHREADS targetThread = JSEvents.getTargetThreadForEventCallback(targetThread); @@ -1677,7 +1677,7 @@ var LibraryHTML5 = { stringToUTF8(id, eventStruct + {{{ C_STRUCTS.EmscriptenPointerlockChangeEvent.id }}}, {{{ cDefs.EM_HTML5_LONG_STRING_LEN_BYTES }}}); }, - $registerPointerlockChangeEventCallback__deps: ['$JSEvents', '$fillPointerlockChangeEventData', '$findEventTarget'], + $registerPointerlockChangeEventCallback__deps: ['$JSEvents', '$fillPointerlockChangeEventData', '$findEventTarget', 'malloc'], $registerPointerlockChangeEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) { #if PTHREADS targetThread = JSEvents.getTargetThreadForEventCallback(targetThread); @@ -1923,7 +1923,7 @@ var LibraryHTML5 = { {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenVisibilityChangeEvent.visibilityState, 'visibilityState', 'i32') }}}; }, - $registerVisibilityChangeEventCallback__deps: ['$JSEvents', '$fillVisibilityChangeEventData', '$findEventTarget'], + $registerVisibilityChangeEventCallback__deps: ['$JSEvents', '$fillVisibilityChangeEventData', '$findEventTarget', 'malloc'], $registerVisibilityChangeEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) { #if PTHREADS targetThread = JSEvents.getTargetThreadForEventCallback(targetThread); @@ -1978,7 +1978,7 @@ var LibraryHTML5 = { return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, - $registerTouchEventCallback__deps: ['$JSEvents', '$findEventTarget', '$getBoundingClientRect'], + $registerTouchEventCallback__deps: ['$JSEvents', '$findEventTarget', '$getBoundingClientRect', 'malloc'], $registerTouchEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) { #if PTHREADS targetThread = JSEvents.getTargetThreadForEventCallback(targetThread); @@ -2137,7 +2137,7 @@ var LibraryHTML5 = { stringToUTF8(e.mapping, eventStruct + {{{ C_STRUCTS.EmscriptenGamepadEvent.mapping }}}, {{{ cDefs.EM_HTML5_MEDIUM_STRING_LEN_BYTES }}}); }, - $registerGamepadEventCallback__deps: ['$JSEvents', '$fillGamepadEventData', '$findEventTarget'], + $registerGamepadEventCallback__deps: ['$JSEvents', '$fillGamepadEventData', '$findEventTarget', 'malloc'], $registerGamepadEventCallback: function(target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) { #if PTHREADS targetThread = JSEvents.getTargetThreadForEventCallback(targetThread); @@ -2305,7 +2305,7 @@ var LibraryHTML5 = { }, emscripten_set_batterychargingchange_callback_on_thread__proxy: 'sync', - emscripten_set_batterychargingchange_callback_on_thread__deps: ['$registerBatteryEventCallback', '$battery', 'malloc'], + emscripten_set_batterychargingchange_callback_on_thread__deps: ['$registerBatteryEventCallback', '$battery'], emscripten_set_batterychargingchange_callback_on_thread: function(userData, callbackfunc, targetThread) { if (!battery()) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; registerBatteryEventCallback(battery(), userData, true, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_BATTERYCHARGINGCHANGE }}}, "chargingchange", targetThread); @@ -2313,7 +2313,7 @@ var LibraryHTML5 = { }, emscripten_set_batterylevelchange_callback_on_thread__proxy: 'sync', - emscripten_set_batterylevelchange_callback_on_thread__deps: ['$registerBatteryEventCallback', '$battery', 'malloc'], + emscripten_set_batterylevelchange_callback_on_thread__deps: ['$registerBatteryEventCallback', '$battery'], emscripten_set_batterylevelchange_callback_on_thread: function(userData, callbackfunc, targetThread) { if (!battery()) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; registerBatteryEventCallback(battery(), userData, true, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_BATTERYLEVELCHANGE }}}, "levelchange", targetThread); diff --git a/src/library_html5_webgl.js b/src/library_html5_webgl.js index 8921d24bbc6f9..5cc64b4a11d1f 100644 --- a/src/library_html5_webgl.js +++ b/src/library_html5_webgl.js @@ -76,6 +76,9 @@ var LibraryHtml5WebGL = { #if LibraryManager.has('library_webgl.js') '$GL', #endif +#if OFFSCREENCANVAS_SUPPORT + 'malloc', +#endif #if PTHREADS && OFFSCREEN_FRAMEBUFFER 'emscripten_webgl_create_context_proxied', #endif @@ -313,6 +316,7 @@ var LibraryHtml5WebGL = { }, emscripten_webgl_destroy_context__proxy: 'sync_on_webgl_context_handle_thread', + emscripten_webgl_destroy_context__deps: ['free'], emscripten_webgl_destroy_context: function(contextHandle) { if (GL.currentContext == contextHandle) GL.currentContext = 0; GL.deleteContext(contextHandle); diff --git a/src/library_idbstore.js b/src/library_idbstore.js index 4245866953e7d..38ec8fc70b2a6 100644 --- a/src/library_idbstore.js +++ b/src/library_idbstore.js @@ -13,6 +13,7 @@ var LibraryIDBStore = { $IDBStore: #include IDBStore.js , + emscripten_idb_async_load__deps: ['$UTF8ToString', 'malloc', 'free'], emscripten_idb_async_load: function(db, id, arg, onload, onerror) { IDBStore.getFile(UTF8ToString(db), UTF8ToString(id), function(error, byteArray) { if (error) { @@ -56,6 +57,7 @@ var LibraryIDBStore = { #if ASYNCIFY emscripten_idb_load__async: true, + emscripten_idb_load__deps: ['malloc'], emscripten_idb_load: function(db, id, pbuffer, pnum, perror) { Asyncify.handleSleep(function(wakeUp) { IDBStore.getFile(UTF8ToString(db), UTF8ToString(id), function(error, byteArray) { diff --git a/src/library_syscall.js b/src/library_syscall.js index 629e3edb96560..85912d6cd0dba 100644 --- a/src/library_syscall.js +++ b/src/library_syscall.js @@ -127,6 +127,13 @@ var SyscallsLibrary = { _mmap_js__deps: ['$SYSCALLS', #if FILESYSTEM && SYSCALLS_REQUIRE_FILESYSTEM '$FS', + // The dependency of FS on `mmapAlloc` and `mmapAlloc` on + // `emscripten_builtin_memalign` are not encoding as hard dependencies, + // so we need to explictly depend on them here to ensure a working + // `FS.mmap`. + // `emscripten_builtin_memalign`). + '$mmapAlloc', + 'emscripten_builtin_memalign', #endif ], _mmap_js: function(len, prot, flags, fd, off, allocated, addr) { diff --git a/src/library_websocket.js b/src/library_websocket.js index 88d0d2b05fd37..a8d83212457ac 100644 --- a/src/library_websocket.js +++ b/src/library_websocket.js @@ -215,7 +215,7 @@ var LibraryWebSocket = { return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, - emscripten_websocket_set_onmessage_callback_on_thread__deps: ['$WS', '$stringToNewUTF8'], + emscripten_websocket_set_onmessage_callback_on_thread__deps: ['$WS', '$stringToNewUTF8', 'malloc', 'free'], emscripten_websocket_set_onmessage_callback_on_thread__proxy: 'sync', emscripten_websocket_set_onmessage_callback_on_thread: function(socketId, userData, callbackFunc, thread) { if (!WS.socketEvent) WS.socketEvent = _malloc(1024); // TODO: sizeof(EmscriptenWebSocketCloseEvent), which is the largest event struct diff --git a/src/settings.js b/src/settings.js index af20a52f8ebff..93ea2feb66600 100644 --- a/src/settings.js +++ b/src/settings.js @@ -2021,22 +2021,6 @@ var IMPORTED_MEMORY = false; // [link] var SPLIT_MODULE = false; -// How to calculate reverse dependencies (dependencies from JS functions to -// native functions) prior to linking native code with wasm-ld. This option -// has three possible values: -// 'auto': (default) Inspect the object code passed to the linker (by running -// llvm-nm on all input) and use the map in deps_info.py to determine -// the set of additional dependencies. -// 'all' : Include the full set of possible reverse dependencies. -// 'none': No reverse dependences will be added by emscriopten. Any reverse -// dependencies will be assumed to be explicitly added to -// EXPORTED_FUNCTIONS and deps_info.py will be completely ignored. -// While 'auto' will produce a minimal set (so is good for code size), 'all' -// and 'none' will give faster link times, especially for very large projects -// (since they both avoid the running of llvm-nm on all linker inputs). -// [link] -var REVERSE_DEPS = 'auto'; - // For MAIN_MODULE builds, automatically load any dynamic library dependencies // on startup, before loading the main module. var AUTOLOAD_DYLIBS = true; @@ -2169,4 +2153,5 @@ var LEGACY_SETTINGS = [ ['MEM_INIT_METHOD', [0], 'No longer supported'], ['USE_PTHREADS', [0, 1], 'No longer needed. Use -pthread instead'], ['USES_DYNAMIC_ALLOC', [1], 'No longer supported. Use -sMALLOC=none'], + ['REVERSE_DEPS', ['auto', 'all', 'none'], 'No longer needed'], ]; diff --git a/test/test_core.py b/test/test_core.py index 2a995f3fdd7f0..235c305c4e96a 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -9687,22 +9687,6 @@ def test_main_module_js_symbol(self): self.emcc_args += ['--js-library', test_file('core/test_main_module_js_symbol.js')] self.do_runf(test_file('core/test_main_module_js_symbol.c')) - def test_REVERSE_DEPS(self): - create_file('connect.c', '#include \nint main() { return (int)(long)&connect; }') - self.run_process([EMCC, 'connect.c']) - base_size = os.path.getsize('a.out.wasm') - - # 'auto' should work (its the default) - self.run_process([EMCC, 'connect.c', '-sREVERSE_DEPS=auto']) - - # 'all' should work too although it should produce a larger binary - self.run_process([EMCC, 'connect.c', '-sREVERSE_DEPS=all']) - self.assertGreater(os.path.getsize('a.out.wasm'), base_size) - - # 'none' should fail to link because the dependency on ntohs was not added. - err = self.expect_fail([EMCC, 'connect.c', '-sREVERSE_DEPS=none']) - self.assertContained('undefined symbol: ntohs', err) - def test_emscripten_async_call(self): self.set_setting('EXIT_RUNTIME') self.do_run_in_out_file_test(test_file('core/test_emscripten_async_call.c')) diff --git a/test/test_other.py b/test/test_other.py index 5588fe353b9ce..1e045ea436a1a 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -35,7 +35,7 @@ from common import compiler_for, EMBUILDER, requires_v8, requires_node, requires_wasm64 from common import requires_wasm_eh, crossplatform, with_both_sjlj from common import also_with_minimal_runtime, also_with_wasm_bigint, EMTEST_BUILD_VERBOSE, PYTHON -from tools import shared, building, utils, deps_info, response_file, cache +from tools import shared, building, utils, response_file, cache from tools.utils import read_file, write_file, delete_file, read_binary import common import jsrun @@ -6944,7 +6944,7 @@ def test_no_missing_symbols(self): # simple hello world should not show any miss }); ''') err = self.expect_fail([EMCC, 'test.c', '--js-library', 'library_foo_missing.js']) - self.assertContained('wasm-ld: error: symbol exported via --export not found: nonexistingvariable', err) + self.assertContained('undefined symbol: nonexistingvariable. Required by my_js', err) # and also for missing C code, of course (without the --js-library, it's just a missing C method) err = self.expect_fail([EMCC, 'test.c']) @@ -10967,7 +10967,7 @@ def test_empty_output_extension(self): self.assertContained('hello, world!', self.run_js('hello')) def test_backwards_deps_in_archive(self): - # Test that JS dependencies from deps_info.json work for code linked via + # Test that JS dependencies on native code work for code linked via # static archives using -l self.run_process([EMCC, '-c', test_file('sockets/test_gethostbyname.c'), '-o', 'a.o']) self.run_process([LLVM_AR, 'cr', 'liba.a', 'a.o']) @@ -11369,7 +11369,7 @@ def test_linker_version(self): # depended on the missing function. def test_chained_js_error_diagnostics(self): err = self.expect_fail([EMCC, test_file('test_chained_js_error_diagnostics.c'), '--js-library', test_file('test_chained_js_error_diagnostics.js')]) - self.assertContained("error: undefined symbol: nonexistent_function (referenced by bar__deps: ['nonexistent_function'], referenced by foo__deps: ['bar'], referenced by top-level compiled C/C++ code)", err) + self.assertContained('emscripten_js_symbols.so: undefined symbol: nonexistent_function. Required by foo', err) # Test without chaining. In this case we don't include the JS library at # all resulting in `foo` being undefined in the native code. @@ -11882,97 +11882,6 @@ def test_relocatable_limited_exports(self): self.assertIn('sendmsg', exports_linkable) self.assertNotIn('sendmsg', exports) - @is_slow_test - def test_deps_info(self): - # Verify that for each symbol listed in deps_info all the reverse - # dependencies are indeed valid. - # To do this we compile a tiny test program that depends on the address - # of each function. Once compiled the resulting JavaScript code should - # contain a reference to each of the dependencies. - - # When debugging set this value to the function that you want to start - # with. All symbols prior will be skipped over. - start_at = None - assert not start_at or start_at in deps_info.get_deps_info() - for function, deps in deps_info.get_deps_info().items(): - if start_at: - if function == start_at: - start_at = None - else: - print(f'skipping {function}') - continue - create_file(function + '.c', ''' - void %s(); - int main() { - return (int)(long)&%s; - } - ''' % (function, function)) - # Compile with -O2 so we get JSDCE run to remove any false positives. This - # also makes the string quotes consistent which makes the test below simpler. - # Including -sREVERSE_DEPS=auto explicitly (even though its the default) to - # be clear this is what we are testing (and in case the default ever changes). - cmd = [EMCC, function + '.c', '-O2', '--minify=0', '--profiling-funcs', '-Wno-incompatible-library-redeclaration', '-sREVERSE_DEPS=auto'] - print(f'compiling test program for: {function}') - if 'emscripten_get_compiler_setting' in function: - cmd.append('-sRETAIN_COMPILER_SETTINGS') - if 'emscripten_pc_get_function' in function: - cmd.append('-sUSE_OFFSET_CONVERTER') - if 'embind' in function: - cmd.append('-lembind') - if 'websocket' in function: - cmd += ['-sPROXY_POSIX_SOCKETS', '-lwebsocket.js'] - if function == 'Mix_LoadWAV_RW': - cmd += ['-sUSE_SDL=2'] - if 'thread' in function: - cmd.append('-pthread') - if 'glGetStringi' in function: - cmd.append('-sUSE_WEBGL2') - if 'glMapBufferRange' in function: - cmd.append('-sFULL_ES3') - if function == 'wgpuDeviceCreateBuffer': - cmd.append('-sUSE_WEBGPU') - # dladdr dlsym etc.. - if function.startswith('dl'): - cmd.append('-sMAIN_MODULE=2') - if function.startswith('emscripten_idb') or function.startswith('emscripten_wget_'): - cmd.append('-sASYNCIFY') - if function.startswith('emscripten_webgl_') or 'offscreencanvas' in function: - cmd.append('-sOFFSCREENCANVAS_SUPPORT') - cmd.append('-pthread') - if function.startswith('wgpu'): - cmd.append('-sUSE_WEBGPU') - if function.startswith('__cxa_'): - cmd.append('-fexceptions') - if function.startswith('glfwGetMonitors'): - cmd.append('-sUSE_GLFW=3') - if 'mmap' in function: - cmd.append('-sFORCE_FILESYSTEM') - # In WebAssemblyLowerEmscriptenEHSjLj pass in the LLVM backend, function - # calls that exist in the same function with setjmp are converted to some - # code sequence that includes emscripten_longjmp. emscripten_longjmp is - # included in deps_info.py because in non-LTO builds setjmp does not exist - # anymore in the object files. So the mere indirect reference of setjmp or - # emscripten_longjmp does not generate calls to its dependencies specified - # in deps_info.py. Also Emscripten EH has a known restriction that setjmp - # cannot be called or referenced indirectly anyway. - if function in ['emscripten_longjmp', 'setjmp']: - continue - print(shared.shlex_join(cmd)) - self.run_process(cmd) - js = read_file('a.out.js') - for dep in deps: - direct = '_' + dep + '(' - via_module = '"_%s"](' % dep - assignment = ' = _' + dep - print(f' checking for: {dep}') - if direct not in js and via_module not in js and assignment not in js: - self.fail(f'use of declared dependency {dep} not found in JS output for {function}') - - # Check that the dependency not a JS library function. Dependencies on JS functions - # do not need entries in deps_info.py. - if f'function _{dep}(' in js: - self.fail(f'dependency {dep} in deps_info.py looks like a JS function (but should be native)') - @requires_v8 def test_shell_Oz(self): # regression test for -Oz working on non-web, non-node environments that diff --git a/tools/building.py b/tools/building.py index 9125335950d0f..d73879ceef7a2 100644 --- a/tools/building.py +++ b/tools/building.py @@ -40,8 +40,6 @@ binaryen_checked = False EXPECTED_BINARYEN_VERSION = 112 -# cache results of nm - it can be slow to run -nm_cache = {} _is_ar_cache: Dict[str, bool] = {} # the exports the user requested user_requested_exports: Set[str] = set() @@ -84,34 +82,6 @@ def get_building_env(): return env -@ToolchainProfiler.profile() -def llvm_nm_multiple(files): - """Runs llvm-nm for the given list of files. - - The results are populated in nm_cache, and also returned as an array with - order corresponding with the input files. - If a given file cannot be processed, None will be present in its place. - """ - if len(files) == 0: - return [] - # Run llvm-nm on files that we haven't cached yet - cmd = [LLVM_NM, '--print-file-name'] + [f for f in files if f not in nm_cache] - cmd = get_command_with_possible_response_file(cmd) - results = run_process(cmd, stdout=PIPE, stderr=PIPE, check=False) - - # If one or more of the input files cannot be processed, llvm-nm will return - # a non-zero error code, but it will still process and print out all the - # other files in order. So even if process return code is non zero, we should - # always look at what we got to stdout. - if results.returncode != 0: - logger.debug(f'Subcommand {" ".join(cmd)} failed with return code {results.returncode}! (An input file was corrupt?)') - - for key, value in parse_llvm_nm_symbols(results.stdout).items(): - nm_cache[key] = value - - return [nm_cache[f] if f in nm_cache else {'defs': set(), 'undefs': set(), 'parse_error': True} for f in files] - - def llvm_backend_args(): # disable slow and relatively unimportant optimization passes args = ['-combiner-global-alias-analysis=false'] @@ -146,13 +116,47 @@ def link_to_object(args, target): link_lld(args + ['--relocatable'], target) +def side_module_external_deps(external_symbols): + """Find the list of the external symbols that are needed by the + linked side modules. + """ + deps = set() + for sym in settings.SIDE_MODULE_IMPORTS: + sym = demangle_c_symbol_name(sym) + if sym in external_symbols: + deps = deps.union(external_symbols[sym]) + return sorted(list(deps)) + + +def create_stub_object(external_symbols): + """Create a stub object, based on the JS libary symbols and their + dependencies, that we can pass to wasm-ld. + """ + stubfile = shared.get_temp_files().get('libemscripten_js_symbols.so').name + stubs = ['#STUB'] + for name, deps in external_symbols.items(): + if settings.ERROR_ON_UNDEFINED_SYMBOLS: + stubs.append('%s: %s' % (name, ','.join(deps))) + else: + stubs.append(name) + utils.write_file(stubfile, '\n'.join(stubs)) + return stubfile + + def lld_flags_for_executable(external_symbols): cmd = [] - if settings.ERROR_ON_UNDEFINED_SYMBOLS: - undefs = shared.get_temp_files().get('.undefined').name - utils.write_file(undefs, '\n'.join(external_symbols)) - cmd.append('--allow-undefined-file=%s' % undefs) - else: + if external_symbols: + if settings.INCLUDE_FULL_LIBRARY: + all_deps = set() + for deps in external_symbols.values(): + for dep in deps: + if dep not in all_deps: + cmd.append('--export-if-defined=' + dep) + all_deps.add(dep) + stub = create_stub_object(external_symbols) + cmd.append(stub) + + if not settings.ERROR_ON_UNDEFINED_SYMBOLS: cmd.append('--import-undefined') if settings.IMPORTED_MEMORY: @@ -178,6 +182,8 @@ def lld_flags_for_executable(external_symbols): c_exports += settings.EXPORT_IF_DEFINED # Filter out symbols external/JS symbols c_exports = [e for e in c_exports if e not in external_symbols] + if settings.MAIN_MODULE: + c_exports += side_module_external_deps(external_symbols) for export in c_exports: cmd.append('--export-if-defined=' + export) @@ -288,58 +294,6 @@ def get_command_with_possible_response_file(cmd): return new_cmd -# Parses the output of llvm-nm and returns a dictionary of symbols for each file in the output. -# This function can be called either for a single file output listing ("llvm-nm a.o", or for -# multiple files listing ("llvm-nm a.o b.o"). -def parse_llvm_nm_symbols(output): - # If response files are used in a call to llvm-nm, the output printed by llvm-nm has a - # quirk that it will contain double backslashes as directory separators on Windows. (it will - # not remove the escape characters when printing) - # Therefore canonicalize the output to single backslashes. - output = output.replace('\\\\', '\\') - - # a dictionary from 'filename' -> { 'defs': set(), 'undefs': set(), 'commons': set() } - symbols = {} - - for line in output.split('\n'): - # Line format: "[archive filename:]object filename: address status name" - entry_pos = line.rfind(': ') - if entry_pos < 0: - continue - - filename_end = line.rfind(':', 0, entry_pos) - # Disambiguate between - # C:\bar.o: T main - # and - # /foo.a:bar.o: T main - # (both of these have same number of ':'s, but in the first, the file name on disk is "C:\bar.o", in second, it is "/foo.a") - if filename_end < 0 or line[filename_end + 1] in '/\\': - filename_end = entry_pos - - filename = line[:filename_end] - if entry_pos + 13 >= len(line): - exit_with_error('error parsing output of llvm-nm: `%s`\nIf the symbol name here contains a colon, and starts with __invoke_, then the object file was likely built with an old version of llvm (please rebuild it).' % line) - - # Skip address, which is always fixed-length 8 chars (plus 2 leading chars `: ` and one trailing space) - status = line[entry_pos + 11] - symbol = line[entry_pos + 13:] - - if filename not in symbols: - record = symbols.setdefault(filename, { - 'defs': set(), - 'undefs': set(), - 'commons': set(), - 'parse_error': False - }) - if status == 'U': - record['undefs'] |= {symbol} - elif status == 'C': - record['commons'] |= {symbol} - elif status == status.upper(): - record['defs'] |= {symbol} - return symbols - - def emar(action, output_filename, filenames, stdout=None, stderr=None, env=None): utils.delete_file(output_filename) cmd = [EMAR, action, output_filename] + filenames diff --git a/tools/deps_info.py b/tools/deps_info.py deleted file mode 100644 index b05890878d923..0000000000000 --- a/tools/deps_info.py +++ /dev/null @@ -1,208 +0,0 @@ -# Copyright 2020 The Emscripten Authors. All rights reserved. -# Emscripten is available under two separate licenses, the MIT license and the -# University of Illinois/NCSA Open Source License. Both these licenses can be -# found in the LICENSE file. - -# deps_info is a mechanism that lets JS code depend on C functions. This -# needs special help because of how linking works: -# -# 1. Receive some input files (.o, .c, etc.) from the user. -# 2. Link them with system libraries. -# 3. Whatever symbols are still unresolved, look in JS libraries for them. -# -# This makes C->JS calls work in a natural way: if compiled code depends on -# a function foo() that is implemented in a JS library, it will be unresolved -# after stage 2, and therefore linked in at stage 3. The problem is the other -# direction: if a JS library function decides it needs some function from say -# libc, then at stage 3 it is too late to link in more libc code. That's -# where deps_info comes in. -# -# Specifically, before stage 2 (linking with system libraries) we look at what -# symbols are required by the input files. Imagine that js_func in a JS -# library depends on libc_func in libc. Then if deps_info tells us -# -# "js_func": ["libc_func"] -# -# then if we see js_func is required (undefined) before stage 2, then we add -# a requirement to link in libc_func when linking in system libraries. All -# we do with deps_info is see if any of the keys are among the -# undefined symbols before stage 2, and if they are, add their values to the -# things we need to link in. -# -# This usually works the way you want, but note that it happens *before* stage -# 2 and not after it. That is, we look for js_func before linking in system -# libraries. If you have a situation where -# -# user_code => other_libc_func => js_func => libc_func -# -# then the deps_info entry must contain -# -# "other_libc_func": ["libc_func"] -# -# because that is what we see before stage 2: all we see is that -# other_libc_func is going to be linked in, and we don't know yet that it -# will end up calling js_func. But the presence of a call to other_libc_func -# indicates that we will need libc_func linked in as well, so that is what the -# deps_info entry should contain. -# -# TODO: Move all __deps from src/library*.js to deps_info, and use that single source of info -# both here and in the JS compiler. - -from tools.settings import settings - -_deps_info = { - 'alarm': ['_emscripten_timeout'], - 'sched_yield': ['_emscripten_timeout'], - 'setitimer': ['_emscripten_timeout'], - 'SDL_GL_GetProcAddress': ['malloc'], - 'SDL_LockSurface': ['malloc', 'free'], - 'SDL_OpenAudio': ['malloc', 'free'], - 'SDL_PushEvent': ['malloc', 'free'], - '_embind_register_class': ['free'], - '_embind_register_enum_value': ['free'], - '_embind_register_function': ['free'], - '_embind_register_std_string': ['free'], - '_embind_register_std_wstring': ['free'], - 'alGetString': ['malloc'], - 'alcGetString': ['malloc'], - 'bind': ['ntohs', 'htons'], - 'connect': ['ntohs', 'htons'], - 'ctime': ['malloc'], - 'gmtime': ['malloc'], - 'ctime_r': ['malloc'], - 'dladdr': ['malloc'], - 'dlopen': ['__dl_seterr', 'malloc'], - 'dlsym': ['__dl_seterr'], - 'eglGetProcAddress': ['malloc'], - 'eglQueryString': ['malloc'], - 'emscripten_GetProcAddress': ['malloc'], - 'emscripten_SDL_SetEventHandler': ['malloc', 'free'], - 'emscripten_alcGetStringiSOFT': ['malloc'], - 'emscripten_async_wget2_data': ['malloc', 'free'], - 'emscripten_async_wget_data': ['malloc', 'free'], - 'emscripten_create_worker': ['malloc', 'free'], - 'emscripten_get_compiler_setting': ['malloc'], - 'emscripten_get_window_title': ['malloc'], - 'emscripten_idb_async_load': ['malloc', 'free'], - 'emscripten_idb_load': ['malloc', 'free'], - 'emscripten_init_websocket_to_posix_socket_bridge': ['malloc', 'free'], - # This list is the same as setjmp's dependencies. In non-LTO builds, setjmp - # does not exist in the object files; it is converted into a code sequence - # that includes several functions, one of which is emscripten_longjmp. This is - # a trick to include these dependencies for setjmp even when setjmp does not - # exist. Refer to setjmp's entry for more details. - 'emscripten_longjmp': ['malloc', 'free', 'saveSetjmp', 'setThrew'], - 'emscripten_pc_get_file': ['malloc', 'free'], - 'emscripten_pc_get_function': ['malloc', 'free'], - 'emscripten_run_script_string': ['malloc', 'free'], - 'emscripten_set_blur_callback_on_thread': ['malloc'], - 'emscripten_set_click_callback_on_thread': ['malloc'], - 'emscripten_set_dblclick_callback_on_thread': ['malloc'], - 'emscripten_set_devicemotion_callback_on_thread': ['malloc'], - 'emscripten_set_deviceorientation_callback_on_thread': ['malloc'], - 'emscripten_set_focus_callback_on_thread': ['malloc'], - 'emscripten_set_focusin_callback_on_thread': ['malloc'], - 'emscripten_set_focusout_callback_on_thread': ['malloc'], - 'emscripten_set_fullscreenchange_callback_on_thread': ['malloc'], - 'emscripten_set_gamepadconnected_callback_on_thread': ['malloc'], - 'emscripten_set_gamepaddisconnected_callback_on_thread': ['malloc'], - 'emscripten_set_keydown_callback_on_thread': ['malloc'], - 'emscripten_set_keypress_callback_on_thread': ['malloc'], - 'emscripten_set_keyup_callback_on_thread': ['malloc'], - 'emscripten_set_mousedown_callback_on_thread': ['malloc'], - 'emscripten_set_mouseenter_callback_on_thread': ['malloc'], - 'emscripten_set_mouseleave_callback_on_thread': ['malloc'], - 'emscripten_set_mousemove_callback_on_thread': ['malloc'], - 'emscripten_set_mouseout_callback_on_thread': ['malloc'], - 'emscripten_set_mouseover_callback_on_thread': ['malloc'], - 'emscripten_set_mouseup_callback_on_thread': ['malloc'], - 'emscripten_set_orientationchange_callback_on_thread': ['malloc'], - 'emscripten_set_pointerlockchange_callback_on_thread': ['malloc'], - 'emscripten_set_resize_callback_on_thread': ['malloc'], - 'emscripten_set_scroll_callback_on_thread': ['malloc'], - 'emscripten_set_touchcancel_callback_on_thread': ['malloc'], - 'emscripten_set_touchend_callback_on_thread': ['malloc'], - 'emscripten_set_touchmove_callback_on_thread': ['malloc'], - 'emscripten_set_touchstart_callback_on_thread': ['malloc'], - 'emscripten_set_visibilitychange_callback_on_thread': ['malloc'], - 'emscripten_set_wheel_callback_on_thread': ['malloc'], - 'emscripten_thread_sleep': ['_emscripten_timeout'], - 'emscripten_webgl_get_parameter_utf8': ['malloc'], - 'emscripten_webgl_get_program_info_log_utf8': ['malloc'], - 'emscripten_webgl_get_shader_info_log_utf8': ['malloc'], - 'emscripten_webgl_get_shader_source_utf8': ['malloc'], - 'emscripten_webgl_get_supported_extensions': ['malloc'], - 'emscripten_websocket_set_onclose_callback_on_thread': ['malloc'], - 'emscripten_websocket_set_onerror_callback_on_thread': ['malloc'], - 'emscripten_websocket_set_onmessage_callback_on_thread': ['malloc', 'free'], - 'emscripten_websocket_set_onopen_callback_on_thread': ['malloc'], - 'emscripten_wget_data': ['malloc', 'free'], - 'getaddrinfo': ['malloc', 'htonl', 'htons', 'ntohs'], - 'gethostbyaddr': ['malloc', 'htons'], - 'gethostbyname': ['malloc', 'htons'], - 'gethostbyname_r': ['malloc', 'free', 'htons', 'memcpy'], - 'getnameinfo': ['htons', 'ntohs'], - 'getpeername': ['htons'], - 'getsockname': ['htons'], - 'glGetString': ['malloc'], - 'glGetStringi': ['malloc'], - 'glMapBufferRange': ['malloc'], - 'glewInit': ['malloc'], - 'glfwGetProcAddress': ['malloc'], - 'glfwInit': ['malloc', 'free'], - 'glfwSleep': ['sleep', 'malloc'], - 'glfwGetMonitors': ['malloc'], - 'localtime': ['malloc'], - 'localtime_r': ['malloc'], - 'mktime': ['malloc'], - 'recv': ['htons'], - 'recvmsg': ['htons'], - 'accept': ['htons'], - 'recvfrom': ['htons'], - 'send': ['ntohs', 'htons'], - 'sendmsg': ['ntohs', 'htons'], - # In WebAssemblyLowerEmscriptenEHSjLj pass in the LLVM backend, function calls - # that exist in the same function with setjmp are converted to some code - # sequence that includes invokes, malloc, free, saveSetjmp, and - # emscripten_longjmp. setThrew is called from invokes, but there's no way to - # directly include invokes in deps_info.py, so we list it as a setjmp's - # dependency. - 'setjmp': ['malloc', 'free', 'saveSetjmp', 'setThrew'], - 'syslog': ['malloc', 'ntohs', 'htons'], - 'vsyslog': ['malloc', 'ntohs', 'htons'], - 'timegm': ['malloc'], - 'tzset': ['malloc'], - 'emscripten_glGetString': ['malloc'], -} - - -def append_deps_info(js_symbol_deps): - for key, value in js_symbol_deps.items(): - if value: - _deps_info.setdefault(key, []) - _deps_info[key] += value - - -def get_deps_info(): - if not settings.WASM_EXCEPTIONS and settings.LINK_AS_CXX: - _deps_info['__cxa_end_catch'] = ['setThrew', '__cxa_decrement_exception_refcount'] - base_js_exception_deps = ['__cxa_is_pointer_type'] - _deps_info['__cxa_throw'] = base_js_exception_deps - _deps_info['__cxa_begin_catch'] = base_js_exception_deps + ['__cxa_increment_exception_refcount'] - _deps_info['__cxa_find_matching_catch'] = base_js_exception_deps + ['__cxa_can_catch', 'setTempRet0'] - for i in range(1, 10): - _deps_info['__cxa_find_matching_catch_%d' % i] = _deps_info['__cxa_find_matching_catch'] - if settings.PTHREADS and settings.OFFSCREENCANVAS_SUPPORT: - _deps_info['pthread_create'] = ['malloc'] - if settings.FILESYSTEM and settings.SYSCALLS_REQUIRE_FILESYSTEM: - _deps_info['mmap'] = ['emscripten_builtin_memalign'] - if settings.PTHREADS: - _deps_info['glutCreateWindow'] = ['malloc'] - _deps_info['emscripten_webgl_create_context'] = ['malloc'] - _deps_info['emscripten_webgl_destroy_context'] = ['free'] - if settings.OFFSCREEN_FRAMEBUFFER: - # When OFFSCREEN_FRAMEBUFFER is defined these functions are defined in native code, - # otherwise they are defined in src/library_html5_webgl.js. - _deps_info['emscripten_webgl_destroy_context'] += ['emscripten_webgl_make_context_current', 'emscripten_webgl_get_current_context'] - - return _deps_info diff --git a/tools/shared.py b/tools/shared.py index b1780587347de..fb9cb90ace857 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -418,7 +418,7 @@ def perform_sanity_checks(): check_node() with ToolchainProfiler.profile_block('sanity LLVM'): - for cmd in [CLANG_CC, LLVM_AR, LLVM_NM]: + for cmd in [CLANG_CC, LLVM_AR]: if not os.path.exists(cmd) and not os.path.exists(cmd + '.exe'): # .exe extension required for Windows exit_with_error('Cannot find %s, check the paths in %s', cmd, config.EM_CONFIG) diff --git a/tools/system_libs.py b/tools/system_libs.py index 88f533d758c29..b249565c7561f 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -15,10 +15,8 @@ from typing import List, Optional from . import shared, building, utils -from . import deps_info from . import diagnostics from . import cache -from tools.shared import demangle_c_symbol_name from tools.settings import settings from tools.utils import read_file @@ -90,10 +88,38 @@ def run_build_commands(commands): logger.info('compiled %d inputs' % len(commands)) +def objectfile_sort_key(filename): + """Sort object files that we pass to llvm-ar.""" + # In general, we simply use alphabetical order, but we special case certain + # object files such they come first. For example, `vmlock.o` contains the + # definition of `__vm_wait`, but `mmap.o` also contains a dummy/weak definition + # for use by `mmap.o` when `vmlock.o` is not otherwise included. + # + # When another object looks for `__vm_wait` we prefer that it always find the + # real definition first and not refer to the dummy one (which is really + # intended to be local to `mmap.o` but due to the fact the weak aliases can't + # have internal linkage). + # + # The reason we care is that once an object file is pulled into certain aspects + # of it cannot be undone/removed by the linker. For example, static + # constructors or stub library dependencies. + # + # In the case of `mmap.o`, once it get included by the linker, it pulls in the + # the reverse dependencies of the mmap syscall (memalign). If we don't do this + # sorting we see a slight regression in test_metadce_minimal_pthreads due to + # memalign being included. + basename = os.path.basename(filename) + if basename in {'vmlock.o'}: + return 'AAA_' + basename + else: + return basename + + def create_lib(libname, inputs): """Create a library from a set of input objects.""" suffix = shared.suffix(libname) - inputs = sorted(inputs, key=lambda x: os.path.basename(x)) + + inputs = sorted(inputs, key=objectfile_sort_key) if suffix in ('.bc', '.o'): if len(inputs) == 1: if inputs[0] != libname: @@ -219,7 +245,7 @@ def join(flags): out += f' CFLAGS = {join(custom_flags)}' out += '\n' - objects = sorted(objects, key=lambda x: os.path.basename(x)) + objects = sorted(objects, key=objectfile_sort_key) objects = ' '.join(objects) out += f'build {libname}: archive {objects}\n' @@ -2012,67 +2038,6 @@ class libstubs(DebugLibrary): src_files = ['emscripten_syscall_stubs.c', 'emscripten_libc_stubs.c'] -# If main() is not in EXPORTED_FUNCTIONS, it may be dce'd out. This can be -# confusing, so issue a warning. -def warn_on_unexported_main(symbolses): - # In STANDALONE_WASM we don't expect main to be explicitly exported. - # In PROXY_TO_PTHREAD we export emscripten_proxy_main instead of main. - if settings.STANDALONE_WASM or settings.PROXY_TO_PTHREAD: - return - if '_main' not in settings.EXPORTED_FUNCTIONS: - for symbols in symbolses: - if 'main' in symbols['defs']: - logger.warning('main() is in the input files, but "_main" is not in EXPORTED_FUNCTIONS, which means it may be eliminated as dead code. Export it if you want main() to run.') - return - - -def handle_reverse_deps(input_files): - if settings.REVERSE_DEPS == 'none' or settings.SIDE_MODULE: - return - elif settings.REVERSE_DEPS == 'all': - # When not optimizing we add all possible reverse dependencies rather - # than scanning the input files - for symbols in deps_info.get_deps_info().values(): - for symbol in symbols: - settings.REQUIRED_EXPORTS.append(symbol) - return - - if settings.REVERSE_DEPS != 'auto': - shared.exit_with_error(f'invalid values for REVERSE_DEPS: {settings.REVERSE_DEPS}') - - added = set() - - def add_reverse_deps(need): - more = False - for ident, deps in deps_info.get_deps_info().items(): - if ident in need['undefs'] and ident not in added: - added.add(ident) - more = True - for dep in deps: - need['undefs'].add(dep) - logger.debug('adding dependency on %s due to deps-info on %s' % (dep, ident)) - settings.REQUIRED_EXPORTS.append(dep) - if more: - add_reverse_deps(need) # recurse to get deps of deps - - # Scan symbols - symbolses = building.llvm_nm_multiple([os.path.abspath(t) for t in input_files]) - - warn_on_unexported_main(symbolses) - - if len(symbolses) == 0: - symbolses.append({'defs': set(), 'undefs': set()}) - - # depend on exported functions - for export in settings.EXPORTED_FUNCTIONS + settings.SIDE_MODULE_IMPORTS: - if settings.VERBOSE: - logger.debug('adding dependency on export %s' % export) - symbolses[0]['undefs'].add(demangle_c_symbol_name(export)) - - for symbols in symbolses: - add_reverse_deps(symbols) - - def get_libs_to_link(args, forced, only_forced): libs_to_link = [] @@ -2211,19 +2176,15 @@ def add_sanitizer_libs(): return libs_to_link -def calculate(input_files, args, forced): +def calculate(args, forced): # Setting this will only use the forced libs in EMCC_FORCE_STDLIBS. This avoids spending time checking # for unresolved symbols in your project files, which can speed up linking, but if you do not have - # the proper list of actually needed libraries, errors can occur. See below for how we must - # export all the symbols in deps_info when using this option. + # the proper list of actually needed libraries, errors can occur. only_forced = os.environ.get('EMCC_ONLY_FORCED_STDLIBS') if only_forced: # One of the purposes EMCC_ONLY_FORCED_STDLIBS was to skip the scanning # of the input files for reverse dependencies. - diagnostics.warning('deprecated', 'EMCC_ONLY_FORCED_STDLIBS is deprecated. Use `-nostdlib` and/or `-sREVERSE_DEPS=none` depending on the desired result') - settings.REVERSE_DEPS = 'all' - - handle_reverse_deps(input_files) + diagnostics.warning('deprecated', 'EMCC_ONLY_FORCED_STDLIBS is deprecated. Use `-nostdlib` to avoid linking standard libraries') libs_to_link = get_libs_to_link(args, forced, only_forced) From 8ae3b24e7c365233e19c6b31c7d8ae1c6e498eee Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 18 Apr 2023 09:19:11 -0700 Subject: [PATCH 0137/1523] Add explicit GL dependency to library_html5_webgl (#19196) The dependency wrangling here was a workaround for a problem that was solved in #16405 (see the command that is being deleted). Pretty much all the functions in this depend either directly or indirectly on the global GL object, so it makes sense to use autoAddDeps rather than try to add individual deps. --- src/library_html5_webgl.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/library_html5_webgl.js b/src/library_html5_webgl.js index 5cc64b4a11d1f..fe9f93bce1a3a 100644 --- a/src/library_html5_webgl.js +++ b/src/library_html5_webgl.js @@ -68,14 +68,7 @@ var LibraryHtml5WebGL = { emscripten_webgl_commit_frame: 'emscripten_webgl_do_commit_frame', #endif - // This code is called from emscripten_webgl_create_context() and proxied - // to the main thread when in offscreen framebuffer mode. This won't be - // called if GL is not linked in, but also make sure to not add a dep on - // GL unnecessarily from here, as that would cause a linker error. emscripten_webgl_do_create_context__deps: [ -#if LibraryManager.has('library_webgl.js') - '$GL', -#endif #if OFFSCREENCANVAS_SUPPORT 'malloc', #endif @@ -616,6 +609,10 @@ function handleWebGLProxying(funcs) { } handleWebGLProxying(LibraryHtml5WebGL); +#endif // USE_PTHREADS + +#if LibraryManager.has('library_webgl.js') +autoAddDeps(LibraryHtml5WebGL, '$GL'); #endif mergeInto(LibraryManager.library, LibraryHtml5WebGL); From 9538b4fa8943f6cc5373f8ff1ff64679445da067 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 18 Apr 2023 10:39:45 -0700 Subject: [PATCH 0138/1523] Consistently use normal object access notation for GLctx (#19024) We were already using the normal notation in most cases anyway: ``` $ git grep "GLctx\[" | wc -l 74 $ git grep "GLctx\." | wc -l 505 ``` IIUC we have tests that verify this doesn't break with --closure=1. --- src/library_webgl.js | 48 +++++++++++----------- src/library_webgl2.js | 96 +++++++++++++++++++++---------------------- test/common.py | 10 ++++- test/test_other.py | 38 +++++++++++++++++ 4 files changed, 119 insertions(+), 73 deletions(-) diff --git a/src/library_webgl.js b/src/library_webgl.js index 7455cf0317a0a..3e8ce10a61b0d 100644 --- a/src/library_webgl.js +++ b/src/library_webgl.js @@ -1428,14 +1428,14 @@ var LibraryGL = { #if MAX_WEBGL_VERSION >= 2 if ({{{ isCurrentContextWebGL2() }}}) { // WebGL 2 provides new garbage-free entry points to call to WebGL. Use those always when possible. if (GLctx.currentPixelUnpackBufferBinding || !imageSize) { - GLctx['compressedTexImage2D'](target, level, internalFormat, width, height, border, imageSize, data); + GLctx.compressedTexImage2D(target, level, internalFormat, width, height, border, imageSize, data); } else { - GLctx['compressedTexImage2D'](target, level, internalFormat, width, height, border, HEAPU8, data, imageSize); + GLctx.compressedTexImage2D(target, level, internalFormat, width, height, border, HEAPU8, data, imageSize); } return; } #endif - GLctx['compressedTexImage2D'](target, level, internalFormat, width, height, border, data ? {{{ makeHEAPView('U8', 'data', 'data+imageSize') }}} : null); + GLctx.compressedTexImage2D(target, level, internalFormat, width, height, border, data ? {{{ makeHEAPView('U8', 'data', 'data+imageSize') }}} : null); }, @@ -1443,14 +1443,14 @@ var LibraryGL = { #if MAX_WEBGL_VERSION >= 2 if ({{{ isCurrentContextWebGL2() }}}) { // WebGL 2 provides new garbage-free entry points to call to WebGL. Use those always when possible. if (GLctx.currentPixelUnpackBufferBinding || !imageSize) { - GLctx['compressedTexSubImage2D'](target, level, xoffset, yoffset, width, height, format, imageSize, data); + GLctx.compressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data); } else { - GLctx['compressedTexSubImage2D'](target, level, xoffset, yoffset, width, height, format, HEAPU8, data, imageSize); + GLctx.compressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, HEAPU8, data, imageSize); } return; } #endif - GLctx['compressedTexSubImage2D'](target, level, xoffset, yoffset, width, height, format, data ? {{{ makeHEAPView('U8', 'data', 'data+imageSize') }}} : null); + GLctx.compressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, data ? {{{ makeHEAPView('U8', 'data', 'data+imageSize') }}} : null); }, $computeUnpackAlignedImageSize: function(width, height, sizePerPixel, alignment) { @@ -1918,7 +1918,7 @@ var LibraryGL = { } #if MAX_WEBGL_VERSION >= 2 else { - param = GLctx['getQueryParameter'](query, pname); + param = GLctx.getQueryParameter(query, pname); } #endif var ret; @@ -3553,7 +3553,7 @@ var LibraryGL = { _emulGlGenVertexArrays(n, arrays); #else #if GL_ASSERTIONS - assert(GLctx['createVertexArray'], 'Must have WebGL2 or OES_vertex_array_object to use vao'); + assert(GLctx.createVertexArray, 'Must have WebGL2 or OES_vertex_array_object to use vao'); #endif __glGenObject(n, arrays, 'createVertexArray', GL.vaos #if GL_ASSERTIONS @@ -3571,11 +3571,11 @@ var LibraryGL = { _emulGlDeleteVertexArrays(n, vaos); #else #if GL_ASSERTIONS - assert(GLctx['deleteVertexArray'], 'Must have WebGL2 or OES_vertex_array_object to use vao'); + assert(GLctx.deleteVertexArray, 'Must have WebGL2 or OES_vertex_array_object to use vao'); #endif for (var i = 0; i < n; i++) { var id = {{{ makeGetValue('vaos', 'i*4', 'i32') }}}; - GLctx['deleteVertexArray'](GL.vaos[id]); + GLctx.deleteVertexArray(GL.vaos[id]); GL.vaos[id] = null; } #endif @@ -3589,9 +3589,9 @@ var LibraryGL = { _emulGlBindVertexArray(vao); #else #if GL_ASSERTIONS - assert(GLctx['bindVertexArray'], 'Must have WebGL2 or OES_vertex_array_object to use vao'); + assert(GLctx.bindVertexArray, 'Must have WebGL2 or OES_vertex_array_object to use vao'); #endif - GLctx['bindVertexArray'](GL.vaos[vao]); + GLctx.bindVertexArray(GL.vaos[vao]); #endif #if FULL_ES2 || LEGACY_GL_EMULATION var ibo = GLctx.getParameter(0x8895 /*ELEMENT_ARRAY_BUFFER_BINDING*/); @@ -3607,12 +3607,12 @@ var LibraryGL = { return _emulGlIsVertexArray(array); #else #if GL_ASSERTIONS - assert(GLctx['isVertexArray'], 'Must have WebGL2 or OES_vertex_array_object to use vao'); + assert(GLctx.isVertexArray, 'Must have WebGL2 or OES_vertex_array_object to use vao'); #endif var vao = GL.vaos[array]; if (!vao) return 0; - return GLctx['isVertexArray'](vao); + return GLctx.isVertexArray(vao); #endif }, @@ -3759,23 +3759,23 @@ var LibraryGL = { glVertexAttribDivisor: function(index, divisor) { #if GL_ASSERTIONS - assert(GLctx['vertexAttribDivisor'], 'Must have ANGLE_instanced_arrays extension or WebGL 2 to use WebGL instancing'); + assert(GLctx.vertexAttribDivisor, 'Must have ANGLE_instanced_arrays extension or WebGL 2 to use WebGL instancing'); #endif - GLctx['vertexAttribDivisor'](index, divisor); + GLctx.vertexAttribDivisor(index, divisor); }, glDrawArraysInstanced: function(mode, first, count, primcount) { #if GL_ASSERTIONS - assert(GLctx['drawArraysInstanced'], 'Must have ANGLE_instanced_arrays extension or WebGL 2 to use WebGL instancing'); + assert(GLctx.drawArraysInstanced, 'Must have ANGLE_instanced_arrays extension or WebGL 2 to use WebGL instancing'); #endif - GLctx['drawArraysInstanced'](mode, first, count, primcount); + GLctx.drawArraysInstanced(mode, first, count, primcount); }, glDrawElementsInstanced: function(mode, count, type, indices, primcount) { #if GL_ASSERTIONS - assert(GLctx['drawElementsInstanced'], 'Must have ANGLE_instanced_arrays extension or WebGL 2 to use WebGL instancing'); + assert(GLctx.drawElementsInstanced, 'Must have ANGLE_instanced_arrays extension or WebGL 2 to use WebGL instancing'); #endif - GLctx['drawElementsInstanced'](mode, count, type, indices, primcount); + GLctx.drawElementsInstanced(mode, count, type, indices, primcount); }, // OpenGL Desktop/ES 2.0 instancing extensions compatibility @@ -3797,7 +3797,7 @@ var LibraryGL = { glDrawBuffers__deps: ['$tempFixedLengthArray'], glDrawBuffers: function(n, bufs) { #if GL_ASSERTIONS - assert(GLctx['drawBuffers'], 'Must have WebGL2 or WEBGL_draw_buffers extension to use drawBuffers'); + assert(GLctx.drawBuffers, 'Must have WebGL2 or WEBGL_draw_buffers extension to use drawBuffers'); #endif #if GL_ASSERTIONS assert(n < tempFixedLengthArray.length, 'Invalid count of numBuffers=' + n + ' passed to glDrawBuffers (that many draw buffer points do not exist in GL)'); @@ -3808,7 +3808,7 @@ var LibraryGL = { bufArray[i] = {{{ makeGetValue('bufs', 'i*4', 'i32') }}}; } - GLctx['drawBuffers'](bufArray); + GLctx.drawBuffers(bufArray); }, // OpenGL ES 2.0 draw buffer extensions compatibility @@ -4052,8 +4052,8 @@ function createGLPassthroughFunctions(lib, funcs) { const num = data[0]; const names = data[1]; const args = range(num).map((i) => 'x' + i ).join(', '); - const plainStub = '(function(' + args + ') { GLctx[\'NAME\'](' + args + ') })'; - const returnStub = '(function(' + args + ') { return GLctx[\'NAME\'](' + args + ') })'; + const plainStub = '(function(' + args + ') { GLctx.NAME(' + args + ') })'; + const returnStub = '(function(' + args + ') { return GLctx.NAME(' + args + ') })'; const sigEnd = range(num).map(() => 'i').join(''); names.split(' ').forEach((name) => { let stub = plainStub; diff --git a/src/library_webgl2.js b/src/library_webgl2.js index ad97365dfb9b5..060393a1c7d72 100644 --- a/src/library_webgl2.js +++ b/src/library_webgl2.js @@ -72,7 +72,7 @@ var LibraryWebGL2 = { return; } #endif - var ret = GLctx['getInternalformatParameter'](target, internalformat, pname); + var ret = GLctx.getInternalformatParameter(target, internalformat, pname); if (ret === null) return; for (var i = 0; i < ret.length && i < bufSize; ++i) { {{{ makeSetValue('params', 'i*4', 'ret[i]', 'i32') }}}; @@ -81,17 +81,17 @@ var LibraryWebGL2 = { glCompressedTexImage3D: function(target, level, internalFormat, width, height, depth, border, imageSize, data) { if (GLctx.currentPixelUnpackBufferBinding) { - GLctx['compressedTexImage3D'](target, level, internalFormat, width, height, depth, border, imageSize, data); + GLctx.compressedTexImage3D(target, level, internalFormat, width, height, depth, border, imageSize, data); } else { - GLctx['compressedTexImage3D'](target, level, internalFormat, width, height, depth, border, HEAPU8, data, imageSize); + GLctx.compressedTexImage3D(target, level, internalFormat, width, height, depth, border, HEAPU8, data, imageSize); } }, glCompressedTexSubImage3D: function(target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data) { if (GLctx.currentPixelUnpackBufferBinding) { - GLctx['compressedTexSubImage3D'](target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data); + GLctx.compressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data); } else { - GLctx['compressedTexSubImage3D'](target, level, xoffset, yoffset, zoffset, width, height, depth, format, HEAPU8, data, imageSize); + GLctx.compressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, HEAPU8, data, imageSize); } }, @@ -123,7 +123,7 @@ var LibraryWebGL2 = { return; } #endif - size && GLctx['getBufferSubData'](target, offset, HEAPU8, data, size); + size && GLctx.getBufferSubData(target, offset, HEAPU8, data, size); }, glInvalidateFramebuffer__deps: ['$tempFixedLengthArray'], @@ -136,7 +136,7 @@ var LibraryWebGL2 = { list[i] = {{{ makeGetValue('attachments', 'i*4', 'i32') }}}; } - GLctx['invalidateFramebuffer'](target, list); + GLctx.invalidateFramebuffer(target, list); }, glInvalidateSubFramebuffer__deps: ['$tempFixedLengthArray'], @@ -149,30 +149,30 @@ var LibraryWebGL2 = { list[i] = {{{ makeGetValue('attachments', 'i*4', 'i32') }}}; } - GLctx['invalidateSubFramebuffer'](target, list, x, y, width, height); + GLctx.invalidateSubFramebuffer(target, list, x, y, width, height); }, glTexImage3D__deps: ['$heapObjectForWebGLType', '$heapAccessShiftForWebGLHeap'], glTexImage3D: function(target, level, internalFormat, width, height, depth, border, format, type, pixels) { if (GLctx.currentPixelUnpackBufferBinding) { - GLctx['texImage3D'](target, level, internalFormat, width, height, depth, border, format, type, pixels); + GLctx.texImage3D(target, level, internalFormat, width, height, depth, border, format, type, pixels); } else if (pixels) { var heap = heapObjectForWebGLType(type); - GLctx['texImage3D'](target, level, internalFormat, width, height, depth, border, format, type, heap, pixels >> heapAccessShiftForWebGLHeap(heap)); + GLctx.texImage3D(target, level, internalFormat, width, height, depth, border, format, type, heap, pixels >> heapAccessShiftForWebGLHeap(heap)); } else { - GLctx['texImage3D'](target, level, internalFormat, width, height, depth, border, format, type, null); + GLctx.texImage3D(target, level, internalFormat, width, height, depth, border, format, type, null); } }, glTexSubImage3D__deps: ['$heapObjectForWebGLType', '$heapAccessShiftForWebGLHeap'], glTexSubImage3D: function(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels) { if (GLctx.currentPixelUnpackBufferBinding) { - GLctx['texSubImage3D'](target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); + GLctx.texSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); } else if (pixels) { var heap = heapObjectForWebGLType(type); - GLctx['texSubImage3D'](target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, heap, pixels >> heapAccessShiftForWebGLHeap(heap)); + GLctx.texSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, heap, pixels >> heapAccessShiftForWebGLHeap(heap)); } else { - GLctx['texSubImage3D'](target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, null); + GLctx.texSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, null); } }, @@ -191,7 +191,7 @@ var LibraryWebGL2 = { var id = {{{ makeGetValue('ids', 'i*4', 'i32') }}}; var query = GL.queries[id]; if (!query) continue; // GL spec: "unused names in ids are ignored, as is the name zero." - GLctx['deleteQuery'](query); + GLctx.deleteQuery(query); GL.queries[id] = null; } }, @@ -199,14 +199,14 @@ var LibraryWebGL2 = { glIsQuery: function(id) { var query = GL.queries[id]; if (!query) return 0; - return GLctx['isQuery'](query); + return GLctx.isQuery(query); }, glBeginQuery: function(target, id) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.queries, id, 'glBeginQuery', 'id'); #endif - GLctx['beginQuery'](target, GL.queries[id]); + GLctx.beginQuery(target, GL.queries[id]); }, glGetQueryiv: function(target, pname, params) { @@ -221,7 +221,7 @@ var LibraryWebGL2 = { return; } #endif - {{{ makeSetValue('params', '0', 'GLctx[\'getQuery\'](target, pname)', 'i32') }}}; + {{{ makeSetValue('params', '0', 'GLctx.getQuery(target, pname)', 'i32') }}}; }, glGetQueryObjectuiv: function(id, pname, params) { @@ -240,7 +240,7 @@ var LibraryWebGL2 = { GL.validateGLObjectID(GL.queries, id, 'glGetQueryObjectuiv', 'id'); #endif var query = GL.queries[id]; - var param = GLctx['getQueryParameter'](query, pname); + var param = GLctx.getQueryParameter(query, pname); var ret; if (typeof param == 'boolean') { ret = param ? 1 : 0; @@ -265,7 +265,7 @@ var LibraryWebGL2 = { var id = {{{ makeGetValue('samplers', 'i*4', 'i32') }}}; var sampler = GL.samplers[id]; if (!sampler) continue; - GLctx['deleteSampler'](sampler); + GLctx.deleteSampler(sampler); sampler.name = 0; GL.samplers[id] = null; } @@ -274,28 +274,28 @@ var LibraryWebGL2 = { glIsSampler: function(id) { var sampler = GL.samplers[id]; if (!sampler) return 0; - return GLctx['isSampler'](sampler); + return GLctx.isSampler(sampler); }, glBindSampler: function(unit, sampler) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.samplers, sampler, 'glBindSampler', 'sampler'); #endif - GLctx['bindSampler'](unit, GL.samplers[sampler]); + GLctx.bindSampler(unit, GL.samplers[sampler]); }, glSamplerParameterf: function(sampler, pname, param) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.samplers, sampler, 'glBindSampler', 'sampler'); #endif - GLctx['samplerParameterf'](GL.samplers[sampler], pname, param); + GLctx.samplerParameterf(GL.samplers[sampler], pname, param); }, glSamplerParameteri: function(sampler, pname, param) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.samplers, sampler, 'glBindSampler', 'sampler'); #endif - GLctx['samplerParameteri'](GL.samplers[sampler], pname, param); + GLctx.samplerParameteri(GL.samplers[sampler], pname, param); }, glSamplerParameterfv: function(sampler, pname, params) { @@ -303,7 +303,7 @@ var LibraryWebGL2 = { GL.validateGLObjectID(GL.samplers, sampler, 'glBindSampler', 'sampler'); #endif var param = {{{ makeGetValue('params', '0', 'float') }}}; - GLctx['samplerParameterf'](GL.samplers[sampler], pname, param); + GLctx.samplerParameterf(GL.samplers[sampler], pname, param); }, glSamplerParameteriv: function(sampler, pname, params) { @@ -311,7 +311,7 @@ var LibraryWebGL2 = { GL.validateGLObjectID(GL.samplers, sampler, 'glBindSampler', 'sampler'); #endif var param = {{{ makeGetValue('params', '0', 'i32') }}}; - GLctx['samplerParameteri'](GL.samplers[sampler], pname, param); + GLctx.samplerParameteri(GL.samplers[sampler], pname, param); }, glGetSamplerParameterfv: function(sampler, pname, params) { @@ -326,7 +326,7 @@ var LibraryWebGL2 = { return; } #endif - {{{ makeSetValue('params', '0', 'GLctx[\'getSamplerParameter\'](GL.samplers[sampler], pname)', 'float') }}}; + {{{ makeSetValue('params', '0', 'GLctx.getSamplerParameter(GL.samplers[sampler], pname)', 'float') }}}; }, glGetSamplerParameteriv: function(sampler, pname, params) { @@ -341,7 +341,7 @@ var LibraryWebGL2 = { return; } #endif - {{{ makeSetValue('params', '0', 'GLctx[\'getSamplerParameter\'](GL.samplers[sampler], pname)', 'i32') }}}; + {{{ makeSetValue('params', '0', 'GLctx.getSamplerParameter(GL.samplers[sampler], pname)', 'i32') }}}; }, // Transform Feedback @@ -359,21 +359,21 @@ var LibraryWebGL2 = { var id = {{{ makeGetValue('ids', 'i*4', 'i32') }}}; var transformFeedback = GL.transformFeedbacks[id]; if (!transformFeedback) continue; // GL spec: "unused names in ids are ignored, as is the name zero." - GLctx['deleteTransformFeedback'](transformFeedback); + GLctx.deleteTransformFeedback(transformFeedback); transformFeedback.name = 0; GL.transformFeedbacks[id] = null; } }, glIsTransformFeedback: function(id) { - return GLctx['isTransformFeedback'](GL.transformFeedbacks[id]); + return GLctx.isTransformFeedback(GL.transformFeedbacks[id]); }, glBindTransformFeedback: function(target, id) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.transformFeedbacks, id, 'glBindTransformFeedback', 'id'); #endif - GLctx['bindTransformFeedback'](target, GL.transformFeedbacks[id]); + GLctx.bindTransformFeedback(target, GL.transformFeedbacks[id]); }, glTransformFeedbackVaryings: function(program, count, varyings, bufferMode) { @@ -385,7 +385,7 @@ var LibraryWebGL2 = { for (var i = 0; i < count; i++) vars.push(UTF8ToString({{{ makeGetValue('varyings', 'i*4', 'i32') }}})); - GLctx['transformFeedbackVaryings'](program, vars, bufferMode); + GLctx.transformFeedbackVaryings(program, vars, bufferMode); }, glGetTransformFeedbackVarying: function(program, index, bufSize, length, size, type, name) { @@ -393,7 +393,7 @@ var LibraryWebGL2 = { GL.validateGLObjectID(GL.programs, program, 'glGetTransformFeedbackVarying', 'program'); #endif program = GL.programs[program]; - var info = GLctx['getTransformFeedbackVarying'](program, index); + var info = GLctx.getTransformFeedbackVarying(program, index); if (!info) return; // If an error occurred, the return parameters length, size, type and name will be unmodified. if (name && bufSize > 0) { @@ -420,7 +420,7 @@ var LibraryWebGL2 = { return; } #endif - var result = GLctx['getIndexedParameter'](target, index); + var result = GLctx.getIndexedParameter(target, index); var ret; switch (typeof result) { case 'boolean': @@ -486,14 +486,14 @@ var LibraryWebGL2 = { #if GL_ASSERTIONS GL.validateGLObjectID(GL.buffers, buffer, 'glBindBufferBase', 'buffer'); #endif - GLctx['bindBufferBase'](target, index, GL.buffers[buffer]); + GLctx.bindBufferBase(target, index, GL.buffers[buffer]); }, glBindBufferRange: function(target, index, buffer, offset, ptrsize) { #if GL_ASSERTIONS GL.validateGLObjectID(GL.buffers, buffer, 'glBindBufferRange', 'buffer'); #endif - GLctx['bindBufferRange'](target, index, GL.buffers[buffer], offset, ptrsize); + GLctx.bindBufferRange(target, index, GL.buffers[buffer], offset, ptrsize); }, glGetUniformIndices: function(program, uniformCount, uniformNames, uniformIndices) { @@ -520,7 +520,7 @@ var LibraryWebGL2 = { for (var i = 0; i < uniformCount; i++) names.push(UTF8ToString({{{ makeGetValue('uniformNames', 'i*4', 'i32') }}})); - var result = GLctx['getUniformIndices'](program, names); + var result = GLctx.getUniformIndices(program, names); if (!result) return; // GL spec: If an error is generated, nothing is written out to uniformIndices. var len = result.length; @@ -554,7 +554,7 @@ var LibraryWebGL2 = { ids.push({{{ makeGetValue('uniformIndices', 'i*4', 'i32') }}}); } - var result = GLctx['getActiveUniforms'](program, ids, pname); + var result = GLctx.getActiveUniforms(program, ids, pname); if (!result) return; // GL spec: If an error is generated, nothing is written out to params. var len = result.length; @@ -567,7 +567,7 @@ var LibraryWebGL2 = { #if GL_ASSERTIONS GL.validateGLObjectID(GL.programs, program, 'glGetUniformBlockIndex', 'program'); #endif - return GLctx['getUniformBlockIndex'](GL.programs[program], UTF8ToString(uniformBlockName)); + return GLctx.getUniformBlockIndex(GL.programs[program], UTF8ToString(uniformBlockName)); }, glGetActiveUniformBlockiv: function(program, uniformBlockIndex, pname, params) { @@ -588,12 +588,12 @@ var LibraryWebGL2 = { program = GL.programs[program]; if (pname == 0x8A41 /* GL_UNIFORM_BLOCK_NAME_LENGTH */) { - var name = GLctx['getActiveUniformBlockName'](program, uniformBlockIndex); + var name = GLctx.getActiveUniformBlockName(program, uniformBlockIndex); {{{ makeSetValue('params', 0, 'name.length+1', 'i32') }}}; return; } - var result = GLctx['getActiveUniformBlockParameter'](program, uniformBlockIndex, pname); + var result = GLctx.getActiveUniformBlockParameter(program, uniformBlockIndex, pname); if (result === null) return; // If an error occurs, nothing should be written to params. if (pname == 0x8A43 /*GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES*/) { for (var i = 0; i < result.length; i++) { @@ -610,7 +610,7 @@ var LibraryWebGL2 = { #endif program = GL.programs[program]; - var result = GLctx['getActiveUniformBlockName'](program, uniformBlockIndex); + var result = GLctx.getActiveUniformBlockName(program, uniformBlockIndex); if (!result) return; // If an error occurs, nothing will be written to uniformBlockName or length. if (uniformBlockName && bufSize > 0) { var numBytesWrittenExclNull = stringToUTF8(result, uniformBlockName, bufSize); @@ -626,7 +626,7 @@ var LibraryWebGL2 = { #endif program = GL.programs[program]; - GLctx['uniformBlockBinding'](program, uniformBlockIndex, uniformBlockBinding); + GLctx.uniformBlockBinding(program, uniformBlockIndex, uniformBlockBinding); }, glClearBufferiv: function(buffer, drawbuffer, value) { @@ -634,7 +634,7 @@ var LibraryWebGL2 = { assert((value & 3) == 0, 'Pointer to integer data passed to glClearBufferiv must be aligned to four bytes!'); #endif - GLctx['clearBufferiv'](buffer, drawbuffer, HEAP32, value>>2); + GLctx.clearBufferiv(buffer, drawbuffer, HEAP32, value>>2); }, glClearBufferuiv: function(buffer, drawbuffer, value) { @@ -642,7 +642,7 @@ var LibraryWebGL2 = { assert((value & 3) == 0, 'Pointer to integer data passed to glClearBufferuiv must be aligned to four bytes!'); #endif - GLctx['clearBufferuiv'](buffer, drawbuffer, HEAPU32, value>>2); + GLctx.clearBufferuiv(buffer, drawbuffer, HEAPU32, value>>2); }, glClearBufferfv: function(buffer, drawbuffer, value) { @@ -650,7 +650,7 @@ var LibraryWebGL2 = { assert((value & 3) == 0, 'Pointer to float data passed to glClearBufferfv must be aligned to four bytes!'); #endif - GLctx['clearBufferfv'](buffer, drawbuffer, HEAPF32, value>>2); + GLctx.clearBufferfv(buffer, drawbuffer, HEAPF32, value>>2); }, glFenceSync: function(condition, flags) { @@ -738,7 +738,7 @@ var LibraryWebGL2 = { #if GL_ASSERTIONS GL.validateGLObjectID(GL.programs, program, 'glGetFragDataLocation', 'program'); #endif - return GLctx['getFragDataLocation'](GL.programs[program], UTF8ToString(name)); + return GLctx.getFragDataLocation(GL.programs[program], UTF8ToString(name)); }, glGetVertexAttribIiv__deps: ['$emscriptenWebGLGetVertexAttrib'], @@ -942,7 +942,7 @@ var LibraryWebGL2 = { #if GL_ASSERTIONS GL.validateVertexAttribPointer(size, type, stride, ptr); #endif - GLctx['vertexAttribIPointer'](index, size, type, stride, ptr); + GLctx.vertexAttribIPointer(index, size, type, stride, ptr); }, #if !LEGACY_GL_EMULATION diff --git a/test/common.py b/test/common.py index 676738a8e0e55..590b534b1add4 100644 --- a/test/common.py +++ b/test/common.py @@ -323,13 +323,21 @@ def ensure_dir(dirname): dirname.mkdir(parents=True, exist_ok=True) -def limit_size(string, maxbytes=800000 * 20, maxlines=100000, max_line=5000): +def limit_size(string): + maxbytes = 800000 * 20 + if sys.stdout.isatty(): + maxlines = 500 + max_line = 500 + else: + max_line = 5000 + maxlines = 100000 lines = string.splitlines() for i, line in enumerate(lines): if len(line) > max_line: lines[i] = line[:max_line] + '[..]' if len(lines) > maxlines: lines = lines[0:maxlines // 2] + ['[..]'] + lines[-maxlines // 2:] + lines.append('(not all output shown. See `limit_size`)') string = '\n'.join(lines) + '\n' if len(string) > maxbytes: string = string[0:maxbytes // 2] + '\n[..]\n' + string[-maxbytes // 2:] diff --git a/test/test_other.py b/test/test_other.py index 1e045ea436a1a..9bd58772cafa0 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -8701,6 +8701,7 @@ def test_closure_full_js_library(self, args): # Test for closure errors and warnings in the entire JS library. self.build(test_file('hello_world.c'), emcc_args=[ '--closure=1', + '--minify=0', '-Werror=closure', '-sINCLUDE_FULL_LIBRARY', # Enable as many features as possible in order to maximise @@ -8712,6 +8713,43 @@ def test_closure_full_js_library(self, args): '-sMAX_WEBGL_VERSION=2', ] + args) + # Check that closure doesn't minify certain attributes. + # This list allows us to verify that it's safe to use normal accessors over + # string accessors. + glsyms = [ + 'compressedTexImage2D', + 'compressedTexSubImage2D', + 'compressedTexImage3D', + 'compressedTexSubImage3D', + 'bindVertexArray', + 'deleteVertexArray', + 'createVertexArray', + 'isVertexArray', + 'getQueryParameter', + 'drawElementsInstanced', + 'drawBuffers', + 'drawArraysInstanced', + 'vertexAttribDivisor', + 'getInternalformatParameter', + 'beginQuery', + 'getQuery', + 'clearBufferfv', + 'clearBufferuiv', + 'getFragDataLocation', + 'vertexAttribIPointer', + 'samplerParameteri', + 'samplerParameterf', + 'isTransformFeedback', + 'deleteTransformFeedback', + 'transformFeedbackVaryings', + 'getSamplerParameter', + 'uniformBlockBindin', + 'vertexAttribIPointer', + ] + js = read_file('hello_world.js') + for sym in glsyms: + self.assertContained('.' + sym, js) + def test_closure_webgpu(self): # This test can be removed if USE_WEBGPU is later included in INCLUDE_FULL_LIBRARY. self.build(test_file('hello_world.c'), emcc_args=[ From 2693d3636e988ec9416c2492ddb14a007fb9ce7e Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 18 Apr 2023 11:03:01 -0700 Subject: [PATCH 0139/1523] acorn-optimizer.js: Make use of arrow functions (#19203) Also, update `.prettierrc.yml` to use the default setting for `arrowParens` which is `always`. This seems to be the agreed upon norm for JS development. --- .prettierrc.yml | 1 - tools/acorn-optimizer.js | 58 ++++++++++++++++++---------------------- 2 files changed, 26 insertions(+), 33 deletions(-) diff --git a/.prettierrc.yml b/.prettierrc.yml index 32705ec1d0e72..127fb7d085709 100644 --- a/.prettierrc.yml +++ b/.prettierrc.yml @@ -1,4 +1,3 @@ singleQuote: true bracketSpacing: false -arrowParens: avoid printWidth: 100 diff --git a/tools/acorn-optimizer.js b/tools/acorn-optimizer.js index 690829b942b8d..9c2412b1048c7 100755 --- a/tools/acorn-optimizer.js +++ b/tools/acorn-optimizer.js @@ -63,9 +63,7 @@ function visitChildren(node, c) { // Simple post-order walk, calling properties on an object by node type, // if the type exists. function simpleWalk(node, cs) { - visitChildren(node, function (child) { - simpleWalk(child, cs); - }); + visitChildren(node, (child) => simpleWalk(child, cs)); if (node.type in cs) { cs[node.type](node); } @@ -73,9 +71,7 @@ function simpleWalk(node, cs) { // Full post-order walk, calling a single function for all types. function fullWalk(node, c) { - visitChildren(node, function (child) { - fullWalk(child, c); - }); + visitChildren(node, (child) => fullWalk(child, c)); c(node); } @@ -84,9 +80,7 @@ function fullWalk(node, c) { function recursiveWalk(node, cs) { (function c(node) { if (!(node.type in cs)) { - visitChildren(node, function (child) { - recursiveWalk(child, cs); - }); + visitChildren(node, (child) => recursiveWalk(child, cs)); } else { cs[node.type](node, c); } @@ -178,7 +172,7 @@ function ignoreInnerScopes(node) { // Mark inner scopes temporarily as empty statements. function restoreInnerScopes(node, map) { - fullWalk(node, function (node) { + fullWalk(node, (node) => { if (map.has(node)) { node.type = map.get(node); map.delete(node); @@ -220,7 +214,7 @@ function hasSideEffects(node) { // Conservative analysis. const map = ignoreInnerScopes(node); let has = false; - fullWalk(node, function (node) { + fullWalk(node, (node) => { switch (node.type) { // TODO: go through all the ESTree spec case 'Literal': @@ -324,7 +318,7 @@ function runJSDCE(ast, aggressive) { VariableDeclaration(node, c) { const old = node.declarations; let removedHere = 0; - node.declarations = node.declarations.filter(function (node) { + node.declarations = node.declarations.filter((node) => { const curr = node.id.name; const value = node.init; const keep = !(curr in names) || (value && hasSideEffects(value)); @@ -367,7 +361,7 @@ function runJSDCE(ast, aggressive) { ensureData(scopes[scopes.length - 1], node.id.name).def = 1; } const scope = {}; - node.params.forEach(function (param) { + node.params.forEach((param) => { const name = param.name; ensureData(scope, name).def = 1; scope[name].param = 1; @@ -402,7 +396,7 @@ function runJSDCE(ast, aggressive) { }, ObjectExpression(node, c) { // ignore the property identifiers - node.properties.forEach(function (node) { + node.properties.forEach((node) => { if (node.value) { c(node.value); } else if (node.argument) { @@ -515,10 +509,10 @@ function isModuleAsmUse(node) { // Apply import/export name changes (after minifying them) function applyImportAndExportNameChanges(ast) { const mapping = extraInfo.mapping; - fullWalk(ast, function (node) { + fullWalk(ast, (node) => { if (isWasmImportsAssign(node)) { const assignedObject = getWasmImportsValue(node); - assignedObject.properties.forEach(function (item) { + assignedObject.properties.forEach((item) => { if (mapping[item.key.value]) { setLiteralValue(item.key, mapping[item.key.value]); } @@ -714,10 +708,10 @@ function emitDCEGraph(ast) { } } - fullWalk(ast, function (node) { + fullWalk(ast, (node) => { if (isWasmImportsAssign(node)) { const assignedObject = getWasmImportsValue(node); - assignedObject.properties.forEach(function (item) { + assignedObject.properties.forEach((item) => { let value = item.value; if (value.type === 'Literal' || value.type === 'FunctionExpression') { return; // if it's a numeric or function literal, nothing to do here @@ -759,7 +753,7 @@ function emitDCEGraph(ast) { // which looks like a wasm export being received. confirm with the asm use let found = 0; let asmName; - fullWalk(value.right, function (node) { + fullWalk(value.right, (node) => { if (isAsmUse(node)) { found++; asmName = getAsmOrModuleUseName(node); @@ -953,15 +947,15 @@ function emitDCEGraph(ast) { } } } - defuns.forEach(defun => { + defuns.forEach((defun) => { const name = getGraphName(defun.id.name, 'defun'); const info = (infos[name] = { name: name, reaches: {}, }); - fullWalk(defun.body, node => visitNode(node, info)); + fullWalk(defun.body, (node) => visitNode(node, info)); }); - fullWalk(ast, node => visitNode(node, null)); + fullWalk(ast, (node) => visitNode(node, null)); // Final work: print out the graph // sort for determinism function sortedNamesFromMap(map) { @@ -972,7 +966,7 @@ function emitDCEGraph(ast) { names.sort(); return names; } - sortedNamesFromMap(infos).forEach(name => { + sortedNamesFromMap(infos).forEach((name) => { const info = infos[name]; info.reaches = sortedNamesFromMap(info.reaches); graph.push(info); @@ -984,10 +978,10 @@ function emitDCEGraph(ast) { function applyDCEGraphRemovals(ast) { const unused = new Set(extraInfo.unused); - fullWalk(ast, node => { + fullWalk(ast, (node) => { if (isWasmImportsAssign(node)) { const assignedObject = getWasmImportsValue(node); - assignedObject.properties = assignedObject.properties.filter(item => { + assignedObject.properties = assignedObject.properties.filter((item) => { const name = item.key.value; const value = item.value; const full = 'emcc$import$' + name; @@ -1207,7 +1201,7 @@ function littleEndianHeap(ast) { // in each access), see #8365. function growableHeap(ast) { recursiveWalk(ast, { - AssignmentExpression: node => { + AssignmentExpression: (node) => { if (node.left.type === 'Identifier' && isEmscriptenHEAP(node.left.name)) { // Don't transform initial setup of the arrays. return; @@ -1215,9 +1209,9 @@ function growableHeap(ast) { growableHeap(node.left); growableHeap(node.right); }, - VariableDeclaration: node => { + VariableDeclaration: (node) => { // Don't transform the var declarations for HEAP8 etc - node.declarations.forEach(function (decl) { + node.declarations.forEach((decl) => { // but do transform anything that sets a var to // something from HEAP8 etc if (decl.init) { @@ -1225,7 +1219,7 @@ function growableHeap(ast) { } }); }, - Identifier: node => { + Identifier: (node) => { if (node.name.startsWith('HEAP')) { // Turn HEAP8 into GROWABLE_HEAP_I8() etc switch (node.name) { @@ -1305,7 +1299,7 @@ function unsignPointers(ast) { }; } - fullWalk(ast, function (node) { + fullWalk(ast, (node) => { if (node.type === 'MemberExpression') { // Check if this is HEAP*[?] if (node.object.type === 'Identifier' && isHeap(node.object.name) && node.computed) { @@ -1923,7 +1917,7 @@ function reattachComments(ast, comments) { // Collect all code symbols ast.walk( - new terser.TreeWalker(function (node) { + new terser.TreeWalker((node) => { if (node.start && node.start.pos) { symbols.push(node); } @@ -2068,7 +2062,7 @@ const registry = { minifyGlobals: minifyGlobals, }; -passes.forEach(pass => registry[pass](ast)); +passes.forEach((pass) => registry[pass](ast)); if (!noPrint) { const terserAst = terser.AST_Node.from_mozilla_ast(ast); From 7d37daf7b9424b4505e7645473c669712528b509 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 18 Apr 2023 11:04:12 -0700 Subject: [PATCH 0140/1523] Run more posixtest conformance tests. NFC (#19204) --- test/test_posixtest.py | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/test/test_posixtest.py b/test/test_posixtest.py index 6cde914733f8f..bdf75927c32ee 100644 --- a/test/test_posixtest.py +++ b/test/test_posixtest.py @@ -3,7 +3,7 @@ # University of Illinois/NCSA Open Source License. Both these licenses can be # found in the LICENSE file. -"""Runs the pthreads test from the upstream posixtest suite in: +"""Runs conformance test from the upstream posixtest suite in: ./test/third_party/posixtestsuite See https://github.com/emscripten-core/posixtestsuite @@ -28,20 +28,29 @@ class posixtest(RunnerCore): def filter_tests(all_tests): - pthread_tests = [t for t in all_tests if t.startswith('pthread_')] - return pthread_tests + prefixes = [ + 'pthread_', + 'strftime', + 'asctime', + 'gmtime' + ] + def enable_test(t): + return any(t.startswith(p) for p in prefixes) -def get_pthread_tests(): - # For now, we don't require the submodule to exist. In this case we just report - # no tests - pthread_test_root = os.path.join(testsuite_root, 'conformance', 'interfaces') - if not os.path.exists(pthread_test_root): + return [t for t in all_tests if enable_test(t)] + + +def get_tests(): + # For now, we don't require the submodule to exist. In this case we + # just report no tests + test_root = os.path.join(testsuite_root, 'conformance', 'interfaces') + if not os.path.exists(test_root): print('posixtestsuite not found (run git submodule update --init?)') return [] - pthread_tests = filter_tests(os.listdir(pthread_test_root)) - pthread_tests = [os.path.join(pthread_test_root, t) for t in pthread_tests] - return pthread_tests + tests = filter_tests(os.listdir(test_root)) + tests = [os.path.join(test_root, t) for t in tests] + return tests # Mark certain tests as unsupported @@ -157,6 +166,7 @@ def f(self): '-Werror', '-Wno-format-security', '-Wno-int-conversion', + '-Wno-format', '-pthread', '-sEXIT_RUNTIME', '-sTOTAL_MEMORY=256mb', @@ -172,7 +182,7 @@ def f(self): return f -for testdir in get_pthread_tests(): +for testdir in get_tests(): basename = os.path.basename(testdir) for test_file in glob.glob(os.path.join(testdir, '*.c')): if not os.path.basename(test_file)[0].isdigit(): From 604fde4507f15027f9760ca29f3471a055a8aceb Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 18 Apr 2023 13:19:00 -0700 Subject: [PATCH 0141/1523] Update the minimum Firefox verson to 68 (#19191) This is still a version from 3 years ago, so it is a very small change, but it does bring us to a version that has wasm-bigint enabled, which will help #19156 --- ChangeLog.md | 1 + src/settings.js | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index d3aebb21461ff..6956d3a8797f5 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -27,6 +27,7 @@ See docs/process.md for more on how version tagging works. since we no longer need scan linker inputs using `llvm-nm`. It also completely removes the need for the `REVERSE_DEPS` settings which has now been deprecated. (#18905) +- Bump the default minimum Firefox version from 65 to 68 (#19191). 3.1.36 - 04/16/23 ----------------- diff --git a/src/settings.js b/src/settings.js index 93ea2feb66600..f93140d04c4e3 100644 --- a/src/settings.js +++ b/src/settings.js @@ -1745,10 +1745,10 @@ var AUTO_NATIVE_LIBRARIES = true; // versions >= MIN_FIREFOX_VERSION // are desired to work. Pass -sMIN_FIREFOX_VERSION=majorVersion to drop support // for Firefox versions older than < majorVersion. -// Firefox ESR 60.5 (Firefox 65) was released on 2019-01-29. +// Firefox ESR 68 was released on July 9, 2019. // MAX_INT (0x7FFFFFFF, or -1) specifies that target is not supported. // [link] -var MIN_FIREFOX_VERSION = 65; +var MIN_FIREFOX_VERSION = 68; // Specifies the oldest version of desktop Safari to target. Version is encoded // in MMmmVV, e.g. 70101 denotes Safari 7.1.1. From 7a8b36fa28ef2b9e6c9e94bba60d53cd98ffd40c Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 18 Apr 2023 14:00:08 -0700 Subject: [PATCH 0142/1523] Remove `__syscall_link` in favor `__syscall_linkat`. NFC (#19205) We already did this for most other syscalls that have both flavors. This matters less since we don't even implement it. --- src/library_sigs.js | 1 - src/library_syscall.js | 5 ----- system/lib/libc/emscripten_syscall_stubs.c | 2 +- system/lib/libc/musl/arch/emscripten/bits/syscall.h | 1 - system/lib/libc/musl/arch/emscripten/syscall_arch.h | 1 - 5 files changed, 1 insertion(+), 9 deletions(-) diff --git a/src/library_sigs.js b/src/library_sigs.js index 593db24837ccf..c4086947097e4 100644 --- a/src/library_sigs.js +++ b/src/library_sigs.js @@ -244,7 +244,6 @@ sigs = { __syscall_getsockname__sig: 'iippiii', __syscall_getsockopt__sig: 'iiiippi', __syscall_ioctl__sig: 'iiip', - __syscall_linkat__sig: 'iipipi', __syscall_listen__sig: 'iiiiiii', __syscall_lstat64__sig: 'ipp', __syscall_mkdirat__sig: 'iipi', diff --git a/src/library_syscall.js b/src/library_syscall.js index 85912d6cd0dba..9192995f60200 100644 --- a/src/library_syscall.js +++ b/src/library_syscall.js @@ -864,11 +864,6 @@ var SyscallsLibrary = { FS.rename(oldpath, newpath); return 0; }, - __syscall_linkat__nothrow: true, - __syscall_linkat__proxy: false, - __syscall_linkat: function(olddirfd, oldpath, newdirfd, newpath, flags) { - return -{{{ cDefs.EMLINK }}}; // no hardlinks for us - }, __syscall_symlinkat: function(target, newdirfd, linkpath) { #if SYSCALL_DEBUG dbg('warning: untested syscall'); diff --git a/system/lib/libc/emscripten_syscall_stubs.c b/system/lib/libc/emscripten_syscall_stubs.c index 19ee3b4895ff6..248efbdcb2331 100644 --- a/system/lib/libc/emscripten_syscall_stubs.c +++ b/system/lib/libc/emscripten_syscall_stubs.c @@ -108,7 +108,7 @@ weak int __syscall_getppid() { return g_ppid; } -weak int __syscall_link(intptr_t oldpath, intptr_t newpath) { +weak int __syscall_linkat(int olddirfd, intptr_t oldpath, int newdirfd, intptr_t newpath, int flags) { return -EMLINK; // no hardlinks for us } diff --git a/system/lib/libc/musl/arch/emscripten/bits/syscall.h b/system/lib/libc/musl/arch/emscripten/bits/syscall.h index 5e7ef67eaba64..2522f9daee7fd 100644 --- a/system/lib/libc/musl/arch/emscripten/bits/syscall.h +++ b/system/lib/libc/musl/arch/emscripten/bits/syscall.h @@ -1,4 +1,3 @@ -#define SYS_link __syscall_link #define SYS_chdir __syscall_chdir #define SYS_chmod __syscall_chmod #define SYS_getpid __syscall_getpid diff --git a/system/lib/libc/musl/arch/emscripten/syscall_arch.h b/system/lib/libc/musl/arch/emscripten/syscall_arch.h index a467661690c1d..bad86ad4e98df 100644 --- a/system/lib/libc/musl/arch/emscripten/syscall_arch.h +++ b/system/lib/libc/musl/arch/emscripten/syscall_arch.h @@ -12,7 +12,6 @@ extern "C" { #endif -int __syscall_link(intptr_t oldpath, intptr_t newpath); int __syscall_chdir(intptr_t path); int __syscall_mknod(intptr_t path, int mode, int dev); int __syscall_chmod(intptr_t path, int mode); From aef5d392a0e6b23874a30dab4c70039357edce67 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 18 Apr 2023 15:41:53 -0700 Subject: [PATCH 0143/1523] Set minimum node version in emcc invocation in tests and gen_struct_info (#19193) This is not needed now, but when we switch to wasm-bigint by default then we'd lose the ability to run in older nodes without it. That is, with this change, we tell emcc the version of node we'll be running in, so it can decide properly on how to build (and if the version is too old, we'll disable wasm-bigint). --- test/common.py | 11 +++++++++++ tools/building.py | 11 +++++++++++ tools/gen_struct_info.py | 5 ++++- 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/test/common.py b/test/common.py index 590b534b1add4..d19187087ddb5 100644 --- a/test/common.py +++ b/test/common.py @@ -614,6 +614,17 @@ def setUp(self): # https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode self.node_args.append('--unhandled-rejections=throw') + # If the version we are running tests in is lower than the version that + # emcc targets then we need to tell emcc to target that older version. + emcc_min_node_version_str = str(shared.settings.MIN_NODE_VERSION) + emcc_min_node_version = ( + int(emcc_min_node_version_str[0:2]), + int(emcc_min_node_version_str[2:4]), + int(emcc_min_node_version_str[4:6]) + ) + if node_version < emcc_min_node_version: + self.emcc_args += building.get_emcc_node_flags(node_version) + self.v8_args = ['--wasm-staging'] self.env = {} self.temp_files_before_run = [] diff --git a/tools/building.py b/tools/building.py index d73879ceef7a2..20a8ce465d744 100644 --- a/tools/building.py +++ b/tools/building.py @@ -1292,3 +1292,14 @@ def js_legalization_pass_flags(): # assumes they are imports. flags += ['--pass-arg=legalize-js-interface-exported-helpers'] return flags + + +# Returns a list of flags to pass to emcc that make the output run properly in +# the given node version. +def get_emcc_node_flags(node_version): + if not node_version: + return [] + # Convert to the format we use in our settings, XXYYZZ, for example, + # 10.1.7 will turn into "100107". + str_node_version = "%02d%02d%02d" % node_version + return [f'-sMIN_NODE_VERSION={str_node_version}'] diff --git a/tools/gen_struct_info.py b/tools/gen_struct_info.py index ec746aee87d74..4eddd8d93541b 100755 --- a/tools/gen_struct_info.py +++ b/tools/gen_struct_info.py @@ -67,6 +67,7 @@ __rootdir__ = os.path.dirname(__scriptdir__) sys.path.append(__rootdir__) +from tools import building from tools import shared from tools import system_libs from tools import utils @@ -239,6 +240,8 @@ def inspect_headers(headers, cflags): else: compiler = shared.EMCC + node_flags = building.get_emcc_node_flags(shared.check_node_version()) + # -O1+ produces calls to iprintf, which libcompiler_rt doesn't support cmd = [compiler] + cflags + ['-o', js_file[1], src_file[1], '-O0', @@ -248,7 +251,7 @@ def inspect_headers(headers, cflags): compiler_rt, '-sBOOTSTRAPPING_STRUCT_INFO', '-sSTRICT', - '-sASSERTIONS=0'] + '-sASSERTIONS=0'] + node_flags # Default behavior for emcc is to warn for binaryen version check mismatches # so we should try to match that behavior. From 0f059c93c621930ad9a789baab9ded75a3652eff Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 17 Apr 2023 19:34:16 -0700 Subject: [PATCH 0144/1523] Rebaseline codesize expectations. NFC --- test/other/metadce/test_metadce_minimal_pthreads.jssize | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/other/metadce/test_metadce_minimal_pthreads.jssize b/test/other/metadce/test_metadce_minimal_pthreads.jssize index 691c02c06b388..fa365d0234845 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.jssize +++ b/test/other/metadce/test_metadce_minimal_pthreads.jssize @@ -1 +1 @@ -15562 +15528 From 863a09cbf3e5fc45e93446e44343a7463ba63f17 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 20 Apr 2023 13:46:41 -0700 Subject: [PATCH 0145/1523] Cleanup test_utf8_textdecoder and add some tracing. NFC (#19215) I've seen this test fail in CI a few times with a timeout. The cause must be to do with the ransom see I would guess so add some tracing so we can reproduce if it ever happens again. --- .../{benchmark_utf8.cpp => benchmark_utf8.c} | 28 +++++++++++-------- test/test_browser.py | 2 +- test/test_core.py | 3 +- 3 files changed, 18 insertions(+), 15 deletions(-) rename test/benchmark/{benchmark_utf8.cpp => benchmark_utf8.c} (71%) diff --git a/test/benchmark/benchmark_utf8.cpp b/test/benchmark/benchmark_utf8.c similarity index 71% rename from test/benchmark/benchmark_utf8.cpp rename to test/benchmark/benchmark_utf8.c index adc79e1cfc8e6..38a93b25902db 100644 --- a/test/benchmark/benchmark_utf8.cpp +++ b/test/benchmark/benchmark_utf8.c @@ -6,16 +6,18 @@ #include #include #include -#include -#include +#include #include +#include + +EM_JS_DEPS(deps, "$UTF8ToString,emscripten_get_now"); double test(const char *str) { double res = EM_ASM_DOUBLE({ var t0 = _emscripten_get_now(); - var str = Module.UTF8ToString($0); + var str = UTF8ToString($0); var t1 = _emscripten_get_now(); -// out('t: ' + (t1 - t0) + ', len(result): ' + str.length + ', result: ' + str.slice(0, 100)); + // out('t: ' + (t1 - t0) + ', len(result): ' + str.length + ', result: ' + str.slice(0, 100)); return (t1-t0); }, str); return res; @@ -30,38 +32,40 @@ char *randomString(int len) { fseek(handle, 0, SEEK_END); utf8_corpus_length = ftell(handle); assert(utf8_corpus_length > 0); - utf8_corpus = new char[utf8_corpus_length+1]; + utf8_corpus = malloc(utf8_corpus_length+1); fseek(handle, 0, SEEK_SET); fread(utf8_corpus, 1, utf8_corpus_length, handle); fclose(handle); utf8_corpus[utf8_corpus_length] = '\0'; } int startIdx = rand() % (utf8_corpus_length - len); - while(((unsigned char)utf8_corpus[startIdx] & 0xC0) == 0x80) { + while (((unsigned char)utf8_corpus[startIdx] & 0xC0) == 0x80) { ++startIdx; if (startIdx + len > utf8_corpus_length) len = utf8_corpus_length - startIdx; } assert(len > 0); - char *s = new char[len+1]; + char *s = malloc(len+1); memcpy(s, utf8_corpus + startIdx, len); s[len] = '\0'; - while(len > 0 && ((unsigned char)s[len-1] & 0xC0) == 0x80) { s[--len] = '\0'; } - while(len > 0 && ((unsigned char)s[len-1] & 0xC0) == 0xC0) { s[--len] = '\0'; } + while (len > 0 && ((unsigned char)s[len-1] & 0xC0) == 0x80) { s[--len] = '\0'; } + while (len > 0 && ((unsigned char)s[len-1] & 0xC0) == 0xC0) { s[--len] = '\0'; } assert(len >= 0); return s; } int main() { - srand(time(NULL)); + time_t seed = time(NULL); + printf("Random seed: %lld\n", seed); + srand(seed); double t = 0; double t2 = emscripten_get_now(); - for(int i = 0; i < 100000; ++i) { + for (int i = 0; i < 100000; ++i) { // Create strings of lengths 1-32, because the internals of text decoding // have a cutoff of 16 for when to use TextDecoder, and we wish to test both // (see UTF8ArrayToString). char *str = randomString((i % 32) + 1); t += test(str); - delete [] str; + free(str); } double t3 = emscripten_get_now(); printf("OK. Time: %f (%f).\n", t, t3-t2); diff --git a/test/test_browser.py b/test/test_browser.py index 3cb8a2ff790c9..ad46cfc423f86 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -4363,7 +4363,7 @@ def test_wasm_locate_file(self): @also_with_threads def test_utf8_textdecoder(self): - self.btest_exit(test_file('benchmark/benchmark_utf8.cpp'), 0, args=['--embed-file', test_file('utf8_corpus.txt') + '@/utf8_corpus.txt', '-sEXPORTED_RUNTIME_METHODS=[UTF8ToString]']) + self.btest_exit(test_file('benchmark/benchmark_utf8.c'), 0, args=['--embed-file', test_file('utf8_corpus.txt') + '@/utf8_corpus.txt']) @also_with_threads def test_utf16_textdecoder(self): diff --git a/test/test_core.py b/test/test_core.py index 235c305c4e96a..7030c6337265a 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -5896,9 +5896,8 @@ def test_utf8(self): @also_with_wasm_bigint def test_utf8_textdecoder(self): - self.set_setting('EXPORTED_RUNTIME_METHODS', ['UTF8ToString', 'stringToUTF8']) self.emcc_args += ['--embed-file', test_file('utf8_corpus.txt') + '@/utf8_corpus.txt'] - self.do_runf(test_file('benchmark/benchmark_utf8.cpp'), 'OK.') + self.do_runf(test_file('benchmark/benchmark_utf8.c'), 'OK.') # Test that invalid character in UTF8 does not cause decoding to crash. def test_utf8_invalid(self): From 2bf4b388c13d5b4633397fa62cc14b7fce830e9b Mon Sep 17 00:00:00 2001 From: juj Date: Thu, 20 Apr 2023 23:51:30 +0300 Subject: [PATCH 0146/1523] Workaround Python multiprocessing pool limitation to fix parallel test suite on Windows. (#19216) --- test/parallel_testsuite.py | 4 +++- tools/shared.py | 13 ++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/test/parallel_testsuite.py b/test/parallel_testsuite.py index fac328dcf146b..b5889f81c865f 100644 --- a/test/parallel_testsuite.py +++ b/test/parallel_testsuite.py @@ -12,6 +12,8 @@ import common +from tools.shared import cap_max_workers_in_pool + NUM_CORES = None @@ -52,7 +54,7 @@ def run(self, result): # issues. # multiprocessing.set_start_method('spawn') tests = list(self.reversed_tests()) - use_cores = min(self.max_cores, len(tests), num_cores()) + use_cores = cap_max_workers_in_pool(min(self.max_cores, len(tests), num_cores())) print('Using %s parallel test processes' % use_cores) pool = multiprocessing.Pool(use_cores) results = [pool.apply_async(run_test, (t,)) for t in tests] diff --git a/tools/shared.py b/tools/shared.py index fb9cb90ace857..f63806a8a699e 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -142,6 +142,13 @@ def returncode_to_str(code): return f'returned {code}' +def cap_max_workers_in_pool(max_workers): + # Python has an issue that it can only use max 61 cores on Windows: https://github.com/python/cpython/issues/89240 + if WINDOWS: + return min(max_workers, 61) + return max_workers + + def run_multiple_processes(commands, env=None, route_stdout_to_temp_files_suffix=None): @@ -161,13 +168,9 @@ def run_multiple_processes(commands, # faster, but may not work on Windows. if int(os.getenv('EM_PYTHON_MULTIPROCESSING', '0')): import multiprocessing - max_workers = get_num_cores() global multiprocessing_pool if not multiprocessing_pool: - if WINDOWS: - # Fix for python < 3.8 on windows. See: https://github.com/python/cpython/pull/13132 - max_workers = min(max_workers, 61) - multiprocessing_pool = multiprocessing.Pool(processes=max_workers) + multiprocessing_pool = multiprocessing.Pool(processes=cap_max_workers_in_pool(get_num_cores())) return multiprocessing_pool.map(mp_run_process, [(cmd, env, route_stdout_to_temp_files_suffix) for cmd in commands], chunksize=1) std_outs = [] From c5c2714a438f3e51d2907c85c25e0c01f9385bde Mon Sep 17 00:00:00 2001 From: juj Date: Fri, 21 Apr 2023 00:38:20 +0300 Subject: [PATCH 0147/1523] Fix typo in @requires_scons (#19214) --- test/test_other.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_other.py b/test/test_other.py index 9bd58772cafa0..1023aaf0d488f 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -141,7 +141,7 @@ def decorated(self, *args, **kwargs): if 'EMTEST_SKIP_SCONS' in os.environ: self.skipTest('test requires scons and EMTEST_SKIP_SCONS is set') else: - self.fail('scons required to run this test. Use EMTEST_SKIP_SKIP to skip') + self.fail('scons required to run this test. Use EMTEST_SKIP_SCONS to skip') return func(self, *args, **kwargs) return decorated From 384514e2797d1e57f8e5407989ec9ad7a43878d5 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 20 Apr 2023 16:22:44 -0700 Subject: [PATCH 0148/1523] Issue warning on use of `--memory-init-file` without `-sWASM=0` (#19217) Issue warning on use of `--memory-init-file` without `-sWASM=0` --- emcc.py | 4 ++-- test/test_browser.py | 32 ++++++++++++++++++-------------- test/test_other.py | 4 ++++ tools/shared.py | 1 + 4 files changed, 25 insertions(+), 16 deletions(-) diff --git a/emcc.py b/emcc.py index 4f1ee56a94cfc..ca01f096764d9 100755 --- a/emcc.py +++ b/emcc.py @@ -2597,6 +2597,8 @@ def check_memory_setting(setting): # shared memory builds we must keep the memory segments in the wasm as # they will be passive segments which the .mem format cannot handle. settings.MEM_INIT_IN_WASM = not options.memory_init_file or settings.SINGLE_FILE or settings.SHARED_MEMORY + elif options.memory_init_file: + diagnostics.warning('unsupported', '--memory-init-file is only supported with -sWASM=0') if ( settings.MAYBE_WASM2JS or @@ -3544,8 +3546,6 @@ def consume_arg_file(): ports.show_ports() should_exit = True elif check_arg('--memory-init-file'): - # This flag is ignored unless targetting wasm2js. - # TODO(sbc): Error out if used without wasm2js. options.memory_init_file = int(consume_arg()) elif check_flag('--proxy-to-worker'): settings_changes.append('PROXY_TO_WORKER=1') diff --git a/test/test_browser.py b/test/test_browser.py index ad46cfc423f86..a038179fdbb48 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -743,13 +743,14 @@ def test_sdl_image(self): shutil.copyfile(test_file('screenshot.jpg'), 'screenshot.jpg') src = test_file('browser/test_sdl_image.c') - for mem in [0, 1]: + for args in [[], ['--memory-init-file=1', '-sWASM=0']]: for dest, dirname, basename in [('screenshot.jpg', '/', 'screenshot.jpg'), ('screenshot.jpg@/assets/screenshot.jpg', '/assets', 'screenshot.jpg')]: - self.btest_exit(src, args=[ - '-O2', '-lSDL', '-lGL', '--memory-init-file', str(mem), + self.btest_exit(src, args=args + [ + '-O2', '-lSDL', '-lGL', '--preload-file', dest, '-DSCREENSHOT_DIRNAME="' + dirname + '"', '-DSCREENSHOT_BASENAME="' + basename + '"', '--use-preload-plugins' ]) + return @also_with_wasmfs def test_sdl_image_jpeg(self): @@ -1485,11 +1486,11 @@ def test_idbstore(self): def test_idbstore_sync(self): secret = str(time.time()) self.clear() - self.btest(test_file('idbstore_sync.c'), '6', args=['-lidbstore.js', '-DSECRET=\"' + secret + '\"', '--memory-init-file', '1', '-O3', '-g2', '-sASYNCIFY']) + self.btest(test_file('idbstore_sync.c'), '6', args=['-lidbstore.js', '-DSECRET=\"' + secret + '\"', '-O3', '-g2', '-sASYNCIFY']) def test_idbstore_sync_worker(self): secret = str(time.time()) - self.btest(test_file('idbstore_sync_worker.c'), expected='0', args=['-lidbstore.js', '-DSECRET=\"' + secret + '\"', '--memory-init-file', '1', '-O3', '-g2', '--proxy-to-worker', '-sINITIAL_MEMORY=80MB', '-sASYNCIFY']) + self.btest(test_file('idbstore_sync_worker.c'), expected='0', args=['-lidbstore.js', '-DSECRET=\"' + secret + '\"', '-O3', '-g2', '--proxy-to-worker', '-sINITIAL_MEMORY=80MB', '-sASYNCIFY']) def test_force_exit(self): self.btest_exit('force_exit.c', assert_returncode=10) @@ -2347,8 +2348,8 @@ def test_pre_run_deps(self): }; ''') - for mem in [0, 1]: - self.btest('pre_run_deps.cpp', expected='10', args=['--pre-js', 'pre.js', '--memory-init-file', str(mem)]) + for args in [[], ['-sWASM=0', '--memory-init-file=1']]: + self.btest('pre_run_deps.cpp', expected='10', args=args + ['--pre-js', 'pre.js']) def test_mem_init(self): self.set_setting('WASM_ASYNC_COMPILATION', 0) @@ -2398,7 +2399,7 @@ def test(what, status): @parameterized({ '': ([],), - 'asmjs': (['-sWASM=0'],) + 'asmjs': (['-sWASM=0', '--memory-init-file=1'],) }) def test_runtime_misuse(self, mode): self.set_setting('DEFAULT_LIBRARY_FUNCS_TO_INCLUDE', '$ccall,$cwrap') @@ -2483,7 +2484,7 @@ def test_runtime_misuse(self, mode): print('mem init, so async, call too early') create_file('post.js', post_prep + post_test + post_hook) - self.btest(filename, expected='600', args=['--post-js', 'post.js', '--memory-init-file', '1', '-sEXIT_RUNTIME'] + extra_args + mode, reporting=Reporting.NONE) + self.btest(filename, expected='600', args=['--post-js', 'post.js', '-sEXIT_RUNTIME'] + extra_args + mode, reporting=Reporting.NONE) print('sync startup, call too late') create_file('post.js', post_prep + 'Module.postRun.push(function() { ' + post_test + ' });' + post_hook) self.btest(filename, expected=str(second_code), args=['--post-js', 'post.js', '-sEXIT_RUNTIME'] + extra_args + mode, reporting=Reporting.NONE) @@ -2902,11 +2903,11 @@ def test_sdl2_image(self): # load an image file, get pixel data. Also O2 coverage for --preload-file, and memory-init shutil.copyfile(test_file('screenshot.jpg'), 'screenshot.jpg') - for mem in [0, 1]: + for args in [[], ['--memory-init-file=1', '-sWASM=0']]: for dest, dirname, basename in [('screenshot.jpg', '/', 'screenshot.jpg'), ('screenshot.jpg@/assets/screenshot.jpg', '/assets', 'screenshot.jpg')]: - self.btest_exit('browser/test_sdl2_image.c', 600, args=[ - '-O2', '--memory-init-file', str(mem), + self.btest_exit('browser/test_sdl2_image.c', 600, args=args + [ + '-O2', '--preload-file', dest, '-DSCREENSHOT_DIRNAME="' + dirname + '"', '-DSCREENSHOT_BASENAME="' + basename + '"', @@ -4137,16 +4138,19 @@ def test_pthread_call_async_on_main_thread(self): # Tests that spawning a new thread does not cause a reinitialization of the global data section of the application memory area. @requires_threads def test_pthread_global_data_initialization(self): - mem_init_modes = [[], ['--memory-init-file', '0'], ['--memory-init-file', '1']] + # --memory-init-file mode disabled because WASM=0 does not seem to work with EXPORT_NAME + mem_init_modes = [[]] # ['-sWASM=0', '--memory-init-file', '0'], ['-sWASM=0', '--memory-init-file', '1']] for mem_init_mode in mem_init_modes: + print(mem_init_mode) for args in [['-sMODULARIZE', '-sEXPORT_NAME=MyModule', '--shell-file', test_file('shell_that_launches_modularize.html')], ['-O3']]: self.btest_exit(test_file('pthread/test_pthread_global_data_initialization.c'), args=args + mem_init_mode + ['-pthread', '-sPROXY_TO_PTHREAD', '-sPTHREAD_POOL_SIZE']) @requires_threads @requires_sync_compilation def test_pthread_global_data_initialization_in_sync_compilation_mode(self): - mem_init_modes = [[], ['--memory-init-file', '0'], ['--memory-init-file', '1']] + mem_init_modes = [[], ['-sWASM=0', '--memory-init-file', '0'], ['-sWASM=0', '--memory-init-file', '1']] for mem_init_mode in mem_init_modes: + print(mem_init_mode) args = ['-sWASM_ASYNC_COMPILATION=0'] self.btest_exit(test_file('pthread/test_pthread_global_data_initialization.c'), args=args + mem_init_mode + ['-pthread', '-sPROXY_TO_PTHREAD', '-sPTHREAD_POOL_SIZE']) diff --git a/test/test_other.py b/test/test_other.py index 1023aaf0d488f..cb8f17634d39e 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -13374,3 +13374,7 @@ def run(args, expect_bulk_mem): # -pthread implicitly enables bulk memory too. self.setup_node_pthreads() run(['-pthread'], expect_bulk_mem=True) + + def test_memory_init_file_unsupported(self): + err = self.expect_fail([EMCC, test_file('hello_world.c'), '-Werror', '--memory-init-file=1']) + self.assertContained('error: --memory-init-file is only supported with -sWASM=0 [-Wunsupported] [-Werror]', err) diff --git a/tools/shared.py b/tools/shared.py index f63806a8a699e..560e124d1e0c8 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -78,6 +78,7 @@ diagnostics.add_warning('em-js-i64') diagnostics.add_warning('js-compiler') diagnostics.add_warning('compatibility') +diagnostics.add_warning('unsupported') # Closure warning are not (yet) enabled by default diagnostics.add_warning('closure', enabled=False) From 5cc6b7ab805463b6625e0256bb9c1d5971fbe9e6 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 21 Apr 2023 08:59:30 -0700 Subject: [PATCH 0149/1523] Use `asyncLoad` helper in loadDynamicLibrary (#19221) The other places in the JS library code that do binary downloading all use this helper already. --- src/library_dylink.js | 4 ++-- test/other/metadce/test_metadce_hello_dylink.jssize | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/library_dylink.js b/src/library_dylink.js index d19669c1dfaeb..b46ffa798dca7 100644 --- a/src/library_dylink.js +++ b/src/library_dylink.js @@ -888,7 +888,7 @@ var LibraryDylink = { // If a library was already loaded, it is not loaded a second time. However // flags.global and flags.nodelete are handled every time a load request is made. // Once a library becomes "global" or "nodelete", it cannot be removed or unloaded. - $loadDynamicLibrary__deps: ['$LDSO', '$loadWebAssemblyModule', '$isInternalSym', '$mergeLibSymbols', '$newDSO'], + $loadDynamicLibrary__deps: ['$LDSO', '$loadWebAssemblyModule', '$isInternalSym', '$mergeLibSymbols', '$newDSO', '$asyncLoad'], $loadDynamicLibrary__docs: ` /** * @param {number=} handle @@ -945,7 +945,7 @@ var LibraryDylink = { var libFile = locateFile(libName); if (flags.loadAsync) { return new Promise(function(resolve, reject) { - readAsync(libFile, (data) => resolve(new Uint8Array(data)), reject); + asyncLoad(libFile, (data) => resolve(data), reject); }); } diff --git a/test/other/metadce/test_metadce_hello_dylink.jssize b/test/other/metadce/test_metadce_hello_dylink.jssize index af1f987c7b7f8..9c624710cb31b 100644 --- a/test/other/metadce/test_metadce_hello_dylink.jssize +++ b/test/other/metadce/test_metadce_hello_dylink.jssize @@ -1 +1 @@ -27937 +28123 From bffb81b50a0f967ba3a0151f554e7b261cccaa9d Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 21 Apr 2023 09:04:25 -0700 Subject: [PATCH 0150/1523] Implement emscripten_async_load_script under node (#19209) --- src/library_browser.js | 35 +++++++++++++------ src/node_shell_read.js | 6 ++-- test/pthread/foo.js | 3 ++ ...n_script.cpp => test_pthread_run_script.c} | 19 +++++----- test/test_browser.py | 9 ++--- test/test_core.py | 21 ++++++++++- ....c => test_emscripten_async_load_script.c} | 4 ++- 7 files changed, 67 insertions(+), 30 deletions(-) create mode 100644 test/pthread/foo.js rename test/pthread/{test_pthread_run_script.cpp => test_pthread_run_script.c} (87%) rename test/{emscripten_api_browser2.c => test_emscripten_async_load_script.c} (94%) diff --git a/src/library_browser.js b/src/library_browser.js index 821e2d83defe3..8dea0309aef86 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -832,27 +832,27 @@ var LibraryBrowser = { emscripten_async_run_script__deps: ['emscripten_run_script', '$safeSetTimeout'], emscripten_async_run_script: function(script, millis) { // TODO: cache these to avoid generating garbage - safeSetTimeout(function() { - _emscripten_run_script(script); - }, millis); + safeSetTimeout(() => _emscripten_run_script(script), millis); }, // TODO: currently not callable from a pthread, but immediately calls onerror() if not on main thread. + emscripten_async_load_script__deps: ['$UTF8ToString'], emscripten_async_load_script: function(url, onload, onerror) { + url = UTF8ToString(url); onload = {{{ makeDynCall('v', 'onload') }}}; onerror = {{{ makeDynCall('v', 'onerror') }}}; #if PTHREADS if (ENVIRONMENT_IS_PTHREAD) { - err('emscripten_async_load_script("' + UTF8ToString(url) + '") failed, emscripten_async_load_script is currently not available in pthreads!'); + err('emscripten_async_load_script("' + url + '") failed, emscripten_async_load_script is currently not available in pthreads!'); return onerror ? onerror() : undefined; } #endif + assert(runDependencies === 0, 'async_load_script must be run when no other dependencies are active'); + {{{ runtimeKeepalivePush() }}} - assert(runDependencies === 0, 'async_load_script must be run when no other dependencies are active'); - var script = document.createElement('script'); - script.onload = function script_onload() { + var loadDone = () => { {{{ runtimeKeepalivePop() }}} if (onload) { if (runDependencies > 0) { @@ -861,12 +861,27 @@ var LibraryBrowser = { onload(); } } - }; - script.onerror = () => { + } + + var loadError = () => { {{{ runtimeKeepalivePop() }}} if (onerror) onerror(); }; - script.src = UTF8ToString(url); + +#if ENVIRONMENT_MAY_BE_NODE && DYNAMIC_EXECUTION + if (ENVIRONMENT_IS_NODE) { + readAsync(url, (data) => { + eval(data); + loadDone(); + }, loadError, false); + return; + } +#endif + + var script = document.createElement('script'); + script.onload = loadDone; + script.onerror = loadError; + script.src = url; document.body.appendChild(script); }, diff --git a/src/node_shell_read.js b/src/node_shell_read.js index 1069a4496db0a..a0a8de24e4902 100644 --- a/src/node_shell_read.js +++ b/src/node_shell_read.js @@ -28,7 +28,7 @@ readBinary = (filename) => { return ret; }; -readAsync = (filename, onload, onerror) => { +readAsync = (filename, onload, onerror, binary = true) => { #if SUPPORT_BASE64_EMBEDDING var ret = tryParseAsDataURI(filename); if (ret) { @@ -37,8 +37,8 @@ readAsync = (filename, onload, onerror) => { #endif // See the comment in the `read_` function. filename = isFileURI(filename) ? new URL(filename) : nodePath.normalize(filename); - fs.readFile(filename, function(err, data) { + fs.readFile(filename, binary ? undefined : 'utf8', (err, data) => { if (err) onerror(err); - else onload(data.buffer); + else onload(binary ? data.buffer : data); }); }; diff --git a/test/pthread/foo.js b/test/pthread/foo.js new file mode 100644 index 0000000000000..5165e1c2668e5 --- /dev/null +++ b/test/pthread/foo.js @@ -0,0 +1,3 @@ +console.log("foo.js loaded!"); + +foo_loaded = true; diff --git a/test/pthread/test_pthread_run_script.cpp b/test/pthread/test_pthread_run_script.c similarity index 87% rename from test/pthread/test_pthread_run_script.cpp rename to test/pthread/test_pthread_run_script.c index 636a96ceb998c..745a3f1200965 100644 --- a/test/pthread/test_pthread_run_script.cpp +++ b/test/pthread/test_pthread_run_script.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -6,15 +7,13 @@ #include #include -extern "C" void EMSCRIPTEN_KEEPALIVE FinishTest(int result) -{ +EMSCRIPTEN_KEEPALIVE void FinishTest(int result) { printf("Test finished, result: %d\n", result); assert(result == 1); exit(0); } -void TestAsyncRunScript() -{ +void TestAsyncRunScript() { // 5. Test emscripten_async_run_script() runs in a pthread. #if __EMSCRIPTEN_PTHREADS__ emscripten_async_run_script("Module['_FinishTest'](ENVIRONMENT_IS_PTHREAD && (typeof ENVIRONMENT_IS_WORKER !== 'undefined' && ENVIRONMENT_IS_WORKER));", 1); @@ -23,20 +22,17 @@ void TestAsyncRunScript() #endif } -void AsyncScriptLoaded() -{ +void AsyncScriptLoaded() { printf("async script load succeeded!\n"); TestAsyncRunScript(); } -void AsyncScriptFailed() -{ +void AsyncScriptFailed() { printf("async script load failed!\n"); TestAsyncRunScript(); } int main() { - // 1. Test that emscripten_run_script() works in a pthread, and it gets // executed in the web worker and not on the main thread. #if __EMSCRIPTEN_PTHREADS__ @@ -52,7 +48,7 @@ int main() { #else int result = emscripten_run_script_int("Module['ranScript'];"); #endif - printf("Module['ranScript']=%d\n", result); + printf("Module['ranScript'] = %d\n", result); assert(result); // 3. Test emscripten_run_script_string() runs in a pthread. @@ -69,6 +65,7 @@ int main() { // 4. Test emscripten_async_load_script() runs in a pthread. emscripten_async_load_script("foo.js", AsyncScriptLoaded, AsyncScriptFailed); - // Should never get here + // This return code should be ignored since emscripten_async_load_script + // keeps the runtime alive until FinishTest is called. return 99; } diff --git a/test/test_browser.py b/test/test_browser.py index a038179fdbb48..057b9cd58c59e 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -1854,7 +1854,7 @@ def test_clientside_vertex_arrays_es3(self): def test_emscripten_api(self): self.btest_exit('emscripten_api_browser.c', args=['-sEXPORTED_FUNCTIONS=_main,_third', '-lSDL']) - def test_emscripten_api2(self): + def test_emscripten_async_load_script(self): def setup(): create_file('script1.js', ''' Module._set(456); @@ -1864,7 +1864,7 @@ def setup(): setup() self.run_process([FILE_PACKAGER, 'test.data', '--preload', 'file1.txt', 'file2.txt'], stdout=open('script2.js', 'w')) - self.btest_exit('emscripten_api_browser2.c', args=['-sEXPORTED_FUNCTIONS=_main,_set', '-sFORCE_FILESYSTEM']) + self.btest_exit('test_emscripten_async_load_script.c', args=['-sFORCE_FILESYSTEM']) # check using file packager to another dir self.clear() @@ -1872,7 +1872,7 @@ def setup(): ensure_dir('sub') self.run_process([FILE_PACKAGER, 'sub/test.data', '--preload', 'file1.txt', 'file2.txt'], stdout=open('script2.js', 'w')) shutil.copyfile(Path('sub/test.data'), 'test.data') - self.btest_exit('emscripten_api_browser2.c', args=['-sEXPORTED_FUNCTIONS=_main,_set', '-sFORCE_FILESYSTEM']) + self.btest_exit('test_emscripten_async_load_script.c', args=['-sFORCE_FILESYSTEM']) def test_emscripten_api_infloop(self): self.btest_exit('emscripten_api_browser_infloop.cpp', assert_returncode=7) @@ -4739,8 +4739,9 @@ def test_emscripten_get_device_pixel_ratio(self): # Tests that emscripten_run_script() variants of functions work in pthreads. @requires_threads def test_pthread_run_script(self): + shutil.copyfile(test_file('pthread/foo.js'), 'foo.js') for args in [[], ['-pthread', '-sPROXY_TO_PTHREAD']]: - self.btest_exit(test_file('pthread/test_pthread_run_script.cpp'), args=['-O3'] + args) + self.btest_exit(test_file('pthread/test_pthread_run_script.c'), args=['-O3'] + args) # Tests emscripten_set_canvas_element_size() and OffscreenCanvas functionality in different build configurations. @requires_threads diff --git a/test/test_core.py b/test/test_core.py index 7030c6337265a..66c7d983d8ee9 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -20,7 +20,7 @@ raise Exception('do not run this file directly; do something like: test/runner') from tools.shared import PIPE -from tools.shared import EMCC, EMAR +from tools.shared import EMCC, EMAR, FILE_PACKAGER from tools.utils import WINDOWS, MACOS, write_file, delete_file from tools import shared, building, config, webassembly import common @@ -2919,6 +2919,16 @@ def test_pthread_tls_dylink(self): self.emcc_args.append('-Wno-experimental') self.do_run_in_out_file_test('pthread/test_pthread_tls_dylink.c') + def test_pthread_run_script(self): + shutil.copyfile(test_file('pthread/foo.js'), 'foo.js') + self.do_runf(test_file('pthread/test_pthread_run_script.c')) + + # Run the test again with PROXY_TO_PTHREAD + self.setup_node_pthreads() + self.set_setting('PROXY_TO_PTHREAD') + self.set_setting('EXIT_RUNTIME') + self.do_runf(test_file('pthread/test_pthread_run_script.c')) + def test_tcgetattr(self): self.do_runf(test_file('termios/test_tcgetattr.c'), 'success') @@ -9754,6 +9764,15 @@ def test_promise(self): self.set_setting('MIN_CHROME_VERSION', '85') self.do_core_test('test_promise.c') + def test_emscripten_async_load_script(self): + create_file('script1.js', 'Module._set(456);''') + create_file('file1.txt', 'first') + create_file('file2.txt', 'second') + # `--from-emcc` needed here otherwise the output defines `var Module =` which will shadow the + # global `Module`. + self.run_process([FILE_PACKAGER, 'test.data', '--preload', 'file1.txt', 'file2.txt', '--from-emcc', '--js-output=script2.js']) + self.do_runf(test_file('test_emscripten_async_load_script.c'), emcc_args=['-sFORCE_FILESYSTEM']) + # Generate tests for everything def make_run(name, emcc_args, settings=None, env=None, diff --git a/test/emscripten_api_browser2.c b/test/test_emscripten_async_load_script.c similarity index 94% rename from test/emscripten_api_browser2.c rename to test/test_emscripten_async_load_script.c index 29d521eef14ac..5164808bc7b62 100644 --- a/test/emscripten_api_browser2.c +++ b/test/test_emscripten_async_load_script.c @@ -12,7 +12,7 @@ int value = 0; -void set(int x) { +EMSCRIPTEN_KEEPALIVE void set(int x) { printf("set! %d\n", x); value = x; } @@ -23,12 +23,14 @@ void load2() { char buffer[10]; memset(buffer, 0, 10); FILE *f = fopen("file1.txt", "r"); + assert(f); fread(buffer, 1, 5, f); fclose(f); assert(strcmp(buffer, "first") == 0); memset(buffer, 0, 10); f = fopen("file2.txt", "r"); + assert(f); fread(buffer, 1, 6, f); fclose(f); assert(strcmp(buffer, "second") == 0); From ae33626f8280ed5f805c502788ce041ff32fb6c8 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 21 Apr 2023 10:12:05 -0700 Subject: [PATCH 0151/1523] Cleanup IDB store test code. NFC (#19223) Add ability to give btests a name other than "test". Use that to create a N different test executables for the N different stages of test_idbstore. This means that after the test runs all the different stages are present in `out/test`: idbstore_0.html idbstore_0.js idbstore_0.wasm* idbstore_1.html idbstore_1.js idbstore_1.wasm* idbstore_2.html idbstore_2.js idbstore_2.wasm* idbstore_3.html idbstore_3.js idbstore_3.wasm* idbstore_4.html idbstore_4.js idbstore_4.wasm* idbstore_5.html idbstore_5.js idbstore_5.wasm* As opposed to only the last one to run. --- test/{idbstore.c => browser/test_idbstore.c} | 0 .../test_idbstore_sync.c} | 0 .../test_idbstore_sync_worker.c} | 0 test/common.py | 5 ++-- test/test_browser.py | 28 +++++++++---------- 5 files changed, 16 insertions(+), 17 deletions(-) rename test/{idbstore.c => browser/test_idbstore.c} (100%) rename test/{idbstore_sync.c => browser/test_idbstore_sync.c} (100%) rename test/{idbstore_sync_worker.c => browser/test_idbstore_sync_worker.c} (100%) diff --git a/test/idbstore.c b/test/browser/test_idbstore.c similarity index 100% rename from test/idbstore.c rename to test/browser/test_idbstore.c diff --git a/test/idbstore_sync.c b/test/browser/test_idbstore_sync.c similarity index 100% rename from test/idbstore_sync.c rename to test/browser/test_idbstore_sync.c diff --git a/test/idbstore_sync_worker.c b/test/browser/test_idbstore_sync_worker.c similarity index 100% rename from test/idbstore_sync_worker.c rename to test/browser/test_idbstore_sync_worker.c diff --git a/test/common.py b/test/common.py index d19187087ddb5..6eb9415b83c92 100644 --- a/test/common.py +++ b/test/common.py @@ -1906,7 +1906,8 @@ def btest(self, filename, expected=None, reference=None, args=None, also_proxied=False, url_suffix='', timeout=None, also_wasm2js=False, manually_trigger_reftest=False, extra_tries=1, - reporting=Reporting.FULL): + reporting=Reporting.FULL, + output_basename='test'): assert expected or reference, 'a btest must either expect an output, or have a reference image' if args is None: args = [] @@ -1923,7 +1924,7 @@ def btest(self, filename, expected=None, reference=None, else: # manual_reference only makes sense for reference tests assert manual_reference is None - outfile = 'test.html' + outfile = output_basename + '.html' args += [filename, '-o', outfile] # print('all args:', args) utils.delete_file(outfile) diff --git a/test/test_browser.py b/test/test_browser.py index 057b9cd58c59e..eb1cd9266fc48 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -791,7 +791,6 @@ def test_sdl_stb_image(self): def test_sdl_stb_image_bpp(self): # load grayscale image without alpha - self.clear() shutil.copyfile(test_file('browser/test_sdl-stb-bpp1.png'), 'screenshot.not') self.btest('browser/test_sdl_stb_image.c', reference='browser/test_sdl-stb-bpp1.png', args=['-sSTB_IMAGE', '--preload-file', 'screenshot.not', '-lSDL', '-lGL']) @@ -820,7 +819,6 @@ def test_sdl_stb_image_cleanup(self): self.btest_exit('browser/test_sdl_stb_image_cleanup.c', args=['-sSTB_IMAGE', '--preload-file', 'screenshot.not', '-lSDL', '-lGL', '--memoryprofiler']) def test_sdl_canvas(self): - self.clear() self.btest_exit('browser/test_sdl_canvas.c', args=['-sLEGACY_GL_EMULATION', '-lSDL', '-lGL']) # some extra coverage self.clear() @@ -1350,14 +1348,14 @@ def test_fs_idbfs_sync(self): self.set_setting('DEFAULT_LIBRARY_FUNCS_TO_INCLUDE', '$ccall') for extra in [[], ['-DEXTRA_WORK']]: secret = str(time.time()) - self.btest(test_file('fs/test_idbfs_sync.c'), '1', args=['-lidbfs.js', '-DFIRST', '-DSECRET=\"' + secret + '\"', '-sEXPORTED_FUNCTIONS=_main,_test,_success', '-lidbfs.js']) - self.btest(test_file('fs/test_idbfs_sync.c'), '1', args=['-lidbfs.js', '-DSECRET=\"' + secret + '\"', '-sEXPORTED_FUNCTIONS=_main,_test,_success', '-lidbfs.js'] + extra) + self.btest(test_file('fs/test_idbfs_sync.c'), '1', args=['-lidbfs.js', '-DFIRST', f'-DSECRET="{secret}"', '-sEXPORTED_FUNCTIONS=_main,_test,_success', '-lidbfs.js']) + self.btest(test_file('fs/test_idbfs_sync.c'), '1', args=['-lidbfs.js', f'-DSECRET="{secret }"', '-sEXPORTED_FUNCTIONS=_main,_test,_success', '-lidbfs.js'] + extra) def test_fs_idbfs_sync_force_exit(self): self.set_setting('DEFAULT_LIBRARY_FUNCS_TO_INCLUDE', '$ccall') secret = str(time.time()) - self.btest(test_file('fs/test_idbfs_sync.c'), '1', args=['-lidbfs.js', '-DFIRST', '-DSECRET=\"' + secret + '\"', '-sEXPORTED_FUNCTIONS=_main,_test,_success', '-sEXIT_RUNTIME', '-DFORCE_EXIT', '-lidbfs.js']) - self.btest(test_file('fs/test_idbfs_sync.c'), '1', args=['-lidbfs.js', '-DSECRET=\"' + secret + '\"', '-sEXPORTED_FUNCTIONS=_main,_test,_success', '-sEXIT_RUNTIME', '-DFORCE_EXIT', '-lidbfs.js']) + self.btest(test_file('fs/test_idbfs_sync.c'), '1', args=['-lidbfs.js', '-DFIRST', f'-DSECRET="{secret}"', '-sEXPORTED_FUNCTIONS=_main,_test,_success', '-sEXIT_RUNTIME', '-DFORCE_EXIT', '-lidbfs.js']) + self.btest(test_file('fs/test_idbfs_sync.c'), '1', args=['-lidbfs.js', f'-DSECRET="{secret }"', '-sEXPORTED_FUNCTIONS=_main,_test,_success', '-sEXIT_RUNTIME', '-DFORCE_EXIT', '-lidbfs.js']) def test_fs_idbfs_fsync(self): # sync from persisted state into memory before main() @@ -1377,13 +1375,13 @@ def test_fs_idbfs_fsync(self): args = ['--pre-js', 'pre.js', '-lidbfs.js', '-sEXIT_RUNTIME', '-sASYNCIFY'] secret = str(time.time()) - self.btest(test_file('fs/test_idbfs_fsync.c'), '1', args=args + ['-DFIRST', '-DSECRET=\"' + secret + '\"', '-sEXPORTED_FUNCTIONS=_main,_success', '-lidbfs.js']) - self.btest(test_file('fs/test_idbfs_fsync.c'), '1', args=args + ['-DSECRET=\"' + secret + '\"', '-sEXPORTED_FUNCTIONS=_main,_success', '-lidbfs.js']) + self.btest(test_file('fs/test_idbfs_fsync.c'), '1', args=args + ['-DFIRST', f'-DSECRET="{secret }"', '-sEXPORTED_FUNCTIONS=_main,_success', '-lidbfs.js']) + self.btest(test_file('fs/test_idbfs_fsync.c'), '1', args=args + [f'-DSECRET="{secret}"', '-sEXPORTED_FUNCTIONS=_main,_success', '-lidbfs.js']) def test_fs_memfs_fsync(self): args = ['-sASYNCIFY', '-sEXIT_RUNTIME'] secret = str(time.time()) - self.btest_exit(test_file('fs/test_memfs_fsync.c'), args=args + ['-DSECRET=\"' + secret + '\"']) + self.btest_exit(test_file('fs/test_memfs_fsync.c'), args=args + [f'-DSECRET="{secret}"']) def test_fs_workerfs_read(self): secret = 'a' * 10 @@ -1400,7 +1398,7 @@ def test_fs_workerfs_read(self): }, '/work'); }; ''' % (secret, secret2)) - self.btest_exit(test_file('fs/test_workerfs_read.c'), args=['-lworkerfs.js', '--pre-js', 'pre.js', '-DSECRET=\"' + secret + '\"', '-DSECRET2=\"' + secret2 + '\"', '--proxy-to-worker', '-lworkerfs.js']) + self.btest_exit(test_file('fs/test_workerfs_read.c'), args=['-lworkerfs.js', '--pre-js', 'pre.js', f'-DSECRET="{secret }"', f'-DSECRET2="{secret2}"', '--proxy-to-worker', '-lworkerfs.js']) def test_fs_workerfs_package(self): self.set_setting('DEFAULT_LIBRARY_FUNCS_TO_INCLUDE', '$ccall') @@ -1479,18 +1477,18 @@ def test_separate_metadata_later(self): def test_idbstore(self): secret = str(time.time()) for stage in [0, 1, 2, 3, 0, 1, 2, 0, 0, 1, 4, 2, 5]: - self.clear() print(stage) - self.btest_exit(test_file('idbstore.c'), args=['-lidbstore.js', '-DSTAGE=' + str(stage), '-DSECRET=\"' + secret + '\"']) + self.btest_exit(test_file('browser/test_idbstore.c'), + args=['-lidbstore.js', f'-DSTAGE={stage}', f'-DSECRET="{secret}"'], + output_basename=f'idbstore_{stage}') def test_idbstore_sync(self): secret = str(time.time()) - self.clear() - self.btest(test_file('idbstore_sync.c'), '6', args=['-lidbstore.js', '-DSECRET=\"' + secret + '\"', '-O3', '-g2', '-sASYNCIFY']) + self.btest(test_file('browser/test_idbstore_sync.c'), '6', args=['-lidbstore.js', f'-DSECRET="{secret}"', '-O3', '-g2', '-sASYNCIFY']) def test_idbstore_sync_worker(self): secret = str(time.time()) - self.btest(test_file('idbstore_sync_worker.c'), expected='0', args=['-lidbstore.js', '-DSECRET=\"' + secret + '\"', '-O3', '-g2', '--proxy-to-worker', '-sINITIAL_MEMORY=80MB', '-sASYNCIFY']) + self.btest(test_file('browser/test_idbstore_sync_worker.c'), expected='0', args=['-lidbstore.js', f'-DSECRET="{secret}"', '-O3', '-g2', '--proxy-to-worker', '-sINITIAL_MEMORY=80MB', '-sASYNCIFY']) def test_force_exit(self): self.btest_exit('force_exit.c', assert_returncode=10) From 1b36ec57d8c3d0f077476e67ecb9e2c487463dee Mon Sep 17 00:00:00 2001 From: juj Date: Fri, 21 Apr 2023 21:04:59 +0300 Subject: [PATCH 0152/1523] Clarify which userData field flows to which function callback in Web Audio. Addresses #18989. (#19010) --- system/include/emscripten/webaudio.h | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/system/include/emscripten/webaudio.h b/system/include/emscripten/webaudio.h index f2f6e6de003eb..5f9108c127695 100644 --- a/system/include/emscripten/webaudio.h +++ b/system/include/emscripten/webaudio.h @@ -34,11 +34,12 @@ typedef int AUDIO_CONTEXT_STATE; #define AUDIO_CONTEXT_STATE_CLOSED 2 #define AUDIO_CONTEXT_STATE_INTERRUPTED 3 -typedef void (*EmscriptenResumeAudioContextCallback)(EMSCRIPTEN_WEBAUDIO_T audioContext, AUDIO_CONTEXT_STATE state, void *userData); +typedef void (*EmscriptenResumeAudioContextCallback)(EMSCRIPTEN_WEBAUDIO_T audioContext, AUDIO_CONTEXT_STATE state, void *userData1); // Resumes the given AudioContext. The specified callback will fire when the AudioContext has completed resuming. Call this function // inside a user event handler (mousedown, button click, etc.) -void emscripten_resume_audio_context_async(EMSCRIPTEN_WEBAUDIO_T audioContext, EmscriptenResumeAudioContextCallback callback, void *userData); +// userData1: A custom userdata pointer to pass to the callback function. This value will be passed on to the call to the given EmscriptenResumeAudioContextCallback callback function. +void emscripten_resume_audio_context_async(EMSCRIPTEN_WEBAUDIO_T audioContext, EmscriptenResumeAudioContextCallback callback, void *userData1); // Synchronously attempts to resume the given AudioContext. void emscripten_resume_audio_context_sync(EMSCRIPTEN_WEBAUDIO_T audioContext); @@ -46,7 +47,7 @@ void emscripten_resume_audio_context_sync(EMSCRIPTEN_WEBAUDIO_T audioContext); // Returns the current AudioContext state. AUDIO_CONTEXT_STATE emscripten_audio_context_state(EMSCRIPTEN_WEBAUDIO_T audioContext); -typedef void (*EmscriptenStartWebAudioWorkletCallback)(EMSCRIPTEN_WEBAUDIO_T audioContext, EM_BOOL success, void *userData); +typedef void (*EmscriptenStartWebAudioWorkletCallback)(EMSCRIPTEN_WEBAUDIO_T audioContext, EM_BOOL success, void *userData2); // Calls .suspend() on the given AudioContext and releases the JS object table // reference to the given audio context. The specified handle is invalid @@ -65,8 +66,8 @@ void emscripten_destroy_web_audio_node(EMSCRIPTEN_WEBAUDIO_T objectHandle); // stackLowestAddress: The base address for the thread's stack. Must be aligned to 16 bytes. Use e.g. memalign(16, 1024) to allocate a 1KB stack for the thread. // stackSize: The size of the thread's stack. Must be a multiple of 16 bytes. // callback: The callback function that will be run when thread creation either succeeds or fails. -// userData: A custom userdata pointer to pass to the callback function. -void emscripten_start_wasm_audio_worklet_thread_async(EMSCRIPTEN_WEBAUDIO_T audioContext, void *stackLowestAddress, uint32_t stackSize, EmscriptenStartWebAudioWorkletCallback callback, void *userData); +// userData2: A custom userdata pointer to pass to the callback function. This value will be passed on to the call to the given EmscriptenStartWebAudioWorkletCallback callback function. +void emscripten_start_wasm_audio_worklet_thread_async(EMSCRIPTEN_WEBAUDIO_T audioContext, void *stackLowestAddress, uint32_t stackSize, EmscriptenStartWebAudioWorkletCallback callback, void *userData2); typedef int WEBAUDIO_PARAM_AUTOMATION_RATE; #define WEBAUDIO_PARAM_A_RATE 0 @@ -88,10 +89,11 @@ typedef struct WebAudioWorkletProcessorCreateOptions const WebAudioParamDescriptor *audioParamDescriptors; } WebAudioWorkletProcessorCreateOptions; -typedef void (*EmscriptenWorkletProcessorCreatedCallback)(EMSCRIPTEN_WEBAUDIO_T audioContext, EM_BOOL success, void *userData); +typedef void (*EmscriptenWorkletProcessorCreatedCallback)(EMSCRIPTEN_WEBAUDIO_T audioContext, EM_BOOL success, void *userData3); // Creates a new AudioWorkletProcessor with the given name and specified set of control parameters. -void emscripten_create_wasm_audio_worklet_processor_async(EMSCRIPTEN_WEBAUDIO_T audioContext, const WebAudioWorkletProcessorCreateOptions *options, EmscriptenWorkletProcessorCreatedCallback callback, void *userData); +// userData3: A custom userdata pointer to pass to the callback function. This value will be passed on to the call to the given EmscriptenWorkletProcessorCreatedCallback callback function. +void emscripten_create_wasm_audio_worklet_processor_async(EMSCRIPTEN_WEBAUDIO_T audioContext, const WebAudioWorkletProcessorCreateOptions *options, EmscriptenWorkletProcessorCreatedCallback callback, void *userData3); typedef int EMSCRIPTEN_AUDIO_WORKLET_NODE_T; @@ -111,7 +113,7 @@ typedef struct AudioParamFrame float *data; } AudioParamFrame; -typedef EM_BOOL (*EmscriptenWorkletNodeProcessCallback)(int numInputs, const AudioSampleFrame *inputs, int numOutputs, AudioSampleFrame *outputs, int numParams, const AudioParamFrame *params, void *userData); +typedef EM_BOOL (*EmscriptenWorkletNodeProcessCallback)(int numInputs, const AudioSampleFrame *inputs, int numOutputs, AudioSampleFrame *outputs, int numParams, const AudioParamFrame *params, void *userData4); typedef struct EmscriptenAudioWorkletNodeCreateOptions { @@ -124,7 +126,8 @@ typedef struct EmscriptenAudioWorkletNodeCreateOptions } EmscriptenAudioWorkletNodeCreateOptions; // Instantiates the given AudioWorkletProcessor as an AudioWorkletNode, which continuously calls the specified processCallback() function on the browser's audio thread to perform audio processing. -EMSCRIPTEN_AUDIO_WORKLET_NODE_T emscripten_create_wasm_audio_worklet_node(EMSCRIPTEN_WEBAUDIO_T audioContext, const char *name, const EmscriptenAudioWorkletNodeCreateOptions *options, EmscriptenWorkletNodeProcessCallback processCallback, void *userData); +// userData4: A custom userdata pointer to pass to the callback function. This value will be passed on to the call to the given EmscriptenWorkletNodeProcessCallback callback function. +EMSCRIPTEN_AUDIO_WORKLET_NODE_T emscripten_create_wasm_audio_worklet_node(EMSCRIPTEN_WEBAUDIO_T audioContext, const char *name, const EmscriptenAudioWorkletNodeCreateOptions *options, EmscriptenWorkletNodeProcessCallback processCallback, void *userData4); // Returns EM_TRUE if the current thread is executing a Wasm AudioWorklet, EM_FALSE otherwise. // Note that calling this function can be relatively slow as it incurs a Wasm->JS transition, From 0a3c59d63af5eafd4fd06cebc4192be86bef4152 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 21 Apr 2023 12:30:12 -0700 Subject: [PATCH 0153/1523] Rebaseline codesize expectations. NFC --- test/other/metadce/test_metadce_cxx_ctors1.jssize | 2 +- test/other/metadce/test_metadce_cxx_ctors1.size | 2 +- test/other/metadce/test_metadce_cxx_ctors2.jssize | 2 +- test/other/metadce/test_metadce_cxx_ctors2.size | 2 +- test/other/metadce/test_metadce_cxx_except.jssize | 2 +- test/other/metadce/test_metadce_cxx_except.size | 2 +- test/other/metadce/test_metadce_cxx_except_wasm.jssize | 2 +- test/other/metadce/test_metadce_cxx_except_wasm.size | 2 +- test/other/metadce/test_metadce_cxx_mangle.jssize | 2 +- test/other/metadce/test_metadce_cxx_mangle.size | 2 +- test/other/metadce/test_metadce_cxx_noexcept.jssize | 2 +- test/other/metadce/test_metadce_cxx_noexcept.size | 2 +- test/other/metadce/test_metadce_hello_O0.jssize | 2 +- test/other/metadce/test_metadce_hello_O1.jssize | 2 +- test/other/metadce/test_metadce_hello_O2.jssize | 2 +- test/other/metadce/test_metadce_hello_O3.jssize | 2 +- test/other/metadce/test_metadce_hello_Os.jssize | 2 +- test/other/metadce/test_metadce_hello_Oz.jssize | 2 +- test/other/metadce/test_metadce_hello_dylink.jssize | 2 +- test/other/metadce/test_metadce_hello_export_nothing.jssize | 2 +- test/other/metadce/test_metadce_libcxxabi_message_O3.jssize | 2 +- .../metadce/test_metadce_libcxxabi_message_O3_standalone.jssize | 2 +- test/other/metadce/test_metadce_mem_O3.jssize | 2 +- test/other/metadce/test_metadce_mem_O3_grow.jssize | 2 +- test/other/metadce/test_metadce_mem_O3_grow_standalone.jssize | 2 +- test/other/metadce/test_metadce_mem_O3_standalone.jssize | 2 +- test/other/metadce/test_metadce_mem_O3_standalone_lib.jssize | 2 +- test/other/metadce/test_metadce_mem_O3_standalone_narg.jssize | 2 +- .../metadce/test_metadce_mem_O3_standalone_narg_flto.jssize | 2 +- test/other/metadce/test_metadce_minimal_64.jssize | 2 +- test/other/metadce/test_metadce_minimal_O0.jssize | 2 +- test/other/metadce/test_metadce_minimal_O1.jssize | 2 +- test/other/metadce/test_metadce_minimal_O2.jssize | 2 +- test/other/metadce/test_metadce_minimal_O3.jssize | 2 +- test/other/metadce/test_metadce_minimal_Os.jssize | 2 +- test/other/metadce/test_metadce_minimal_Oz-ctors.jssize | 2 +- test/other/metadce/test_metadce_minimal_Oz.jssize | 2 +- test/other/metadce/test_metadce_minimal_pthreads.jssize | 2 +- test/other/metadce/test_metadce_minimal_pthreads.size | 2 +- test/other/test_unoptimized_code_size.js.size | 2 +- test/other/test_unoptimized_code_size_no_asserts.js.size | 2 +- test/other/test_unoptimized_code_size_strict.js.size | 2 +- 42 files changed, 42 insertions(+), 42 deletions(-) diff --git a/test/other/metadce/test_metadce_cxx_ctors1.jssize b/test/other/metadce/test_metadce_cxx_ctors1.jssize index eaa1bce3a3169..2d59af73314ee 100644 --- a/test/other/metadce/test_metadce_cxx_ctors1.jssize +++ b/test/other/metadce/test_metadce_cxx_ctors1.jssize @@ -1 +1 @@ -26064 +26083 diff --git a/test/other/metadce/test_metadce_cxx_ctors1.size b/test/other/metadce/test_metadce_cxx_ctors1.size index fba69b18f9001..926498087fac1 100644 --- a/test/other/metadce/test_metadce_cxx_ctors1.size +++ b/test/other/metadce/test_metadce_cxx_ctors1.size @@ -1 +1 @@ -123454 +123438 diff --git a/test/other/metadce/test_metadce_cxx_ctors2.jssize b/test/other/metadce/test_metadce_cxx_ctors2.jssize index de572e787d4bc..8d96ed08e903f 100644 --- a/test/other/metadce/test_metadce_cxx_ctors2.jssize +++ b/test/other/metadce/test_metadce_cxx_ctors2.jssize @@ -1 +1 @@ -26028 +26047 diff --git a/test/other/metadce/test_metadce_cxx_ctors2.size b/test/other/metadce/test_metadce_cxx_ctors2.size index 96fcfdd147414..f8ee7683ac499 100644 --- a/test/other/metadce/test_metadce_cxx_ctors2.size +++ b/test/other/metadce/test_metadce_cxx_ctors2.size @@ -1 +1 @@ -123359 +123332 diff --git a/test/other/metadce/test_metadce_cxx_except.jssize b/test/other/metadce/test_metadce_cxx_except.jssize index 907b6f9c52048..d80e90bb407d3 100644 --- a/test/other/metadce/test_metadce_cxx_except.jssize +++ b/test/other/metadce/test_metadce_cxx_except.jssize @@ -1 +1 @@ -30578 +30597 diff --git a/test/other/metadce/test_metadce_cxx_except.size b/test/other/metadce/test_metadce_cxx_except.size index 2cab05e0ebf11..24bc171ec8d9a 100644 --- a/test/other/metadce/test_metadce_cxx_except.size +++ b/test/other/metadce/test_metadce_cxx_except.size @@ -1 +1 @@ -166230 +166210 diff --git a/test/other/metadce/test_metadce_cxx_except_wasm.jssize b/test/other/metadce/test_metadce_cxx_except_wasm.jssize index 4d5bbdb566ccb..aa8d53d4bc130 100644 --- a/test/other/metadce/test_metadce_cxx_except_wasm.jssize +++ b/test/other/metadce/test_metadce_cxx_except_wasm.jssize @@ -1 +1 @@ -25873 +25892 diff --git a/test/other/metadce/test_metadce_cxx_except_wasm.size b/test/other/metadce/test_metadce_cxx_except_wasm.size index 10c3b52813608..23414de4bbcef 100644 --- a/test/other/metadce/test_metadce_cxx_except_wasm.size +++ b/test/other/metadce/test_metadce_cxx_except_wasm.size @@ -1 +1 @@ -137028 +137008 diff --git a/test/other/metadce/test_metadce_cxx_mangle.jssize b/test/other/metadce/test_metadce_cxx_mangle.jssize index 1c6ad02b459b4..158bd3c8b7f99 100644 --- a/test/other/metadce/test_metadce_cxx_mangle.jssize +++ b/test/other/metadce/test_metadce_cxx_mangle.jssize @@ -1 +1 @@ -30582 +30601 diff --git a/test/other/metadce/test_metadce_cxx_mangle.size b/test/other/metadce/test_metadce_cxx_mangle.size index 264492efef7b6..010c68af7f9e6 100644 --- a/test/other/metadce/test_metadce_cxx_mangle.size +++ b/test/other/metadce/test_metadce_cxx_mangle.size @@ -1 +1 @@ -221326 +219392 diff --git a/test/other/metadce/test_metadce_cxx_noexcept.jssize b/test/other/metadce/test_metadce_cxx_noexcept.jssize index eaa1bce3a3169..2d59af73314ee 100644 --- a/test/other/metadce/test_metadce_cxx_noexcept.jssize +++ b/test/other/metadce/test_metadce_cxx_noexcept.jssize @@ -1 +1 @@ -26064 +26083 diff --git a/test/other/metadce/test_metadce_cxx_noexcept.size b/test/other/metadce/test_metadce_cxx_noexcept.size index f4b7350835a3f..3b99dcaf0173e 100644 --- a/test/other/metadce/test_metadce_cxx_noexcept.size +++ b/test/other/metadce/test_metadce_cxx_noexcept.size @@ -1 +1 @@ -126251 +126231 diff --git a/test/other/metadce/test_metadce_hello_O0.jssize b/test/other/metadce/test_metadce_hello_O0.jssize index e8bcc8a6af475..bc29a314d92a0 100644 --- a/test/other/metadce/test_metadce_hello_O0.jssize +++ b/test/other/metadce/test_metadce_hello_O0.jssize @@ -1 +1 @@ -24028 +24060 diff --git a/test/other/metadce/test_metadce_hello_O1.jssize b/test/other/metadce/test_metadce_hello_O1.jssize index e4d150b45c423..cf35faf9dce13 100644 --- a/test/other/metadce/test_metadce_hello_O1.jssize +++ b/test/other/metadce/test_metadce_hello_O1.jssize @@ -1 +1 @@ -8555 +8587 diff --git a/test/other/metadce/test_metadce_hello_O2.jssize b/test/other/metadce/test_metadce_hello_O2.jssize index e086a733090d3..385e1b57afd33 100644 --- a/test/other/metadce/test_metadce_hello_O2.jssize +++ b/test/other/metadce/test_metadce_hello_O2.jssize @@ -1 +1 @@ -6070 +6089 diff --git a/test/other/metadce/test_metadce_hello_O3.jssize b/test/other/metadce/test_metadce_hello_O3.jssize index 6762ad20ec827..45463003085f8 100644 --- a/test/other/metadce/test_metadce_hello_O3.jssize +++ b/test/other/metadce/test_metadce_hello_O3.jssize @@ -1 +1 @@ -5896 +5915 diff --git a/test/other/metadce/test_metadce_hello_Os.jssize b/test/other/metadce/test_metadce_hello_Os.jssize index 6762ad20ec827..45463003085f8 100644 --- a/test/other/metadce/test_metadce_hello_Os.jssize +++ b/test/other/metadce/test_metadce_hello_Os.jssize @@ -1 +1 @@ -5896 +5915 diff --git a/test/other/metadce/test_metadce_hello_Oz.jssize b/test/other/metadce/test_metadce_hello_Oz.jssize index e885b56e61b25..680ccbafeb3bd 100644 --- a/test/other/metadce/test_metadce_hello_Oz.jssize +++ b/test/other/metadce/test_metadce_hello_Oz.jssize @@ -1 +1 @@ -5855 +5874 diff --git a/test/other/metadce/test_metadce_hello_dylink.jssize b/test/other/metadce/test_metadce_hello_dylink.jssize index 9c624710cb31b..041ee984857a1 100644 --- a/test/other/metadce/test_metadce_hello_dylink.jssize +++ b/test/other/metadce/test_metadce_hello_dylink.jssize @@ -1 +1 @@ -28123 +28142 diff --git a/test/other/metadce/test_metadce_hello_export_nothing.jssize b/test/other/metadce/test_metadce_hello_export_nothing.jssize index d464190f4f303..092b8f173fcb7 100644 --- a/test/other/metadce/test_metadce_hello_export_nothing.jssize +++ b/test/other/metadce/test_metadce_hello_export_nothing.jssize @@ -1 +1 @@ -4639 +4658 diff --git a/test/other/metadce/test_metadce_libcxxabi_message_O3.jssize b/test/other/metadce/test_metadce_libcxxabi_message_O3.jssize index 95494025b416c..27d80a3e2e52e 100644 --- a/test/other/metadce/test_metadce_libcxxabi_message_O3.jssize +++ b/test/other/metadce/test_metadce_libcxxabi_message_O3.jssize @@ -1 +1 @@ -5166 +5185 diff --git a/test/other/metadce/test_metadce_libcxxabi_message_O3_standalone.jssize b/test/other/metadce/test_metadce_libcxxabi_message_O3_standalone.jssize index 2874bd57eeefd..cc1d64bcf857b 100644 --- a/test/other/metadce/test_metadce_libcxxabi_message_O3_standalone.jssize +++ b/test/other/metadce/test_metadce_libcxxabi_message_O3_standalone.jssize @@ -1 +1 @@ -5234 +5253 diff --git a/test/other/metadce/test_metadce_mem_O3.jssize b/test/other/metadce/test_metadce_mem_O3.jssize index b0f791df0f893..cc841ddb939d2 100644 --- a/test/other/metadce/test_metadce_mem_O3.jssize +++ b/test/other/metadce/test_metadce_mem_O3.jssize @@ -1 +1 @@ -6104 +6124 diff --git a/test/other/metadce/test_metadce_mem_O3_grow.jssize b/test/other/metadce/test_metadce_mem_O3_grow.jssize index f04ad2bec3f0a..7cadbcb28841d 100644 --- a/test/other/metadce/test_metadce_mem_O3_grow.jssize +++ b/test/other/metadce/test_metadce_mem_O3_grow.jssize @@ -1 +1 @@ -6441 +6460 diff --git a/test/other/metadce/test_metadce_mem_O3_grow_standalone.jssize b/test/other/metadce/test_metadce_mem_O3_grow_standalone.jssize index 4d958ef476ea6..eaadb4de9b93a 100644 --- a/test/other/metadce/test_metadce_mem_O3_grow_standalone.jssize +++ b/test/other/metadce/test_metadce_mem_O3_grow_standalone.jssize @@ -1 +1 @@ -5831 +5850 diff --git a/test/other/metadce/test_metadce_mem_O3_standalone.jssize b/test/other/metadce/test_metadce_mem_O3_standalone.jssize index da710c1aba587..ebbcf42ed4e54 100644 --- a/test/other/metadce/test_metadce_mem_O3_standalone.jssize +++ b/test/other/metadce/test_metadce_mem_O3_standalone.jssize @@ -1 +1 @@ -5753 +5772 diff --git a/test/other/metadce/test_metadce_mem_O3_standalone_lib.jssize b/test/other/metadce/test_metadce_mem_O3_standalone_lib.jssize index 7ac3c34e4749d..05112f24d5e8d 100644 --- a/test/other/metadce/test_metadce_mem_O3_standalone_lib.jssize +++ b/test/other/metadce/test_metadce_mem_O3_standalone_lib.jssize @@ -1 +1 @@ -5252 +5271 diff --git a/test/other/metadce/test_metadce_mem_O3_standalone_narg.jssize b/test/other/metadce/test_metadce_mem_O3_standalone_narg.jssize index 2874bd57eeefd..cc1d64bcf857b 100644 --- a/test/other/metadce/test_metadce_mem_O3_standalone_narg.jssize +++ b/test/other/metadce/test_metadce_mem_O3_standalone_narg.jssize @@ -1 +1 @@ -5234 +5253 diff --git a/test/other/metadce/test_metadce_mem_O3_standalone_narg_flto.jssize b/test/other/metadce/test_metadce_mem_O3_standalone_narg_flto.jssize index 2874bd57eeefd..cc1d64bcf857b 100644 --- a/test/other/metadce/test_metadce_mem_O3_standalone_narg_flto.jssize +++ b/test/other/metadce/test_metadce_mem_O3_standalone_narg_flto.jssize @@ -1 +1 @@ -5234 +5253 diff --git a/test/other/metadce/test_metadce_minimal_64.jssize b/test/other/metadce/test_metadce_minimal_64.jssize index a7f7f14163139..801c306ed34de 100644 --- a/test/other/metadce/test_metadce_minimal_64.jssize +++ b/test/other/metadce/test_metadce_minimal_64.jssize @@ -1 +1 @@ -4077 +4096 diff --git a/test/other/metadce/test_metadce_minimal_O0.jssize b/test/other/metadce/test_metadce_minimal_O0.jssize index ee659efaeef94..ee1f2431383fb 100644 --- a/test/other/metadce/test_metadce_minimal_O0.jssize +++ b/test/other/metadce/test_metadce_minimal_O0.jssize @@ -1 +1 @@ -20274 +20309 diff --git a/test/other/metadce/test_metadce_minimal_O1.jssize b/test/other/metadce/test_metadce_minimal_O1.jssize index d4c9c722de609..e3bda3519fc45 100644 --- a/test/other/metadce/test_metadce_minimal_O1.jssize +++ b/test/other/metadce/test_metadce_minimal_O1.jssize @@ -1 +1 @@ -4869 +4901 diff --git a/test/other/metadce/test_metadce_minimal_O2.jssize b/test/other/metadce/test_metadce_minimal_O2.jssize index bb778e4e859fc..bcd68d60a016c 100644 --- a/test/other/metadce/test_metadce_minimal_O2.jssize +++ b/test/other/metadce/test_metadce_minimal_O2.jssize @@ -1 +1 @@ -3737 +3756 diff --git a/test/other/metadce/test_metadce_minimal_O3.jssize b/test/other/metadce/test_metadce_minimal_O3.jssize index 1149062c66bf4..34d73a1238d21 100644 --- a/test/other/metadce/test_metadce_minimal_O3.jssize +++ b/test/other/metadce/test_metadce_minimal_O3.jssize @@ -1 +1 @@ -3666 +3685 diff --git a/test/other/metadce/test_metadce_minimal_Os.jssize b/test/other/metadce/test_metadce_minimal_Os.jssize index 1149062c66bf4..34d73a1238d21 100644 --- a/test/other/metadce/test_metadce_minimal_Os.jssize +++ b/test/other/metadce/test_metadce_minimal_Os.jssize @@ -1 +1 @@ -3666 +3685 diff --git a/test/other/metadce/test_metadce_minimal_Oz-ctors.jssize b/test/other/metadce/test_metadce_minimal_Oz-ctors.jssize index 2ae555a2e692c..1149062c66bf4 100644 --- a/test/other/metadce/test_metadce_minimal_Oz-ctors.jssize +++ b/test/other/metadce/test_metadce_minimal_Oz-ctors.jssize @@ -1 +1 @@ -3647 +3666 diff --git a/test/other/metadce/test_metadce_minimal_Oz.jssize b/test/other/metadce/test_metadce_minimal_Oz.jssize index 1149062c66bf4..34d73a1238d21 100644 --- a/test/other/metadce/test_metadce_minimal_Oz.jssize +++ b/test/other/metadce/test_metadce_minimal_Oz.jssize @@ -1 +1 @@ -3666 +3685 diff --git a/test/other/metadce/test_metadce_minimal_pthreads.jssize b/test/other/metadce/test_metadce_minimal_pthreads.jssize index fa365d0234845..75f405c07dd20 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.jssize +++ b/test/other/metadce/test_metadce_minimal_pthreads.jssize @@ -1 +1 @@ -15528 +15547 diff --git a/test/other/metadce/test_metadce_minimal_pthreads.size b/test/other/metadce/test_metadce_minimal_pthreads.size index ef216c038b7ad..d68caa14c4ead 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.size +++ b/test/other/metadce/test_metadce_minimal_pthreads.size @@ -1 +1 @@ -18968 +18994 diff --git a/test/other/test_unoptimized_code_size.js.size b/test/other/test_unoptimized_code_size.js.size index 945c40bdcfd9f..f506c84049a5e 100644 --- a/test/other/test_unoptimized_code_size.js.size +++ b/test/other/test_unoptimized_code_size.js.size @@ -1 +1 @@ -59729 +59784 diff --git a/test/other/test_unoptimized_code_size_no_asserts.js.size b/test/other/test_unoptimized_code_size_no_asserts.js.size index 6d8f14511f2ba..ef712ab7159a8 100644 --- a/test/other/test_unoptimized_code_size_no_asserts.js.size +++ b/test/other/test_unoptimized_code_size_no_asserts.js.size @@ -1 +1 @@ -33348 +33403 diff --git a/test/other/test_unoptimized_code_size_strict.js.size b/test/other/test_unoptimized_code_size_strict.js.size index 504971565a78a..20347f1fe5107 100644 --- a/test/other/test_unoptimized_code_size_strict.js.size +++ b/test/other/test_unoptimized_code_size_strict.js.size @@ -1 +1 @@ -58671 +58726 From b2c497401dd28e59a1c3592b8e5f350707090a5b Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 21 Apr 2023 13:39:28 -0700 Subject: [PATCH 0154/1523] Remove use of EM_PYTHON_MULTIPROCESSING environment variable. NFC (#19224) This was added a fallback to pre-existing behaviour by was always intended to be temporary. --- ChangeLog.md | 2 ++ test/test_other.py | 6 ------ tools/shared.py | 13 ------------- 3 files changed, 2 insertions(+), 19 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 6956d3a8797f5..53c25e67fe79c 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -20,6 +20,8 @@ See docs/process.md for more on how version tagging works. 3.1.37 (in development) ----------------------- +- The `EM_PYTHON_MULTIPROCESSING` environment variable no longer has any effect. + This was added a temporary fallback but should no longer be needed. (#19224) - The old reverse dependency system based on `tools/deps_info.py` has been removed and the existing `__deps` entries in JS library files can now be used to express JS-to-native dependencies. As well being more precise, and diff --git a/test/test_other.py b/test/test_other.py index cb8f17634d39e..bcc325a69cf3e 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -12032,12 +12032,6 @@ def test_output_name_collision(self): self.assertExists('hello_.wasm') self.assertContained('hello, world!', self.run_js('hello.wasm')) - def test_EM_PYTHON_MULTIPROCESSING(self): - with env_modify({'EM_PYTHON_MULTIPROCESSING': '1'}): - # wasm2js optimizations use multiprocessing to run multiple node - # invocations - self.run_process([EMCC, test_file('hello_world.c'), '-sWASM=0', '-O2']) - def test_main_module_no_undefined(self): # Test that ERROR_ON_UNDEFINED_SYMBOLS works with MAIN_MODULE. self.do_runf(test_file('hello_world.c'), emcc_args=['-sMAIN_MODULE', '-sERROR_ON_UNDEFINED_SYMBOLS']) diff --git a/tools/shared.py b/tools/shared.py index 560e124d1e0c8..e5abfb365e9e5 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -51,8 +51,6 @@ MINIMUM_NODE_VERSION = (10, 19, 0) EXPECTED_LLVM_VERSION = 17 -# Used only when EM_PYTHON_MULTIPROCESSING=1 env. var is set. -multiprocessing_pool = None logger = logging.getLogger('shared') # warning about absolute-paths is disabled by default, and not enabled by -Wall @@ -163,17 +161,6 @@ def run_multiple_processes(commands, if env is None: env = os.environ.copy() - # By default, avoid using Python multiprocessing library due to a large amount - # of bugs it has on Windows (#8013, #718, etc.) - # Use EM_PYTHON_MULTIPROCESSING=1 environment variable to enable it. It can be - # faster, but may not work on Windows. - if int(os.getenv('EM_PYTHON_MULTIPROCESSING', '0')): - import multiprocessing - global multiprocessing_pool - if not multiprocessing_pool: - multiprocessing_pool = multiprocessing.Pool(processes=cap_max_workers_in_pool(get_num_cores())) - return multiprocessing_pool.map(mp_run_process, [(cmd, env, route_stdout_to_temp_files_suffix) for cmd in commands], chunksize=1) - std_outs = [] # TODO: Experiment with registering a signal handler here to see if that helps with Ctrl-C locking up the command prompt From d8c1a8a66087b38ea993f1f9f578a3f21808accb Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 21 Apr 2023 14:31:00 -0700 Subject: [PATCH 0155/1523] Support multiple arguments to err/out under node + pthreads (#19228) --- src/shell.js | 4 ++-- test/test_other.py | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/shell.js b/src/shell.js index b007cce288047..53ce84c2660a2 100644 --- a/src/shell.js +++ b/src/shell.js @@ -446,8 +446,8 @@ if (ENVIRONMENT_IS_NODE) { var defaultPrint = console.log.bind(console); var defaultPrintErr = console.warn.bind(console); if (ENVIRONMENT_IS_NODE) { - defaultPrint = (str) => fs.writeSync(1, str + '\n'); - defaultPrintErr = (str) => fs.writeSync(2, str + '\n'); + defaultPrint = (...args) => fs.writeSync(1, args.join(' ') + '\n'); + defaultPrintErr = (...args) => fs.writeSync(2, args.join(' ') + '\n'); } {{{ makeModuleReceiveWithVar('out', 'print', 'defaultPrint', true) }}} {{{ makeModuleReceiveWithVar('err', 'printErr', 'defaultPrintErr', true) }}} diff --git a/test/test_other.py b/test/test_other.py index bcc325a69cf3e..73242bbc2207b 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -13372,3 +13372,8 @@ def run(args, expect_bulk_mem): def test_memory_init_file_unsupported(self): err = self.expect_fail([EMCC, test_file('hello_world.c'), '-Werror', '--memory-init-file=1']) self.assertContained('error: --memory-init-file is only supported with -sWASM=0 [-Wunsupported] [-Werror]', err) + + @node_pthreads + def test_node_pthreads_err_out(self): + create_file('post.js', 'err(1, 2, "hello"); out("foo", 42);') + self.do_runf(test_file('hello_world.c'), '1 2 hello\nfoo 42\n', emcc_args=['--post-js=post.js']) From f011b5c6802ed536891766a8df40decfb1d2e29e Mon Sep 17 00:00:00 2001 From: Ingvar Stepanyan Date: Sat, 22 Apr 2023 00:02:08 +0100 Subject: [PATCH 0156/1523] Fix unescaped NUL character in JS (#19231) --- src/library_strings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/library_strings.js b/src/library_strings.js index a7da5dec1af7f..1fb4b9040b0a1 100644 --- a/src/library_strings.js +++ b/src/library_strings.js @@ -101,7 +101,7 @@ mergeInto(LibraryManager.library, { * @param {number} ptr * @param {number=} maxBytesToRead - An optional length that specifies the * maximum number of bytes to read. You can omit this parameter to scan the - * string until the first \0 byte. If maxBytesToRead is passed, and the string + * string until the first 0 byte. If maxBytesToRead is passed, and the string * at [ptr, ptr+maxBytesToReadr[ contains a null byte in the middle, then the * string will cut short at that byte index (i.e. maxBytesToRead will not * produce a string of exact length [ptr, ptr+maxBytesToRead[) N.B. mixing From 9757ac1b48e9ea63dba9647fd40c1ac7eaf45e6b Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Sat, 22 Apr 2023 13:23:38 +0200 Subject: [PATCH 0157/1523] Make Node.js pthreads behavior in line with native (#19073) By marking workers as weakly referenced. This corresponds to the ideal scenario as mentioned in commit a9cbf47. --- ChangeLog.md | 1 + src/library_pthread.js | 34 ++++++++++---- src/library_sigs.js | 1 + system/lib/libc/crt1_proxy_main.c | 7 +++ system/lib/pthread/emscripten_yield.c | 10 +++-- system/lib/pthread/threading_internal.h | 9 ++++ test/core/pthread/test_pthread_weak_ref.c | 44 +++++++++++++++++++ test/core/pthread/test_pthread_weak_ref.out | 3 ++ .../test_metadce_minimal_pthreads.exports | 2 +- .../test_metadce_minimal_pthreads.imports | 1 + .../test_metadce_minimal_pthreads.jssize | 2 +- .../test_metadce_minimal_pthreads.sent | 1 + .../test_metadce_minimal_pthreads.size | 2 +- test/test_core.py | 4 ++ 14 files changed, 106 insertions(+), 15 deletions(-) create mode 100644 test/core/pthread/test_pthread_weak_ref.c create mode 100644 test/core/pthread/test_pthread_weak_ref.out diff --git a/ChangeLog.md b/ChangeLog.md index 53c25e67fe79c..50bcdca76fb20 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -30,6 +30,7 @@ See docs/process.md for more on how version tagging works. completely removes the need for the `REVERSE_DEPS` settings which has now been deprecated. (#18905) - Bump the default minimum Firefox version from 65 to 68 (#19191). +- Background pthreads no longer prevent a Node.js app from exiting. (#19073) 3.1.36 - 04/16/23 ----------------- diff --git a/src/library_pthread.js b/src/library_pthread.js index 170d9f5f0ed71..a630f0cd91240 100644 --- a/src/library_pthread.js +++ b/src/library_pthread.js @@ -211,11 +211,12 @@ var LibraryPThread = { // worker pool as an unused worker. worker.pthread_ptr = 0; -#if ENVIRONMENT_MAY_BE_NODE +#if ENVIRONMENT_MAY_BE_NODE && PROXY_TO_PTHREAD if (ENVIRONMENT_IS_NODE) { - // Once a pthread has finished and the worker becomes idle, mark it - // as weakly referenced so that its existence does not prevent Node.js - // from exiting. + // Once the proxied main thread has finished, mark it as weakly + // referenced so that its existence does not prevent Node.js from + // exiting. This has no effect if the worker is already weakly + // referenced. worker.unref(); } #endif @@ -286,7 +287,7 @@ var LibraryPThread = { cancelThread(d['thread']); } else if (cmd === 'loaded') { worker.loaded = true; -#if ENVIRONMENT_MAY_BE_NODE +#if ENVIRONMENT_MAY_BE_NODE && PTHREAD_POOL_SIZE // Check that this worker doesn't have an associated pthread. if (ENVIRONMENT_IS_NODE && !worker.pthread_ptr) { // Once worker is loaded & idle, mark it as weakly referenced, @@ -571,6 +572,19 @@ var LibraryPThread = { else postMessage({ 'cmd': 'cleanupThread', 'thread': thread }); }, + _emscripten_thread_set_strongref: function(thread) { + // Called when a thread needs to be strongly referenced. + // Currently only used for: + // - keeping the "main" thread alive in PROXY_TO_PTHREAD mode; + // - crashed threads that needs to propagate the uncaught exception + // back to the main thread. +#if ENVIRONMENT_MAY_BE_NODE + if (ENVIRONMENT_IS_NODE) { + PThread.pthreads[thread].ref(); + } +#endif + }, + $cleanupThread: function(pthread_ptr) { #if PTHREADS_DEBUG dbg('cleanupThread: ' + ptrToString(pthread_ptr)) @@ -674,14 +688,16 @@ var LibraryPThread = { msg.moduleCanvasId = threadParams.moduleCanvasId; msg.offscreenCanvases = threadParams.offscreenCanvases; #endif - // Ask the worker to start executing its pthread entry point function. #if ENVIRONMENT_MAY_BE_NODE if (ENVIRONMENT_IS_NODE) { - // Mark worker as strongly referenced once we start executing a pthread, - // so that Node.js doesn't exit while the pthread is running. - worker.ref(); + // Mark worker as weakly referenced once we start executing a pthread, + // so that its existence does not prevent Node.js from exiting. This + // has no effect if the worker is already weakly referenced (e.g. if + // this worker was previously idle/unused). + worker.unref(); } #endif + // Ask the worker to start executing its pthread entry point function. worker.postMessage(msg, threadParams.transferList); return 0; }, diff --git a/src/library_sigs.js b/src/library_sigs.js index c4086947097e4..51dae2f194323 100644 --- a/src/library_sigs.js +++ b/src/library_sigs.js @@ -290,6 +290,7 @@ sigs = { _emscripten_set_offscreencanvas_size__sig: 'ipii', _emscripten_thread_exit_joinable__sig: 'vp', _emscripten_thread_mailbox_await__sig: 'vp', + _emscripten_thread_set_strongref__sig: 'vp', _emscripten_throw_longjmp__sig: 'v', _gmtime_js__sig: 'vpp', _localtime_js__sig: 'vpp', diff --git a/system/lib/libc/crt1_proxy_main.c b/system/lib/libc/crt1_proxy_main.c index 7934aac0a6b21..458f69b9993ad 100644 --- a/system/lib/libc/crt1_proxy_main.c +++ b/system/lib/libc/crt1_proxy_main.c @@ -13,6 +13,8 @@ #include #include +#include "threading_internal.h" + static int _main_argc; static char** _main_argv; @@ -49,5 +51,10 @@ EMSCRIPTEN_KEEPALIVE int _emscripten_proxy_main(int argc, char** argv) { pthread_t thread; int rc = pthread_create(&thread, &attr, _main_thread, NULL); pthread_attr_destroy(&attr); + if (rc == 0) { + // Mark the thread as strongly referenced, so that Node.js doesn't exit + // while the pthread is running. + _emscripten_thread_set_strongref(thread); + } return rc; } diff --git a/system/lib/pthread/emscripten_yield.c b/system/lib/pthread/emscripten_yield.c index 007244960a41a..471b7c8dc93fd 100644 --- a/system/lib/pthread/emscripten_yield.c +++ b/system/lib/pthread/emscripten_yield.c @@ -7,10 +7,10 @@ #include "syscall.h" #include "threading_internal.h" -static _Atomic bool thread_crashed = false; +static _Atomic pthread_t crashed_thread_id = NULL; void _emscripten_thread_crashed() { - thread_crashed = true; + crashed_thread_id = pthread_self(); } static void dummy(double now) @@ -28,7 +28,11 @@ void _emscripten_yield(double now) { // allocate (or otherwise itself crash) so use a low level atomic primitive // for this signal. if (is_runtime_thread) { - if (thread_crashed) { + if (crashed_thread_id) { + // Mark the crashed thread as strongly referenced so that Node.js doesn't + // exit while the pthread is propagating the uncaught exception back to + // the main thread. + _emscripten_thread_set_strongref(crashed_thread_id); // Return the event loop so we can handle the message from the crashed // thread. emscripten_exit_with_live_runtime(); diff --git a/system/lib/pthread/threading_internal.h b/system/lib/pthread/threading_internal.h index fc5ab4bf947ca..a76f04e57ed97 100644 --- a/system/lib/pthread/threading_internal.h +++ b/system/lib/pthread/threading_internal.h @@ -118,6 +118,15 @@ void __emscripten_thread_cleanup(pthread_t thread); hidden void* _emscripten_tls_init(void); hidden void _emscripten_tls_free(void); +// Marks the given thread as strongly referenced. This is used to prevent the +// Node.js application from exiting as long as there are strongly referenced +// threads still running. Normally you don't need to call this function, and +// the pthread behaviour will match native in that background threads won't +// keep runtime alive, but waiting for them via e.g. pthread_join will. +// However, this is useful for features like PROXY_TO_PTHREAD where we want to +// keep running as long as the detached pthread is. +void _emscripten_thread_set_strongref(pthread_t thread); + // Checks certain structural invariants. This allows us to detect when // already-freed threads are used in some APIs. Technically this is undefined // behaviour, but we have a couple of places where we add these checks so that diff --git a/test/core/pthread/test_pthread_weak_ref.c b/test/core/pthread/test_pthread_weak_ref.c new file mode 100644 index 0000000000000..86fec4d0aaca1 --- /dev/null +++ b/test/core/pthread/test_pthread_weak_ref.c @@ -0,0 +1,44 @@ +#include +#include +#include +#include +#include + +pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + +bool running = false; + +void *worker_thread(void *arg) { + printf("worker_thread\n"); + + pthread_mutex_lock(&mutex); + running = true; + pthread_cond_signal(&cond); + pthread_mutex_unlock(&mutex); + + // Infinite loop + while (1) {} + + return NULL; +} + +int main() { + pthread_t thread; + + printf("main\n"); + int rc = pthread_create(&thread, NULL, worker_thread, NULL); + assert(rc == 0); + + pthread_mutex_lock(&mutex); + + // Wait until the thread executes its entry point + while (!running) { + pthread_cond_wait(&cond, &mutex); + } + + pthread_mutex_unlock(&mutex); + + printf("done\n"); + return 0; +} diff --git a/test/core/pthread/test_pthread_weak_ref.out b/test/core/pthread/test_pthread_weak_ref.out new file mode 100644 index 0000000000000..8d2e5b54e78c7 --- /dev/null +++ b/test/core/pthread/test_pthread_weak_ref.out @@ -0,0 +1,3 @@ +main +worker_thread +done diff --git a/test/other/metadce/test_metadce_minimal_pthreads.exports b/test/other/metadce/test_metadce_minimal_pthreads.exports index 9c917676e4d2a..fcb5627b2e747 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.exports +++ b/test/other/metadce/test_metadce_minimal_pthreads.exports @@ -4,7 +4,7 @@ C D E F -p +G q r s diff --git a/test/other/metadce/test_metadce_minimal_pthreads.imports b/test/other/metadce/test_metadce_minimal_pthreads.imports index fcc5923256f40..259d8061349ff 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.imports +++ b/test/other/metadce/test_metadce_minimal_pthreads.imports @@ -13,3 +13,4 @@ a.l a.m a.n a.o +a.p diff --git a/test/other/metadce/test_metadce_minimal_pthreads.jssize b/test/other/metadce/test_metadce_minimal_pthreads.jssize index 75f405c07dd20..408489c67ae57 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.jssize +++ b/test/other/metadce/test_metadce_minimal_pthreads.jssize @@ -1 +1 @@ -15547 +15593 diff --git a/test/other/metadce/test_metadce_minimal_pthreads.sent b/test/other/metadce/test_metadce_minimal_pthreads.sent index f8c295c135e5d..b03757ea914f6 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.sent +++ b/test/other/metadce/test_metadce_minimal_pthreads.sent @@ -13,3 +13,4 @@ l m n o +p diff --git a/test/other/metadce/test_metadce_minimal_pthreads.size b/test/other/metadce/test_metadce_minimal_pthreads.size index d68caa14c4ead..78ae000359105 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.size +++ b/test/other/metadce/test_metadce_minimal_pthreads.size @@ -1 +1 @@ -18994 +19019 diff --git a/test/test_core.py b/test/test_core.py index 66c7d983d8ee9..982780bf2f47d 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -9359,6 +9359,10 @@ def test_pthread_exit_process(self): def test_pthread_keepalive(self): self.do_run_in_out_file_test('core/pthread/test_pthread_keepalive.c') + @node_pthreads + def test_pthread_weak_ref(self): + self.do_run_in_out_file_test('core/pthread/test_pthread_weak_ref.c') + @node_pthreads def test_pthread_exit_main(self): self.do_run_in_out_file_test('core/pthread/test_pthread_exit_main.c') From f651079a7357378722ad5cd98b781ccc033cc23a Mon Sep 17 00:00:00 2001 From: juj Date: Sat, 22 Apr 2023 17:45:14 +0300 Subject: [PATCH 0158/1523] Add support for handling WebGL built-in preprocessor variables when custom preprocessor is in use (#19226) * Add support for handling WebGL built-in preprocessor variables GL_ES and __VERSION__, and add a note of __FILE__ and __LINE__ not being handled (since there is no apparent benefit/uses of these, and adding them would just increase code size). Add a unit test for these variables. * Address review --- src/library_webgl.js | 12 ++++- test/test_browser.py | 10 ++++ test/webgl_preprocessor_variables.c | 79 +++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 test/webgl_preprocessor_variables.c diff --git a/src/library_webgl.js b/src/library_webgl.js index 3e8ce10a61b0d..8c4d788c5d8cb 100644 --- a/src/library_webgl.js +++ b/src/library_webgl.js @@ -3038,9 +3038,19 @@ var LibraryGL = { #if GL_DEBUG dbg('Input shader source: ' + source); #endif + +#if ASSERTIONS + // These are not expected to be meaningful in WebGL, but issue a warning if they are present, to give some diagnostics about if they are present. + if (source.includes('__FILE__')) warnOnce(`When compiling shader: ${source}: Preprocessor variable __FILE__ is not handled by -sGL_EXPLICIT_UNIFORM_LOCATION/-sGL_EXPLICIT_UNIFORM_BINDING options!`); + if (source.includes('__LINE__')) warnOnce(`When compiling shader: ${source}: Preprocessor variable __LINE__ is not handled by -sGL_EXPLICIT_UNIFORM_LOCATION/-sGL_EXPLICIT_UNIFORM_BINDING options!`); +#endif // Remove comments and C-preprocess the input shader first, so that we can appropriately // parse the layout location directives. - source = preprocess_c_code(remove_cpp_comments_in_shaders(source), { 'GL_FRAGMENT_PRECISION_HIGH': function() { return 1; }}); + source = preprocess_c_code(remove_cpp_comments_in_shaders(source), { + 'GL_FRAGMENT_PRECISION_HIGH': () => 1, + 'GL_ES': () => 1, + '__VERSION__': () => source.includes('#version 300') ? 300 : 100 + }); #if GL_DEBUG dbg('Shader source after preprocessing: ' + source); #endif diff --git a/test/test_browser.py b/test/test_browser.py index eb1cd9266fc48..fd86fe0e134d6 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -2724,6 +2724,16 @@ def test_html5_webgl_api(self): continue self.btest_exit(test_file('html5_webgl.c'), args=['-sMAX_WEBGL_VERSION=2', '-lGL'] + mode) + @parameterized({ + 'webgl1': (['-DWEBGL_VERSION=1'],), + 'webgl2': (['-sMAX_WEBGL_VERSION=2', '-DWEBGL_VERSION=2'],), + 'webgl1_extensions': (['-DWEBGL_VERSION=1', '-sGL_EXPLICIT_UNIFORM_LOCATION'],), + 'webgl2_extensions': (['-sMAX_WEBGL_VERSION=2', '-DWEBGL_VERSION=2', '-sGL_EXPLICIT_UNIFORM_LOCATION', '-sGL_EXPLICIT_UNIFORM_BINDING'],), + }) + @requires_graphics_hardware + def test_webgl_preprocessor_variables(self, opts): + self.btest_exit(test_file('webgl_preprocessor_variables.c'), args=['-lGL'] + opts) + @requires_graphics_hardware def test_webgl2_ubos(self): self.btest_exit(test_file('webgl2_ubos.cpp'), args=['-sMAX_WEBGL_VERSION=2', '-lGL']) diff --git a/test/webgl_preprocessor_variables.c b/test/webgl_preprocessor_variables.c new file mode 100644 index 0000000000000..e58dcb129742e --- /dev/null +++ b/test/webgl_preprocessor_variables.c @@ -0,0 +1,79 @@ +#include +#include +#include +#include +#include +#include +#include + +void test(const char *src) +{ + GLuint shader = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(shader, 1, &src, NULL); + glCompileShader(shader); + printf("%s\n", emscripten_webgl_get_shader_info_log_utf8(shader)); + assert(emscripten_webgl_get_shader_parameter_d(shader, GL_COMPILE_STATUS) == 1); +} + +int main() +{ + EmscriptenWebGLContextAttributes attrs; + emscripten_webgl_init_context_attributes(&attrs); + attrs.majorVersion = WEBGL_VERSION; + EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context = emscripten_webgl_create_context("#canvas", &attrs); + emscripten_webgl_make_context_current(context); + + // Test the presence of GL_FRAGMENT_PRECISION_HIGH built-in preprocessor + test("#ifdef GL_FRAGMENT_PRECISION_HIGH\n" + "void main() {}\n" + "#endif"); + test("#if GL_FRAGMENT_PRECISION_HIGH == 1\n" + "void main() {}\n" + "#endif"); + + // Test GL_ES built-in preprocessor directive + test("#ifdef GL_ES\n" + "void main() {}\n" + "#endif"); + test("#if GL_ES == 1\n" + "void main() {}\n" + "#endif"); + test("#if GL_ES != 1\n" // Also check negation, i.e. that #if is not tautologically true + "error!\n" + "#else\n" + "void main() {}\n" + "#endif"); + + // Test __VERSION__ built-in preprocessor directive. + // Note that when WebGL 2 contexts are created, shaders + // still default to #version 100, unless explicit + // "#version 300 es" is specified. + test("#ifdef __VERSION__\n" + "void main() {}\n" + "#endif"); + test("#if __VERSION__ == 100\n" + "void main() {}\n" + "#endif"); + test("#if defined(GL_ES) && __VERSION__ < 300\n" + "void main() {}\n" + "#endif"); + test("#if !defined(GL_ES) || __VERSION__ >= 300\n" // for good measure, check via negation + "error!\n" + "#else\n" + "void main() {}\n" + "#endif"); + +#if WEBGL_VERSION >= 2 + test("#version 100\n" + "#if __VERSION__ == 300\n" + "error!\n" + "#endif\n" + "void main() {}"); + test("#version 300 es\n" + "#if __VERSION__ == 300\n" + "void main() {}\n" + "#endif"); +#endif + + return 0; +} From e8535a814a96039279c33017449805b0ddb64578 Mon Sep 17 00:00:00 2001 From: juj Date: Sat, 22 Apr 2023 17:51:06 +0300 Subject: [PATCH 0159/1523] Work around Windows bug https://github.com/microsoft/terminal/issues/15212 (#19212) * Work around Windows bug https://github.com/microsoft/terminal/issues/15212 where %~dp0 expansion is broken, by attempting to look up emcc first in EMSCRIPTEN, and then in PATH if it cannot be expanded to via %~dp0. Add a new test other.test_windows_batch_file_dp0_expansion_bug to check for this scenario. * Update bat scripts to avoid ':' inside if() blocks. --- em++.bat | 28 ++++++++++++++++++++++++++-- em-config.bat | 32 ++++++++++++++++++++++++++++---- emar.bat | 32 ++++++++++++++++++++++++++++---- embuilder.bat | 32 ++++++++++++++++++++++++++++---- emcc.bat | 28 ++++++++++++++++++++++++++-- emcmake.bat | 32 ++++++++++++++++++++++++++++---- emconfigure.bat | 32 ++++++++++++++++++++++++++++---- emdump.bat | 32 ++++++++++++++++++++++++++++---- emdwp.bat | 32 ++++++++++++++++++++++++++++---- emmake.bat | 32 ++++++++++++++++++++++++++++---- emnm.bat | 32 ++++++++++++++++++++++++++++---- emprofile.bat | 32 ++++++++++++++++++++++++++++---- emranlib.bat | 32 ++++++++++++++++++++++++++++---- emrun.bat | 32 ++++++++++++++++++++++++++++---- emscons.bat | 32 ++++++++++++++++++++++++++++---- emsize.bat | 32 ++++++++++++++++++++++++++++---- emstrip.bat | 32 ++++++++++++++++++++++++++++---- emsymbolizer.bat | 32 ++++++++++++++++++++++++++++---- system/bin/sdl-config.bat | 32 ++++++++++++++++++++++++++++---- system/bin/sdl2-config.bat | 32 ++++++++++++++++++++++++++++---- test/common.py | 7 +++++++ test/runner.bat | 32 ++++++++++++++++++++++++++++---- test/test_other.py | 8 +++++++- tools/file_packager.bat | 32 ++++++++++++++++++++++++++++---- tools/run_python.bat | 32 ++++++++++++++++++++++++++++---- tools/run_python_compiler.bat | 28 ++++++++++++++++++++++++++-- tools/webidl_binder.bat | 32 ++++++++++++++++++++++++++++---- 27 files changed, 708 insertions(+), 95 deletions(-) diff --git a/em++.bat b/em++.bat index cc5e8d3cfd59c..86ae9bb841f35 100644 --- a/em++.bat +++ b/em++.bat @@ -5,6 +5,9 @@ :: To make modifications to this file, edit `tools/run_python_compiler.bat` and :: then run `tools/create_entry_points.py` +:: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, +:: or there will be a parsing error. + :: All env. vars specified in this file are to be local only to this script. @setlocal :: -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal @@ -15,13 +18,34 @@ set EM_PY=python ) +:: Work around Windows bug https://github.com/microsoft/terminal/issues/15212 : If this +:: script is invoked via enclosing the invocation in quotes via PATH lookup, then %~f0 and +:: %~dp0 expansions will not work. +:: So first try if %~dp0 might work, and if not, manually look up this script from PATH. +@if exist %~f0 ( + set MYDIR=%~dp0 + goto FOUND_MYDIR +) +@for %%I in (%~n0.bat) do ( + @if exist %%~$PATH:I ( + set MYDIR=%%~dp$PATH:I + ) else ( + echo Fatal Error! Due to a Windows bug, we are unable to locate the path to %~n0.bat. + echo To help this issue, try removing unnecessary quotes in the invocation of emcc, + echo or add Emscripten directory to PATH. + echo See github.com/microsoft/terminal/issues/15212 and + echo github.com/emscripten-core/emscripten/issues/19207 for more details. + ) +) +:FOUND_MYDIR + :: If _EMCC_CCACHE is not set, do a regular invocation of the python compiler driver. :: Otherwise remove the ccache env. var, and then reinvoke this script with ccache enabled. @if "%_EMCC_CCACHE%"=="" ( - set CMD="%EM_PY%" -E "%~dp0\%~n0.py" + set CMD="%EM_PY%" -E "%MYDIR%%~n0.py" ) else ( set _EMCC_CCACHE= - set CMD=ccache "%~dp0\%~n0.bat" + set CMD=ccache "%MYDIR%%~n0.bat" ) :: Python Windows bug https://bugs.python.org/issue34780: If this script was invoked via a diff --git a/em-config.bat b/em-config.bat index 84872e7a0b933..34900168d5856 100644 --- a/em-config.bat +++ b/em-config.bat @@ -5,6 +5,9 @@ :: To make modifications to this file, edit `tools/run_python.bat` and then run :: `tools/create_entry_points.py` +:: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, +:: or there will be a parsing error. + :: All env. vars specified in this file are to be local only to this script. @setlocal :: -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal @@ -15,6 +18,27 @@ set EM_PY=python ) +:: Work around Windows bug https://github.com/microsoft/terminal/issues/15212 : If this +:: script is invoked via enclosing the invocation in quotes via PATH lookup, then %~f0 and +:: %~dp0 expansions will not work. +:: So first try if %~dp0 might work, and if not, manually look up this script from PATH. +@if exist %~f0 ( + set MYDIR=%~dp0 + goto FOUND_MYDIR +) +@for %%I in (%~n0.bat) do ( + @if exist %%~$PATH:I ( + set MYDIR=%%~dp$PATH:I + ) else ( + echo Fatal Error! Due to a Windows bug, we are unable to locate the path to %~n0.bat. + echo To help this issue, try removing unnecessary quotes in the invocation of emcc, + echo or add Emscripten directory to PATH. + echo See github.com/microsoft/terminal/issues/15212 and + echo github.com/emscripten-core/emscripten/issues/19207 for more details. + ) +) +:FOUND_MYDIR + :: Python Windows bug https://bugs.python.org/issue34780: If this script was invoked via a :: shared stdin handle from the parent process, and that parent process stdin handle is in :: a certain state, running python.exe might hang here. To work around this, if @@ -47,16 +71,16 @@ ) :NORMAL_EXIT -@"%EM_PY%" -E "%~dp0\%~n0.py" %* +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* @exit %ERRORLEVEL% :MUTE_STDIN -@"%EM_PY%" -E "%~dp0\%~n0.py" %* < NUL +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* < NUL @exit /b %ERRORLEVEL% :MUTE_STDIN_EXIT -@"%EM_PY%" -E "%~dp0\%~n0.py" %* < NUL +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* < NUL @exit %ERRORLEVEL% :NORMAL -@"%EM_PY%" -E "%~dp0\%~n0.py" %* +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* diff --git a/emar.bat b/emar.bat index 84872e7a0b933..34900168d5856 100644 --- a/emar.bat +++ b/emar.bat @@ -5,6 +5,9 @@ :: To make modifications to this file, edit `tools/run_python.bat` and then run :: `tools/create_entry_points.py` +:: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, +:: or there will be a parsing error. + :: All env. vars specified in this file are to be local only to this script. @setlocal :: -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal @@ -15,6 +18,27 @@ set EM_PY=python ) +:: Work around Windows bug https://github.com/microsoft/terminal/issues/15212 : If this +:: script is invoked via enclosing the invocation in quotes via PATH lookup, then %~f0 and +:: %~dp0 expansions will not work. +:: So first try if %~dp0 might work, and if not, manually look up this script from PATH. +@if exist %~f0 ( + set MYDIR=%~dp0 + goto FOUND_MYDIR +) +@for %%I in (%~n0.bat) do ( + @if exist %%~$PATH:I ( + set MYDIR=%%~dp$PATH:I + ) else ( + echo Fatal Error! Due to a Windows bug, we are unable to locate the path to %~n0.bat. + echo To help this issue, try removing unnecessary quotes in the invocation of emcc, + echo or add Emscripten directory to PATH. + echo See github.com/microsoft/terminal/issues/15212 and + echo github.com/emscripten-core/emscripten/issues/19207 for more details. + ) +) +:FOUND_MYDIR + :: Python Windows bug https://bugs.python.org/issue34780: If this script was invoked via a :: shared stdin handle from the parent process, and that parent process stdin handle is in :: a certain state, running python.exe might hang here. To work around this, if @@ -47,16 +71,16 @@ ) :NORMAL_EXIT -@"%EM_PY%" -E "%~dp0\%~n0.py" %* +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* @exit %ERRORLEVEL% :MUTE_STDIN -@"%EM_PY%" -E "%~dp0\%~n0.py" %* < NUL +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* < NUL @exit /b %ERRORLEVEL% :MUTE_STDIN_EXIT -@"%EM_PY%" -E "%~dp0\%~n0.py" %* < NUL +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* < NUL @exit %ERRORLEVEL% :NORMAL -@"%EM_PY%" -E "%~dp0\%~n0.py" %* +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* diff --git a/embuilder.bat b/embuilder.bat index 84872e7a0b933..34900168d5856 100644 --- a/embuilder.bat +++ b/embuilder.bat @@ -5,6 +5,9 @@ :: To make modifications to this file, edit `tools/run_python.bat` and then run :: `tools/create_entry_points.py` +:: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, +:: or there will be a parsing error. + :: All env. vars specified in this file are to be local only to this script. @setlocal :: -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal @@ -15,6 +18,27 @@ set EM_PY=python ) +:: Work around Windows bug https://github.com/microsoft/terminal/issues/15212 : If this +:: script is invoked via enclosing the invocation in quotes via PATH lookup, then %~f0 and +:: %~dp0 expansions will not work. +:: So first try if %~dp0 might work, and if not, manually look up this script from PATH. +@if exist %~f0 ( + set MYDIR=%~dp0 + goto FOUND_MYDIR +) +@for %%I in (%~n0.bat) do ( + @if exist %%~$PATH:I ( + set MYDIR=%%~dp$PATH:I + ) else ( + echo Fatal Error! Due to a Windows bug, we are unable to locate the path to %~n0.bat. + echo To help this issue, try removing unnecessary quotes in the invocation of emcc, + echo or add Emscripten directory to PATH. + echo See github.com/microsoft/terminal/issues/15212 and + echo github.com/emscripten-core/emscripten/issues/19207 for more details. + ) +) +:FOUND_MYDIR + :: Python Windows bug https://bugs.python.org/issue34780: If this script was invoked via a :: shared stdin handle from the parent process, and that parent process stdin handle is in :: a certain state, running python.exe might hang here. To work around this, if @@ -47,16 +71,16 @@ ) :NORMAL_EXIT -@"%EM_PY%" -E "%~dp0\%~n0.py" %* +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* @exit %ERRORLEVEL% :MUTE_STDIN -@"%EM_PY%" -E "%~dp0\%~n0.py" %* < NUL +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* < NUL @exit /b %ERRORLEVEL% :MUTE_STDIN_EXIT -@"%EM_PY%" -E "%~dp0\%~n0.py" %* < NUL +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* < NUL @exit %ERRORLEVEL% :NORMAL -@"%EM_PY%" -E "%~dp0\%~n0.py" %* +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* diff --git a/emcc.bat b/emcc.bat index cc5e8d3cfd59c..86ae9bb841f35 100644 --- a/emcc.bat +++ b/emcc.bat @@ -5,6 +5,9 @@ :: To make modifications to this file, edit `tools/run_python_compiler.bat` and :: then run `tools/create_entry_points.py` +:: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, +:: or there will be a parsing error. + :: All env. vars specified in this file are to be local only to this script. @setlocal :: -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal @@ -15,13 +18,34 @@ set EM_PY=python ) +:: Work around Windows bug https://github.com/microsoft/terminal/issues/15212 : If this +:: script is invoked via enclosing the invocation in quotes via PATH lookup, then %~f0 and +:: %~dp0 expansions will not work. +:: So first try if %~dp0 might work, and if not, manually look up this script from PATH. +@if exist %~f0 ( + set MYDIR=%~dp0 + goto FOUND_MYDIR +) +@for %%I in (%~n0.bat) do ( + @if exist %%~$PATH:I ( + set MYDIR=%%~dp$PATH:I + ) else ( + echo Fatal Error! Due to a Windows bug, we are unable to locate the path to %~n0.bat. + echo To help this issue, try removing unnecessary quotes in the invocation of emcc, + echo or add Emscripten directory to PATH. + echo See github.com/microsoft/terminal/issues/15212 and + echo github.com/emscripten-core/emscripten/issues/19207 for more details. + ) +) +:FOUND_MYDIR + :: If _EMCC_CCACHE is not set, do a regular invocation of the python compiler driver. :: Otherwise remove the ccache env. var, and then reinvoke this script with ccache enabled. @if "%_EMCC_CCACHE%"=="" ( - set CMD="%EM_PY%" -E "%~dp0\%~n0.py" + set CMD="%EM_PY%" -E "%MYDIR%%~n0.py" ) else ( set _EMCC_CCACHE= - set CMD=ccache "%~dp0\%~n0.bat" + set CMD=ccache "%MYDIR%%~n0.bat" ) :: Python Windows bug https://bugs.python.org/issue34780: If this script was invoked via a diff --git a/emcmake.bat b/emcmake.bat index 84872e7a0b933..34900168d5856 100644 --- a/emcmake.bat +++ b/emcmake.bat @@ -5,6 +5,9 @@ :: To make modifications to this file, edit `tools/run_python.bat` and then run :: `tools/create_entry_points.py` +:: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, +:: or there will be a parsing error. + :: All env. vars specified in this file are to be local only to this script. @setlocal :: -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal @@ -15,6 +18,27 @@ set EM_PY=python ) +:: Work around Windows bug https://github.com/microsoft/terminal/issues/15212 : If this +:: script is invoked via enclosing the invocation in quotes via PATH lookup, then %~f0 and +:: %~dp0 expansions will not work. +:: So first try if %~dp0 might work, and if not, manually look up this script from PATH. +@if exist %~f0 ( + set MYDIR=%~dp0 + goto FOUND_MYDIR +) +@for %%I in (%~n0.bat) do ( + @if exist %%~$PATH:I ( + set MYDIR=%%~dp$PATH:I + ) else ( + echo Fatal Error! Due to a Windows bug, we are unable to locate the path to %~n0.bat. + echo To help this issue, try removing unnecessary quotes in the invocation of emcc, + echo or add Emscripten directory to PATH. + echo See github.com/microsoft/terminal/issues/15212 and + echo github.com/emscripten-core/emscripten/issues/19207 for more details. + ) +) +:FOUND_MYDIR + :: Python Windows bug https://bugs.python.org/issue34780: If this script was invoked via a :: shared stdin handle from the parent process, and that parent process stdin handle is in :: a certain state, running python.exe might hang here. To work around this, if @@ -47,16 +71,16 @@ ) :NORMAL_EXIT -@"%EM_PY%" -E "%~dp0\%~n0.py" %* +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* @exit %ERRORLEVEL% :MUTE_STDIN -@"%EM_PY%" -E "%~dp0\%~n0.py" %* < NUL +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* < NUL @exit /b %ERRORLEVEL% :MUTE_STDIN_EXIT -@"%EM_PY%" -E "%~dp0\%~n0.py" %* < NUL +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* < NUL @exit %ERRORLEVEL% :NORMAL -@"%EM_PY%" -E "%~dp0\%~n0.py" %* +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* diff --git a/emconfigure.bat b/emconfigure.bat index 84872e7a0b933..34900168d5856 100644 --- a/emconfigure.bat +++ b/emconfigure.bat @@ -5,6 +5,9 @@ :: To make modifications to this file, edit `tools/run_python.bat` and then run :: `tools/create_entry_points.py` +:: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, +:: or there will be a parsing error. + :: All env. vars specified in this file are to be local only to this script. @setlocal :: -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal @@ -15,6 +18,27 @@ set EM_PY=python ) +:: Work around Windows bug https://github.com/microsoft/terminal/issues/15212 : If this +:: script is invoked via enclosing the invocation in quotes via PATH lookup, then %~f0 and +:: %~dp0 expansions will not work. +:: So first try if %~dp0 might work, and if not, manually look up this script from PATH. +@if exist %~f0 ( + set MYDIR=%~dp0 + goto FOUND_MYDIR +) +@for %%I in (%~n0.bat) do ( + @if exist %%~$PATH:I ( + set MYDIR=%%~dp$PATH:I + ) else ( + echo Fatal Error! Due to a Windows bug, we are unable to locate the path to %~n0.bat. + echo To help this issue, try removing unnecessary quotes in the invocation of emcc, + echo or add Emscripten directory to PATH. + echo See github.com/microsoft/terminal/issues/15212 and + echo github.com/emscripten-core/emscripten/issues/19207 for more details. + ) +) +:FOUND_MYDIR + :: Python Windows bug https://bugs.python.org/issue34780: If this script was invoked via a :: shared stdin handle from the parent process, and that parent process stdin handle is in :: a certain state, running python.exe might hang here. To work around this, if @@ -47,16 +71,16 @@ ) :NORMAL_EXIT -@"%EM_PY%" -E "%~dp0\%~n0.py" %* +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* @exit %ERRORLEVEL% :MUTE_STDIN -@"%EM_PY%" -E "%~dp0\%~n0.py" %* < NUL +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* < NUL @exit /b %ERRORLEVEL% :MUTE_STDIN_EXIT -@"%EM_PY%" -E "%~dp0\%~n0.py" %* < NUL +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* < NUL @exit %ERRORLEVEL% :NORMAL -@"%EM_PY%" -E "%~dp0\%~n0.py" %* +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* diff --git a/emdump.bat b/emdump.bat index 3b921317678c3..c0d7d3ecd28e8 100644 --- a/emdump.bat +++ b/emdump.bat @@ -5,6 +5,9 @@ :: To make modifications to this file, edit `tools/run_python.bat` and then run :: `tools/create_entry_points.py` +:: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, +:: or there will be a parsing error. + :: All env. vars specified in this file are to be local only to this script. @setlocal :: -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal @@ -15,6 +18,27 @@ set EM_PY=python ) +:: Work around Windows bug https://github.com/microsoft/terminal/issues/15212 : If this +:: script is invoked via enclosing the invocation in quotes via PATH lookup, then %~f0 and +:: %~dp0 expansions will not work. +:: So first try if %~dp0 might work, and if not, manually look up this script from PATH. +@if exist %~f0 ( + set MYDIR=%~dp0 + goto FOUND_MYDIR +) +@for %%I in (tools\emdump.bat) do ( + @if exist %%~$PATH:I ( + set MYDIR=%%~dp$PATH:I + ) else ( + echo Fatal Error! Due to a Windows bug, we are unable to locate the path to tools\emdump.bat. + echo To help this issue, try removing unnecessary quotes in the invocation of emcc, + echo or add Emscripten directory to PATH. + echo See github.com/microsoft/terminal/issues/15212 and + echo github.com/emscripten-core/emscripten/issues/19207 for more details. + ) +) +:FOUND_MYDIR + :: Python Windows bug https://bugs.python.org/issue34780: If this script was invoked via a :: shared stdin handle from the parent process, and that parent process stdin handle is in :: a certain state, running python.exe might hang here. To work around this, if @@ -47,16 +71,16 @@ ) :NORMAL_EXIT -@"%EM_PY%" -E "%~dp0\tools\emdump.py" %* +@"%EM_PY%" -E "%MYDIR%tools\emdump.py" %* @exit %ERRORLEVEL% :MUTE_STDIN -@"%EM_PY%" -E "%~dp0\tools\emdump.py" %* < NUL +@"%EM_PY%" -E "%MYDIR%tools\emdump.py" %* < NUL @exit /b %ERRORLEVEL% :MUTE_STDIN_EXIT -@"%EM_PY%" -E "%~dp0\tools\emdump.py" %* < NUL +@"%EM_PY%" -E "%MYDIR%tools\emdump.py" %* < NUL @exit %ERRORLEVEL% :NORMAL -@"%EM_PY%" -E "%~dp0\tools\emdump.py" %* +@"%EM_PY%" -E "%MYDIR%tools\emdump.py" %* diff --git a/emdwp.bat b/emdwp.bat index cfae2d0a47f25..3c056794f3564 100644 --- a/emdwp.bat +++ b/emdwp.bat @@ -5,6 +5,9 @@ :: To make modifications to this file, edit `tools/run_python.bat` and then run :: `tools/create_entry_points.py` +:: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, +:: or there will be a parsing error. + :: All env. vars specified in this file are to be local only to this script. @setlocal :: -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal @@ -15,6 +18,27 @@ set EM_PY=python ) +:: Work around Windows bug https://github.com/microsoft/terminal/issues/15212 : If this +:: script is invoked via enclosing the invocation in quotes via PATH lookup, then %~f0 and +:: %~dp0 expansions will not work. +:: So first try if %~dp0 might work, and if not, manually look up this script from PATH. +@if exist %~f0 ( + set MYDIR=%~dp0 + goto FOUND_MYDIR +) +@for %%I in (tools\emdwp.bat) do ( + @if exist %%~$PATH:I ( + set MYDIR=%%~dp$PATH:I + ) else ( + echo Fatal Error! Due to a Windows bug, we are unable to locate the path to tools\emdwp.bat. + echo To help this issue, try removing unnecessary quotes in the invocation of emcc, + echo or add Emscripten directory to PATH. + echo See github.com/microsoft/terminal/issues/15212 and + echo github.com/emscripten-core/emscripten/issues/19207 for more details. + ) +) +:FOUND_MYDIR + :: Python Windows bug https://bugs.python.org/issue34780: If this script was invoked via a :: shared stdin handle from the parent process, and that parent process stdin handle is in :: a certain state, running python.exe might hang here. To work around this, if @@ -47,16 +71,16 @@ ) :NORMAL_EXIT -@"%EM_PY%" -E "%~dp0\tools\emdwp.py" %* +@"%EM_PY%" -E "%MYDIR%tools\emdwp.py" %* @exit %ERRORLEVEL% :MUTE_STDIN -@"%EM_PY%" -E "%~dp0\tools\emdwp.py" %* < NUL +@"%EM_PY%" -E "%MYDIR%tools\emdwp.py" %* < NUL @exit /b %ERRORLEVEL% :MUTE_STDIN_EXIT -@"%EM_PY%" -E "%~dp0\tools\emdwp.py" %* < NUL +@"%EM_PY%" -E "%MYDIR%tools\emdwp.py" %* < NUL @exit %ERRORLEVEL% :NORMAL -@"%EM_PY%" -E "%~dp0\tools\emdwp.py" %* +@"%EM_PY%" -E "%MYDIR%tools\emdwp.py" %* diff --git a/emmake.bat b/emmake.bat index 84872e7a0b933..34900168d5856 100644 --- a/emmake.bat +++ b/emmake.bat @@ -5,6 +5,9 @@ :: To make modifications to this file, edit `tools/run_python.bat` and then run :: `tools/create_entry_points.py` +:: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, +:: or there will be a parsing error. + :: All env. vars specified in this file are to be local only to this script. @setlocal :: -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal @@ -15,6 +18,27 @@ set EM_PY=python ) +:: Work around Windows bug https://github.com/microsoft/terminal/issues/15212 : If this +:: script is invoked via enclosing the invocation in quotes via PATH lookup, then %~f0 and +:: %~dp0 expansions will not work. +:: So first try if %~dp0 might work, and if not, manually look up this script from PATH. +@if exist %~f0 ( + set MYDIR=%~dp0 + goto FOUND_MYDIR +) +@for %%I in (%~n0.bat) do ( + @if exist %%~$PATH:I ( + set MYDIR=%%~dp$PATH:I + ) else ( + echo Fatal Error! Due to a Windows bug, we are unable to locate the path to %~n0.bat. + echo To help this issue, try removing unnecessary quotes in the invocation of emcc, + echo or add Emscripten directory to PATH. + echo See github.com/microsoft/terminal/issues/15212 and + echo github.com/emscripten-core/emscripten/issues/19207 for more details. + ) +) +:FOUND_MYDIR + :: Python Windows bug https://bugs.python.org/issue34780: If this script was invoked via a :: shared stdin handle from the parent process, and that parent process stdin handle is in :: a certain state, running python.exe might hang here. To work around this, if @@ -47,16 +71,16 @@ ) :NORMAL_EXIT -@"%EM_PY%" -E "%~dp0\%~n0.py" %* +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* @exit %ERRORLEVEL% :MUTE_STDIN -@"%EM_PY%" -E "%~dp0\%~n0.py" %* < NUL +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* < NUL @exit /b %ERRORLEVEL% :MUTE_STDIN_EXIT -@"%EM_PY%" -E "%~dp0\%~n0.py" %* < NUL +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* < NUL @exit %ERRORLEVEL% :NORMAL -@"%EM_PY%" -E "%~dp0\%~n0.py" %* +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* diff --git a/emnm.bat b/emnm.bat index d22226e2fb38b..4257155a7a8d9 100644 --- a/emnm.bat +++ b/emnm.bat @@ -5,6 +5,9 @@ :: To make modifications to this file, edit `tools/run_python.bat` and then run :: `tools/create_entry_points.py` +:: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, +:: or there will be a parsing error. + :: All env. vars specified in this file are to be local only to this script. @setlocal :: -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal @@ -15,6 +18,27 @@ set EM_PY=python ) +:: Work around Windows bug https://github.com/microsoft/terminal/issues/15212 : If this +:: script is invoked via enclosing the invocation in quotes via PATH lookup, then %~f0 and +:: %~dp0 expansions will not work. +:: So first try if %~dp0 might work, and if not, manually look up this script from PATH. +@if exist %~f0 ( + set MYDIR=%~dp0 + goto FOUND_MYDIR +) +@for %%I in (tools\emnm.bat) do ( + @if exist %%~$PATH:I ( + set MYDIR=%%~dp$PATH:I + ) else ( + echo Fatal Error! Due to a Windows bug, we are unable to locate the path to tools\emnm.bat. + echo To help this issue, try removing unnecessary quotes in the invocation of emcc, + echo or add Emscripten directory to PATH. + echo See github.com/microsoft/terminal/issues/15212 and + echo github.com/emscripten-core/emscripten/issues/19207 for more details. + ) +) +:FOUND_MYDIR + :: Python Windows bug https://bugs.python.org/issue34780: If this script was invoked via a :: shared stdin handle from the parent process, and that parent process stdin handle is in :: a certain state, running python.exe might hang here. To work around this, if @@ -47,16 +71,16 @@ ) :NORMAL_EXIT -@"%EM_PY%" -E "%~dp0\tools\emnm.py" %* +@"%EM_PY%" -E "%MYDIR%tools\emnm.py" %* @exit %ERRORLEVEL% :MUTE_STDIN -@"%EM_PY%" -E "%~dp0\tools\emnm.py" %* < NUL +@"%EM_PY%" -E "%MYDIR%tools\emnm.py" %* < NUL @exit /b %ERRORLEVEL% :MUTE_STDIN_EXIT -@"%EM_PY%" -E "%~dp0\tools\emnm.py" %* < NUL +@"%EM_PY%" -E "%MYDIR%tools\emnm.py" %* < NUL @exit %ERRORLEVEL% :NORMAL -@"%EM_PY%" -E "%~dp0\tools\emnm.py" %* +@"%EM_PY%" -E "%MYDIR%tools\emnm.py" %* diff --git a/emprofile.bat b/emprofile.bat index 78aeb4ed8b065..5908117caad95 100644 --- a/emprofile.bat +++ b/emprofile.bat @@ -5,6 +5,9 @@ :: To make modifications to this file, edit `tools/run_python.bat` and then run :: `tools/create_entry_points.py` +:: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, +:: or there will be a parsing error. + :: All env. vars specified in this file are to be local only to this script. @setlocal :: -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal @@ -15,6 +18,27 @@ set EM_PY=python ) +:: Work around Windows bug https://github.com/microsoft/terminal/issues/15212 : If this +:: script is invoked via enclosing the invocation in quotes via PATH lookup, then %~f0 and +:: %~dp0 expansions will not work. +:: So first try if %~dp0 might work, and if not, manually look up this script from PATH. +@if exist %~f0 ( + set MYDIR=%~dp0 + goto FOUND_MYDIR +) +@for %%I in (tools\emprofile.bat) do ( + @if exist %%~$PATH:I ( + set MYDIR=%%~dp$PATH:I + ) else ( + echo Fatal Error! Due to a Windows bug, we are unable to locate the path to tools\emprofile.bat. + echo To help this issue, try removing unnecessary quotes in the invocation of emcc, + echo or add Emscripten directory to PATH. + echo See github.com/microsoft/terminal/issues/15212 and + echo github.com/emscripten-core/emscripten/issues/19207 for more details. + ) +) +:FOUND_MYDIR + :: Python Windows bug https://bugs.python.org/issue34780: If this script was invoked via a :: shared stdin handle from the parent process, and that parent process stdin handle is in :: a certain state, running python.exe might hang here. To work around this, if @@ -47,16 +71,16 @@ ) :NORMAL_EXIT -@"%EM_PY%" -E "%~dp0\tools\emprofile.py" %* +@"%EM_PY%" -E "%MYDIR%tools\emprofile.py" %* @exit %ERRORLEVEL% :MUTE_STDIN -@"%EM_PY%" -E "%~dp0\tools\emprofile.py" %* < NUL +@"%EM_PY%" -E "%MYDIR%tools\emprofile.py" %* < NUL @exit /b %ERRORLEVEL% :MUTE_STDIN_EXIT -@"%EM_PY%" -E "%~dp0\tools\emprofile.py" %* < NUL +@"%EM_PY%" -E "%MYDIR%tools\emprofile.py" %* < NUL @exit %ERRORLEVEL% :NORMAL -@"%EM_PY%" -E "%~dp0\tools\emprofile.py" %* +@"%EM_PY%" -E "%MYDIR%tools\emprofile.py" %* diff --git a/emranlib.bat b/emranlib.bat index 84872e7a0b933..34900168d5856 100644 --- a/emranlib.bat +++ b/emranlib.bat @@ -5,6 +5,9 @@ :: To make modifications to this file, edit `tools/run_python.bat` and then run :: `tools/create_entry_points.py` +:: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, +:: or there will be a parsing error. + :: All env. vars specified in this file are to be local only to this script. @setlocal :: -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal @@ -15,6 +18,27 @@ set EM_PY=python ) +:: Work around Windows bug https://github.com/microsoft/terminal/issues/15212 : If this +:: script is invoked via enclosing the invocation in quotes via PATH lookup, then %~f0 and +:: %~dp0 expansions will not work. +:: So first try if %~dp0 might work, and if not, manually look up this script from PATH. +@if exist %~f0 ( + set MYDIR=%~dp0 + goto FOUND_MYDIR +) +@for %%I in (%~n0.bat) do ( + @if exist %%~$PATH:I ( + set MYDIR=%%~dp$PATH:I + ) else ( + echo Fatal Error! Due to a Windows bug, we are unable to locate the path to %~n0.bat. + echo To help this issue, try removing unnecessary quotes in the invocation of emcc, + echo or add Emscripten directory to PATH. + echo See github.com/microsoft/terminal/issues/15212 and + echo github.com/emscripten-core/emscripten/issues/19207 for more details. + ) +) +:FOUND_MYDIR + :: Python Windows bug https://bugs.python.org/issue34780: If this script was invoked via a :: shared stdin handle from the parent process, and that parent process stdin handle is in :: a certain state, running python.exe might hang here. To work around this, if @@ -47,16 +71,16 @@ ) :NORMAL_EXIT -@"%EM_PY%" -E "%~dp0\%~n0.py" %* +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* @exit %ERRORLEVEL% :MUTE_STDIN -@"%EM_PY%" -E "%~dp0\%~n0.py" %* < NUL +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* < NUL @exit /b %ERRORLEVEL% :MUTE_STDIN_EXIT -@"%EM_PY%" -E "%~dp0\%~n0.py" %* < NUL +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* < NUL @exit %ERRORLEVEL% :NORMAL -@"%EM_PY%" -E "%~dp0\%~n0.py" %* +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* diff --git a/emrun.bat b/emrun.bat index 84872e7a0b933..34900168d5856 100644 --- a/emrun.bat +++ b/emrun.bat @@ -5,6 +5,9 @@ :: To make modifications to this file, edit `tools/run_python.bat` and then run :: `tools/create_entry_points.py` +:: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, +:: or there will be a parsing error. + :: All env. vars specified in this file are to be local only to this script. @setlocal :: -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal @@ -15,6 +18,27 @@ set EM_PY=python ) +:: Work around Windows bug https://github.com/microsoft/terminal/issues/15212 : If this +:: script is invoked via enclosing the invocation in quotes via PATH lookup, then %~f0 and +:: %~dp0 expansions will not work. +:: So first try if %~dp0 might work, and if not, manually look up this script from PATH. +@if exist %~f0 ( + set MYDIR=%~dp0 + goto FOUND_MYDIR +) +@for %%I in (%~n0.bat) do ( + @if exist %%~$PATH:I ( + set MYDIR=%%~dp$PATH:I + ) else ( + echo Fatal Error! Due to a Windows bug, we are unable to locate the path to %~n0.bat. + echo To help this issue, try removing unnecessary quotes in the invocation of emcc, + echo or add Emscripten directory to PATH. + echo See github.com/microsoft/terminal/issues/15212 and + echo github.com/emscripten-core/emscripten/issues/19207 for more details. + ) +) +:FOUND_MYDIR + :: Python Windows bug https://bugs.python.org/issue34780: If this script was invoked via a :: shared stdin handle from the parent process, and that parent process stdin handle is in :: a certain state, running python.exe might hang here. To work around this, if @@ -47,16 +71,16 @@ ) :NORMAL_EXIT -@"%EM_PY%" -E "%~dp0\%~n0.py" %* +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* @exit %ERRORLEVEL% :MUTE_STDIN -@"%EM_PY%" -E "%~dp0\%~n0.py" %* < NUL +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* < NUL @exit /b %ERRORLEVEL% :MUTE_STDIN_EXIT -@"%EM_PY%" -E "%~dp0\%~n0.py" %* < NUL +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* < NUL @exit %ERRORLEVEL% :NORMAL -@"%EM_PY%" -E "%~dp0\%~n0.py" %* +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* diff --git a/emscons.bat b/emscons.bat index 84872e7a0b933..34900168d5856 100644 --- a/emscons.bat +++ b/emscons.bat @@ -5,6 +5,9 @@ :: To make modifications to this file, edit `tools/run_python.bat` and then run :: `tools/create_entry_points.py` +:: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, +:: or there will be a parsing error. + :: All env. vars specified in this file are to be local only to this script. @setlocal :: -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal @@ -15,6 +18,27 @@ set EM_PY=python ) +:: Work around Windows bug https://github.com/microsoft/terminal/issues/15212 : If this +:: script is invoked via enclosing the invocation in quotes via PATH lookup, then %~f0 and +:: %~dp0 expansions will not work. +:: So first try if %~dp0 might work, and if not, manually look up this script from PATH. +@if exist %~f0 ( + set MYDIR=%~dp0 + goto FOUND_MYDIR +) +@for %%I in (%~n0.bat) do ( + @if exist %%~$PATH:I ( + set MYDIR=%%~dp$PATH:I + ) else ( + echo Fatal Error! Due to a Windows bug, we are unable to locate the path to %~n0.bat. + echo To help this issue, try removing unnecessary quotes in the invocation of emcc, + echo or add Emscripten directory to PATH. + echo See github.com/microsoft/terminal/issues/15212 and + echo github.com/emscripten-core/emscripten/issues/19207 for more details. + ) +) +:FOUND_MYDIR + :: Python Windows bug https://bugs.python.org/issue34780: If this script was invoked via a :: shared stdin handle from the parent process, and that parent process stdin handle is in :: a certain state, running python.exe might hang here. To work around this, if @@ -47,16 +71,16 @@ ) :NORMAL_EXIT -@"%EM_PY%" -E "%~dp0\%~n0.py" %* +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* @exit %ERRORLEVEL% :MUTE_STDIN -@"%EM_PY%" -E "%~dp0\%~n0.py" %* < NUL +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* < NUL @exit /b %ERRORLEVEL% :MUTE_STDIN_EXIT -@"%EM_PY%" -E "%~dp0\%~n0.py" %* < NUL +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* < NUL @exit %ERRORLEVEL% :NORMAL -@"%EM_PY%" -E "%~dp0\%~n0.py" %* +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* diff --git a/emsize.bat b/emsize.bat index 84872e7a0b933..34900168d5856 100644 --- a/emsize.bat +++ b/emsize.bat @@ -5,6 +5,9 @@ :: To make modifications to this file, edit `tools/run_python.bat` and then run :: `tools/create_entry_points.py` +:: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, +:: or there will be a parsing error. + :: All env. vars specified in this file are to be local only to this script. @setlocal :: -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal @@ -15,6 +18,27 @@ set EM_PY=python ) +:: Work around Windows bug https://github.com/microsoft/terminal/issues/15212 : If this +:: script is invoked via enclosing the invocation in quotes via PATH lookup, then %~f0 and +:: %~dp0 expansions will not work. +:: So first try if %~dp0 might work, and if not, manually look up this script from PATH. +@if exist %~f0 ( + set MYDIR=%~dp0 + goto FOUND_MYDIR +) +@for %%I in (%~n0.bat) do ( + @if exist %%~$PATH:I ( + set MYDIR=%%~dp$PATH:I + ) else ( + echo Fatal Error! Due to a Windows bug, we are unable to locate the path to %~n0.bat. + echo To help this issue, try removing unnecessary quotes in the invocation of emcc, + echo or add Emscripten directory to PATH. + echo See github.com/microsoft/terminal/issues/15212 and + echo github.com/emscripten-core/emscripten/issues/19207 for more details. + ) +) +:FOUND_MYDIR + :: Python Windows bug https://bugs.python.org/issue34780: If this script was invoked via a :: shared stdin handle from the parent process, and that parent process stdin handle is in :: a certain state, running python.exe might hang here. To work around this, if @@ -47,16 +71,16 @@ ) :NORMAL_EXIT -@"%EM_PY%" -E "%~dp0\%~n0.py" %* +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* @exit %ERRORLEVEL% :MUTE_STDIN -@"%EM_PY%" -E "%~dp0\%~n0.py" %* < NUL +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* < NUL @exit /b %ERRORLEVEL% :MUTE_STDIN_EXIT -@"%EM_PY%" -E "%~dp0\%~n0.py" %* < NUL +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* < NUL @exit %ERRORLEVEL% :NORMAL -@"%EM_PY%" -E "%~dp0\%~n0.py" %* +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* diff --git a/emstrip.bat b/emstrip.bat index 84872e7a0b933..34900168d5856 100644 --- a/emstrip.bat +++ b/emstrip.bat @@ -5,6 +5,9 @@ :: To make modifications to this file, edit `tools/run_python.bat` and then run :: `tools/create_entry_points.py` +:: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, +:: or there will be a parsing error. + :: All env. vars specified in this file are to be local only to this script. @setlocal :: -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal @@ -15,6 +18,27 @@ set EM_PY=python ) +:: Work around Windows bug https://github.com/microsoft/terminal/issues/15212 : If this +:: script is invoked via enclosing the invocation in quotes via PATH lookup, then %~f0 and +:: %~dp0 expansions will not work. +:: So first try if %~dp0 might work, and if not, manually look up this script from PATH. +@if exist %~f0 ( + set MYDIR=%~dp0 + goto FOUND_MYDIR +) +@for %%I in (%~n0.bat) do ( + @if exist %%~$PATH:I ( + set MYDIR=%%~dp$PATH:I + ) else ( + echo Fatal Error! Due to a Windows bug, we are unable to locate the path to %~n0.bat. + echo To help this issue, try removing unnecessary quotes in the invocation of emcc, + echo or add Emscripten directory to PATH. + echo See github.com/microsoft/terminal/issues/15212 and + echo github.com/emscripten-core/emscripten/issues/19207 for more details. + ) +) +:FOUND_MYDIR + :: Python Windows bug https://bugs.python.org/issue34780: If this script was invoked via a :: shared stdin handle from the parent process, and that parent process stdin handle is in :: a certain state, running python.exe might hang here. To work around this, if @@ -47,16 +71,16 @@ ) :NORMAL_EXIT -@"%EM_PY%" -E "%~dp0\%~n0.py" %* +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* @exit %ERRORLEVEL% :MUTE_STDIN -@"%EM_PY%" -E "%~dp0\%~n0.py" %* < NUL +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* < NUL @exit /b %ERRORLEVEL% :MUTE_STDIN_EXIT -@"%EM_PY%" -E "%~dp0\%~n0.py" %* < NUL +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* < NUL @exit %ERRORLEVEL% :NORMAL -@"%EM_PY%" -E "%~dp0\%~n0.py" %* +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* diff --git a/emsymbolizer.bat b/emsymbolizer.bat index 84872e7a0b933..34900168d5856 100644 --- a/emsymbolizer.bat +++ b/emsymbolizer.bat @@ -5,6 +5,9 @@ :: To make modifications to this file, edit `tools/run_python.bat` and then run :: `tools/create_entry_points.py` +:: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, +:: or there will be a parsing error. + :: All env. vars specified in this file are to be local only to this script. @setlocal :: -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal @@ -15,6 +18,27 @@ set EM_PY=python ) +:: Work around Windows bug https://github.com/microsoft/terminal/issues/15212 : If this +:: script is invoked via enclosing the invocation in quotes via PATH lookup, then %~f0 and +:: %~dp0 expansions will not work. +:: So first try if %~dp0 might work, and if not, manually look up this script from PATH. +@if exist %~f0 ( + set MYDIR=%~dp0 + goto FOUND_MYDIR +) +@for %%I in (%~n0.bat) do ( + @if exist %%~$PATH:I ( + set MYDIR=%%~dp$PATH:I + ) else ( + echo Fatal Error! Due to a Windows bug, we are unable to locate the path to %~n0.bat. + echo To help this issue, try removing unnecessary quotes in the invocation of emcc, + echo or add Emscripten directory to PATH. + echo See github.com/microsoft/terminal/issues/15212 and + echo github.com/emscripten-core/emscripten/issues/19207 for more details. + ) +) +:FOUND_MYDIR + :: Python Windows bug https://bugs.python.org/issue34780: If this script was invoked via a :: shared stdin handle from the parent process, and that parent process stdin handle is in :: a certain state, running python.exe might hang here. To work around this, if @@ -47,16 +71,16 @@ ) :NORMAL_EXIT -@"%EM_PY%" -E "%~dp0\%~n0.py" %* +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* @exit %ERRORLEVEL% :MUTE_STDIN -@"%EM_PY%" -E "%~dp0\%~n0.py" %* < NUL +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* < NUL @exit /b %ERRORLEVEL% :MUTE_STDIN_EXIT -@"%EM_PY%" -E "%~dp0\%~n0.py" %* < NUL +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* < NUL @exit %ERRORLEVEL% :NORMAL -@"%EM_PY%" -E "%~dp0\%~n0.py" %* +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* diff --git a/system/bin/sdl-config.bat b/system/bin/sdl-config.bat index 84872e7a0b933..34900168d5856 100644 --- a/system/bin/sdl-config.bat +++ b/system/bin/sdl-config.bat @@ -5,6 +5,9 @@ :: To make modifications to this file, edit `tools/run_python.bat` and then run :: `tools/create_entry_points.py` +:: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, +:: or there will be a parsing error. + :: All env. vars specified in this file are to be local only to this script. @setlocal :: -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal @@ -15,6 +18,27 @@ set EM_PY=python ) +:: Work around Windows bug https://github.com/microsoft/terminal/issues/15212 : If this +:: script is invoked via enclosing the invocation in quotes via PATH lookup, then %~f0 and +:: %~dp0 expansions will not work. +:: So first try if %~dp0 might work, and if not, manually look up this script from PATH. +@if exist %~f0 ( + set MYDIR=%~dp0 + goto FOUND_MYDIR +) +@for %%I in (%~n0.bat) do ( + @if exist %%~$PATH:I ( + set MYDIR=%%~dp$PATH:I + ) else ( + echo Fatal Error! Due to a Windows bug, we are unable to locate the path to %~n0.bat. + echo To help this issue, try removing unnecessary quotes in the invocation of emcc, + echo or add Emscripten directory to PATH. + echo See github.com/microsoft/terminal/issues/15212 and + echo github.com/emscripten-core/emscripten/issues/19207 for more details. + ) +) +:FOUND_MYDIR + :: Python Windows bug https://bugs.python.org/issue34780: If this script was invoked via a :: shared stdin handle from the parent process, and that parent process stdin handle is in :: a certain state, running python.exe might hang here. To work around this, if @@ -47,16 +71,16 @@ ) :NORMAL_EXIT -@"%EM_PY%" -E "%~dp0\%~n0.py" %* +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* @exit %ERRORLEVEL% :MUTE_STDIN -@"%EM_PY%" -E "%~dp0\%~n0.py" %* < NUL +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* < NUL @exit /b %ERRORLEVEL% :MUTE_STDIN_EXIT -@"%EM_PY%" -E "%~dp0\%~n0.py" %* < NUL +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* < NUL @exit %ERRORLEVEL% :NORMAL -@"%EM_PY%" -E "%~dp0\%~n0.py" %* +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* diff --git a/system/bin/sdl2-config.bat b/system/bin/sdl2-config.bat index 84872e7a0b933..34900168d5856 100644 --- a/system/bin/sdl2-config.bat +++ b/system/bin/sdl2-config.bat @@ -5,6 +5,9 @@ :: To make modifications to this file, edit `tools/run_python.bat` and then run :: `tools/create_entry_points.py` +:: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, +:: or there will be a parsing error. + :: All env. vars specified in this file are to be local only to this script. @setlocal :: -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal @@ -15,6 +18,27 @@ set EM_PY=python ) +:: Work around Windows bug https://github.com/microsoft/terminal/issues/15212 : If this +:: script is invoked via enclosing the invocation in quotes via PATH lookup, then %~f0 and +:: %~dp0 expansions will not work. +:: So first try if %~dp0 might work, and if not, manually look up this script from PATH. +@if exist %~f0 ( + set MYDIR=%~dp0 + goto FOUND_MYDIR +) +@for %%I in (%~n0.bat) do ( + @if exist %%~$PATH:I ( + set MYDIR=%%~dp$PATH:I + ) else ( + echo Fatal Error! Due to a Windows bug, we are unable to locate the path to %~n0.bat. + echo To help this issue, try removing unnecessary quotes in the invocation of emcc, + echo or add Emscripten directory to PATH. + echo See github.com/microsoft/terminal/issues/15212 and + echo github.com/emscripten-core/emscripten/issues/19207 for more details. + ) +) +:FOUND_MYDIR + :: Python Windows bug https://bugs.python.org/issue34780: If this script was invoked via a :: shared stdin handle from the parent process, and that parent process stdin handle is in :: a certain state, running python.exe might hang here. To work around this, if @@ -47,16 +71,16 @@ ) :NORMAL_EXIT -@"%EM_PY%" -E "%~dp0\%~n0.py" %* +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* @exit %ERRORLEVEL% :MUTE_STDIN -@"%EM_PY%" -E "%~dp0\%~n0.py" %* < NUL +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* < NUL @exit /b %ERRORLEVEL% :MUTE_STDIN_EXIT -@"%EM_PY%" -E "%~dp0\%~n0.py" %* < NUL +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* < NUL @exit %ERRORLEVEL% :NORMAL -@"%EM_PY%" -E "%~dp0\%~n0.py" %* +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* diff --git a/test/common.py b/test/common.py index 6eb9415b83c92..30c8428740fdf 100644 --- a/test/common.py +++ b/test/common.py @@ -161,6 +161,13 @@ def no_windows(note=''): return lambda f: f +def only_windows(note=''): + assert not callable(note) + if not WINDOWS: + return unittest.skip(note) + return lambda f: f + + def requires_native_clang(func): assert callable(func) diff --git a/test/runner.bat b/test/runner.bat index 84872e7a0b933..34900168d5856 100644 --- a/test/runner.bat +++ b/test/runner.bat @@ -5,6 +5,9 @@ :: To make modifications to this file, edit `tools/run_python.bat` and then run :: `tools/create_entry_points.py` +:: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, +:: or there will be a parsing error. + :: All env. vars specified in this file are to be local only to this script. @setlocal :: -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal @@ -15,6 +18,27 @@ set EM_PY=python ) +:: Work around Windows bug https://github.com/microsoft/terminal/issues/15212 : If this +:: script is invoked via enclosing the invocation in quotes via PATH lookup, then %~f0 and +:: %~dp0 expansions will not work. +:: So first try if %~dp0 might work, and if not, manually look up this script from PATH. +@if exist %~f0 ( + set MYDIR=%~dp0 + goto FOUND_MYDIR +) +@for %%I in (%~n0.bat) do ( + @if exist %%~$PATH:I ( + set MYDIR=%%~dp$PATH:I + ) else ( + echo Fatal Error! Due to a Windows bug, we are unable to locate the path to %~n0.bat. + echo To help this issue, try removing unnecessary quotes in the invocation of emcc, + echo or add Emscripten directory to PATH. + echo See github.com/microsoft/terminal/issues/15212 and + echo github.com/emscripten-core/emscripten/issues/19207 for more details. + ) +) +:FOUND_MYDIR + :: Python Windows bug https://bugs.python.org/issue34780: If this script was invoked via a :: shared stdin handle from the parent process, and that parent process stdin handle is in :: a certain state, running python.exe might hang here. To work around this, if @@ -47,16 +71,16 @@ ) :NORMAL_EXIT -@"%EM_PY%" -E "%~dp0\%~n0.py" %* +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* @exit %ERRORLEVEL% :MUTE_STDIN -@"%EM_PY%" -E "%~dp0\%~n0.py" %* < NUL +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* < NUL @exit /b %ERRORLEVEL% :MUTE_STDIN_EXIT -@"%EM_PY%" -E "%~dp0\%~n0.py" %* < NUL +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* < NUL @exit %ERRORLEVEL% :NORMAL -@"%EM_PY%" -E "%~dp0\%~n0.py" %* +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* diff --git a/test/test_other.py b/test/test_other.py index 73242bbc2207b..4b449c19b250d 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -30,7 +30,7 @@ from tools.shared import EMCC, EMXX, EMAR, EMRANLIB, FILE_PACKAGER, WINDOWS, LLVM_NM from tools.shared import CLANG_CC, CLANG_CXX, LLVM_AR, LLVM_DWARFDUMP, LLVM_DWP, EMCMAKE, EMCONFIGURE from common import RunnerCore, path_from_root, is_slow_test, ensure_dir, disabled, make_executable -from common import env_modify, no_mac, no_windows, requires_native_clang, with_env_modify +from common import env_modify, no_mac, no_windows, only_windows, requires_native_clang, with_env_modify from common import create_file, parameterized, NON_ZERO, node_pthreads, TEST_ROOT, test_file from common import compiler_for, EMBUILDER, requires_v8, requires_node, requires_wasm64 from common import requires_wasm_eh, crossplatform, with_both_sjlj @@ -13377,3 +13377,9 @@ def test_memory_init_file_unsupported(self): def test_node_pthreads_err_out(self): create_file('post.js', 'err(1, 2, "hello"); out("foo", 42);') self.do_runf(test_file('hello_world.c'), '1 2 hello\nfoo 42\n', emcc_args=['--post-js=post.js']) + + @only_windows('This test verifies Windows batch script behavior against bug https://github.com/microsoft/terminal/issues/15212') + @with_env_modify({'PATH': path_from_root() + os.pathsep + os.getenv('PATH')}) + def test_windows_batch_file_dp0_expansion_bug(self): + create_file('build_with_quotes.bat', f'@"emcc" {test_file("hello_world.c")}') + self.run_process(['build_with_quotes.bat']) diff --git a/tools/file_packager.bat b/tools/file_packager.bat index 84872e7a0b933..34900168d5856 100644 --- a/tools/file_packager.bat +++ b/tools/file_packager.bat @@ -5,6 +5,9 @@ :: To make modifications to this file, edit `tools/run_python.bat` and then run :: `tools/create_entry_points.py` +:: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, +:: or there will be a parsing error. + :: All env. vars specified in this file are to be local only to this script. @setlocal :: -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal @@ -15,6 +18,27 @@ set EM_PY=python ) +:: Work around Windows bug https://github.com/microsoft/terminal/issues/15212 : If this +:: script is invoked via enclosing the invocation in quotes via PATH lookup, then %~f0 and +:: %~dp0 expansions will not work. +:: So first try if %~dp0 might work, and if not, manually look up this script from PATH. +@if exist %~f0 ( + set MYDIR=%~dp0 + goto FOUND_MYDIR +) +@for %%I in (%~n0.bat) do ( + @if exist %%~$PATH:I ( + set MYDIR=%%~dp$PATH:I + ) else ( + echo Fatal Error! Due to a Windows bug, we are unable to locate the path to %~n0.bat. + echo To help this issue, try removing unnecessary quotes in the invocation of emcc, + echo or add Emscripten directory to PATH. + echo See github.com/microsoft/terminal/issues/15212 and + echo github.com/emscripten-core/emscripten/issues/19207 for more details. + ) +) +:FOUND_MYDIR + :: Python Windows bug https://bugs.python.org/issue34780: If this script was invoked via a :: shared stdin handle from the parent process, and that parent process stdin handle is in :: a certain state, running python.exe might hang here. To work around this, if @@ -47,16 +71,16 @@ ) :NORMAL_EXIT -@"%EM_PY%" -E "%~dp0\%~n0.py" %* +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* @exit %ERRORLEVEL% :MUTE_STDIN -@"%EM_PY%" -E "%~dp0\%~n0.py" %* < NUL +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* < NUL @exit /b %ERRORLEVEL% :MUTE_STDIN_EXIT -@"%EM_PY%" -E "%~dp0\%~n0.py" %* < NUL +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* < NUL @exit %ERRORLEVEL% :NORMAL -@"%EM_PY%" -E "%~dp0\%~n0.py" %* +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* diff --git a/tools/run_python.bat b/tools/run_python.bat index 84872e7a0b933..34900168d5856 100644 --- a/tools/run_python.bat +++ b/tools/run_python.bat @@ -5,6 +5,9 @@ :: To make modifications to this file, edit `tools/run_python.bat` and then run :: `tools/create_entry_points.py` +:: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, +:: or there will be a parsing error. + :: All env. vars specified in this file are to be local only to this script. @setlocal :: -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal @@ -15,6 +18,27 @@ set EM_PY=python ) +:: Work around Windows bug https://github.com/microsoft/terminal/issues/15212 : If this +:: script is invoked via enclosing the invocation in quotes via PATH lookup, then %~f0 and +:: %~dp0 expansions will not work. +:: So first try if %~dp0 might work, and if not, manually look up this script from PATH. +@if exist %~f0 ( + set MYDIR=%~dp0 + goto FOUND_MYDIR +) +@for %%I in (%~n0.bat) do ( + @if exist %%~$PATH:I ( + set MYDIR=%%~dp$PATH:I + ) else ( + echo Fatal Error! Due to a Windows bug, we are unable to locate the path to %~n0.bat. + echo To help this issue, try removing unnecessary quotes in the invocation of emcc, + echo or add Emscripten directory to PATH. + echo See github.com/microsoft/terminal/issues/15212 and + echo github.com/emscripten-core/emscripten/issues/19207 for more details. + ) +) +:FOUND_MYDIR + :: Python Windows bug https://bugs.python.org/issue34780: If this script was invoked via a :: shared stdin handle from the parent process, and that parent process stdin handle is in :: a certain state, running python.exe might hang here. To work around this, if @@ -47,16 +71,16 @@ ) :NORMAL_EXIT -@"%EM_PY%" -E "%~dp0\%~n0.py" %* +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* @exit %ERRORLEVEL% :MUTE_STDIN -@"%EM_PY%" -E "%~dp0\%~n0.py" %* < NUL +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* < NUL @exit /b %ERRORLEVEL% :MUTE_STDIN_EXIT -@"%EM_PY%" -E "%~dp0\%~n0.py" %* < NUL +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* < NUL @exit %ERRORLEVEL% :NORMAL -@"%EM_PY%" -E "%~dp0\%~n0.py" %* +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* diff --git a/tools/run_python_compiler.bat b/tools/run_python_compiler.bat index cc5e8d3cfd59c..86ae9bb841f35 100644 --- a/tools/run_python_compiler.bat +++ b/tools/run_python_compiler.bat @@ -5,6 +5,9 @@ :: To make modifications to this file, edit `tools/run_python_compiler.bat` and :: then run `tools/create_entry_points.py` +:: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, +:: or there will be a parsing error. + :: All env. vars specified in this file are to be local only to this script. @setlocal :: -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal @@ -15,13 +18,34 @@ set EM_PY=python ) +:: Work around Windows bug https://github.com/microsoft/terminal/issues/15212 : If this +:: script is invoked via enclosing the invocation in quotes via PATH lookup, then %~f0 and +:: %~dp0 expansions will not work. +:: So first try if %~dp0 might work, and if not, manually look up this script from PATH. +@if exist %~f0 ( + set MYDIR=%~dp0 + goto FOUND_MYDIR +) +@for %%I in (%~n0.bat) do ( + @if exist %%~$PATH:I ( + set MYDIR=%%~dp$PATH:I + ) else ( + echo Fatal Error! Due to a Windows bug, we are unable to locate the path to %~n0.bat. + echo To help this issue, try removing unnecessary quotes in the invocation of emcc, + echo or add Emscripten directory to PATH. + echo See github.com/microsoft/terminal/issues/15212 and + echo github.com/emscripten-core/emscripten/issues/19207 for more details. + ) +) +:FOUND_MYDIR + :: If _EMCC_CCACHE is not set, do a regular invocation of the python compiler driver. :: Otherwise remove the ccache env. var, and then reinvoke this script with ccache enabled. @if "%_EMCC_CCACHE%"=="" ( - set CMD="%EM_PY%" -E "%~dp0\%~n0.py" + set CMD="%EM_PY%" -E "%MYDIR%%~n0.py" ) else ( set _EMCC_CCACHE= - set CMD=ccache "%~dp0\%~n0.bat" + set CMD=ccache "%MYDIR%%~n0.bat" ) :: Python Windows bug https://bugs.python.org/issue34780: If this script was invoked via a diff --git a/tools/webidl_binder.bat b/tools/webidl_binder.bat index 84872e7a0b933..34900168d5856 100644 --- a/tools/webidl_binder.bat +++ b/tools/webidl_binder.bat @@ -5,6 +5,9 @@ :: To make modifications to this file, edit `tools/run_python.bat` and then run :: `tools/create_entry_points.py` +:: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, +:: or there will be a parsing error. + :: All env. vars specified in this file are to be local only to this script. @setlocal :: -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal @@ -15,6 +18,27 @@ set EM_PY=python ) +:: Work around Windows bug https://github.com/microsoft/terminal/issues/15212 : If this +:: script is invoked via enclosing the invocation in quotes via PATH lookup, then %~f0 and +:: %~dp0 expansions will not work. +:: So first try if %~dp0 might work, and if not, manually look up this script from PATH. +@if exist %~f0 ( + set MYDIR=%~dp0 + goto FOUND_MYDIR +) +@for %%I in (%~n0.bat) do ( + @if exist %%~$PATH:I ( + set MYDIR=%%~dp$PATH:I + ) else ( + echo Fatal Error! Due to a Windows bug, we are unable to locate the path to %~n0.bat. + echo To help this issue, try removing unnecessary quotes in the invocation of emcc, + echo or add Emscripten directory to PATH. + echo See github.com/microsoft/terminal/issues/15212 and + echo github.com/emscripten-core/emscripten/issues/19207 for more details. + ) +) +:FOUND_MYDIR + :: Python Windows bug https://bugs.python.org/issue34780: If this script was invoked via a :: shared stdin handle from the parent process, and that parent process stdin handle is in :: a certain state, running python.exe might hang here. To work around this, if @@ -47,16 +71,16 @@ ) :NORMAL_EXIT -@"%EM_PY%" -E "%~dp0\%~n0.py" %* +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* @exit %ERRORLEVEL% :MUTE_STDIN -@"%EM_PY%" -E "%~dp0\%~n0.py" %* < NUL +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* < NUL @exit /b %ERRORLEVEL% :MUTE_STDIN_EXIT -@"%EM_PY%" -E "%~dp0\%~n0.py" %* < NUL +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* < NUL @exit %ERRORLEVEL% :NORMAL -@"%EM_PY%" -E "%~dp0\%~n0.py" %* +@"%EM_PY%" -E "%MYDIR%%~n0.py" %* From 2473fbe4ba42f87094540813397937ef6d274d57 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Sat, 22 Apr 2023 10:42:45 -0700 Subject: [PATCH 0160/1523] Rebaseline codesize expectations. NFC --- test/other/metadce/test_metadce_minimal_pthreads.exports | 2 +- test/other/metadce/test_metadce_minimal_pthreads.imports | 1 - test/other/metadce/test_metadce_minimal_pthreads.jssize | 2 +- test/other/metadce/test_metadce_minimal_pthreads.sent | 1 - test/other/metadce/test_metadce_minimal_pthreads.size | 2 +- 5 files changed, 3 insertions(+), 5 deletions(-) diff --git a/test/other/metadce/test_metadce_minimal_pthreads.exports b/test/other/metadce/test_metadce_minimal_pthreads.exports index fcb5627b2e747..9c917676e4d2a 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.exports +++ b/test/other/metadce/test_metadce_minimal_pthreads.exports @@ -4,7 +4,7 @@ C D E F -G +p q r s diff --git a/test/other/metadce/test_metadce_minimal_pthreads.imports b/test/other/metadce/test_metadce_minimal_pthreads.imports index 259d8061349ff..fcc5923256f40 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.imports +++ b/test/other/metadce/test_metadce_minimal_pthreads.imports @@ -13,4 +13,3 @@ a.l a.m a.n a.o -a.p diff --git a/test/other/metadce/test_metadce_minimal_pthreads.jssize b/test/other/metadce/test_metadce_minimal_pthreads.jssize index 408489c67ae57..439e54c6aec56 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.jssize +++ b/test/other/metadce/test_metadce_minimal_pthreads.jssize @@ -1 +1 @@ -15593 +15560 diff --git a/test/other/metadce/test_metadce_minimal_pthreads.sent b/test/other/metadce/test_metadce_minimal_pthreads.sent index b03757ea914f6..f8c295c135e5d 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.sent +++ b/test/other/metadce/test_metadce_minimal_pthreads.sent @@ -13,4 +13,3 @@ l m n o -p diff --git a/test/other/metadce/test_metadce_minimal_pthreads.size b/test/other/metadce/test_metadce_minimal_pthreads.size index 78ae000359105..d68caa14c4ead 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.size +++ b/test/other/metadce/test_metadce_minimal_pthreads.size @@ -1 +1 @@ -19019 +18994 From c4ea62182e9b8bada1c7abd9bf45b3d9d08112ae Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Sat, 22 Apr 2023 12:49:42 -0700 Subject: [PATCH 0161/1523] Rebaseline codesize expectations. NFC --- test/other/metadce/test_metadce_minimal_pthreads.exports | 2 +- test/other/metadce/test_metadce_minimal_pthreads.imports | 1 + test/other/metadce/test_metadce_minimal_pthreads.jssize | 2 +- test/other/metadce/test_metadce_minimal_pthreads.sent | 1 + test/other/metadce/test_metadce_minimal_pthreads.size | 2 +- 5 files changed, 5 insertions(+), 3 deletions(-) diff --git a/test/other/metadce/test_metadce_minimal_pthreads.exports b/test/other/metadce/test_metadce_minimal_pthreads.exports index 9c917676e4d2a..fcb5627b2e747 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.exports +++ b/test/other/metadce/test_metadce_minimal_pthreads.exports @@ -4,7 +4,7 @@ C D E F -p +G q r s diff --git a/test/other/metadce/test_metadce_minimal_pthreads.imports b/test/other/metadce/test_metadce_minimal_pthreads.imports index fcc5923256f40..259d8061349ff 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.imports +++ b/test/other/metadce/test_metadce_minimal_pthreads.imports @@ -13,3 +13,4 @@ a.l a.m a.n a.o +a.p diff --git a/test/other/metadce/test_metadce_minimal_pthreads.jssize b/test/other/metadce/test_metadce_minimal_pthreads.jssize index 439e54c6aec56..408489c67ae57 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.jssize +++ b/test/other/metadce/test_metadce_minimal_pthreads.jssize @@ -1 +1 @@ -15560 +15593 diff --git a/test/other/metadce/test_metadce_minimal_pthreads.sent b/test/other/metadce/test_metadce_minimal_pthreads.sent index f8c295c135e5d..b03757ea914f6 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.sent +++ b/test/other/metadce/test_metadce_minimal_pthreads.sent @@ -13,3 +13,4 @@ l m n o +p diff --git a/test/other/metadce/test_metadce_minimal_pthreads.size b/test/other/metadce/test_metadce_minimal_pthreads.size index d68caa14c4ead..78ae000359105 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.size +++ b/test/other/metadce/test_metadce_minimal_pthreads.size @@ -1 +1 @@ -18994 +19019 From 4f4b0e6d444c99c7c2ed5e9e8f277e6f4c9ba196 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Sat, 22 Apr 2023 14:00:51 -0700 Subject: [PATCH 0162/1523] Make more use of JS arrow functions. NFC (#19218) --- src/IDBStore.js | 44 +++++++------------ src/headless.js | 12 ++--- src/library.js | 6 +-- src/library_browser.js | 14 +++--- src/library_dylink.js | 34 +++++++------- src/library_html5_webgl.js | 2 +- src/library_lz4.js | 4 +- src/library_openal.js | 9 ++-- src/library_sdl.js | 18 ++++---- src/memoryprofiler.js | 12 ++--- src/preamble.js | 36 +++++++-------- src/proxyWorker.js | 8 +--- src/runtime_math.js | 8 ++-- src/shell.html | 12 ++--- src/shell.js | 14 +++--- src/shell_minimal.html | 12 ++--- .../metadce/test_metadce_cxx_ctors1.jssize | 2 +- .../metadce/test_metadce_cxx_ctors2.jssize | 2 +- .../metadce/test_metadce_cxx_except.jssize | 2 +- .../test_metadce_cxx_except_wasm.jssize | 2 +- .../metadce/test_metadce_cxx_mangle.jssize | 2 +- .../metadce/test_metadce_cxx_noexcept.jssize | 2 +- .../metadce/test_metadce_hello_O0.jssize | 2 +- .../metadce/test_metadce_hello_O1.jssize | 2 +- .../metadce/test_metadce_hello_O2.jssize | 2 +- .../metadce/test_metadce_hello_O3.jssize | 2 +- .../metadce/test_metadce_hello_Os.jssize | 2 +- .../metadce/test_metadce_hello_Oz.jssize | 2 +- .../metadce/test_metadce_hello_dylink.jssize | 2 +- .../test_metadce_hello_export_nothing.jssize | 2 +- .../test_metadce_libcxxabi_message_O3.jssize | 2 +- ...dce_libcxxabi_message_O3_standalone.jssize | 2 +- test/other/metadce/test_metadce_mem_O3.jssize | 2 +- .../metadce/test_metadce_mem_O3_grow.jssize | 2 +- ...test_metadce_mem_O3_grow_standalone.jssize | 2 +- .../test_metadce_mem_O3_standalone.jssize | 2 +- .../test_metadce_mem_O3_standalone_lib.jssize | 2 +- ...test_metadce_mem_O3_standalone_narg.jssize | 2 +- ...metadce_mem_O3_standalone_narg_flto.jssize | 2 +- .../metadce/test_metadce_minimal_64.jssize | 2 +- .../metadce/test_metadce_minimal_O0.jssize | 2 +- .../metadce/test_metadce_minimal_O1.jssize | 2 +- .../metadce/test_metadce_minimal_O2.jssize | 2 +- .../metadce/test_metadce_minimal_O3.jssize | 2 +- .../metadce/test_metadce_minimal_Os.jssize | 2 +- .../test_metadce_minimal_Oz-ctors.jssize | 2 +- .../metadce/test_metadce_minimal_Oz.jssize | 2 +- .../test_metadce_minimal_pthreads.jssize | 2 +- test/other/test_unoptimized_code_size.js.size | 2 +- ...t_unoptimized_code_size_no_asserts.js.size | 2 +- .../test_unoptimized_code_size_strict.js.size | 2 +- test/test_browser.py | 2 +- 52 files changed, 145 insertions(+), 172 deletions(-) diff --git a/src/IDBStore.js b/src/IDBStore.js index 508df1dc6c8a8..60ac176ee3e79 100644 --- a/src/IDBStore.js +++ b/src/IDBStore.js @@ -28,7 +28,7 @@ } catch (e) { return callback(e); } - req.onupgradeneeded = function(e) { + req.onupgradeneeded = (e) => { var db = /** @type {IDBDatabase} */ (e.target.result); var transaction = e.target.transaction; var fileStore; @@ -38,24 +38,24 @@ fileStore = db.createObjectStore(IDBStore.DB_STORE_NAME); } }; - req.onsuccess = function() { + req.onsuccess = () => { db = /** @type {IDBDatabase} */ (req.result); // add to the cache IDBStore.dbs[name] = db; callback(null, db); }; - req.onerror = /** @this{IDBOpenDBRequest} */ function(e) { - callback(this.error); - e.preventDefault(); + req.onerror = function(event) { + callback(event.target.error || 'unknown error'); + event.preventDefault(); }; }, getStore: function(dbName, type, callback) { IDBStore.getDB(dbName, function(error, db) { if (error) return callback(error); var transaction = db.transaction([IDBStore.DB_STORE_NAME], type); - transaction.onerror = function(e) { - callback(this.error || 'unknown error'); - e.preventDefault(); + transaction.onerror = (event) => { + callback(event.target.error || 'unknown error'); + event.preventDefault(); }; var store = transaction.objectStore(IDBStore.DB_STORE_NAME); callback(null, store); @@ -66,14 +66,14 @@ IDBStore.getStore(dbName, 'readonly', function(err, store) { if (err) return callback(err); var req = store.get(id); - req.onsuccess = function(event) { + req.onsuccess = (event) => { var result = event.target.result; if (!result) { return callback('file ' + id + ' not found'); } return callback(null, result); }; - req.onerror = function(error) { + req.onerror = (error) => { callback(error); }; }); @@ -82,36 +82,24 @@ IDBStore.getStore(dbName, 'readwrite', function(err, store) { if (err) return callback(err); var req = store.put(data, id); - req.onsuccess = function(event) { - callback(); - }; - req.onerror = function(error) { - callback(error); - }; + req.onsuccess = (event) => callback(); + req.onerror = (error) => callback(error); }); }, deleteFile: function(dbName, id, callback) { IDBStore.getStore(dbName, 'readwrite', function(err, store) { if (err) return callback(err); var req = store.delete(id); - req.onsuccess = function(event) { - callback(); - }; - req.onerror = function(error) { - callback(error); - }; + req.onsuccess = (event) => callback(); + req.onerror = (error) => callback(error); }); }, existsFile: function(dbName, id, callback) { IDBStore.getStore(dbName, 'readonly', function(err, store) { if (err) return callback(err); var req = store.count(id); - req.onsuccess = function(event) { - callback(null, event.target.result > 0); - }; - req.onerror = function(error) { - callback(error); - }; + req.onsuccess = (event) => callback(null, event.target.result > 0); + req.onerror = (error) => callback(error); }); }, } diff --git a/src/headless.js b/src/headless.js index 7f1fcc704789c..93ac6b8a90f1b 100644 --- a/src/headless.js +++ b/src/headless.js @@ -43,7 +43,7 @@ var window = { func: func, when: window.fakeNow + (ms || 0) }); - window.timeouts.sort(function(x, y) { return y.when - x.when }); + window.timeouts.sort((x, y) => { return y.when - x.when }); }, runEventLoop: function() { // run forever until an exception stops this replay @@ -101,7 +101,7 @@ var window = { callEventListeners: function(id) { var listeners = this.eventListeners[id]; if (listeners) { - listeners.forEach(function(listener) { listener() }); + listeners.forEach((listener) => listener()); } }, URL: { @@ -136,12 +136,12 @@ var document = { case 'canvas': return document.getElementById(what); case 'script': { var ret = {}; - window.setTimeout(function() { + window.setTimeout(() => { headlessPrint('loading script: ' + ret.src); load(ret.src); headlessPrint(' script loaded.'); if (ret.onload) { - window.setTimeout(function() { + window.setTimeout(() => { ret.onload(); // yeah yeah this might vanish }); } @@ -265,7 +265,7 @@ var Worker = (workerPath) => { this.postMessage = (msg) => { msg.messageId = Worker.messageId++; headlessPrint('main thread sending message ' + msg.messageId + ' to worker ' + workerPath); - window.setTimeout(function() { + window.setTimeout(() => { headlessPrint('worker ' + workerPath + ' receiving message ' + msg.messageId); onmessage({ data: duplicateJSON(msg) }); }); @@ -274,7 +274,7 @@ var Worker = (workerPath) => { var postMessage = (msg) => { msg.messageId = Worker.messageId++; headlessPrint('worker ' + workerPath + ' sending message ' + msg.messageId); - window.setTimeout(function() { + window.setTimeout(() => { headlessPrint('main thread receiving message ' + msg.messageId + ' from ' + workerPath); thisWorker.onmessage({ data: duplicateJSON(msg) }); }); diff --git a/src/library.js b/src/library.js index 6c1dab396ffa4..4702f1f5c1d1b 100644 --- a/src/library.js +++ b/src/library.js @@ -3174,8 +3174,8 @@ mergeInto(LibraryManager.library, { if (!elements) { elements = [document, document.getElementById('canvas')]; } - ['keydown', 'mousedown', 'touchstart'].forEach(function(event) { - elements.forEach(function(element) { + ['keydown', 'mousedown', 'touchstart'].forEach((event) => { + elements.forEach((element) => { if (element) { listenOnce(element, event, () => { if (ctx.state === 'suspended') ctx.resume(); @@ -3548,7 +3548,7 @@ mergeInto(LibraryManager.library, { $safeSetTimeout__docs: '/** @param {number=} timeout */', $safeSetTimeout: function(func, timeout) { {{{ runtimeKeepalivePush() }}} - return setTimeout(function() { + return setTimeout(() => { {{{ runtimeKeepalivePop() }}} callUserCallback(func); }, timeout); diff --git a/src/library_browser.js b/src/library_browser.js index 8dea0309aef86..675a0011ae718 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -236,7 +236,7 @@ var LibraryBrowser = { }; audio.src = url; // workaround for chrome bug 124926 - we do not always get oncanplaythrough or onerror - safeSetTimeout(function() { + safeSetTimeout(() => { finish(audio); // try to use it even though it is not necessarily ready to play }, 10000); } else { @@ -320,7 +320,7 @@ var LibraryBrowser = { Browser.init(); var handled = false; - Module['preloadPlugins'].forEach(function(plugin) { + Module['preloadPlugins'].forEach((plugin) => { if (handled) return; if (plugin['canHandle'](fullname)) { plugin['handle'](byteArray, fullname, finish, onerror); @@ -376,7 +376,7 @@ var LibraryBrowser = { Module.ctx = ctx; if (useWebGL) GL.makeContextCurrent(contextHandle); Module.useWebGL = useWebGL; - Browser.moduleContextCreatedCallbacks.forEach(function(callback) { callback() }); + Browser.moduleContextCreatedCallbacks.forEach((callback) => callback()); Browser.init(); } return ctx; @@ -465,7 +465,7 @@ var LibraryBrowser = { document['mozCancelFullScreen'] || document['msExitFullscreen'] || document['webkitCancelFullScreen'] || - (function() {}); + (() => {}); CFS.apply(document, []); return true; }, @@ -515,7 +515,7 @@ var LibraryBrowser = { }, safeRequestAnimationFrame: function(func) { {{{ runtimeKeepalivePush() }}} - return Browser.requestAnimationFrame(function() { + return Browser.requestAnimationFrame(() => { {{{ runtimeKeepalivePop() }}} callUserCallback(func); }); @@ -695,9 +695,7 @@ var LibraryBrowser = { updateResizeListeners: function() { var canvas = Module['canvas']; - Browser.resizeListeners.forEach(function(listener) { - listener(canvas.width, canvas.height); - }); + Browser.resizeListeners.forEach((listener) => listener(canvas.width, canvas.height)); }, setCanvasSize: function(width, height, noUpdates) { diff --git a/src/library_dylink.js b/src/library_dylink.js index b46ffa798dca7..91691a4303c99 100644 --- a/src/library_dylink.js +++ b/src/library_dylink.js @@ -301,7 +301,7 @@ var LibraryDylink = { #if DYLINK_DEBUG dbg('dlSetError: ' + msg); #endif - withStackSave(function() { + withStackSave(() => { var cmsg = stringToUTF8OnStack(msg); ___dl_seterr(cmsg, 0); }); @@ -807,9 +807,9 @@ var LibraryDylink = { var instance = new WebAssembly.Instance(binary, info); return Promise.resolve(postInstantiation(instance)); } - return WebAssembly.instantiate(binary, info).then(function(result) { - return postInstantiation(result.instance); - }); + return WebAssembly.instantiate(binary, info).then( + (result) => postInstantiation(result.instance) + ); } var module = binary instanceof WebAssembly.Module ? binary : new WebAssembly.Module(binary); @@ -819,18 +819,14 @@ var LibraryDylink = { // now load needed libraries and the module itself. if (flags.loadAsync) { - return metadata.neededDynlibs.reduce(function(chain, dynNeeded) { - return chain.then(function() { + return metadata.neededDynlibs.reduce((chain, dynNeeded) => { + return chain.then(() => { return loadDynamicLibrary(dynNeeded, flags); }); - }, Promise.resolve()).then(function() { - return loadModule(); - }); + }, Promise.resolve()).then(loadModule); } - metadata.neededDynlibs.forEach(function(dynNeeded) { - loadDynamicLibrary(dynNeeded, flags, localScope); - }); + metadata.neededDynlibs.forEach((needed) => loadDynamicLibrary(needed, flags, localScope)); return loadModule(); }, @@ -1015,11 +1011,11 @@ var LibraryDylink = { // Load binaries asynchronously addRunDependency('loadDylibs'); - dynamicLibraries.reduce(function(chain, lib) { - return chain.then(function() { + dynamicLibraries.reduce((chain, lib) => { + return chain.then(() => { return loadDynamicLibrary(lib, {loadAsync: true, global: true, nodelete: true, allowUndefined: true}); }); - }, Promise.resolve()).then(function() { + }, Promise.resolve()).then(() => { // we got them all, wonderful reportUndefinedSymbols(); removeRunDependency('loadDylibs'); @@ -1093,13 +1089,13 @@ var LibraryDylink = { #endif _dlopen_js: function(handle) { #if ASYNCIFY - return Asyncify.handleSleep(function(wakeUp) { + return Asyncify.handleSleep((wakeUp) => { var jsflags = { loadAsync: true, fs: FS, // load libraries from provided filesystem } var promise = dlopenInternal(handle, jsflags); - promise.then(wakeUp).catch(function() { wakeUp(0) }); + promise.then(wakeUp).catch(() => wakeUp(0)); }); #else var jsflags = { @@ -1118,11 +1114,11 @@ var LibraryDylink = { var filename = UTF8ToString({{{ makeGetValue('handle', C_STRUCTS.dso.name, '*') }}}); dlSetError('Could not load dynamic lib: ' + filename + '\n' + e); {{{ runtimeKeepalivePop() }}} - callUserCallback(function () { {{{ makeDynCall('vpp', 'onerror') }}}(handle, user_data); }); + callUserCallback(() => {{{ makeDynCall('vpp', 'onerror') }}}(handle, user_data)); } function successCallback() { {{{ runtimeKeepalivePop() }}} - callUserCallback(function () { {{{ makeDynCall('vpp', 'onsuccess') }}}(handle, user_data); }); + callUserCallback(() => {{{ makeDynCall('vpp', 'onsuccess') }}}(handle, user_data)); } {{{ runtimeKeepalivePush() }}} diff --git a/src/library_html5_webgl.js b/src/library_html5_webgl.js index fe9f93bce1a3a..559068f3f5432 100644 --- a/src/library_html5_webgl.js +++ b/src/library_html5_webgl.js @@ -404,7 +404,7 @@ var LibraryHtml5WebGL = { if (!target) target = Module['canvas']; #endif - var webGlEventHandlerFunc = function(e = event) { + var webGlEventHandlerFunc = (e = event) => { #if PTHREADS if (targetThread) JSEvents.queueEventHandlerOnThread_iiii(targetThread, callbackfunc, eventTypeId, 0, userData); else diff --git a/src/library_lz4.js b/src/library_lz4.js index dce368890a89b..60fe36ff84374 100644 --- a/src/library_lz4.js +++ b/src/library_lz4.js @@ -57,9 +57,7 @@ mergeInto(LibraryManager.library, { if (plugin['canHandle'](fullname)) { var dep = getUniqueRunDependency('fp ' + fullname); addRunDependency(dep); - var finish = function() { - removeRunDependency(dep); - } + var finish = () => removeRunDependency(dep); var byteArray = FS.readFile(fullname); plugin['handle'](byteArray, fullname, finish, finish); handled = true; diff --git a/src/library_openal.js b/src/library_openal.js index 6d5ecf7d26db6..1731e5bfa9790 100644 --- a/src/library_openal.js +++ b/src/library_openal.js @@ -545,7 +545,7 @@ var LibraryOpenAL = { var lUpY = listener.up[1]; var lUpZ = listener.up[2]; - var inverseMagnitude = function(x, y, z) { + var inverseMagnitude = (x, y, z) => { var length = Math.sqrt(x * x + y * y + z * z); if (length < Number.EPSILON) { @@ -1765,13 +1765,13 @@ var LibraryOpenAL = { // Preparing for getUserMedia() - var onError = function(mediaStreamError) { + var onError = (mediaStreamError) => { newCapture.mediaStreamError = mediaStreamError; #if OPENAL_DEBUG dbg('navigator.getUserMedia() errored with: ' + mediaStreamError); #endif }; - var onSuccess = function(mediaStream) { + var onSuccess = (mediaStream) => { newCapture.mediaStreamSourceNode = newCapture.audioCtx.createMediaStreamSource(mediaStream); newCapture.mediaStream = mediaStream; @@ -1819,8 +1819,7 @@ var LibraryOpenAL = { newCapture.scriptProcessorNode.connect(newCapture.audioCtx.destination); - newCapture.scriptProcessorNode.onaudioprocess = function(audioProcessingEvent) { - + newCapture.scriptProcessorNode.onaudioprocess = (audioProcessingEvent) => { if (!newCapture.isCapturing) { return; } diff --git a/src/library_sdl.js b/src/library_sdl.js index 9154fb688b91e..129cb567d7b50 100644 --- a/src/library_sdl.js +++ b/src/library_sdl.js @@ -2191,17 +2191,17 @@ var LibrarySDL = { IMG_Load_RW: function(rwopsID, freeSrc) { try { // stb_image integration support - var cleanup = function() { + var cleanup = () => { if (rwops && freeSrc) _SDL_FreeRW(rwopsID); } - var addCleanup = function(func) { + var addCleanup = (func) => { var old = cleanup; - cleanup = function added_cleanup() { + cleanup = () => { old(); func(); } } - var callStbImage = function(func, params) { + var callStbImage = (func, params) => { var x = _malloc({{{ getNativeTypeSize('i32') }}}); var y = _malloc({{{ getNativeTypeSize('i32') }}}); var comp = _malloc({{{ getNativeTypeSize('i32') }}}); @@ -2426,7 +2426,7 @@ var LibrarySDL = { // setTimeouts to ensure that we get the finest granularity possible and as many chances from the browser to fill // new audio data. This is because setTimeouts alone have very poor granularity for audio streaming purposes, but also // the application might not be using emscripten_set_main_loop to drive the main loop, so we cannot rely on that alone. - SDL.audio.queueNewAudioData = function SDL_queueNewAudioData() { + SDL.audio.queueNewAudioData = () => { if (!SDL.audio) return; for (var i = 0; i < SDL.audio.numSimultaneouslyQueuedBuffers; ++i) { @@ -2443,11 +2443,11 @@ var LibrarySDL = { } #if ASYNCIFY - var sleepCallback = function() { + var sleepCallback = () => { if (SDL.audio && SDL.audio.queueNewAudioData) SDL.audio.queueNewAudioData(); }; Asyncify.sleepCallbacks.push(sleepCallback); - SDL.audio.callbackRemover = function() { + SDL.audio.callbackRemover = () => { Asyncify.sleepCallbacks = Asyncify.sleepCallbacks.filter(function(callback) { return callback !== sleepCallback; }); @@ -2455,7 +2455,7 @@ var LibrarySDL = { #endif // Create a callback function that will be routinely called to ask more audio data from the user application. - SDL.audio.caller = function SDL_audioCaller() { + SDL.audio.caller = () => { if (!SDL.audio) return; --SDL.audio.numAudioTimersPending; @@ -2768,7 +2768,7 @@ var LibrarySDL = { // after loading. Therefore prepare an array of callback handlers to run when this audio decoding is complete, which // will then start the playback (with some delay). webAudio.onDecodeComplete = []; // While this member array exists, decoding hasn't finished yet. - var onDecodeComplete = function(data) { + var onDecodeComplete = (data) => { webAudio.decodedBuffer = data; // Call all handlers that were waiting for this decode to finish, and clear the handler list. webAudio.onDecodeComplete.forEach(function(e) { e(); }); diff --git a/src/memoryprofiler.js b/src/memoryprofiler.js index cbb4169e1ef62..a8a358130a27f 100644 --- a/src/memoryprofiler.js +++ b/src/memoryprofiler.js @@ -248,7 +248,7 @@ var emscriptenMemoryProfiler = { // Add a tracking mechanism to detect when VFS loading is complete. if (!Module['preRun']) Module['preRun'] = []; - Module['preRun'].push(function() { emscriptenMemoryProfiler.onPreloadComplete(); }); + Module['preRun'].push(emscriptenMemoryProfiler.onPreloadComplete); if (emscriptenMemoryProfiler.hookStackAlloc && typeof stackAlloc == 'function') { // Inject stack allocator. @@ -291,15 +291,15 @@ var emscriptenMemoryProfiler = { self.memoryprofiler_summary = document.getElementById('memoryprofiler_summary'); self.memoryprofiler_ptrs = document.getElementById('memoryprofiler_ptrs'); - document.getElementById('memoryprofiler_min_tracked_alloc_size').addEventListener("change", function(e){self.trackedCallstackMinSizeBytes=parseInt(this.value, undefined /* https://github.com/google/closure-compiler/issues/3230 / https://github.com/google/closure-compiler/issues/3548 */);}); - document.getElementById('memoryprofiler_min_tracked_alloc_count').addEventListener("change", function(e){self.trackedCallstackMinAllocCount=parseInt(this.value, undefined);}); - document.getElementById('memoryprofiler_clear_alloc_stats').addEventListener("click", function(e){self.allocationsAtLoc = {}; self.allocationSitePtrs = {};}); + document.getElementById('memoryprofiler_min_tracked_alloc_size').addEventListener("change", (e) => self.trackedCallstackMinSizeBytes=parseInt(this.value, undefined /* https://github.com/google/closure-compiler/issues/3230 / https://github.com/google/closure-compiler/issues/3548 */)); + document.getElementById('memoryprofiler_min_tracked_alloc_count').addEventListener("change", (e) => self.trackedCallstackMinAllocCount=parseInt(this.value, undefined)); + document.getElementById('memoryprofiler_clear_alloc_stats').addEventListener("click", (e) => {self.allocationsAtLoc = {}; self.allocationSitePtrs = {};}); self.canvas = document.getElementById('memoryprofiler_canvas'); self.canvas.width = document.documentElement.clientWidth - 32; self.drawContext = self.canvas.getContext('2d'); self.updateUi(); - setInterval(function() { emscriptenMemoryProfiler.updateUi() }, self.uiUpdateIntervalMsecs); + setInterval(() => emscriptenMemoryProfiler.updateUi(), self.uiUpdateIntervalMsecs); }; // User might initialize memoryprofiler in the of a page, when @@ -613,7 +613,7 @@ var emscriptenMemoryProfiler = { if (calls.length > 0) { if (sortOrder != 'fixed') { var sortIdx = (sortOrder == 'count') ? 0 : 1; - calls.sort(function(a,b) { return b[sortIdx] - a[sortIdx]; }); + calls.sort((a,b) => { return b[sortIdx] - a[sortIdx]; }); } html += '

Allocation sites with more than ' + self.formatBytes(self.trackedCallstackMinSizeBytes) + ' of accumulated allocations, or more than ' + self.trackedCallstackMinAllocCount + ' simultaneously outstanding allocations:

' for (var i in calls) { diff --git a/src/preamble.js b/src/preamble.js index 1c3a74ac5744e..b6cb5d2d2de56 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -375,7 +375,7 @@ function addRunDependency(id) { runDependencyTracking[id] = 1; if (runDependencyWatcher === null && typeof setInterval != 'undefined') { // Check for missing dependencies every few seconds - runDependencyWatcher = setInterval(function() { + runDependencyWatcher = setInterval(() => { if (ABORT) { clearInterval(runDependencyWatcher); runDependencyWatcher = null; @@ -674,21 +674,19 @@ function getBinaryPromise(binaryFile) { && !isFileURI(binaryFile) #endif ) { - return fetch(binaryFile, {{{ makeModuleReceiveExpr('fetchSettings', "{ credentials: 'same-origin' }") }}}).then(function(response) { + return fetch(binaryFile, {{{ makeModuleReceiveExpr('fetchSettings', "{ credentials: 'same-origin' }") }}}).then((response) => { if (!response['ok']) { throw "failed to load wasm binary file at '" + binaryFile + "'"; } return response['arrayBuffer'](); - }).catch(function () { - return getBinary(binaryFile); - }); + }).catch(() => getBinary(binaryFile)); } #if ENVIRONMENT_MAY_BE_WEBVIEW else { if (readAsync) { // fetch is not available or url is file => try XHR (readAsync uses XHR internally) - return new Promise(function(resolve, reject) { - readAsync(binaryFile, function(response) { resolve(new Uint8Array(/** @type{!ArrayBuffer} */(response))) }, reject) + return new Promise((resolve, reject) => { + readAsync(binaryFile, (response) => resolve(new Uint8Array(/** @type{!ArrayBuffer} */(response))), reject) }); } } @@ -696,7 +694,7 @@ function getBinaryPromise(binaryFile) { } // Otherwise, getBinary should be able to get it synchronously - return Promise.resolve().then(function() { return getBinary(binaryFile); }); + return Promise.resolve().then(() => getBinary(binaryFile)); } #if LOAD_SOURCE_MAP @@ -822,19 +820,19 @@ function instantiateArrayBuffer(binaryFile, imports, receiver) { #if USE_OFFSET_CONVERTER var savedBinary; #endif - return getBinaryPromise(binaryFile).then(function(binary) { + return getBinaryPromise(binaryFile).then((binary) => { #if USE_OFFSET_CONVERTER savedBinary = binary; #endif return WebAssembly.instantiate(binary, imports); - }).then(function (instance) { + }).then((instance) => { #if USE_OFFSET_CONVERTER // wasmOffsetConverter needs to be assigned before calling the receiver // (receiveInstantiationResult). See comments below in instantiateAsync. wasmOffsetConverter = new WasmOffsetConverter(savedBinary, instance.module); #endif return instance; - }).then(receiver, function(reason) { + }).then(receiver, (reason) => { err('failed to asynchronously prepare wasm: ' + reason); #if WASM == 2 @@ -883,7 +881,7 @@ function instantiateAsync(binary, binaryFile, imports, callback) { !ENVIRONMENT_IS_NODE && #endif typeof fetch == 'function') { - return fetch(binaryFile, {{{ makeModuleReceiveExpr('fetchSettings', "{ credentials: 'same-origin' }") }}}).then(function(response) { + return fetch(binaryFile, {{{ makeModuleReceiveExpr('fetchSettings', "{ credentials: 'same-origin' }") }}}).then((response) => { // Suppress closure warning here since the upstream definition for // instantiateStreaming only allows Promise rather than // an actual Response. @@ -914,12 +912,12 @@ function instantiateAsync(binary, binaryFile, imports, callback) { // offset converter (in the case of pthreads, it will create the // pthreads and send them the offsets along with the wasm instance). - clonedResponsePromise.then(function(arrayBufferResult) { - wasmOffsetConverter = new WasmOffsetConverter(new Uint8Array(arrayBufferResult), instantiationResult.module); - callback(instantiationResult); - }, function(reason) { - err('failed to initialize offset-converter: ' + reason); - }); + clonedResponsePromise.then((arrayBufferResult) => { + wasmOffsetConverter = new WasmOffsetConverter(new Uint8Array(arrayBufferResult), instantiationResult.module); + callback(instantiationResult); + }, + (reason) => err('failed to initialize offset-converter: ' + reason) + ); }, #endif function(reason) { @@ -1203,7 +1201,7 @@ function runMemoryInitializer() { removeRunDependency('memory initializer'); }; var doBrowserLoad = () => { - readAsync(memoryInitializer, applyMemoryInitializer, function() { + readAsync(memoryInitializer, applyMemoryInitializer, () => { var e = new Error('could not load memory initializer ' + memoryInitializer); #if MODULARIZE readyPromiseReject(e); diff --git a/src/proxyWorker.js b/src/proxyWorker.js index c70aaa90b1d2a..9a6b50d7da331 100644 --- a/src/proxyWorker.js +++ b/src/proxyWorker.js @@ -98,9 +98,7 @@ function EventListener() { event.preventDefault = function(){}; if (event.type in this.listeners) { - this.listeners[event.type].forEach(function(listener) { - listener(event); - }); + this.listeners[event.type].forEach((listener) => listener(event)); } }; } @@ -406,9 +404,7 @@ function messageResender() { if (calledMain) { assert(messageBuffer && messageBuffer.length > 0); messageResenderTimeout = null; - messageBuffer.forEach(function(message) { - onmessage(message); - }); + messageBuffer.forEach((message) => onmessage(message)); messageBuffer = null; } else { messageResenderTimeout = setTimeout(messageResender, 100); diff --git a/src/runtime_math.js b/src/runtime_math.js index 4b8310e1a24d5..9a14fd5afe5c9 100644 --- a/src/runtime_math.js +++ b/src/runtime_math.js @@ -8,7 +8,7 @@ #if POLYFILL_OLD_MATH_FUNCTIONS || MIN_CHROME_VERSION < 28 || MIN_EDGE_VERSION < 12 || MIN_FIREFOX_VERSION < 20 || MIN_IE_VERSION != TARGET_NOT_SUPPORTED || MIN_SAFARI_VERSION < 90000 // || MIN_NODE_VERSION < 0.12 // || MIN_NODE_VERSION < 0.12 // check for imul support, and also for correctness ( https://bugs.webkit.org/show_bug.cgi?id=126345 ) -if (!Math.imul || Math.imul(0xffffffff, 5) !== -5) Math.imul = function imul(a, b) { +if (!Math.imul || Math.imul(0xffffffff, 5) !== -5) Math.imul = (a, b) => { var ah = a >>> 16; var al = a & 0xffff; var bh = b >>> 16; @@ -21,13 +21,13 @@ if (!Math.imul || Math.imul(0xffffffff, 5) !== -5) Math.imul = function imul(a, #if POLYFILL_OLD_MATH_FUNCTIONS || MIN_CHROME_VERSION < 38 || MIN_EDGE_VERSION < 12 || MIN_FIREFOX_VERSION < 26 || MIN_IE_VERSION != TARGET_NOT_SUPPORTED || MIN_SAFARI_VERSION < 80000 // || MIN_NODE_VERSION < 0.12 if (!Math.fround) { var froundBuffer = new Float32Array(1); - Math.fround = function(x) { froundBuffer[0] = x; return froundBuffer[0] }; + Math.fround = (x) => { froundBuffer[0] = x; return froundBuffer[0] }; } #endif // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/clz32 #if POLYFILL_OLD_MATH_FUNCTIONS || MIN_CHROME_VERSION < 38 || MIN_EDGE_VERSION < 12 || MIN_FIREFOX_VERSION < 31 || MIN_IE_VERSION != TARGET_NOT_SUPPORTED // || MIN_NODE_VERSION < 0.12 -if (!Math.clz32) Math.clz32 = function(x) { +if (!Math.clz32) Math.clz32 = (x) => { var n = 32; var y = x >> 16; if (y) { n -= 16; x = y; } y = x >> 8; if (y) { n -= 8; x = y; } @@ -40,7 +40,7 @@ if (!Math.clz32) Math.clz32 = function(x) { // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/trunc #if POLYFILL_OLD_MATH_FUNCTIONS || MIN_CHROME_VERSION < 38 || MIN_EDGE_VERSION < 12 || MIN_FIREFOX_VERSION < 25 || MIN_IE_VERSION != TARGET_NOT_SUPPORTED || MIN_SAFARI_VERSION < 80000 // || MIN_NODE_VERSION < 0.12 -if (!Math.trunc) Math.trunc = function(x) { +if (!Math.trunc) Math.trunc = (x) => { return x < 0 ? Math.ceil(x) : Math.floor(x); }; #endif diff --git a/src/shell.html b/src/shell.html index 58cfe57994cdd..67a4fe6837c65 100644 --- a/src/shell.html +++ b/src/shell.html @@ -1241,17 +1241,17 @@ } }; })(), - canvas: (function() { + canvas: (() => { var canvas = document.getElementById('canvas'); // As a default initial behavior, pop up an alert when webgl context is lost. To make your // application robust, you may want to override this behavior before shipping! // See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2 - canvas.addEventListener("webglcontextlost", function(e) { alert('WebGL context lost. You will need to reload the page.'); e.preventDefault(); }, false); + canvas.addEventListener("webglcontextlost", (e) => { alert('WebGL context lost. You will need to reload the page.'); e.preventDefault(); }, false); return canvas; })(), - setStatus: function(text) { + setStatus: (text) => { if (!Module.setStatus.last) Module.setStatus.last = { time: Date.now(), text: '' }; if (text === Module.setStatus.last.text) return; var m = text.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/); @@ -1274,17 +1274,17 @@ statusElement.innerHTML = text; }, totalDependencies: 0, - monitorRunDependencies: function(left) { + monitorRunDependencies: (left) => { this.totalDependencies = Math.max(this.totalDependencies, left); Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.'); } }; Module.setStatus('Downloading...'); - window.onerror = function(event) { + window.onerror = (event) => { // TODO: do not warn on ok events like simulating an infinite loop or exitStatus Module.setStatus('Exception thrown, see JavaScript console'); spinnerElement.style.display = 'none'; - Module.setStatus = function(text) { + Module.setStatus = (text) => { if (text) console.error('[post-exception status] ' + text); }; }; diff --git a/src/shell.js b/src/shell.js index 53ce84c2660a2..8796c478b1046 100644 --- a/src/shell.js +++ b/src/shell.js @@ -64,7 +64,7 @@ var Module = typeof {{{ EXPORT_NAME }}} != 'undefined' ? {{{ EXPORT_NAME }}} : { #if MODULARIZE // Set up the promise that indicates the Module is initialized var readyPromiseResolve, readyPromiseReject; -Module['ready'] = new Promise(function(resolve, reject) { +Module['ready'] = new Promise((resolve, reject) => { readyPromiseResolve = resolve; readyPromiseReject = reject; }); @@ -233,7 +233,7 @@ if (ENVIRONMENT_IS_NODE) { #endif #if NODEJS_CATCH_EXIT - process.on('uncaughtException', function(ex) { + process.on('uncaughtException', (ex) => { // suppress ExitStatus exceptions from showing an error #if RUNTIME_DEBUG dbg('node: uncaughtException: ' + ex) @@ -252,7 +252,7 @@ if (ENVIRONMENT_IS_NODE) { // See https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode var nodeMajor = process.versions.node.split(".")[0]; if (nodeMajor < 15) { - process.on('unhandledRejection', function(reason) { throw reason; }); + process.on('unhandledRejection', (reason) => { throw reason; }); } #endif @@ -261,7 +261,7 @@ if (ENVIRONMENT_IS_NODE) { throw toThrow; }; - Module['inspect'] = function () { return '[Emscripten Module object]'; }; + Module['inspect'] = () => '[Emscripten Module object]'; #if PTHREADS let nodeWorkerThreads; @@ -291,7 +291,7 @@ if (ENVIRONMENT_IS_SHELL) { #endif if (typeof read != 'undefined') { - read_ = function shell_read(f) { + read_ = (f) => { #if SUPPORT_BASE64_EMBEDDING const data = tryParseAsDataURI(f); if (data) { @@ -302,7 +302,7 @@ if (ENVIRONMENT_IS_SHELL) { }; } - readBinary = function readBinary(f) { + readBinary = (f) => { let data; #if SUPPORT_BASE64_EMBEDDING data = tryParseAsDataURI(f); @@ -318,7 +318,7 @@ if (ENVIRONMENT_IS_SHELL) { return data; }; - readAsync = function readAsync(f, onload, onerror) { + readAsync = (f, onload, onerror) => { setTimeout(() => onload(readBinary(f)), 0); }; diff --git a/src/shell_minimal.html b/src/shell_minimal.html index 14af0b17f5f4c..423441f697608 100644 --- a/src/shell_minimal.html +++ b/src/shell_minimal.html @@ -93,17 +93,17 @@ } }; })(), - canvas: (function() { + canvas: (() => { var canvas = document.getElementById('canvas'); // As a default initial behavior, pop up an alert when webgl context is lost. To make your // application robust, you may want to override this behavior before shipping! // See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2 - canvas.addEventListener("webglcontextlost", function(e) { alert('WebGL context lost. You will need to reload the page.'); e.preventDefault(); }, false); + canvas.addEventListener("webglcontextlost", (e) => { alert('WebGL context lost. You will need to reload the page.'); e.preventDefault(); }, false); return canvas; })(), - setStatus: function(text) { + setStatus: (text) => { if (!Module.setStatus.last) Module.setStatus.last = { time: Date.now(), text: '' }; if (text === Module.setStatus.last.text) return; var m = text.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/); @@ -126,16 +126,16 @@ statusElement.innerHTML = text; }, totalDependencies: 0, - monitorRunDependencies: function(left) { + monitorRunDependencies: (left) => { this.totalDependencies = Math.max(this.totalDependencies, left); Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.'); } }; Module.setStatus('Downloading...'); - window.onerror = function() { + window.onerror = () => { Module.setStatus('Exception thrown, see JavaScript console'); spinnerElement.style.display = 'none'; - Module.setStatus = function(text) { + Module.setStatus = (text) => { if (text) console.error('[post-exception status] ' + text); }; }; diff --git a/test/other/metadce/test_metadce_cxx_ctors1.jssize b/test/other/metadce/test_metadce_cxx_ctors1.jssize index 2d59af73314ee..49e2b95cc2ae9 100644 --- a/test/other/metadce/test_metadce_cxx_ctors1.jssize +++ b/test/other/metadce/test_metadce_cxx_ctors1.jssize @@ -1 +1 @@ -26083 +25939 diff --git a/test/other/metadce/test_metadce_cxx_ctors2.jssize b/test/other/metadce/test_metadce_cxx_ctors2.jssize index 8d96ed08e903f..8c9d5517f8bda 100644 --- a/test/other/metadce/test_metadce_cxx_ctors2.jssize +++ b/test/other/metadce/test_metadce_cxx_ctors2.jssize @@ -1 +1 @@ -26047 +25903 diff --git a/test/other/metadce/test_metadce_cxx_except.jssize b/test/other/metadce/test_metadce_cxx_except.jssize index d80e90bb407d3..ad26bc5dd957b 100644 --- a/test/other/metadce/test_metadce_cxx_except.jssize +++ b/test/other/metadce/test_metadce_cxx_except.jssize @@ -1 +1 @@ -30597 +30453 diff --git a/test/other/metadce/test_metadce_cxx_except_wasm.jssize b/test/other/metadce/test_metadce_cxx_except_wasm.jssize index aa8d53d4bc130..7b9c7d539c3a4 100644 --- a/test/other/metadce/test_metadce_cxx_except_wasm.jssize +++ b/test/other/metadce/test_metadce_cxx_except_wasm.jssize @@ -1 +1 @@ -25892 +25748 diff --git a/test/other/metadce/test_metadce_cxx_mangle.jssize b/test/other/metadce/test_metadce_cxx_mangle.jssize index 158bd3c8b7f99..b827c6486a83a 100644 --- a/test/other/metadce/test_metadce_cxx_mangle.jssize +++ b/test/other/metadce/test_metadce_cxx_mangle.jssize @@ -1 +1 @@ -30601 +30457 diff --git a/test/other/metadce/test_metadce_cxx_noexcept.jssize b/test/other/metadce/test_metadce_cxx_noexcept.jssize index 2d59af73314ee..49e2b95cc2ae9 100644 --- a/test/other/metadce/test_metadce_cxx_noexcept.jssize +++ b/test/other/metadce/test_metadce_cxx_noexcept.jssize @@ -1 +1 @@ -26083 +25939 diff --git a/test/other/metadce/test_metadce_hello_O0.jssize b/test/other/metadce/test_metadce_hello_O0.jssize index bc29a314d92a0..c5c5bf593e07c 100644 --- a/test/other/metadce/test_metadce_hello_O0.jssize +++ b/test/other/metadce/test_metadce_hello_O0.jssize @@ -1 +1 @@ -24060 +23795 diff --git a/test/other/metadce/test_metadce_hello_O1.jssize b/test/other/metadce/test_metadce_hello_O1.jssize index cf35faf9dce13..477a586314ed3 100644 --- a/test/other/metadce/test_metadce_hello_O1.jssize +++ b/test/other/metadce/test_metadce_hello_O1.jssize @@ -1 +1 @@ -8587 +8364 diff --git a/test/other/metadce/test_metadce_hello_O2.jssize b/test/other/metadce/test_metadce_hello_O2.jssize index 385e1b57afd33..638de7309a0eb 100644 --- a/test/other/metadce/test_metadce_hello_O2.jssize +++ b/test/other/metadce/test_metadce_hello_O2.jssize @@ -1 +1 @@ -6089 +5944 diff --git a/test/other/metadce/test_metadce_hello_O3.jssize b/test/other/metadce/test_metadce_hello_O3.jssize index 45463003085f8..f6cc210c14d5d 100644 --- a/test/other/metadce/test_metadce_hello_O3.jssize +++ b/test/other/metadce/test_metadce_hello_O3.jssize @@ -1 +1 @@ -5915 +5770 diff --git a/test/other/metadce/test_metadce_hello_Os.jssize b/test/other/metadce/test_metadce_hello_Os.jssize index 45463003085f8..f6cc210c14d5d 100644 --- a/test/other/metadce/test_metadce_hello_Os.jssize +++ b/test/other/metadce/test_metadce_hello_Os.jssize @@ -1 +1 @@ -5915 +5770 diff --git a/test/other/metadce/test_metadce_hello_Oz.jssize b/test/other/metadce/test_metadce_hello_Oz.jssize index 680ccbafeb3bd..07176ad9c13dc 100644 --- a/test/other/metadce/test_metadce_hello_Oz.jssize +++ b/test/other/metadce/test_metadce_hello_Oz.jssize @@ -1 +1 @@ -5874 +5729 diff --git a/test/other/metadce/test_metadce_hello_dylink.jssize b/test/other/metadce/test_metadce_hello_dylink.jssize index 041ee984857a1..1f68fb0a193ea 100644 --- a/test/other/metadce/test_metadce_hello_dylink.jssize +++ b/test/other/metadce/test_metadce_hello_dylink.jssize @@ -1 +1 @@ -28142 +27884 diff --git a/test/other/metadce/test_metadce_hello_export_nothing.jssize b/test/other/metadce/test_metadce_hello_export_nothing.jssize index 092b8f173fcb7..bc14fa04a5289 100644 --- a/test/other/metadce/test_metadce_hello_export_nothing.jssize +++ b/test/other/metadce/test_metadce_hello_export_nothing.jssize @@ -1 +1 @@ -4658 +4514 diff --git a/test/other/metadce/test_metadce_libcxxabi_message_O3.jssize b/test/other/metadce/test_metadce_libcxxabi_message_O3.jssize index 27d80a3e2e52e..89810b1541216 100644 --- a/test/other/metadce/test_metadce_libcxxabi_message_O3.jssize +++ b/test/other/metadce/test_metadce_libcxxabi_message_O3.jssize @@ -1 +1 @@ -5185 +5040 diff --git a/test/other/metadce/test_metadce_libcxxabi_message_O3_standalone.jssize b/test/other/metadce/test_metadce_libcxxabi_message_O3_standalone.jssize index cc1d64bcf857b..800920fac0dbc 100644 --- a/test/other/metadce/test_metadce_libcxxabi_message_O3_standalone.jssize +++ b/test/other/metadce/test_metadce_libcxxabi_message_O3_standalone.jssize @@ -1 +1 @@ -5253 +5108 diff --git a/test/other/metadce/test_metadce_mem_O3.jssize b/test/other/metadce/test_metadce_mem_O3.jssize index cc841ddb939d2..a37e2a8309c39 100644 --- a/test/other/metadce/test_metadce_mem_O3.jssize +++ b/test/other/metadce/test_metadce_mem_O3.jssize @@ -1 +1 @@ -6124 +5980 diff --git a/test/other/metadce/test_metadce_mem_O3_grow.jssize b/test/other/metadce/test_metadce_mem_O3_grow.jssize index 7cadbcb28841d..21faf3262f93b 100644 --- a/test/other/metadce/test_metadce_mem_O3_grow.jssize +++ b/test/other/metadce/test_metadce_mem_O3_grow.jssize @@ -1 +1 @@ -6460 +6316 diff --git a/test/other/metadce/test_metadce_mem_O3_grow_standalone.jssize b/test/other/metadce/test_metadce_mem_O3_grow_standalone.jssize index eaadb4de9b93a..1e587493b7d85 100644 --- a/test/other/metadce/test_metadce_mem_O3_grow_standalone.jssize +++ b/test/other/metadce/test_metadce_mem_O3_grow_standalone.jssize @@ -1 +1 @@ -5850 +5706 diff --git a/test/other/metadce/test_metadce_mem_O3_standalone.jssize b/test/other/metadce/test_metadce_mem_O3_standalone.jssize index ebbcf42ed4e54..142e175a948df 100644 --- a/test/other/metadce/test_metadce_mem_O3_standalone.jssize +++ b/test/other/metadce/test_metadce_mem_O3_standalone.jssize @@ -1 +1 @@ -5772 +5628 diff --git a/test/other/metadce/test_metadce_mem_O3_standalone_lib.jssize b/test/other/metadce/test_metadce_mem_O3_standalone_lib.jssize index 05112f24d5e8d..8fc0c002218ce 100644 --- a/test/other/metadce/test_metadce_mem_O3_standalone_lib.jssize +++ b/test/other/metadce/test_metadce_mem_O3_standalone_lib.jssize @@ -1 +1 @@ -5271 +5126 diff --git a/test/other/metadce/test_metadce_mem_O3_standalone_narg.jssize b/test/other/metadce/test_metadce_mem_O3_standalone_narg.jssize index cc1d64bcf857b..800920fac0dbc 100644 --- a/test/other/metadce/test_metadce_mem_O3_standalone_narg.jssize +++ b/test/other/metadce/test_metadce_mem_O3_standalone_narg.jssize @@ -1 +1 @@ -5253 +5108 diff --git a/test/other/metadce/test_metadce_mem_O3_standalone_narg_flto.jssize b/test/other/metadce/test_metadce_mem_O3_standalone_narg_flto.jssize index cc1d64bcf857b..800920fac0dbc 100644 --- a/test/other/metadce/test_metadce_mem_O3_standalone_narg_flto.jssize +++ b/test/other/metadce/test_metadce_mem_O3_standalone_narg_flto.jssize @@ -1 +1 @@ -5253 +5108 diff --git a/test/other/metadce/test_metadce_minimal_64.jssize b/test/other/metadce/test_metadce_minimal_64.jssize index 801c306ed34de..12167a2b4e159 100644 --- a/test/other/metadce/test_metadce_minimal_64.jssize +++ b/test/other/metadce/test_metadce_minimal_64.jssize @@ -1 +1 @@ -4096 +3952 diff --git a/test/other/metadce/test_metadce_minimal_O0.jssize b/test/other/metadce/test_metadce_minimal_O0.jssize index ee1f2431383fb..276217eb048bd 100644 --- a/test/other/metadce/test_metadce_minimal_O0.jssize +++ b/test/other/metadce/test_metadce_minimal_O0.jssize @@ -1 +1 @@ -20309 +20044 diff --git a/test/other/metadce/test_metadce_minimal_O1.jssize b/test/other/metadce/test_metadce_minimal_O1.jssize index e3bda3519fc45..3c4089ce00ff3 100644 --- a/test/other/metadce/test_metadce_minimal_O1.jssize +++ b/test/other/metadce/test_metadce_minimal_O1.jssize @@ -1 +1 @@ -4901 +4678 diff --git a/test/other/metadce/test_metadce_minimal_O2.jssize b/test/other/metadce/test_metadce_minimal_O2.jssize index bcd68d60a016c..ffb0927ae4ae7 100644 --- a/test/other/metadce/test_metadce_minimal_O2.jssize +++ b/test/other/metadce/test_metadce_minimal_O2.jssize @@ -1 +1 @@ -3756 +3612 diff --git a/test/other/metadce/test_metadce_minimal_O3.jssize b/test/other/metadce/test_metadce_minimal_O3.jssize index 34d73a1238d21..c9818c5c65dfe 100644 --- a/test/other/metadce/test_metadce_minimal_O3.jssize +++ b/test/other/metadce/test_metadce_minimal_O3.jssize @@ -1 +1 @@ -3685 +3541 diff --git a/test/other/metadce/test_metadce_minimal_Os.jssize b/test/other/metadce/test_metadce_minimal_Os.jssize index 34d73a1238d21..c9818c5c65dfe 100644 --- a/test/other/metadce/test_metadce_minimal_Os.jssize +++ b/test/other/metadce/test_metadce_minimal_Os.jssize @@ -1 +1 @@ -3685 +3541 diff --git a/test/other/metadce/test_metadce_minimal_Oz-ctors.jssize b/test/other/metadce/test_metadce_minimal_Oz-ctors.jssize index 1149062c66bf4..51feb77641d07 100644 --- a/test/other/metadce/test_metadce_minimal_Oz-ctors.jssize +++ b/test/other/metadce/test_metadce_minimal_Oz-ctors.jssize @@ -1 +1 @@ -3666 +3522 diff --git a/test/other/metadce/test_metadce_minimal_Oz.jssize b/test/other/metadce/test_metadce_minimal_Oz.jssize index 34d73a1238d21..c9818c5c65dfe 100644 --- a/test/other/metadce/test_metadce_minimal_Oz.jssize +++ b/test/other/metadce/test_metadce_minimal_Oz.jssize @@ -1 +1 @@ -3685 +3541 diff --git a/test/other/metadce/test_metadce_minimal_pthreads.jssize b/test/other/metadce/test_metadce_minimal_pthreads.jssize index 408489c67ae57..a8720b55c8c44 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.jssize +++ b/test/other/metadce/test_metadce_minimal_pthreads.jssize @@ -1 +1 @@ -15593 +15448 diff --git a/test/other/test_unoptimized_code_size.js.size b/test/other/test_unoptimized_code_size.js.size index f506c84049a5e..f44658ab30b09 100644 --- a/test/other/test_unoptimized_code_size.js.size +++ b/test/other/test_unoptimized_code_size.js.size @@ -1 +1 @@ -59784 +59613 diff --git a/test/other/test_unoptimized_code_size_no_asserts.js.size b/test/other/test_unoptimized_code_size_no_asserts.js.size index ef712ab7159a8..684f212104582 100644 --- a/test/other/test_unoptimized_code_size_no_asserts.js.size +++ b/test/other/test_unoptimized_code_size_no_asserts.js.size @@ -1 +1 @@ -33403 +33284 diff --git a/test/other/test_unoptimized_code_size_strict.js.size b/test/other/test_unoptimized_code_size_strict.js.size index 20347f1fe5107..cd1258f5c0977 100644 --- a/test/other/test_unoptimized_code_size_strict.js.size +++ b/test/other/test_unoptimized_code_size_strict.js.size @@ -1 +1 @@ -58726 +58555 diff --git a/test/test_browser.py b/test/test_browser.py index fd86fe0e134d6..7cf8cd999665e 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -4414,7 +4414,7 @@ def test_small_js_flags(self): size = os.path.getsize('test.js') print('size:', size) # Note that this size includes test harness additions (for reporting the result, etc.). - self.assertLess(abs(size - 5100), 100) + self.assertLess(abs(size - 4930), 100) # Tests that it is possible to initialize and render WebGL content in a pthread by using OffscreenCanvas. # -DTEST_CHAINED_WEBGL_CONTEXT_PASSING: Tests that it is possible to transfer WebGL canvas in a chain from main thread -> thread 1 -> thread 2 and then init and render WebGL content there. From a531c682f162633d94f64a7787db2e50186c0c0c Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 24 Apr 2023 13:36:33 -0700 Subject: [PATCH 0163/1523] Deprecate `sep` argument to makeSetValue. NFC (#19240) This argument was not actually being used anywhere. Its last usage was removed in #18678. --- src/parseTools.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/parseTools.js b/src/parseTools.js index b11f046982430..20fda91a03ce8 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -357,20 +357,21 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align) { * @param {bool} noNeedFirst Whether to ignore the offset in the pointer itself. * @param {bool} ignore: legacy, ignored. * @param {number} align: legacy, ignored. - * @param {string} sep: TODO + * @param {string} sep: legacy, ignored. * @return {TODO} */ -function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, sep = ';') { +function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, sep) { assert(typeof align === 'undefined', 'makeSetValue no longer supports align parameter'); assert(typeof noNeedFirst === 'undefined', 'makeSetValue no longer supports noNeedFirst parameter'); + assert(typeof sep === 'undefined', 'makeSetValue no longer supports sep parameter'); if (type == 'i64' && (!WASM_BIGINT || !MEMORY64)) { // If we lack either BigInt support or Memory64 then we must fall back to an // unaligned read of a 64-bit value: without BigInt we do not have HEAP64, // and without Memory64 i64 fields are not guaranteed to be aligned to 64 // bits, so HEAP64[ptr>>3] might be broken. return '(tempI64 = [' + splitI64(value) + '],' + - makeSetValue(ptr, pos, 'tempI64[0]', 'i32', noNeedFirst, ignore, align, ',') + ',' + - makeSetValue(ptr, getFastValue(pos, '+', getNativeTypeSize('i32')), 'tempI64[1]', 'i32', noNeedFirst, ignore, align, ',') + ')'; + makeSetValue(ptr, pos, 'tempI64[0]', 'i32') + ',' + + makeSetValue(ptr, getFastValue(pos, '+', getNativeTypeSize('i32')), 'tempI64[1]', 'i32') + ')'; } const offset = calcFastOffset(ptr, pos); From e3f334c00ba0240b42fd5fed9508db3252096392 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 24 Apr 2023 14:23:07 -0700 Subject: [PATCH 0164/1523] Add auto-generated signatures for LEGACY_GL_EMULATION symbols. NFC (#19235) I had to add declaration for a few GL extensions which we define in JS both via the ARB name as well as the base name. --- emcc.py | 6 ++- src/library_glemu.js | 22 +++----- src/library_sigs.js | 105 ++++++++++++++++++++++++++++++++++++++ src/library_webgl.js | 16 +++--- system/include/GL/glext.h | 4 ++ tools/gen_sig_info.py | 14 +++-- 6 files changed, 137 insertions(+), 30 deletions(-) diff --git a/emcc.py b/emcc.py index ca01f096764d9..781132126d8fb 100755 --- a/emcc.py +++ b/emcc.py @@ -1950,11 +1950,13 @@ def phase_linker_setup(options, state, newargs): if '_main' in settings.EXPORTED_FUNCTIONS: settings.EXPORT_IF_DEFINED.append('__main_argc_argv') - elif settings.ASSERTIONS: - # In debug builds when `main` is not explictly requested as an + elif settings.ASSERTIONS and not settings.STANDALONE_WASM: + # In debug builds when `main` is not explicitly requested as an # export we still add it to EXPORT_IF_DEFINED so that we can warn # users who forget to explicitly export `main`. # See other.test_warn_unexported_main. + # This is not needed in STANDALONE_WASM mode since we export _start + # (unconditionally) rather than main. settings.EXPORT_IF_DEFINED.append('main') if settings.ASSERTIONS: diff --git a/src/library_glemu.js b/src/library_glemu.js index 654ee7a130db8..4b10f3bc6252e 100644 --- a/src/library_glemu.js +++ b/src/library_glemu.js @@ -754,7 +754,6 @@ var LibraryGLEmulation = { }, glDeleteObject__deps: ['glDeleteProgram', 'glDeleteShader'], - glDeleteObject__sig: 'vi', glDeleteObject: function(id) { if (GL.programs[id]) { _glDeleteProgram(id); @@ -766,7 +765,6 @@ var LibraryGLEmulation = { }, glDeleteObjectARB: 'glDeleteObject', - glGetObjectParameteriv__sig: 'viii', glGetObjectParameteriv__deps: ['glGetProgramiv', 'glGetShaderiv'], glGetObjectParameteriv: function(id, type, result) { if (GL.programs[id]) { @@ -797,7 +795,6 @@ var LibraryGLEmulation = { glGetObjectParameterivARB: 'glGetObjectParameteriv', glGetInfoLog__deps: ['glGetProgramInfoLog', 'glGetShaderInfoLog'], - glGetInfoLog__sig: 'viiii', glGetInfoLog: function(id, maxLength, length, infoLog) { if (GL.programs[id]) { _glGetProgramInfoLog(id, maxLength, length, infoLog); @@ -809,7 +806,6 @@ var LibraryGLEmulation = { }, glGetInfoLogARB: 'glGetInfoLog', - glBindProgram__sig: 'vii', glBindProgram: function(type, id) { #if ASSERTIONS assert(id == 0); @@ -3515,7 +3511,6 @@ var LibraryGLEmulation = { #endif }, - glClientActiveTexture__sig: 'vi', glClientActiveTexture: function(texture) { GLImmediate.clientActiveTexture = texture - 0x84C0; // GL_TEXTURE0 }, @@ -3562,9 +3557,8 @@ var LibraryGLEmulation = { }, // Vertex array object (VAO) support. TODO: when the WebGL extension is popular, use that and remove this code and GL.vaos - emulGlGenVertexArrays__deps: ['$GLEmulation'], - emulGlGenVertexArrays__sig: 'vii', - emulGlGenVertexArrays: function(n, vaos) { + $emulGlGenVertexArrays__deps: ['$GLEmulation'], + $emulGlGenVertexArrays: function(n, vaos) { for (var i = 0; i < n; i++) { var id = GL.getNewId(GLEmulation.vaos); GLEmulation.vaos[id] = { @@ -3578,23 +3572,20 @@ var LibraryGLEmulation = { {{{ makeSetValue('vaos', 'i*4', 'id', 'i32') }}}; } }, - emulGlDeleteVertexArrays__sig: 'vii', - emulGlDeleteVertexArrays: function(n, vaos) { + $emulGlDeleteVertexArrays: function(n, vaos) { for (var i = 0; i < n; i++) { var id = {{{ makeGetValue('vaos', 'i*4', 'i32') }}}; GLEmulation.vaos[id] = null; if (GLEmulation.currentVao && GLEmulation.currentVao.id == id) GLEmulation.currentVao = null; } }, - emulGlIsVertexArray__sig: 'vi', - emulGlIsVertexArray: function(array) { + $emulGlIsVertexArray: function(array) { var vao = GLEmulation.vaos[array]; if (!vao) return 0; return 1; }, - emulGlBindVertexArray__deps: ['glBindBuffer', 'glEnableVertexAttribArray', 'glVertexAttribPointer', 'glEnableClientState'], - emulGlBindVertexArray__sig: 'vi', - emulGlBindVertexArray: function(vao) { + $emulGlBindVertexArray__deps: ['glBindBuffer', 'glEnableVertexAttribArray', 'glVertexAttribPointer', 'glEnableClientState'], + $emulGlBindVertexArray: function(vao) { // undo vao-related things, wipe the slate clean, both for vao of 0 or an actual vao GLEmulation.currentVao = null; // make sure the commands we run here are not recorded if (GLImmediate.lastRenderer) GLImmediate.lastRenderer.cleanup(); @@ -3671,7 +3662,6 @@ var LibraryGLEmulation = { GLImmediate.matrixLib.mat4.set({{{ makeHEAPView('F64', 'matrix', 'matrix+' + (16*8)) }}}, GLImmediate.matrix[GLImmediate.currentMatrix]); }, - glLoadMatrixf__sig: 'vp', glLoadMatrixf: function(matrix) { #if GL_DEBUG if (GL.debug) dbg('glLoadMatrixf receiving: ' + Array.prototype.slice.call(HEAPF32.subarray(matrix >> 2, (matrix >> 2) + 16))); diff --git a/src/library_sigs.js b/src/library_sigs.js index 51dae2f194323..428d72e3557d1 100644 --- a/src/library_sigs.js +++ b/src/library_sigs.js @@ -713,6 +713,7 @@ sigs = { getprotobynumber__sig: 'pi', getprotoent__sig: 'p', glActiveTexture__sig: 'vi', + glAlphaFunc__sig: 'vif', glAttachShader__sig: 'vii', glBegin__sig: 'vi', glBeginQuery__sig: 'vii', @@ -722,7 +723,10 @@ sigs = { glBindBufferBase__sig: 'viii', glBindBufferRange__sig: 'viiipp', glBindFramebuffer__sig: 'vii', + glBindFramebufferOES__sig: 'vii', + glBindProgram__sig: 'vii', glBindRenderbuffer__sig: 'vii', + glBindRenderbufferOES__sig: 'vii', glBindSampler__sig: 'vii', glBindTexture__sig: 'vii', glBindTransformFeedback__sig: 'vii', @@ -737,6 +741,7 @@ sigs = { glBufferData__sig: 'vippi', glBufferSubData__sig: 'vippp', glCheckFramebufferStatus__sig: 'ii', + glCheckFramebufferStatusOES__sig: 'ii', glClear__sig: 'vi', glClearBufferfi__sig: 'viifi', glClearBufferfv__sig: 'viip', @@ -746,8 +751,27 @@ sigs = { glClearDepth__sig: 'vd', glClearDepthf__sig: 'vf', glClearStencil__sig: 'vi', + glClientActiveTexture__sig: 'vi', glClientWaitSync__sig: 'ipij', + glClipPlane__sig: 'vip', + glColor3d__sig: 'vddd', + glColor3f__sig: 'vfff', + glColor3fv__sig: 'vp', + glColor3ub__sig: 'viii', + glColor3ubv__sig: 'vp', + glColor3ui__sig: 'viii', + glColor3uiv__sig: 'vp', + glColor3us__sig: 'viii', + glColor3usv__sig: 'vp', + glColor4d__sig: 'vdddd', + glColor4f__sig: 'vffff', + glColor4fv__sig: 'vp', + glColor4ub__sig: 'viiii', + glColor4ubv__sig: 'vp', + glColor4ui__sig: 'viiii', + glColor4us__sig: 'viiii', glColorMask__sig: 'viiii', + glColorPointer__sig: 'viiip', glCompileShader__sig: 'vi', glCompressedTexImage2D__sig: 'viiiiiiip', glCompressedTexImage3D__sig: 'viiiiiiiip', @@ -762,9 +786,12 @@ sigs = { glCullFace__sig: 'vi', glDeleteBuffers__sig: 'vip', glDeleteFramebuffers__sig: 'vip', + glDeleteFramebuffersOES__sig: 'vip', + glDeleteObject__sig: 'vi', glDeleteProgram__sig: 'vi', glDeleteQueries__sig: 'vip', glDeleteRenderbuffers__sig: 'vip', + glDeleteRenderbuffersOES__sig: 'vip', glDeleteSamplers__sig: 'vip', glDeleteShader__sig: 'vi', glDeleteSync__sig: 'vp', @@ -778,30 +805,46 @@ sigs = { glDepthRangef__sig: 'vff', glDetachShader__sig: 'vii', glDisable__sig: 'vi', + glDisableClientState__sig: 'vi', glDisableVertexAttribArray__sig: 'vi', glDrawArrays__sig: 'viii', glDrawArraysInstanced__sig: 'viiii', glDrawArraysInstancedBaseInstance__sig: 'viiiii', + glDrawBuffer__sig: 'vi', glDrawBuffers__sig: 'vip', glDrawElements__sig: 'viiip', glDrawElementsInstanced__sig: 'viiipi', glDrawRangeElements__sig: 'viiiiip', glEnable__sig: 'vi', + glEnableClientState__sig: 'vi', glEnableVertexAttribArray__sig: 'vi', + glEnd__sig: 'v', glEndQuery__sig: 'vi', glEndTransformFeedback__sig: 'v', glFenceSync__sig: 'pii', glFinish__sig: 'v', glFlush__sig: 'v', glFlushMappedBufferRange__sig: 'vipp', + glFogf__sig: 'vif', + glFogfv__sig: 'vip', + glFogi__sig: 'vii', + glFogiv__sig: 'vip', + glFogx__sig: 'vii', + glFogxv__sig: 'vip', glFramebufferRenderbuffer__sig: 'viiii', + glFramebufferRenderbufferOES__sig: 'viiii', glFramebufferTexture2D__sig: 'viiiii', + glFramebufferTexture2DOES__sig: 'viiiii', glFramebufferTextureLayer__sig: 'viiiii', glFrontFace__sig: 'vi', + glFrustum__sig: 'vdddddd', + glFrustumf__sig: 'vffffff', glGenBuffers__sig: 'vip', glGenFramebuffers__sig: 'vip', + glGenFramebuffersOES__sig: 'vip', glGenQueries__sig: 'vip', glGenRenderbuffers__sig: 'vip', + glGenRenderbuffersOES__sig: 'vip', glGenSamplers__sig: 'vip', glGenTextures__sig: 'vip', glGenTransformFeedbacks__sig: 'vip', @@ -824,17 +867,21 @@ sigs = { glGetFloatv__sig: 'vip', glGetFragDataLocation__sig: 'iip', glGetFramebufferAttachmentParameteriv__sig: 'viiip', + glGetInfoLog__sig: 'viipp', glGetInteger64i_v__sig: 'viip', glGetInteger64v__sig: 'vip', glGetIntegeri_v__sig: 'viip', glGetIntegerv__sig: 'vip', glGetInternalformativ__sig: 'viiiip', + glGetObjectParameteriv__sig: 'viip', + glGetPointerv__sig: 'vip', glGetProgramBinary__sig: 'viippp', glGetProgramInfoLog__sig: 'viipp', glGetProgramiv__sig: 'viip', glGetQueryObjectuiv__sig: 'viip', glGetQueryiv__sig: 'viip', glGetRenderbufferParameteriv__sig: 'viip', + glGetRenderbufferParameterivOES__sig: 'viip', glGetSamplerParameterfv__sig: 'viip', glGetSamplerParameteriv__sig: 'viip', glGetShaderInfoLog__sig: 'viipp', @@ -844,6 +891,9 @@ sigs = { glGetString__sig: 'pi', glGetStringi__sig: 'pii', glGetSynciv__sig: 'vpiipp', + glGetTexEnvfv__sig: 'viip', + glGetTexEnviv__sig: 'viip', + glGetTexLevelParameteriv__sig: 'viiip', glGetTexParameterfv__sig: 'viip', glGetTexParameteriv__sig: 'viip', glGetTransformFeedbackVarying__sig: 'viiipppp', @@ -874,30 +924,57 @@ sigs = { glIsTransformFeedback__sig: 'ii', glIsVertexArray__sig: 'ii', glIsVertexArrayOES__sig: 'ii', + glLightModelf__sig: 'vif', + glLightModelfv__sig: 'vip', + glLightfv__sig: 'viip', glLineWidth__sig: 'vf', glLinkProgram__sig: 'vi', glLoadIdentity__sig: 'v', + glLoadMatrixd__sig: 'vp', + glLoadMatrixf__sig: 'vp', + glLoadTransposeMatrixd__sig: 'vp', + glLoadTransposeMatrixf__sig: 'vp', glMapBufferRange__sig: 'pippi', + glMaterialfv__sig: 'viip', glMatrixMode__sig: 'vi', + glMultMatrixd__sig: 'vp', + glMultMatrixf__sig: 'vp', + glMultTransposeMatrixd__sig: 'vp', + glMultTransposeMatrixf__sig: 'vp', glMultiDrawArrays__sig: 'vippi', glMultiDrawElements__sig: 'vipipi', + glNormal3f__sig: 'vfff', + glNormal3fv__sig: 'vp', + glNormalPointer__sig: 'viip', + glOrtho__sig: 'vdddddd', + glOrthof__sig: 'vffffff', glPauseTransformFeedback__sig: 'v', glPixelStorei__sig: 'vii', + glPointSize__sig: 'vf', + glPolygonMode__sig: 'vii', glPolygonOffset__sig: 'vff', + glPopMatrix__sig: 'v', glProgramBinary__sig: 'viipi', glProgramParameteri__sig: 'viii', + glPushMatrix__sig: 'v', glReadBuffer__sig: 'vi', glReadPixels__sig: 'viiiiiip', glReleaseShaderCompiler__sig: 'v', glRenderbufferStorage__sig: 'viiii', glRenderbufferStorageMultisample__sig: 'viiiii', + glRenderbufferStorageOES__sig: 'viiii', glResumeTransformFeedback__sig: 'v', + glRotated__sig: 'vdddd', + glRotatef__sig: 'vffff', glSampleCoverage__sig: 'vfi', glSamplerParameterf__sig: 'viif', glSamplerParameterfv__sig: 'viip', glSamplerParameteri__sig: 'viii', glSamplerParameteriv__sig: 'viip', + glScaled__sig: 'vddd', + glScalef__sig: 'vfff', glScissor__sig: 'viiii', + glShadeModel__sig: 'vi', glShaderBinary__sig: 'vipipi', glShaderSource__sig: 'viipp', glStencilFunc__sig: 'viii', @@ -906,6 +983,18 @@ sigs = { glStencilMaskSeparate__sig: 'vii', glStencilOp__sig: 'viii', glStencilOpSeparate__sig: 'viiii', + glTexCoord2f__sig: 'vff', + glTexCoord2fv__sig: 'vp', + glTexCoord2i__sig: 'vii', + glTexCoord3f__sig: 'vfff', + glTexCoord4f__sig: 'vffff', + glTexCoordPointer__sig: 'viiip', + glTexEnvf__sig: 'viif', + glTexEnvfv__sig: 'viip', + glTexEnvi__sig: 'viii', + glTexGenfv__sig: 'viip', + glTexGeni__sig: 'viii', + glTexImage1D__sig: 'viiiiiiip', glTexImage2D__sig: 'viiiiiiiip', glTexImage3D__sig: 'viiiiiiiiip', glTexParameterf__sig: 'viif', @@ -917,6 +1006,8 @@ sigs = { glTexSubImage2D__sig: 'viiiiiiiip', glTexSubImage3D__sig: 'viiiiiiiiiip', glTransformFeedbackVaryings__sig: 'viipi', + glTranslated__sig: 'vddd', + glTranslatef__sig: 'vfff', glUniform1f__sig: 'vif', glUniform1fv__sig: 'viip', glUniform1i__sig: 'vii', @@ -954,6 +1045,15 @@ sigs = { glUnmapBuffer__sig: 'ii', glUseProgram__sig: 'vi', glValidateProgram__sig: 'vi', + glVertex2f__sig: 'vff', + glVertex2fv__sig: 'vp', + glVertex2i__sig: 'vii', + glVertex3f__sig: 'vfff', + glVertex3fv__sig: 'vp', + glVertex3i__sig: 'viii', + glVertex4f__sig: 'vffff', + glVertex4fv__sig: 'vp', + glVertex4i__sig: 'viiii', glVertexAttrib1f__sig: 'vif', glVertexAttrib1fv__sig: 'vip', glVertexAttrib2f__sig: 'viff', @@ -977,6 +1077,11 @@ sigs = { glewGetString__sig: 'pi', glewInit__sig: 'i', glewIsSupported__sig: 'ip', + gluLookAt__sig: 'vddddddddd', + gluOrtho2D__sig: 'vdddd', + gluPerspective__sig: 'vdddd', + gluProject__sig: 'idddpppppp', + gluUnProject__sig: 'idddpppppp', glutCreateWindow__sig: 'ip', glutDestroyWindow__sig: 'vi', glutDisplayFunc__sig: 'vp', diff --git a/src/library_webgl.js b/src/library_webgl.js index 8c4d788c5d8cb..0350f6236c435 100644 --- a/src/library_webgl.js +++ b/src/library_webgl.js @@ -3555,12 +3555,12 @@ var LibraryGL = { glGenVertexArrays__deps: ['$__glGenObject' #if LEGACY_GL_EMULATION - , 'emulGlGenVertexArrays' + , '$emulGlGenVertexArrays' #endif ], glGenVertexArrays: function (n, arrays) { #if LEGACY_GL_EMULATION - _emulGlGenVertexArrays(n, arrays); + emulGlGenVertexArrays(n, arrays); #else #if GL_ASSERTIONS assert(GLctx.createVertexArray, 'Must have WebGL2 or OES_vertex_array_object to use vao'); @@ -3574,11 +3574,11 @@ var LibraryGL = { }, #if LEGACY_GL_EMULATION - glDeleteVertexArrays__deps: ['emulGlDeleteVertexArrays'], + glDeleteVertexArrays__deps: ['$emulGlDeleteVertexArrays'], #endif glDeleteVertexArrays: function(n, vaos) { #if LEGACY_GL_EMULATION - _emulGlDeleteVertexArrays(n, vaos); + emulGlDeleteVertexArrays(n, vaos); #else #if GL_ASSERTIONS assert(GLctx.deleteVertexArray, 'Must have WebGL2 or OES_vertex_array_object to use vao'); @@ -3592,11 +3592,11 @@ var LibraryGL = { }, #if LEGACY_GL_EMULATION - glBindVertexArray__deps: ['emulGlBindVertexArray'], + glBindVertexArray__deps: ['$emulGlBindVertexArray'], #endif glBindVertexArray: function(vao) { #if LEGACY_GL_EMULATION - _emulGlBindVertexArray(vao); + emulGlBindVertexArray(vao); #else #if GL_ASSERTIONS assert(GLctx.bindVertexArray, 'Must have WebGL2 or OES_vertex_array_object to use vao'); @@ -3610,11 +3610,11 @@ var LibraryGL = { }, #if LEGACY_GL_EMULATION - glIsVertexArray__deps: ['emulGlIsVertexArray'], + glIsVertexArray__deps: ['$emulGlIsVertexArray'], #endif glIsVertexArray: function(array) { #if LEGACY_GL_EMULATION - return _emulGlIsVertexArray(array); + return emulGlIsVertexArray(array); #else #if GL_ASSERTIONS assert(GLctx.isVertexArray, 'Must have WebGL2 or OES_vertex_array_object to use vao'); diff --git a/system/include/GL/glext.h b/system/include/GL/glext.h index 4f395f62cfe14..26bb40eab3af0 100644 --- a/system/include/GL/glext.h +++ b/system/include/GL/glext.h @@ -3267,6 +3267,7 @@ typedef void (APIENTRYP PFNGLGETPROGRAMSTRINGARBPROC) (GLenum target, GLenum pna typedef GLboolean (APIENTRYP PFNGLISPROGRAMARBPROC) (GLuint program); #ifdef GL_GLEXT_PROTOTYPES GLAPI void APIENTRY glProgramStringARB (GLenum target, GLenum format, GLsizei len, const void *string); +GLAPI void APIENTRY glBindProgram (GLenum target, GLuint program); GLAPI void APIENTRY glBindProgramARB (GLenum target, GLuint program); GLAPI void APIENTRY glDeleteProgramsARB (GLsizei n, const GLuint *programs); GLAPI void APIENTRY glGenProgramsARB (GLsizei n, GLuint *programs); @@ -4151,6 +4152,7 @@ typedef void (APIENTRYP PFNGLGETUNIFORMFVARBPROC) (GLhandleARB programObj, GLint typedef void (APIENTRYP PFNGLGETUNIFORMIVARBPROC) (GLhandleARB programObj, GLint location, GLint *params); typedef void (APIENTRYP PFNGLGETSHADERSOURCEARBPROC) (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source); #ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glDeleteObject (GLhandleARB obj); GLAPI void APIENTRY glDeleteObjectARB (GLhandleARB obj); GLAPI GLhandleARB APIENTRY glGetHandleARB (GLenum pname); GLAPI void APIENTRY glDetachObjectARB (GLhandleARB containerObj, GLhandleARB attachedObj); @@ -4182,7 +4184,9 @@ GLAPI void APIENTRY glUniformMatrix2fvARB (GLint location, GLsizei count, GLbool GLAPI void APIENTRY glUniformMatrix3fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glUniformMatrix4fvARB (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); GLAPI void APIENTRY glGetObjectParameterfvARB (GLhandleARB obj, GLenum pname, GLfloat *params); +GLAPI void APIENTRY glGetObjectParameteriv (GLhandleARB obj, GLenum pname, GLint *params); GLAPI void APIENTRY glGetObjectParameterivARB (GLhandleARB obj, GLenum pname, GLint *params); +GLAPI void APIENTRY glGetInfoLog (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog); GLAPI void APIENTRY glGetInfoLogARB (GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog); GLAPI void APIENTRY glGetAttachedObjectsARB (GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj); GLAPI GLint APIENTRY glGetUniformLocationARB (GLhandleARB programObj, const GLcharARB *name); diff --git a/tools/gen_sig_info.py b/tools/gen_sig_info.py index e1a653c333dd1..7620a5cd3ee2e 100755 --- a/tools/gen_sig_info.py +++ b/tools/gen_sig_info.py @@ -66,9 +66,15 @@ // Public library headers #define GL_GLEXT_PROTOTYPES +#ifdef GLES +#include +#include +#else #include -#include +#include +#endif #include +#include #include #include #include @@ -229,13 +235,12 @@ def extract_sigs(symbols, obj_file): def extract_sig_info(sig_info, extra_settings=None, extra_cflags=None): + print(' .. ' + str(extra_settings) + ' + ' + str(extra_cflags)) tempfiles = shared.get_temp_files() settings = { # Enable as many settings as we can here to ensure the maximum number # of JS symbols are included. 'STACK_OVERFLOW_CHECK': 1, - 'MAX_WEBGL_VERSION': 2, - 'FULL_ES3': 1, 'USE_SDL': 1, 'FETCH': 1, 'PTHREADS': 1, @@ -312,7 +317,8 @@ def main(args): print('generating signatures ...') sig_info = {} - extract_sig_info(sig_info) + extract_sig_info(sig_info, {'LEGACY_GL_EMULATION': 1}, ['-DGLES']) + extract_sig_info(sig_info, {'FULL_ES3': 1, 'MAX_WEBGL_VERSION': 2}) extract_sig_info(sig_info, {'STANDALONE_WASM': 1}) extract_sig_info(sig_info, {'MAIN_MODULE': 2}) From 77c9eabcb323b9fe9b2ee624932f3dbfe29a574d Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 24 Apr 2023 16:13:57 -0700 Subject: [PATCH 0165/1523] Allow `-fexceptions` to work in standalone mode (#19237) Fixes: #19237 --- embuilder.py | 2 +- system/lib/standalone/standalone.c | 14 ++++---------- test/test_other.py | 1 + tools/system_libs.py | 8 +++++++- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/embuilder.py b/embuilder.py index 4a4bd933623ee..c8e65d03d265d 100755 --- a/embuilder.py +++ b/embuilder.py @@ -61,7 +61,7 @@ 'libsockets', 'libstubs', 'libstubs-debug', - 'libstandalonewasm', + 'libstandalonewasm-nocatch', 'crt1', 'crt1_proxy_main', 'libunwind-except', diff --git a/system/lib/standalone/standalone.c b/system/lib/standalone/standalone.c index 366e60d76fd54..f50aef4678c66 100644 --- a/system/lib/standalone/standalone.c +++ b/system/lib/standalone/standalone.c @@ -157,19 +157,13 @@ double emscripten_get_now(void) { // C++ ABI -// Emscripten disables exception catching by default, but not throwing. That -// allows users to see a clear error if a throw happens, and 99% of the -// overhead is in the catching, so this is a reasonable tradeoff. -// For now, in a standalone build just terminate. TODO nice error message -// -// Define these symbols as weak so that when we build with exceptions -// enabled (using wasm-eh) we get the real versions of these functions -// as defined in libc++abi. - -__attribute__((__weak__)) +#if EMSCRIPTEN_NOCATCH +// When exception catching is disabled, we stub out calls to `__cxa_throw`. +// Otherwise, `__cxa_throw` will be imported from the host. void __cxa_throw(void* ptr, void* type, void* destructor) { abort(); } +#endif // WasmFS integration. We stub out file preloading and such, that are not // expected to work anyhow. diff --git a/test/test_other.py b/test/test_other.py index 4b449c19b250d..f3128024aad5b 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -10693,6 +10693,7 @@ def test_fignore_exceptions(self): 'compile_only': (['-fexceptions'], [], False), # just link isn't enough as codegen didn't emit exceptions support 'link_only': ([], ['-fexceptions'], False), + 'standalone': (['-fexceptions'], ['-fexceptions', '-sSTANDALONE_WASM', '-sWASM_BIGINT'], True), }) def test_f_exception(self, compile_flags, link_flags, expect_caught): create_file('src.cpp', r''' diff --git a/tools/system_libs.py b/tools/system_libs.py index b249565c7561f..c03ecf816a37a 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -1959,10 +1959,13 @@ class libstandalonewasm(MuslInternalLibrary): def __init__(self, **kwargs): self.is_mem_grow = kwargs.pop('is_mem_grow') + self.nocatch = kwargs.pop('nocatch') super().__init__(**kwargs) def get_base_name(self): name = super().get_base_name() + if self.nocatch: + name += '-nocatch' if self.is_mem_grow: name += '-memgrow' return name @@ -1972,16 +1975,19 @@ def get_cflags(self): cflags += ['-DNDEBUG', '-DEMSCRIPTEN_STANDALONE_WASM'] if self.is_mem_grow: cflags += ['-DEMSCRIPTEN_MEMORY_GROWTH'] + if self.nocatch: + cflags.append('-DEMSCRIPTEN_NOCATCH') return cflags @classmethod def vary_on(cls): - return super().vary_on() + ['is_mem_grow'] + return super().vary_on() + ['is_mem_grow', 'nocatch'] @classmethod def get_default_variation(cls, **kwargs): return super().get_default_variation( is_mem_grow=settings.ALLOW_MEMORY_GROWTH, + nocatch=settings.DISABLE_EXCEPTION_CATCHING and not settings.WASM_EXCEPTIONS, **kwargs ) From e2918ae67e6ae7df5cff0ab5d7db28376f65ce2a Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 24 Apr 2023 16:53:30 -0700 Subject: [PATCH 0166/1523] Make makeSetValue rounding consistent with HEAPI64.set() (#19239) This change does two things: 1. Require 8 byte alignment for makeSetValue of i64. Natural alignment is already required for all other types in `makeSetValue` and I don't know of good reason not to require this also for i64. The comment here implied that perhaps i64 was not always 8 bytes aligned, perhaps in the fastcomp days. But with wasm32 and wasm64 i64 should always be 8 bytes aligned. Folks with unaligned data already cannot use makeGetValue/makeSetValue. 2. Make splitI64 consistent with assignment to HEAPI64 in the way it handles numbers that are larger than the maximum i64 value. --- src/parseTools.js | 17 +++++++---------- src/preamble.js | 2 ++ src/preamble_minimal.js | 2 +- .../metadce/test_metadce_cxx_ctors1.jssize | 2 +- .../metadce/test_metadce_cxx_ctors2.jssize | 2 +- .../metadce/test_metadce_cxx_except.jssize | 2 +- .../metadce/test_metadce_cxx_except_wasm.jssize | 2 +- .../metadce/test_metadce_cxx_mangle.jssize | 2 +- .../metadce/test_metadce_cxx_noexcept.jssize | 2 +- test/other/test_parseTools.c | 13 ------------- test/other/test_parseTools.js | 13 +++++++------ test/other/test_parseTools.out | 7 ++----- test/other/test_unoptimized_code_size.js.size | 2 +- ...est_unoptimized_code_size_no_asserts.js.size | 2 +- .../test_unoptimized_code_size_strict.js.size | 2 +- 15 files changed, 28 insertions(+), 44 deletions(-) diff --git a/src/parseTools.js b/src/parseTools.js index 20fda91a03ce8..c8df775eb3f61 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -211,7 +211,7 @@ function splitI64(value) { // // $1$0 = ~~$d >>> 0; // $1$1 = Math.abs($d) >= 1 ? ( - // $d > 0 ? Math.min(Math.floor(($d)/ 4294967296.0), 4294967295.0) + // $d > 0 ? Math.floor(($d)/ 4294967296.0) >>> 0, // : Math.ceil(Math.min(-4294967296.0, $d - $1$0)/ 4294967296.0) // ) : 0; // @@ -227,9 +227,8 @@ function splitI64(value) { const high = makeInlineCalculation( asmCoercion('Math.abs(VALUE)', 'double') + ' >= ' + asmEnsureFloat('1', 'double') + ' ? ' + '(VALUE > ' + asmEnsureFloat('0', 'double') + ' ? ' + - asmCoercion('Math.min(' + asmCoercion('Math.floor((VALUE)/' + - asmEnsureFloat(4294967296, 'double') + ')', 'double') + ', ' + - asmEnsureFloat(4294967295, 'double') + ')', 'i32') + '>>>0' + + asmCoercion('Math.floor((VALUE)/' + + asmEnsureFloat(4294967296, 'double') + ')', 'double') + '>>>0' + ' : ' + asmFloatToInt(asmCoercion('Math.ceil((VALUE - +((' + asmFloatToInt('VALUE') + ')>>>0))/' + asmEnsureFloat(4294967296, 'double') + ')', 'double')) + '>>>0' + @@ -364,12 +363,10 @@ function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, sep) { assert(typeof align === 'undefined', 'makeSetValue no longer supports align parameter'); assert(typeof noNeedFirst === 'undefined', 'makeSetValue no longer supports noNeedFirst parameter'); assert(typeof sep === 'undefined', 'makeSetValue no longer supports sep parameter'); - if (type == 'i64' && (!WASM_BIGINT || !MEMORY64)) { - // If we lack either BigInt support or Memory64 then we must fall back to an - // unaligned read of a 64-bit value: without BigInt we do not have HEAP64, - // and without Memory64 i64 fields are not guaranteed to be aligned to 64 - // bits, so HEAP64[ptr>>3] might be broken. - return '(tempI64 = [' + splitI64(value) + '],' + + if (type == 'i64' && !WASM_BIGINT) { + // If we lack either BigInt we must fall back to an reading a pair of I32 + // values. + return '(tempI64 = [' + splitI64(value) + '], ' + makeSetValue(ptr, pos, 'tempI64[0]', 'i32') + ',' + makeSetValue(ptr, getFastValue(pos, '+', getNativeTypeSize('i32')), 'tempI64[1]', 'i32') + ')'; } diff --git a/src/preamble.js b/src/preamble.js index b6cb5d2d2de56..55fb916518437 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -1156,9 +1156,11 @@ function createWasm() { #endif } +#if !WASM_BIGINT // Globals used by JS i64 conversions (see makeSetValue) var tempDouble; var tempI64; +#endif #include "runtime_debug.js" diff --git a/src/preamble_minimal.js b/src/preamble_minimal.js index dd67803067d5e..750374c76d04b 100644 --- a/src/preamble_minimal.js +++ b/src/preamble_minimal.js @@ -39,7 +39,7 @@ function abort(what) { throw {{{ ASSERTIONS ? 'new Error(what)' : 'what' }}}; } -#if SAFE_HEAP +#if SAFE_HEAP && !WASM_BIGINT // Globals used by JS i64 conversions (see makeSetValue) var tempDouble; var tempI64; diff --git a/test/other/metadce/test_metadce_cxx_ctors1.jssize b/test/other/metadce/test_metadce_cxx_ctors1.jssize index 49e2b95cc2ae9..cfd500263a04b 100644 --- a/test/other/metadce/test_metadce_cxx_ctors1.jssize +++ b/test/other/metadce/test_metadce_cxx_ctors1.jssize @@ -1 +1 @@ -25939 +25914 diff --git a/test/other/metadce/test_metadce_cxx_ctors2.jssize b/test/other/metadce/test_metadce_cxx_ctors2.jssize index 8c9d5517f8bda..ad29f7c112c4a 100644 --- a/test/other/metadce/test_metadce_cxx_ctors2.jssize +++ b/test/other/metadce/test_metadce_cxx_ctors2.jssize @@ -1 +1 @@ -25903 +25878 diff --git a/test/other/metadce/test_metadce_cxx_except.jssize b/test/other/metadce/test_metadce_cxx_except.jssize index ad26bc5dd957b..ab4fd0a0713ae 100644 --- a/test/other/metadce/test_metadce_cxx_except.jssize +++ b/test/other/metadce/test_metadce_cxx_except.jssize @@ -1 +1 @@ -30453 +30428 diff --git a/test/other/metadce/test_metadce_cxx_except_wasm.jssize b/test/other/metadce/test_metadce_cxx_except_wasm.jssize index 7b9c7d539c3a4..4cb8626753a4f 100644 --- a/test/other/metadce/test_metadce_cxx_except_wasm.jssize +++ b/test/other/metadce/test_metadce_cxx_except_wasm.jssize @@ -1 +1 @@ -25748 +25723 diff --git a/test/other/metadce/test_metadce_cxx_mangle.jssize b/test/other/metadce/test_metadce_cxx_mangle.jssize index b827c6486a83a..3a436364b573f 100644 --- a/test/other/metadce/test_metadce_cxx_mangle.jssize +++ b/test/other/metadce/test_metadce_cxx_mangle.jssize @@ -1 +1 @@ -30457 +30432 diff --git a/test/other/metadce/test_metadce_cxx_noexcept.jssize b/test/other/metadce/test_metadce_cxx_noexcept.jssize index 49e2b95cc2ae9..cfd500263a04b 100644 --- a/test/other/metadce/test_metadce_cxx_noexcept.jssize +++ b/test/other/metadce/test_metadce_cxx_noexcept.jssize @@ -1 +1 @@ -25939 +25914 diff --git a/test/other/test_parseTools.c b/test/other/test_parseTools.c index 42c27d097afec..724e9720ede07 100644 --- a/test/other/test_parseTools.c +++ b/test/other/test_parseTools.c @@ -7,7 +7,6 @@ void test_makeGetValue(int64_t* ptr); void test_makeSetValue(int64_t* ptr); int test_receiveI64ParamAsI53(int64_t arg1, int64_t arg2); int test_receiveI64ParamAsDouble(int64_t arg1, int64_t arg2); -void test_makeSetValue_unaligned(int64_t* ptr); #define MAX_SAFE_INTEGER (1ll << 53) #define MIN_SAFE_INTEGER (-MAX_SAFE_INTEGER) @@ -55,18 +54,6 @@ int main() { rtn = test_receiveI64ParamAsDouble(MIN_SAFE_INTEGER - 1, 0); printf("rtn = %d\n", rtn); - printf("\ntest_makeSetValue_unaligned\n"); - // Test an unaligned read of an i64 in JS. To do that, get an unaligned - // pointer. i64s are only 32-bit aligned, but we can't rely on the address to - // happen to be unaligned here, so actually force an unaligned address (one - // of the iterations will be unaligned). - char buffer[16]; - for (size_t i = 0; i < 8; i += 4) { - int64_t* unaligned_i64 = (int64_t*)(buffer + i); - test_makeSetValue_unaligned(unaligned_i64); - printf("i64 = 0x%llx\n", *unaligned_i64); - } - printf("\ndone\n"); return 0; } diff --git a/test/other/test_parseTools.js b/test/other/test_parseTools.js index a8da60869d042..6247abbfad7cf 100644 --- a/test/other/test_parseTools.js +++ b/test/other/test_parseTools.js @@ -106,12 +106,17 @@ mergeInto(LibraryManager.library, { {{{ makeSetValue('ptr', '0', 0x12345678AB, 'i64') }}}; _printI64(ptr); - // This value doesn't fit into i64. The current behaviour here is to - // truncate and round (see splitI16 in parseTools.js) + // This value doesn't fit into i64. The current behaviour truncate (i.e. + // ignore the upper bits), in the same way that `BigInt64Array[X] = Y` does. + // (see splitI16 in parseTools.js) _clearI64(ptr); {{{ makeSetValue('ptr', '0', 0x1122334455667788AA, 'i64') }}}; _printI64(ptr); + _clearI64(ptr); + {{{ makeSetValue('ptr', '0', -0x1122334455667788AA, 'i64') }}}; + _printI64(ptr); + _clearI64(ptr); {{{ makeSetValue('ptr', '0', 0x12345678AB, 'i53') }}}; _printI64(ptr); @@ -128,8 +133,4 @@ mergeInto(LibraryManager.library, { {{{ makeSetValue('ptr', '0', 0x12345678ab, 'i32') }}}; _printI64(ptr); }, - - test_makeSetValue_unaligned: function(ptr) { - {{{ makeSetValue('ptr', '0', 0x12345678AB, 'i64') }}}; - }, }); diff --git a/test/other/test_parseTools.out b/test/other/test_parseTools.out index c6c40feaad578..780e7f8f24733 100644 --- a/test/other/test_parseTools.out +++ b/test/other/test_parseTools.out @@ -19,7 +19,8 @@ ptr: edcba988 test_makeSetValue: printI64: 0x12345678ab -printI64: 0xffffffff66780000 +printI64: 0x2233445566780000 +printI64: 0xddccbbaa99880000 printI64: 0x12345678ab printI64: 0xffffffffffffffff printI64: 0xff @@ -61,8 +62,4 @@ arg1: -9007199254740992 arg2: 0 rtn = 0 -test_makeSetValue_unaligned -i64 = 0x12345678ab -i64 = 0x12345678ab - done diff --git a/test/other/test_unoptimized_code_size.js.size b/test/other/test_unoptimized_code_size.js.size index f44658ab30b09..8e0545a3a593b 100644 --- a/test/other/test_unoptimized_code_size.js.size +++ b/test/other/test_unoptimized_code_size.js.size @@ -1 +1 @@ -59613 +59584 diff --git a/test/other/test_unoptimized_code_size_no_asserts.js.size b/test/other/test_unoptimized_code_size_no_asserts.js.size index 684f212104582..2a7a3ea68f817 100644 --- a/test/other/test_unoptimized_code_size_no_asserts.js.size +++ b/test/other/test_unoptimized_code_size_no_asserts.js.size @@ -1 +1 @@ -33284 +33255 diff --git a/test/other/test_unoptimized_code_size_strict.js.size b/test/other/test_unoptimized_code_size_strict.js.size index cd1258f5c0977..32993c88f3353 100644 --- a/test/other/test_unoptimized_code_size_strict.js.size +++ b/test/other/test_unoptimized_code_size_strict.js.size @@ -1 +1 @@ -58555 +58526 From cb5ca6e54161f8baa95c634d80fe4e9347166eed Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 24 Apr 2023 23:09:22 -0700 Subject: [PATCH 0167/1523] [Wasm64] Allow testing of wasm64 + standalone (#18771) --- system/lib/standalone/standalone.c | 5 ++++- test/common.py | 1 + test/test_core.py | 19 ++++++++++++++----- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/system/lib/standalone/standalone.c b/system/lib/standalone/standalone.c index f50aef4678c66..dcb0149bc63cd 100644 --- a/system/lib/standalone/standalone.c +++ b/system/lib/standalone/standalone.c @@ -142,7 +142,10 @@ int emscripten_resize_heap(size_t size) { assert(old_size < size); ssize_t diff = (size - old_size + WASM_PAGE_SIZE - 1) / WASM_PAGE_SIZE; size_t result = __builtin_wasm_memory_grow(0, diff); - if (result != (size_t)-1) { + // Its seems v8 has a bug in memory.grow that causes it to return + // (uint32_t)-1 even with memory64: + // https://bugs.chromium.org/p/v8/issues/detail?id=13948 + if (result != (uint32_t)-1 && result != (size_t)-1) { // Success, update JS (see https://github.com/WebAssembly/WASI/issues/82) emscripten_notify_memory_growth(0); return 1; diff --git a/test/common.py b/test/common.py index 30c8428740fdf..67313a03499be 100644 --- a/test/common.py +++ b/test/common.py @@ -515,6 +515,7 @@ def require_engine(self, engine): self.skipTest(f'Skipping test that requires `{engine}` when `{self.required_engine}` was previously required') self.required_engine = engine self.js_engines = [engine] + self.wasm_engines = [] def require_wasm64(self): if config.NODE_JS and config.NODE_JS in self.js_engines: diff --git a/test/test_core.py b/test/test_core.py index 982780bf2f47d..524985a6cc532 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -156,12 +156,20 @@ def metafunc(self, rawfs): return metafunc -def can_do_standalone(self): +def can_do_wasm2c(self): + # the npm version of wasm2c does not support MEMORY64 + return not self.get_setting('MEMORY64') + + +def can_do_standalone(self, impure=False): + # Pure standalone engines don't support MEMORY64 yet. Even with MEMORY64=2 (lowered) + # the WASI APIs that take pointer values don't have 64-bit variants yet. + if self.get_setting('MEMORY64') and not impure: + return False return self.is_wasm() and \ self.get_setting('STACK_OVERFLOW_CHECK', 0) < 2 and \ not self.get_setting('MINIMAL_RUNTIME') and \ not self.get_setting('SAFE_HEAP') and \ - not self.get_setting('MEMORY64') and \ not any(a.startswith('-fsanitize=') for a in self.emcc_args) @@ -202,7 +210,7 @@ def metafunc(self, standalone): if not standalone: func(self) else: - if not can_do_standalone(self): + if not can_do_standalone(self, impure): self.skipTest('Test configuration is not compatible with STANDALONE_WASM') self.set_setting('STANDALONE_WASM') # we will not legalize the JS ffi interface, so we must use BigInt @@ -213,10 +221,9 @@ def metafunc(self, standalone): # if we are impure, disallow all wasm engines if impure: self.wasm_engines = [] - self.js_engines = [config.NODE_JS] self.node_args += shared.node_bigint_flags() func(self) - if wasm2c: + if wasm2c and can_do_wasm2c(self): print('wasm2c') self.set_setting('WASM2C') self.wasm_engines = [] @@ -7160,6 +7167,8 @@ def test_wasm2c_sandboxing(self, mode): self.node_args += shared.node_bigint_flags() if not can_do_standalone(self): return self.skipTest('standalone mode not supported') + if not can_do_wasm2c(self): + return self.skipTest('wasm2c not supported') self.set_setting('STANDALONE_WASM') self.set_setting('WASM2C') self.set_setting('WASM2C_SANDBOXING', mode) From d02c29f95e9e68f2f50c2b0432c56a671814d5c8 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 25 Apr 2023 09:38:14 -0700 Subject: [PATCH 0168/1523] Add automatic signature generation for embind symbols (#19242) I had to jump through a few hoops here to get the C++ files to be include-able in the sig-generating program, but I think it worth it. --- src/embind/embind.js | 27 ---------------- src/embind/emval.js | 34 --------------------- src/library_sigs.js | 62 +++++++++++++++++++++++++++++++++++++ tools/gen_sig_info.py | 71 ++++++++++++++++++++++++++++++++----------- 4 files changed, 116 insertions(+), 78 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 35f8b2d4e70ab..f4c7ca2fa0563 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -399,7 +399,6 @@ var LibraryEmbind = { return impl; }, - _embind_register_void__sig: 'vpp', _embind_register_void__deps: ['$readLatin1String', '$registerType'], _embind_register_void: function(rawType, name) { name = readLatin1String(name); @@ -417,7 +416,6 @@ var LibraryEmbind = { }); }, - _embind_register_bool__sig: 'vpppii', _embind_register_bool__deps: [ '$getShiftFromSize', '$readLatin1String', '$registerType'], _embind_register_bool: function(rawType, name, size, trueValue, falseValue) { @@ -524,7 +522,6 @@ var LibraryEmbind = { // When converting a number from JS to C++ side, the valid range of the number is // [minRange, maxRange], inclusive. - _embind_register_integer__sig: 'vpppii', _embind_register_integer__deps: [ '$embindRepr', '$getShiftFromSize', '$integerReadValueFromPointer', '$readLatin1String', '$registerType'], @@ -581,7 +578,6 @@ var LibraryEmbind = { }, #if WASM_BIGINT - _embind_register_bigint__sig: 'vpppjj', _embind_register_bigint__deps: [ '$embindRepr', '$readLatin1String', '$registerType', '$integerReadValueFromPointer'], _embind_register_bigint: function(primitiveType, name, size, minRange, maxRange) { @@ -620,7 +616,6 @@ var LibraryEmbind = { _embind_register_bigint: function(primitiveType, name, size, minRange, maxRange) {}, #endif - _embind_register_float__sig: 'vppp', _embind_register_float__deps: [ '$embindRepr', '$floatReadValueFromPointer', '$getShiftFromSize', '$readLatin1String', '$registerType'], @@ -653,7 +648,6 @@ var LibraryEmbind = { return this['fromWireType']({{{ makeGetValue('pointer', '0', 'i32') }}}); }, - _embind_register_std_string__sig: 'vpp', _embind_register_std_string__deps: [ '$readLatin1String', '$registerType', '$simpleReadValueFromPointer', '$throwBindingError', @@ -758,7 +752,6 @@ var LibraryEmbind = { }); }, - _embind_register_std_wstring__sig: 'vppp', _embind_register_std_wstring__deps: [ '$readLatin1String', '$registerType', '$simpleReadValueFromPointer', '$UTF16ToString', '$stringToUTF16', '$lengthBytesUTF16', @@ -835,7 +828,6 @@ var LibraryEmbind = { }); }, - _embind_register_emval__sig: 'vpp', _embind_register_emval__deps: [ '_emval_decref', '$Emval', '$readLatin1String', '$registerType', '$simpleReadValueFromPointer'], @@ -860,7 +852,6 @@ var LibraryEmbind = { }); }, - _embind_register_memory_view__sig: 'vpip', _embind_register_memory_view__deps: ['$readLatin1String', '$registerType'], _embind_register_memory_view: function(rawType, dataTypeIndex, name) { var typeMapping = [ @@ -1183,7 +1174,6 @@ var LibraryEmbind = { return fp; }, - _embind_register_function__sig: 'vpippppi', _embind_register_function__deps: [ '$craftInvokerFunction', '$exposePublicSymbol', '$heap32VectorToArray', '$readLatin1String', '$replacePublicSymbol', '$embind__requireFunction', @@ -1207,7 +1197,6 @@ var LibraryEmbind = { $tupleRegistrations: {}, - _embind_register_value_array__sig: 'vpppppp', _embind_register_value_array__deps: [ '$tupleRegistrations', '$readLatin1String', '$embind__requireFunction'], _embind_register_value_array: function( @@ -1226,7 +1215,6 @@ var LibraryEmbind = { }; }, - _embind_register_value_array_element__sig: 'vppppppppp', _embind_register_value_array_element__deps: [ '$tupleRegistrations', '$embind__requireFunction'], _embind_register_value_array_element: function( @@ -1250,7 +1238,6 @@ var LibraryEmbind = { }); }, - _embind_finalize_value_array__sig: 'vp', _embind_finalize_value_array__deps: [ '$tupleRegistrations', '$runDestructors', '$simpleReadValueFromPointer', '$whenDependentTypesAreResolved'], @@ -1315,7 +1302,6 @@ var LibraryEmbind = { $structRegistrations: {}, - _embind_register_value_object__sig: 'vpppppp', _embind_register_value_object__deps: [ '$structRegistrations', '$readLatin1String', '$embind__requireFunction'], _embind_register_value_object: function( @@ -1334,7 +1320,6 @@ var LibraryEmbind = { }; }, - _embind_register_value_object_field__sig: 'vpppppppppp', _embind_register_value_object_field__deps: [ '$structRegistrations', '$readLatin1String', '$embind__requireFunction'], _embind_register_value_object_field: function( @@ -1360,7 +1345,6 @@ var LibraryEmbind = { }); }, - _embind_finalize_value_object__sig: 'vp', _embind_finalize_value_object__deps: [ '$structRegistrations', '$runDestructors', '$simpleReadValueFromPointer', '$whenDependentTypesAreResolved'], @@ -1985,7 +1969,6 @@ var LibraryEmbind = { }; }, - _embind_register_class__sig: 'vppppppppppppp', _embind_register_class__deps: [ '$BindingError', '$ClassHandle', '$createNamedFunction', '$registeredPointers', '$exposePublicSymbol', @@ -2096,7 +2079,6 @@ var LibraryEmbind = { ); }, - _embind_register_class_constructor__sig: 'vpipppp', _embind_register_class_constructor__deps: [ '$heap32VectorToArray', '$embind__requireFunction', '$runDestructors', '$throwBindingError', '$whenDependentTypesAreResolved', '$registeredTypes', @@ -2184,7 +2166,6 @@ var LibraryEmbind = { classType.registeredClass); }, - _embind_register_class_function__sig: 'vppippppii', _embind_register_class_function__deps: [ '$craftInvokerFunction', '$heap32VectorToArray', '$readLatin1String', '$embind__requireFunction', '$throwUnboundTypeError', @@ -2252,7 +2233,6 @@ var LibraryEmbind = { }); }, - _embind_register_class_property__sig: 'vpppppppppp', _embind_register_class_property__deps: [ '$readLatin1String', '$embind__requireFunction', '$runDestructors', '$throwBindingError', '$throwUnboundTypeError', @@ -2324,7 +2304,6 @@ var LibraryEmbind = { }); }, - _embind_register_class_class_function__sig: 'vppippppi', _embind_register_class_class_function__deps: [ '$craftInvokerFunction', '$ensureOverloadTable', '$heap32VectorToArray', '$readLatin1String', '$embind__requireFunction', '$throwUnboundTypeError', @@ -2382,7 +2361,6 @@ var LibraryEmbind = { }); }, - _embind_register_class_class_property__sig: 'vpppppppp', _embind_register_class_class_property__deps: [ '$readLatin1String', '$embind__requireFunction', '$runDestructors', '$throwBindingError', '$throwUnboundTypeError', @@ -2446,7 +2424,6 @@ var LibraryEmbind = { }); }, - _embind_create_inheriting_constructor__sig: 'pppp', _embind_create_inheriting_constructor__deps: [ '$createNamedFunction', '$Emval', '$PureVirtualError', '$readLatin1String', @@ -2530,7 +2507,6 @@ var LibraryEmbind = { return name; }, - _embind_register_smart_ptr__sig: 'vpppipppppppp', _embind_register_smart_ptr__deps: ['$RegisteredPointer', '$embind__requireFunction', '$whenDependentTypesAreResolved'], _embind_register_smart_ptr: function(rawType, rawPointeeType, @@ -2569,7 +2545,6 @@ var LibraryEmbind = { }); }, - _embind_register_enum__sig: 'vpppi', _embind_register_enum__deps: ['$exposePublicSymbol', '$getShiftFromSize', '$enumReadValueFromPointer', '$readLatin1String', '$registerType'], _embind_register_enum: function(rawType, name, size, isSigned) { @@ -2595,7 +2570,6 @@ var LibraryEmbind = { exposePublicSymbol(name, ctor); }, - _embind_register_enum_value__sig: 'vppp', _embind_register_enum_value__deps: ['$createNamedFunction', '$readLatin1String', '$requireRegisteredType'], _embind_register_enum_value: function(rawEnumType, name, enumValue) { var enumType = requireRegisteredType(rawEnumType, 'enum'); @@ -2611,7 +2585,6 @@ var LibraryEmbind = { Enum[name] = Value; }, - _embind_register_constant__sig: 'vppd', _embind_register_constant__deps: ['$readLatin1String', '$whenDependentTypesAreResolved'], _embind_register_constant: function(name, type, value) { name = readLatin1String(name); diff --git a/src/embind/emval.js b/src/embind/emval.js index 304de99360a1a..9dd882744059d 100644 --- a/src/embind/emval.js +++ b/src/embind/emval.js @@ -83,7 +83,6 @@ var LibraryEmVal = { } }, - _emval_incref__sig: 'vp', _emval_incref__deps: ['$emval_handles'], _emval_incref: function(handle) { if (handle > 4) { @@ -91,7 +90,6 @@ var LibraryEmVal = { } }, - _emval_decref__sig: 'vp', _emval_decref__deps: ['$emval_handles'], _emval_decref: function(handle) { if (handle >= emval_handles.reserved && 0 === --emval_handles.get(handle).refcount) { @@ -99,7 +97,6 @@ var LibraryEmVal = { } }, - _emval_run_destructors__sig: 'vp', _emval_run_destructors__deps: ['_emval_decref', '$Emval', '$runDestructors'], _emval_run_destructors: function(handle) { var destructors = Emval.toValue(handle); @@ -107,13 +104,11 @@ var LibraryEmVal = { __emval_decref(handle); }, - _emval_new_array__sig: 'p', _emval_new_array__deps: ['$Emval'], _emval_new_array: function() { return Emval.toHandle([]); }, - _emval_new_array_from_memory_view__sig: 'pp', _emval_new_array_from_memory_view__deps: ['$Emval'], _emval_new_array_from_memory_view: function(view) { view = Emval.toValue(view); @@ -123,31 +118,26 @@ var LibraryEmVal = { return Emval.toHandle(a); }, - _emval_new_object__sig: 'p', _emval_new_object__deps: ['$Emval'], _emval_new_object: function() { return Emval.toHandle({}); }, - _emval_new_cstring__sig: 'pp', _emval_new_cstring__deps: ['$getStringOrSymbol', '$Emval'], _emval_new_cstring: function(v) { return Emval.toHandle(getStringOrSymbol(v)); }, - _emval_new_u8string__sig: 'pp', _emval_new_u8string__deps: ['$Emval'], _emval_new_u8string: function(v) { return Emval.toHandle(UTF8ToString(v)); }, - _emval_new_u16string__sig: 'pp', _emval_new_u16string__deps: ['$Emval'], _emval_new_u16string: function(v) { return Emval.toHandle(UTF16ToString(v)); }, - _emval_take_value__sig: 'ppp', _emval_take_value__deps: ['$Emval', '$requireRegisteredType'], _emval_take_value: function(type, arg) { type = requireRegisteredType(type, '_emval_take_value'); @@ -215,7 +205,6 @@ var LibraryEmVal = { #endif }, - _emval_new__sig: 'ppipp', _emval_new__deps: ['$craftEmvalAllocator', '$emval_newers', '$Emval'], _emval_new: function(handle, argCount, argTypes, args) { handle = Emval.toValue(handle); @@ -266,7 +255,6 @@ var LibraryEmVal = { })()('return this')(); }, #endif - _emval_get_global__sig: 'pp', _emval_get_global__deps: ['$Emval', '$getStringOrSymbol', '$emval_get_global'], _emval_get_global: function(name) { if (name===0) { @@ -277,14 +265,12 @@ var LibraryEmVal = { } }, - _emval_get_module_property__sig: 'pp', _emval_get_module_property__deps: ['$getStringOrSymbol', '$Emval'], _emval_get_module_property: function(name) { name = getStringOrSymbol(name); return Emval.toHandle(Module[name]); }, - _emval_get_property__sig: 'ppp', _emval_get_property__deps: ['$Emval'], _emval_get_property: function(handle, key) { handle = Emval.toValue(handle); @@ -292,7 +278,6 @@ var LibraryEmVal = { return Emval.toHandle(handle[key]); }, - _emval_set_property__sig: 'vppp', _emval_set_property__deps: ['$Emval'], _emval_set_property: function(handle, key, value) { handle = Emval.toValue(handle); @@ -301,7 +286,6 @@ var LibraryEmVal = { handle[key] = value; }, - _emval_as__sig: 'dppp', _emval_as__deps: ['$Emval', '$requireRegisteredType'], _emval_as: function(handle, returnType, destructorsRef) { handle = Emval.toValue(handle); @@ -313,7 +297,6 @@ var LibraryEmVal = { }, _emval_as_int64__deps: ['$Emval', '$requireRegisteredType'], - _emval_as_int64__sig: 'jpp', _emval_as_int64: function(handle, returnType) { handle = Emval.toValue(handle); returnType = requireRegisteredType(returnType, 'emval::as'); @@ -321,7 +304,6 @@ var LibraryEmVal = { }, _emval_as_uint64__deps: ['$Emval', '$requireRegisteredType'], - _emval_as_uint64__sig: 'jpp', _emval_as_uint64: function(handle, returnType) { handle = Emval.toValue(handle); returnType = requireRegisteredType(returnType, 'emval::as'); @@ -329,7 +311,6 @@ var LibraryEmVal = { }, _emval_equals__deps: ['$Emval'], - _emval_equals__sig: 'ipp', _emval_equals: function(first, second) { first = Emval.toValue(first); second = Emval.toValue(second); @@ -337,7 +318,6 @@ var LibraryEmVal = { }, _emval_strictly_equals__deps: ['$Emval'], - _emval_strictly_equals__sig: 'ipp', _emval_strictly_equals: function(first, second) { first = Emval.toValue(first); second = Emval.toValue(second); @@ -345,7 +325,6 @@ var LibraryEmVal = { }, _emval_greater_than__deps: ['$Emval'], - _emval_greater_than__sig: 'ipp', _emval_greater_than: function(first, second) { first = Emval.toValue(first); second = Emval.toValue(second); @@ -353,7 +332,6 @@ var LibraryEmVal = { }, _emval_less_than__deps: ['$Emval'], - _emval_less_than__sig: 'ipp', _emval_less_than: function(first, second) { first = Emval.toValue(first); second = Emval.toValue(second); @@ -361,13 +339,11 @@ var LibraryEmVal = { }, _emval_not__deps: ['$Emval'], - _emval_not__sig: 'ip', _emval_not: function(object) { object = Emval.toValue(object); return !object; }, - _emval_call__sig: 'ppipp', _emval_call__deps: ['$emval_lookupTypes', '$Emval'], _emval_call: function(handle, argCount, argTypes, argv) { handle = Emval.toValue(handle); @@ -413,7 +389,6 @@ var LibraryEmVal = { }, $emval_registeredMethods: [], - _emval_get_method_caller__sig: 'pip', _emval_get_method_caller__deps: [ '$emval_addMethodCaller', '$emval_lookupTypes',, '$makeLegalFunctionName', '$emval_registeredMethods', @@ -493,7 +468,6 @@ var LibraryEmVal = { }, _emval_call_method__deps: ['$emval_allocateDestructors', '$getStringOrSymbol', '$emval_methodCallers', '$Emval'], - _emval_call_method__sig: 'dppppp', _emval_call_method: function(caller, handle, methodName, destructorsRef, args) { caller = emval_methodCallers[caller]; handle = Emval.toValue(handle); @@ -501,7 +475,6 @@ var LibraryEmVal = { return caller(handle, methodName, emval_allocateDestructors(destructorsRef), args); }, - _emval_call_void_method__sig: 'vpppp', _emval_call_void_method__deps: ['$emval_allocateDestructors', '$getStringOrSymbol', '$emval_methodCallers', '$Emval'], _emval_call_void_method: function(caller, handle, methodName, args) { caller = emval_methodCallers[caller]; @@ -510,7 +483,6 @@ var LibraryEmVal = { caller(handle, methodName, null, args); }, - _emval_typeof__sig: 'pp', _emval_typeof__deps: ['$Emval'], _emval_typeof: function(handle) { handle = Emval.toValue(handle); @@ -518,7 +490,6 @@ var LibraryEmVal = { }, _emval_instanceof__deps: ['$Emval'], - _emval_instanceof__sig: 'ipp', _emval_instanceof: function(object, constructor) { object = Emval.toValue(object); constructor = Emval.toValue(constructor); @@ -526,21 +497,18 @@ var LibraryEmVal = { }, _emval_is_number__deps: ['$Emval'], - _emval_is_number__sig: 'ip', _emval_is_number: function(handle) { handle = Emval.toValue(handle); return typeof handle == 'number'; }, _emval_is_string__deps: ['$Emval'], - _emval_is_string__sig: 'ip', _emval_is_string: function(handle) { handle = Emval.toValue(handle); return typeof handle == 'string'; }, _emval_in__deps: ['$Emval'], - _emval_in__sig: 'ipp', _emval_in: function(item, object) { item = Emval.toValue(item); object = Emval.toValue(object); @@ -548,7 +516,6 @@ var LibraryEmVal = { }, _emval_delete__deps: ['$Emval'], - _emval_delete__sig: 'ipp', _emval_delete: function(object, property) { object = Emval.toValue(object); property = Emval.toValue(property); @@ -556,7 +523,6 @@ var LibraryEmVal = { }, _emval_throw__deps: ['$Emval'], - _emval_throw__sig: 'ip', _emval_throw: function(object) { object = Emval.toValue(object); throw object; diff --git a/src/library_sigs.js b/src/library_sigs.js index 428d72e3557d1..519c72e0f2aa7 100644 --- a/src/library_sigs.js +++ b/src/library_sigs.js @@ -271,6 +271,33 @@ sigs = { _dlopen_js__sig: 'pp', _dlsym_catchup_js__sig: 'ppi', _dlsym_js__sig: 'pppp', + _embind_create_inheriting_constructor__sig: 'pppp', + _embind_finalize_value_array__sig: 'vp', + _embind_finalize_value_object__sig: 'vp', + _embind_register_bigint__sig: 'vpppjj', + _embind_register_bool__sig: 'vpppii', + _embind_register_class__sig: 'vppppppppppppp', + _embind_register_class_class_function__sig: 'vppippppi', + _embind_register_class_class_property__sig: 'vpppppppp', + _embind_register_class_constructor__sig: 'vpipppp', + _embind_register_class_function__sig: 'vppippppii', + _embind_register_class_property__sig: 'vpppppppppp', + _embind_register_constant__sig: 'vppd', + _embind_register_emval__sig: 'vpp', + _embind_register_enum__sig: 'vpppi', + _embind_register_enum_value__sig: 'vppp', + _embind_register_float__sig: 'vppp', + _embind_register_function__sig: 'vpippppi', + _embind_register_integer__sig: 'vpppii', + _embind_register_memory_view__sig: 'vpip', + _embind_register_smart_ptr__sig: 'vpppipppppppp', + _embind_register_std_string__sig: 'vpp', + _embind_register_std_wstring__sig: 'vppp', + _embind_register_value_array__sig: 'vpppppp', + _embind_register_value_array_element__sig: 'vppppppppp', + _embind_register_value_object__sig: 'vpppppp', + _embind_register_value_object_field__sig: 'vpppppppppp', + _embind_register_void__sig: 'vpp', _emscripten_dbg__sig: 'vp', _emscripten_default_pthread_stack_size__sig: 'i', _emscripten_dlopen_js__sig: 'vpppp', @@ -292,6 +319,41 @@ sigs = { _emscripten_thread_mailbox_await__sig: 'vp', _emscripten_thread_set_strongref__sig: 'vp', _emscripten_throw_longjmp__sig: 'v', + _emval_as__sig: 'dppp', + _emval_as_int64__sig: 'jpp', + _emval_as_uint64__sig: 'jpp', + _emval_call__sig: 'ppipp', + _emval_call_method__sig: 'dppppp', + _emval_call_void_method__sig: 'vpppp', + _emval_decref__sig: 'vp', + _emval_delete__sig: 'ipp', + _emval_equals__sig: 'ipp', + _emval_get_global__sig: 'pp', + _emval_get_method_caller__sig: 'pip', + _emval_get_module_property__sig: 'pp', + _emval_get_property__sig: 'ppp', + _emval_greater_than__sig: 'ipp', + _emval_in__sig: 'ipp', + _emval_incref__sig: 'vp', + _emval_instanceof__sig: 'ipp', + _emval_is_number__sig: 'ip', + _emval_is_string__sig: 'ip', + _emval_less_than__sig: 'ipp', + _emval_new__sig: 'ppipp', + _emval_new_array__sig: 'p', + _emval_new_array_from_memory_view__sig: 'pp', + _emval_new_cstring__sig: 'pp', + _emval_new_object__sig: 'p', + _emval_new_u16string__sig: 'pp', + _emval_new_u8string__sig: 'pp', + _emval_not__sig: 'ip', + _emval_register_symbol__sig: 'vp', + _emval_run_destructors__sig: 'vp', + _emval_set_property__sig: 'vppp', + _emval_strictly_equals__sig: 'ipp', + _emval_take_value__sig: 'ppp', + _emval_throw__sig: 'ip', + _emval_typeof__sig: 'pp', _gmtime_js__sig: 'vpp', _localtime_js__sig: 'vpp', _mktime_js__sig: 'ip', diff --git a/tools/gen_sig_info.py b/tools/gen_sig_info.py index 7620a5cd3ee2e..1b7c3d9338cb3 100755 --- a/tools/gen_sig_info.py +++ b/tools/gen_sig_info.py @@ -25,7 +25,7 @@ from tools import shared, utils, webassembly -header = '''/* Auto-generated by %s */ +c_header = '''/* Auto-generated by %s */ #define _GNU_SOURCE @@ -92,6 +92,29 @@ #include ''' % os.path.basename(__file__) +cxx_header = '''/* Auto-generated by %s */ + +// Public emscripen headers +#include +#include +#include + +// Internal emscripten headers +#include "emscripten_internal.h" + +// Public musl/libc headers +#include +#include +#include +#include +#include + +#include + +using namespace emscripten::internal; + +''' % os.path.basename(__file__) + footer = '''\ }; @@ -120,7 +143,7 @@ } -def ignore_symbol(s): +def ignore_symbol(s, cxx): if s in {'SDL_GetKeyState'}: return True if s.startswith('emscripten_gl') or s.startswith('emscripten_alc'): @@ -129,17 +152,19 @@ def ignore_symbol(s): return True if s.startswith('gl') and any(s.endswith(x) for x in ('NV', 'EXT', 'WEBGL', 'ARB', 'ANGLE')): return True + if cxx and s in ('__dlsym', '__asctime_r'): + return True return False -def create_c_file(filename, symbol_list): +def create_c_file(filename, symbol_list, header): source_lines = [header] source_lines.append('\nvoid* symbol_list[] = {') for s in symbol_list: if s in wasi_symbols: - source_lines.append(f' &__wasi_{s},') + source_lines.append(f' (void*)&__wasi_{s},') else: - source_lines.append(f' &{s},') + source_lines.append(f' (void*)&{s},') source_lines.append(footer) utils.write_file(filename, '\n'.join(source_lines) + '\n') @@ -234,7 +259,7 @@ def extract_sigs(symbols, obj_file): return sig_info -def extract_sig_info(sig_info, extra_settings=None, extra_cflags=None): +def extract_sig_info(sig_info, extra_settings=None, extra_cflags=None, cxx=False): print(' .. ' + str(extra_settings) + ' + ' + str(extra_cflags)) tempfiles = shared.get_temp_files() settings = { @@ -267,25 +292,33 @@ def extract_sig_info(sig_info, extra_settings=None, extra_cflags=None): ['--symbols-only', settings_json], stdout=subprocess.PIPE, cwd=utils.path_from_root()) symbols = json.loads(output)['deps'].keys() - symbols = [s for s in symbols if not ignore_symbol(s)] - with tempfiles.get_file('.c') as c_file: - create_c_file(c_file, symbols) + symbols = [s for s in symbols if not ignore_symbol(s, cxx)] + if cxx: + ext = '.cpp' + compiler = shared.EMXX + header = cxx_header + else: + ext = '.c' + compiler = shared.EMCC + header = c_header + with tempfiles.get_file(ext) as c_file: + create_c_file(c_file, symbols, header) # We build the `.c` file twice, once with wasm32 and wasm64. # The first build gives is that base signature of each function. # The second build build allows us to determine which args/returns are pointers # or `size_t` types. These get marked as `p` in the `__sig`. obj_file = 'out.o' - cmd = [shared.EMCC, c_file, '-c', '-pthread', + cmd = [compiler, c_file, '-c', '-pthread', '-Wno-deprecated-declarations', - '-o', obj_file, '-I' + utils.path_from_root('system/lib/libc'), - '-I' + utils.path_from_root('system/lib/pthread'), - '-I' + utils.path_from_root('system/lib/libc/musl/src/include'), - '-I' + utils.path_from_root('system/lib/libc/musl/src/internal'), - '-I' + utils.path_from_root('system/lib/gl'), - '-I' + utils.path_from_root('system/lib/libcxxabi/include'), - '-isysroot', 'c++/v1'] + '-o', obj_file] + if not cxx: + cmd += ['-I' + utils.path_from_root('system/lib/pthread'), + '-I' + utils.path_from_root('system/lib/libc/musl/src/include'), + '-I' + utils.path_from_root('system/lib/libc/musl/src/internal'), + '-I' + utils.path_from_root('system/lib/gl'), + '-I' + utils.path_from_root('system/lib/libcxxabi/include')] if extra_cflags: cmd += extra_cflags shared.check_call(cmd) @@ -317,6 +350,10 @@ def main(args): print('generating signatures ...') sig_info = {} + extract_sig_info(sig_info, {'JS_LIBRARIES': ['src/embind/embind.js', 'src/embind/emval.js'], + 'USE_SDL': 0, + 'MAX_WEBGL_VERSION': 0, + 'AUTO_JS_LIBRARIES': 0}, cxx=True) extract_sig_info(sig_info, {'LEGACY_GL_EMULATION': 1}, ['-DGLES']) extract_sig_info(sig_info, {'FULL_ES3': 1, 'MAX_WEBGL_VERSION': 2}) extract_sig_info(sig_info, {'STANDALONE_WASM': 1}) From 67ebee3261629f7e3c2bd24b61098af0c730d8d9 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 25 Apr 2023 16:13:58 -0700 Subject: [PATCH 0169/1523] Remove whitespace from src/library_glfw.js. NFC --- src/library_glfw.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/library_glfw.js b/src/library_glfw.js index 7c5b742d00223..799833596feb9 100644 --- a/src/library_glfw.js +++ b/src/library_glfw.js @@ -1297,11 +1297,11 @@ var LibraryGLFW = { glfwGetMonitorWorkarea: function(monitor, x, y, w, h) { {{{ makeSetValue('x', '0', '0', 'i32') }}}; {{{ makeSetValue('y', '0', '0', 'i32') }}}; - + {{{ makeSetValue('w', '0', 'screen.availWidth', 'i32') }}}; {{{ makeSetValue('h', '0', 'screen.availHeight', 'i32') }}}; }, - + glfwGetMonitorPhysicalSize__sig: 'viii', glfwGetMonitorPhysicalSize: function(monitor, width, height) { // AFAIK there is no way to do this in javascript @@ -1374,7 +1374,7 @@ var LibraryGLFW = { // Some hints are platform specific. These may be set on any platform but they // will only affect their specific platform. Other platforms will ignore them. }, - + glfwCreateWindow__sig: 'iiiiii', glfwCreateWindow: function(width, height, title, monitor, share) { return GLFW.createWindow(width, height, title, monitor, share); @@ -1447,7 +1447,7 @@ var LibraryGLFW = { glfwGetWindowContentScale__sig: 'viii', glfwGetWindowContentScale: function(winid, x, y) { // winid doesn't matter. all windows will use same scale anyway. - // hope i used this makeSetValue correctly + // hope i used this makeSetValue correctly {{{ makeSetValue('x', '0', 'GLFW.scale', 'float') }}}; {{{ makeSetValue('y', '0', 'GLFW.scale', 'float') }}}; }, @@ -1502,7 +1502,7 @@ var LibraryGLFW = { if (!win) return; win.attributes[attrib] = value; }, - + glfwSetWindowUserPointer__sig: 'vii', glfwSetWindowUserPointer: function(winid, ptr) { var win = GLFW.WindowFromId(winid); @@ -1660,7 +1660,7 @@ var LibraryGLFW = { glfwGetKeyScancode__sig: 'ii', glfwGetKeyScancode: function(key) { throw "glfwGetKeyScancode not implemented."; }, - + glfwGetMouseButton__sig: 'iii', glfwGetMouseButton: function(winid, button) { return GLFW.getMouseButton(winid, button); @@ -1799,12 +1799,12 @@ var LibraryGLFW = { glfwSetJoystickUserPointer: function(jid, ptr) { throw "glfwSetJoystickUserPointer not implemented"; }, - + glfwGetJoystickUserPointer__sig: 'ii', glfwGetJoystickUserPointer: function(jid) { throw "glfwSetJoystickUserPointer not implemented"; }, - + glfwJoystickIsGamepad__sig: 'ii', glfwJoystickIsGamepad: function(jid) { throw "glfwSetJoystickUserPointer not implemented"; From 858eadf5d421e9d0c459a742f1f5db8a002efd53 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 25 Apr 2023 17:58:41 -0700 Subject: [PATCH 0170/1523] Run `prettier` on all JS code under `tools/`. NFC (#19252) --- package.json | 4 ++-- tools/lz4-compress.js | 2 +- tools/preprocessor.js | 8 +++---- tools/unsafe_optimizations.js | 41 ++++++++++++++++++++++++++++------- 4 files changed, 40 insertions(+), 15 deletions(-) diff --git a/package.json b/package.json index e04114fbd9e75..19f924d45ca5e 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ }, "scripts": { "lint": "eslint .", - "fmt": "prettier --write tools/acorn-optimizer.js", - "check": "prettier --check tools/acorn-optimizer.js" + "fmt": "prettier --write tools/*.js", + "check": "prettier --check tools/*.js" } } diff --git a/tools/lz4-compress.js b/tools/lz4-compress.js index 829f3ddad5f5d..1ddd11d3a9b06 100755 --- a/tools/lz4-compress.js +++ b/tools/lz4-compress.js @@ -39,7 +39,7 @@ function load(f) { globalEval(read(f)); } -global.assert = function(x, message) { +global.assert = (x, message) => { if (!x) throw new Error(message); }; diff --git a/tools/preprocessor.js b/tools/preprocessor.js index f57f95f6d5878..f33fa912d3ad0 100755 --- a/tools/preprocessor.js +++ b/tools/preprocessor.js @@ -21,10 +21,10 @@ global.vm = require('vm'); const arguments_ = process.argv.slice(2); const debug = false; -global.print = function(x) { +global.print = (x) => { process.stdout.write(x + '\n'); }; -global.printErr = function(x) { +global.printErr = (x) => { process.stderr.write(x + '\n'); }; @@ -41,12 +41,12 @@ function find(filename) { return filename; } -global.read = function(filename) { +global.read = (filename) => { const absolute = find(filename); return fs.readFileSync(absolute).toString(); }; -global.load = function(f) { +global.load = (f) => { (0, eval)(read(f) + '//# sourceURL=' + find(f)); }; diff --git a/tools/unsafe_optimizations.js b/tools/unsafe_optimizations.js index 84fd37d5b0033..73512749bef6e 100644 --- a/tools/unsafe_optimizations.js +++ b/tools/unsafe_optimizations.js @@ -45,11 +45,18 @@ function optPassSimplifyModularizeFunction(ast) { if (node.params.length == 1 && node.params[0].name == 'Module') { const body = node.body.body; // Nuke 'Module = Module || {};' - if (body[0].type == 'ExpressionStatement' && body[0].expression.type == 'AssignmentExpression' && body[0].expression.left.name == 'Module') { + if ( + body[0].type == 'ExpressionStatement' && + body[0].expression.type == 'AssignmentExpression' && + body[0].expression.left.name == 'Module' + ) { body.splice(0, 1); } // Replace 'function(Module) {var f = Module;' -> 'function(f) {' - if (body[0].type == 'VariableDeclaration' && body[0].declarations[0]?.init?.name == 'Module') { + if ( + body[0].type == 'VariableDeclaration' && + body[0].declarations[0]?.init?.name == 'Module' + ) { node.params[0].name = body[0].declarations[0].id.name; body[0].declarations.splice(0, 1); if (body[0].declarations.length == 0) { @@ -66,8 +73,13 @@ function optPassSimplifyModularizeFunction(ast) { function optPassSimplifyModuleInitialization(ast) { visitNodes(ast, ['BlockStatement', 'Program'], (node) => { for (const n of node.body) { - if (n.type == 'ExpressionStatement' && n.expression.type == 'LogicalExpression' && n.expression.operator == '||' && - n.expression.left.name === n.expression.right.left?.name && n.expression.right.right.name == 'Module') { + if ( + n.type == 'ExpressionStatement' && + n.expression.type == 'LogicalExpression' && + n.expression.operator == '||' && + n.expression.left.name === n.expression.right.left?.name && + n.expression.right.right.name == 'Module' + ) { // Clear out the logical operator. n.expression = n.expression.right; // There is only one Module assignment, so can finish the pass here. @@ -169,7 +181,11 @@ function optPassMergeVarInitializationAssignments(ast) { const name = nodeArray[i].expression.left.name; for (let j = i - 1; j >= 0; --j) { const n = nodeArray[j]; - if (n.type == 'ExpressionStatement' && n.expression.type == 'AssignmentExpression' && n.expression.left.name == name) { + if ( + n.type == 'ExpressionStatement' && + n.expression.type == 'AssignmentExpression' && + n.expression.left.name == name + ) { return [null, null]; } if (n.type == 'VariableDeclaration') { @@ -248,7 +264,10 @@ function test(input, expected) { function runTests() { // optPassSimplifyModularizeFunction: - test('var Module = function(Module) {Module = Module || {};var f = Module;}', 'var Module=function(f){};'); + test( + 'var Module = function(Module) {Module = Module || {};var f = Module;}', + 'var Module=function(f){};' + ); // optPassSimplifyModuleInitialization: test('b || (b = Module);', 'b=Module;'); @@ -258,7 +277,10 @@ function runTests() { test('new Uint16Array(a);', ''); test('new Uint16Array(a),new Uint16Array(a);', ';'); test("new function(a) {new TextDecoder(a);}('utf8');", ''); - test('WebAssembly.instantiate(c.wasm,{}).then(function(a){new Int8Array(b);});', 'WebAssembly.instantiate(c.wasm,{}).then(function(a){});'); + test( + 'WebAssembly.instantiate(c.wasm,{}).then(function(a){new Int8Array(b);});', + 'WebAssembly.instantiate(c.wasm,{}).then(function(a){});' + ); test('let x=new Uint16Array(a);', 'let x=new Uint16Array(a);'); // optPassMergeVarDeclarations: @@ -271,7 +293,10 @@ function runTests() { test('var a = 1, b; ++a; var c;', 'var a=1,b,c;++a;'); // Interaction between multiple passes: - test('var d, f; f = new Uint8Array(16); var h = f.buffer; d = new Uint8Array(h);', 'var f=new Uint8Array(16),h=f.buffer,d=new Uint8Array(h);'); + test( + 'var d, f; f = new Uint8Array(16); var h = f.buffer; d = new Uint8Array(h);', + 'var f=new Uint8Array(16),h=f.buffer,d=new Uint8Array(h);' + ); // Older versions of terser would produce sub-optimal output for this. // We keep this test around to prevent regression. From 165cc15efd6e8e8873fa9e3215ae321d025d4cb6 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 25 Apr 2023 18:03:20 -0700 Subject: [PATCH 0171/1523] Remove dead code (`getTypeFromHeap`) from src/parseTools.js. NFC (#19250) The last reference to this function was removed in f45be307a5493adff72e61530fe948708cbe2c8f --- src/parseTools.js | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/parseTools.js b/src/parseTools.js index c8df775eb3f61..3cbc1a44073d0 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -505,17 +505,6 @@ function charCode(char) { return char.charCodeAt(0); } -function getTypeFromHeap(suffix) { - switch (suffix) { - case '8': return 'i8'; - case '16': return 'i16'; - case '32': return 'i32'; - case 'F32': return 'float'; - case 'F64': return 'double'; - } - assert(false, 'bad type suffix: ' + suffix); -} - function ensureValidFFIType(type) { return type === 'float' ? 'double' : type; // ffi does not tolerate float XXX } From 92e166ccc2005e45a53fc6a84b305d06053c510d Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Wed, 26 Apr 2023 15:45:16 +0200 Subject: [PATCH 0172/1523] library_tty.js: Add explicit dependency on $UTF8ArrayToString (#19238) --- src/library_tty.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/library_tty.js b/src/library_tty.js index 8c78fbd3cd893..b5759dcb25581 100644 --- a/src/library_tty.js +++ b/src/library_tty.js @@ -5,7 +5,7 @@ */ mergeInto(LibraryManager.library, { - $TTY__deps: ['$FS', '$intArrayFromString'], + $TTY__deps: ['$FS', '$intArrayFromString', '$UTF8ArrayToString'], #if !MINIMAL_RUNTIME $TTY__postset: function() { addAtInit('TTY.init();'); From 2a2a29e12b02e647d18878fde7f46d01c9ca928e Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 26 Apr 2023 10:23:28 -0700 Subject: [PATCH 0173/1523] Mark 3.1.37 as released (#19255) --- ChangeLog.md | 5 ++++- emscripten-version.txt | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 50bcdca76fb20..4fe05c3e71c13 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -18,8 +18,11 @@ to browse the changes between the tags. See docs/process.md for more on how version tagging works. -3.1.37 (in development) +3.1.38 (in development) ----------------------- + +3.1.37 - 04/26/23 +----------------- - The `EM_PYTHON_MULTIPROCESSING` environment variable no longer has any effect. This was added a temporary fallback but should no longer be needed. (#19224) - The old reverse dependency system based on `tools/deps_info.py` has been diff --git a/emscripten-version.txt b/emscripten-version.txt index bdba3ba8dcca1..60a4a5635012d 100644 --- a/emscripten-version.txt +++ b/emscripten-version.txt @@ -1 +1 @@ -3.1.37-git +3.1.38-git From 7f3c740d5b4ea9e87503fd1c7ad700ac5e5c060f Mon Sep 17 00:00:00 2001 From: Tellusim <45666012+Tellusim@users.noreply.github.com> Date: Wed, 26 Apr 2023 10:37:16 -0700 Subject: [PATCH 0174/1523] Chrome compatibility. Function arguments are not required anymore. (#19249) Co-authored-by: Alexander Zapryagaev --- src/library_webgpu.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/library_webgpu.js b/src/library_webgpu.js index 1e787a3fbf10a..47f1954530497 100644 --- a/src/library_webgpu.js +++ b/src/library_webgpu.js @@ -2619,9 +2619,7 @@ var LibraryWebGPU = { // WGPUSurface wgpuSurfaceGetPreferredFormat: function(surfaceId, adapterId) { - var context = WebGPU.mgrSurface.get(surfaceId); - var adapter = WebGPU.mgrAdapter.get(adapterId); - var format = context["getPreferredFormat"](adapter); + var format = navigator["gpu"]["getPreferredCanvasFormat"](); return WebGPU.PreferredFormat[format]; }, From f4f93d4b446e8fbd00d46457903d552ec8884e4b Mon Sep 17 00:00:00 2001 From: HCLJason <79225526+HCLJason@users.noreply.github.com> Date: Wed, 26 Apr 2023 15:01:07 -0400 Subject: [PATCH 0175/1523] Updating libpng to v1.6.39 (#19248) --- test/third_party/libpng/pngtest.c | 2 +- tools/ports/libpng.py | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/third_party/libpng/pngtest.c b/test/third_party/libpng/pngtest.c index 38d1adb87250b..13290e8962079 100644 --- a/test/third_party/libpng/pngtest.c +++ b/test/third_party/libpng/pngtest.c @@ -2028,4 +2028,4 @@ main(void) #endif /* Generate a compiler error if there is an old png.h in the search path. */ -typedef png_libpng_version_1_6_37 Your_png_h_is_not_version_1_6_37; +typedef png_libpng_version_1_6_39 Your_png_h_is_not_version_1_6_39; diff --git a/tools/ports/libpng.py b/tools/ports/libpng.py index c15fade4e9c87..e7def306bf26c 100644 --- a/tools/ports/libpng.py +++ b/tools/ports/libpng.py @@ -5,8 +5,8 @@ import os -TAG = '1.6.37' -HASH = '2ce2b855af307ca92a6e053f521f5d262c36eb836b4810cb53c809aa3ea2dcc08f834aee0ffd66137768a54397e28e92804534a74abb6fc9f6f3127f14c9c338' +TAG = '1.6.39' +HASH = '19851afffbe2ffde62d918f7e9017dec778a7ce9c60c75cdc65072f086e6cdc9d9895eb7b207535a84cb5f4ead77ebc2aa9d80025f153662903023e1f7ab9bae' deps = ['zlib'] variants = { @@ -67,9 +67,9 @@ def show(): pnglibconf_h = r'''/* pnglibconf.h - library build configuration */ -/* libpng version 1.6.37 */ +/* libpng version 1.6.39 */ -/* Copyright (c) 2018-2019 Cosmin Truta */ +/* Copyright (c) 2018-2022 Cosmin Truta */ /* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson */ /* This code is released under the libpng license. */ @@ -341,7 +341,7 @@ def show(): #define PNG_USER_MEM_SUPPORTED #define PNG_USER_TRANSFORM_INFO_SUPPORTED #define PNG_USER_TRANSFORM_PTR_SUPPORTED -/*#undef PNG_WARNINGS_SUPPORTED*/ +#define PNG_WARNINGS_SUPPORTED #define PNG_WRITE_16BIT_SUPPORTED #define PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED #define PNG_WRITE_BGR_SUPPORTED From 46b45949c9c18acdf9cd010d535d3b5a756a4761 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 26 Apr 2023 14:26:40 -0700 Subject: [PATCH 0176/1523] Fix copypasta in src/library_glfw.js. NFC (#19253) And make use of `elif`. --- src/library_glfw.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/library_glfw.js b/src/library_glfw.js index 799833596feb9..99f04cf064872 100644 --- a/src/library_glfw.js +++ b/src/library_glfw.js @@ -1802,12 +1802,12 @@ var LibraryGLFW = { glfwGetJoystickUserPointer__sig: 'ii', glfwGetJoystickUserPointer: function(jid) { - throw "glfwSetJoystickUserPointer not implemented"; + throw "glfwGetJoystickUserPointer not implemented"; }, glfwJoystickIsGamepad__sig: 'ii', glfwJoystickIsGamepad: function(jid) { - throw "glfwSetJoystickUserPointer not implemented"; + throw "glfwJoystickIsGamepad not implemented"; }, glfwSetJoystickCallback__sig: 'ii', @@ -1834,9 +1834,7 @@ var LibraryGLFW = { GLFW.swapBuffers(winid); }, -#endif // GLFW 3 - -#if USE_GLFW == 2 +#elif USE_GLFW == 2 glfwOpenWindow: function(width, height, redbits, greenbits, bluebits, alphabits, depthbits, stencilbits, mode) { GLFW.hints[0x00021001] = redbits; // GLFW_RED_BITS GLFW.hints[0x00021002] = greenbits; // GLFW_GREEN_BITS From 6f0238367348f5e33605b3f0a42455fb3a2d739f Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 26 Apr 2023 14:26:54 -0700 Subject: [PATCH 0177/1523] Remove vulcan-specific functions from src/library_glfw.js (#19254) These functions are declared in GLFW/glfw3.h but are inside an `#if defined(VK_VERSION_1_0)` block, and requires a VkInstance type that emscripten doesn't provide, so its not possible enable them at C/C++ compile time. --- src/library_glfw.js | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/library_glfw.js b/src/library_glfw.js index 99f04cf064872..053e8927a70a5 100644 --- a/src/library_glfw.js +++ b/src/library_glfw.js @@ -1733,15 +1733,6 @@ var LibraryGLFW = { glfwGetRequiredInstanceExtensions__sig: 'ii', glfwGetRequiredInstanceExtensions: function(count) { throw "glfwGetRequiredInstanceExtensions is not implemented."; }, - glfwGetInstanceProcAddress__sig: 'iii', - glfwGetInstanceProcAddress: function(instance, procname) { throw "glfwGetInstanceProcAddress is not implemented."; }, - - glfwGetPhysicalDevicePresentationSupport__sig: 'iiii', - glfwGetPhysicalDevicePresentationSupport: function(instance, device, queuefamily) { throw "glfwGetPhysicalDevicePresentationSupport is not implemented"; }, - - glfwCreateWindowSurface__sig: 'iiiii', - glfwCreateWindowSurface: function(instance, winid, allocator, surface) { throw "glfwCreateWindowSurface is not implemented."; }, - glfwJoystickPresent__sig: 'ii', glfwJoystickPresent: function(joy) { GLFW.refreshJoysticks(); From 6791b1c1da0d2046ac50c0054f4f3c28f85684cb Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 28 Apr 2023 10:06:35 -0700 Subject: [PATCH 0178/1523] Remove `getNativeFieldSize` build-time helper. NFC (#19258) This function had exactly one callsite, where its wasn't serving any useful purpose: ``` if (!WASM_BIGINT && getNativeFieldSize(type) > 4 && type == 'i64') { ``` Here the second clause in the condition would always return true when `type` in `i64` making the redundant in the face the third clause. This is because `getNativeFieldSize('i64')` always returns 8. --- src/parseTools.js | 5 +++-- src/parseTools_legacy.js | 4 ++++ src/runtime.js | 4 ---- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/parseTools.js b/src/parseTools.js index 3cbc1a44073d0..cfe3a7d34de6d 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -258,8 +258,9 @@ function indentify(text, indent) { // Correction tools function getHeapOffset(offset, type) { - if (!WASM_BIGINT && getNativeFieldSize(type) > 4 && type == 'i64') { - // we emulate 64-bit integer values as 32 in asmjs-unknown-emscripten, but not double + if (type == 'i64' && !WASM_BIGINT) { + // We are foreced to use the 32-bit heap for 64-bit values when we don't + // have WASM_BIGINT. type = 'i32'; } diff --git a/src/parseTools_legacy.js b/src/parseTools_legacy.js index c3adeb7930295..1a808b0c4a610 100644 --- a/src/parseTools_legacy.js +++ b/src/parseTools_legacy.js @@ -89,6 +89,10 @@ function makeMalloc(source, param) { return `_malloc(${param})`; } +function getNativeFieldSize(type) { + return Math.max(getNativeTypeSize(type), POINTER_SIZE); +} + global.Runtime = { getNativeTypeSize: getNativeTypeSize, getNativeFieldSize: getNativeFieldSize, diff --git a/src/runtime.js b/src/runtime.js index 1110d86316c3e..52ecb963112ec 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -33,7 +33,3 @@ function getNativeTypeSize(type) { } } } - -function getNativeFieldSize(type) { - return Math.max(getNativeTypeSize(type), POINTER_SIZE); -} From c12ec5b45b2c1edb7ffab6731535b606d7124dc2 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 28 Apr 2023 11:11:47 -0700 Subject: [PATCH 0179/1523] makeSetValue: Remove references to long-unused args. NFC (#19257) My hope is that we can move to an options bag instead of positional arguments if we do want to consider adding more options in the figure. --- src/parseTools.js | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/parseTools.js b/src/parseTools.js index cfe3a7d34de6d..299c7b40facd2 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -354,18 +354,11 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align) { * @param {number} value The value to set. * @param {string} type A string defining the type. Used to find the slab (HEAPU8, HEAP16, HEAPU32, etc.). * which means we should write to all slabs, ignore type differences if any on reads, etc. - * @param {bool} noNeedFirst Whether to ignore the offset in the pointer itself. - * @param {bool} ignore: legacy, ignored. - * @param {number} align: legacy, ignored. - * @param {string} sep: legacy, ignored. - * @return {TODO} + * @return {string} JS code for performing the memory set operation */ -function makeSetValue(ptr, pos, value, type, noNeedFirst, ignore, align, sep) { - assert(typeof align === 'undefined', 'makeSetValue no longer supports align parameter'); - assert(typeof noNeedFirst === 'undefined', 'makeSetValue no longer supports noNeedFirst parameter'); - assert(typeof sep === 'undefined', 'makeSetValue no longer supports sep parameter'); +function makeSetValue(ptr, pos, value, type) { if (type == 'i64' && !WASM_BIGINT) { - // If we lack either BigInt we must fall back to an reading a pair of I32 + // If we lack BigInt support we must fall back to an reading a pair of I32 // values. return '(tempI64 = [' + splitI64(value) + '], ' + makeSetValue(ptr, pos, 'tempI64[0]', 'i32') + ',' + From 8874899ad4f345f1880b6876489395844d3d07e1 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 28 Apr 2023 11:16:10 -0700 Subject: [PATCH 0180/1523] Automatic signature generation for glfw symbols. NFC (#19256) --- src/library_glfw.js | 142 ++++------------------------------- src/library_sigs.js | 158 +++++++++++++++++++++++++++++++++++++++ system/include/GL/glfw.h | 22 +++++- tools/gen_sig_info.py | 11 ++- 4 files changed, 201 insertions(+), 132 deletions(-) diff --git a/src/library_glfw.js b/src/library_glfw.js index 053e8927a70a5..39f64da3342b3 100644 --- a/src/library_glfw.js +++ b/src/library_glfw.js @@ -1124,7 +1124,6 @@ var LibraryGLFW = { * GLFW FUNCTIONS ******************************************************************************/ glfwInit__deps: ['emscripten_get_device_pixel_ratio', 'malloc', 'free'], - glfwInit__sig: 'i', glfwInit: function() { if (GLFW.windows) return 1; // GL_TRUE @@ -1168,7 +1167,6 @@ var LibraryGLFW = { return 1; // GL_TRUE }, - glfwTerminate__sig: 'v', glfwTerminate: function() { window.removeEventListener("gamepadconnected", GLFW.onGamepadConnected, true); window.removeEventListener("gamepaddisconnected", GLFW.onGamepadDisconnected, true); @@ -1196,7 +1194,6 @@ var LibraryGLFW = { GLFW.active = null; }, - glfwGetVersion__sig: 'viii', glfwGetVersion: function(major, minor, rev) { #if USE_GLFW == 2 {{{ makeSetValue('major', '0', '2', 'i32') }}}; @@ -1211,24 +1208,19 @@ var LibraryGLFW = { #endif }, - glfwPollEvents__sig: 'v', glfwPollEvents: function() {}, - glfwWaitEvents__sig: 'v', glfwWaitEvents: function() {}, - glfwGetTime__sig: 'd', glfwGetTime: function() { return GLFW.getTime() - GLFW.initialTime; }, - glfwSetTime__sig: 'vd', glfwSetTime: function(time) { GLFW.initialTime = GLFW.getTime() - time; }, glfwExtensionSupported__deps: ['glGetString'], - glfwExtensionSupported__sig: 'ii', glfwExtensionSupported: function(extension) { if (!GLFW.extensions) { GLFW.extensions = UTF8ToString(_glGetString(0x1F03)).split(' '); @@ -1242,7 +1234,6 @@ var LibraryGLFW = { }, glfwSwapInterval__deps: ['emscripten_set_main_loop_timing'], - glfwSwapInterval__sig: 'vi', glfwSwapInterval: function(interval) { interval = Math.abs(interval); // GLFW uses negative values to enable GLX_EXT_swap_control_tear, which we don't have, so just treat negative and positive the same. if (interval == 0) _emscripten_set_main_loop_timing(0/*EM_TIMING_SETTIMEOUT*/, 0); @@ -1250,7 +1241,6 @@ var LibraryGLFW = { }, #if USE_GLFW == 3 - glfwGetVersionString__sig: 'i', glfwGetVersionString: function() { if (!GLFW.versionString) { GLFW.versionString = stringToNewUTF8("3.2.1 JS WebGL Emscripten"); @@ -1258,20 +1248,16 @@ var LibraryGLFW = { return GLFW.versionString; }, - glfwSetErrorCallback__sig: 'ii', glfwSetErrorCallback: function(cbfun) { var prevcbfun = GLFW.errorFunc; GLFW.errorFunc = cbfun; return prevcbfun; }, - glfwWaitEventsTimeout__sig: 'vd', glfwWaitEventsTimeout: function(timeout) {}, - glfwPostEmptyEvent__sig: 'v', glfwPostEmptyEvent: function() {}, - glfwGetMonitors__sig: 'ii', glfwGetMonitors__deps: ['malloc'], glfwGetMonitors: function(count) { {{{ makeSetValue('count', '0', '1', 'i32') }}}; @@ -1282,18 +1268,15 @@ var LibraryGLFW = { return GLFW.monitors; }, - glfwGetPrimaryMonitor__sig: 'i', glfwGetPrimaryMonitor: function() { return 1; }, - glfwGetMonitorPos__sig: 'viii', glfwGetMonitorPos: function(monitor, x, y) { {{{ makeSetValue('x', '0', '0', 'i32') }}}; {{{ makeSetValue('y', '0', '0', 'i32') }}}; }, - glfwGetMonitorWorkarea__sig: 'viiiii', glfwGetMonitorWorkarea: function(monitor, x, y, w, h) { {{{ makeSetValue('x', '0', '0', 'i32') }}}; {{{ makeSetValue('y', '0', '0', 'i32') }}}; @@ -1302,7 +1285,6 @@ var LibraryGLFW = { {{{ makeSetValue('h', '0', 'screen.availHeight', 'i32') }}}; }, - glfwGetMonitorPhysicalSize__sig: 'viii', glfwGetMonitorPhysicalSize: function(monitor, width, height) { // AFAIK there is no way to do this in javascript // Maybe with platform specific ccalls? @@ -1312,13 +1294,11 @@ var LibraryGLFW = { {{{ makeSetValue('height', '0', '0', 'i32') }}}; }, - glfwGetMonitorContentScale__sig: 'viii', glfwGetMonitorContentScale: function(monitor, x, y) { {{{ makeSetValue('x', '0', 'GLFW.scale', 'float') }}}; {{{ makeSetValue('y', '0', 'GLFW.scale', 'float') }}}; }, - glfwGetMonitorName__sig: 'ii', glfwGetMonitorName: function(mon) { if (!GLFW.monitorString) { GLFW.monitorString = stringToNewUTF8("HTML5 WebGL Canvas"); @@ -1326,7 +1306,6 @@ var LibraryGLFW = { return GLFW.monitorString; }, - glfwSetMonitorCallback__sig: 'ii', glfwSetMonitorCallback: function(cbfun) { var prevcbfun = GLFW.monitorFunc; GLFW.monitorFunc = cbfun; @@ -1334,97 +1313,79 @@ var LibraryGLFW = { }, // TODO: implement - glfwGetVideoModes__sig: 'iii', glfwGetVideoModes: function(monitor, count) { {{{ makeSetValue('count', '0', '0', 'i32') }}}; return 0; }, // TODO: implement - glfwGetVideoMode__sig: 'ii', glfwGetVideoMode: function(monitor) { return 0; }, // TODO: implement - glfwSetGamma__sig: 'vif', glfwSetGamma: function(monitor, gamma) { }, - glfwGetGammaRamp__sig: 'ii', glfwGetGammaRamp: function(monitor) { throw "glfwGetGammaRamp not implemented."; }, - glfwSetGammaRamp__sig: 'vii', glfwSetGammaRamp: function(monitor, ramp) { throw "glfwSetGammaRamp not implemented."; }, - glfwDefaultWindowHints__sig: 'v', glfwDefaultWindowHints: function() { GLFW.hints = GLFW.defaultHints; }, - glfwWindowHint__sig: 'vii', glfwWindowHint: function(target, hint) { GLFW.hints[target] = hint; }, - glfwWindowHintString__sig: 'vii', glfwWindowHintString: function(hint, value) { // from glfw docs -> we just ignore this. // Some hints are platform specific. These may be set on any platform but they // will only affect their specific platform. Other platforms will ignore them. }, - glfwCreateWindow__sig: 'iiiiii', glfwCreateWindow: function(width, height, title, monitor, share) { return GLFW.createWindow(width, height, title, monitor, share); }, - glfwDestroyWindow__sig: 'vi', glfwDestroyWindow: function(winid) { return GLFW.destroyWindow(winid); }, - glfwWindowShouldClose__sig: 'ii', glfwWindowShouldClose: function(winid) { var win = GLFW.WindowFromId(winid); if (!win) return 0; return win.shouldClose; }, - glfwSetWindowShouldClose__sig: 'vii', glfwSetWindowShouldClose: function(winid, value) { var win = GLFW.WindowFromId(winid); if (!win) return; win.shouldClose = value; }, - glfwSetWindowTitle__sig: 'vii', glfwSetWindowTitle: function(winid, title) { GLFW.setWindowTitle(winid, title); }, - glfwGetWindowPos__sig: 'viii', glfwGetWindowPos: function(winid, x, y) { GLFW.getWindowPos(winid, x, y); }, - glfwSetWindowPos__sig: 'viii', glfwSetWindowPos: function(winid, x, y) { GLFW.setWindowPos(winid, x, y); }, - glfwGetWindowSize__sig: 'viii', glfwGetWindowSize: function(winid, width, height) { GLFW.getWindowSize(winid, width, height); }, - glfwSetWindowSize__sig: 'viii', glfwSetWindowSize: function(winid, width, height) { GLFW.setWindowSize(winid, width, height); }, - glfwGetFramebufferSize__sig: 'viii', glfwGetFramebufferSize: function(winid, width, height) { var ww = 0; var wh = 0; @@ -1444,7 +1405,6 @@ var LibraryGLFW = { } }, - glfwGetWindowContentScale__sig: 'viii', glfwGetWindowContentScale: function(winid, x, y) { // winid doesn't matter. all windows will use same scale anyway. // hope i used this makeSetValue correctly @@ -1452,72 +1412,60 @@ var LibraryGLFW = { {{{ makeSetValue('y', '0', 'GLFW.scale', 'float') }}}; }, - glfwGetWindowOpacity__sig: 'fi', glfwGetWindowOpacity: function(winid) { return 1.0; }, - glfwSetWindowOpacity__sig: 'vif', glfwSetWindowOpacity: function(winid, opacity) { // error }, - glfwIconifyWindow__sig: 'vi', glfwIconifyWindow: function(winid) { #if ASSERTIONS warnOnce('glfwIconifyWindow is not implemented'); #endif }, - glfwRestoreWindow__sig: 'vi', glfwRestoreWindow: function(winid) { #if ASSERTIONS warnOnce('glfwRestoreWindow is not implemented'); #endif }, - glfwShowWindow__sig: 'vi', glfwShowWindow: function(winid) {}, - glfwHideWindow__sig: 'vi', glfwHideWindow: function(winid) {}, - glfwGetWindowMonitor__sig: 'ii', glfwGetWindowMonitor: function(winid) { var win = GLFW.WindowFromId(winid); if (!win) return 0; return win.monitor; }, - glfwGetWindowAttrib__sig: 'iii', glfwGetWindowAttrib: function(winid, attrib) { var win = GLFW.WindowFromId(winid); if (!win) return 0; return win.attributes[attrib]; }, - glfwSetWindowAttrib__sig: 'viii', glfwSetWindowAttrib: function(winid, attrib, value) { var win = GLFW.WindowFromId(winid); if (!win) return; win.attributes[attrib] = value; }, - glfwSetWindowUserPointer__sig: 'vii', glfwSetWindowUserPointer: function(winid, ptr) { var win = GLFW.WindowFromId(winid); if (!win) return; win.userptr = ptr; }, - glfwGetWindowUserPointer__sig: 'ii', glfwGetWindowUserPointer: function(winid) { var win = GLFW.WindowFromId(winid); if (!win) return 0; return win.userptr; }, - glfwSetWindowPosCallback__sig: 'iii', glfwSetWindowPosCallback: function(winid, cbfun) { var win = GLFW.WindowFromId(winid); if (!win) return null; @@ -1526,22 +1474,18 @@ var LibraryGLFW = { return prevcbfun; }, - glfwSetWindowSizeCallback__sig: 'iii', glfwSetWindowSizeCallback: function(winid, cbfun) { return GLFW.setWindowSizeCallback(winid, cbfun); }, - glfwSetWindowCloseCallback__sig: 'iii', glfwSetWindowCloseCallback: function(winid, cbfun) { return GLFW.setWindowCloseCallback(winid, cbfun); }, - glfwSetWindowRefreshCallback__sig: 'iii', glfwSetWindowRefreshCallback: function(winid, cbfun) { return GLFW.setWindowRefreshCallback(winid, cbfun); }, - glfwSetWindowFocusCallback__sig: 'iii', glfwSetWindowFocusCallback: function(winid, cbfun) { var win = GLFW.WindowFromId(winid); if (!win) return null; @@ -1550,7 +1494,6 @@ var LibraryGLFW = { return prevcbfun; }, - glfwSetWindowIconifyCallback__sig: 'iii', glfwSetWindowIconifyCallback: function(winid, cbfun) { var win = GLFW.WindowFromId(winid); if (!win) return null; @@ -1559,7 +1502,6 @@ var LibraryGLFW = { return prevcbfun; }, - glfwSetWindowMaximizeCallback__sig: 'iii', glfwSetWindowMaximizeCallback: function(winid, cbfun) { var win = GLFW.WindowFromId(winid); if (!win) return null; @@ -1568,43 +1510,30 @@ var LibraryGLFW = { return prevcbfun; }, - glfwSetWindowIcon__sig: 'viii', glfwSetWindowIcon: function(winid, count, images) {}, - glfwSetWindowSizeLimits__sig: 'viiiii', glfwSetWindowSizeLimits: function(winid, minwidth, minheight, maxwidth, maxheight) {}, - glfwSetWindowAspectRatio__sig: 'viii', glfwSetWindowAspectRatio: function(winid, numer, denom) {}, - glfwGetWindowFrameSize__sig: 'viiiii', glfwGetWindowFrameSize: function(winid, left, top, right, bottom) { throw "glfwGetWindowFrameSize not implemented."; }, - glfwMaximizeWindow__sig: 'vi', glfwMaximizeWindow: function(winid) {}, - glfwFocusWindow__sig: 'vi', glfwFocusWindow: function(winid) {}, - glfwRequestWindowAttention__sig: 'vi', glfwRequestWindowAttention: function(winid) {}, // maybe do window.focus()? - glfwSetWindowMonitor__sig: 'viiiiiii', glfwSetWindowMonitor: function(winid, monitor, xpos, ypos, width, height, refreshRate) { throw "glfwSetWindowMonitor not implemented."; }, - glfwCreateCursor__sig: 'iiii', glfwCreateCursor: function(image, xhot, yhot) {}, - glfwCreateStandardCursor__sig: 'ii', glfwCreateStandardCursor: function(shape) {}, - glfwDestroyCursor__sig: 'vi', glfwDestroyCursor: function(cursor) {}, - glfwSetCursor__sig: 'vii', glfwSetCursor: function(winid, cursor) {}, - glfwSetFramebufferSizeCallback__sig: 'iii', glfwSetFramebufferSizeCallback: function(winid, cbfun) { var win = GLFW.WindowFromId(winid); if (!win) return null; @@ -1613,7 +1542,6 @@ var LibraryGLFW = { return prevcbfun; }, - glfwSetWindowContentScaleCallback__sig: 'iii', glfwSetWindowContentScaleCallback: function(winid, cbfun) { var win = GLFW.WindowFromId(winid); if (!win) return null; @@ -1622,7 +1550,6 @@ var LibraryGLFW = { return prevcbfun; }, - glfwGetInputMode__sig: 'iii', glfwGetInputMode: function(winid, mode) { var win = GLFW.WindowFromId(winid); if (!win) return; @@ -1640,67 +1567,53 @@ var LibraryGLFW = { return win.inputModes[mode]; }, - glfwSetInputMode__sig: 'viii', glfwSetInputMode: function(winid, mode, value) { GLFW.setInputMode(winid, mode, value); }, - glfwRawMouseMotionSupported__sig: 'i', glfwRawMouseMotionSupported: function() { return 0; }, - glfwGetKey__sig: 'iii', glfwGetKey: function(winid, key) { return GLFW.getKey(winid, key); }, - glfwGetKeyName__sig: 'iii', glfwGetKeyName: function(key, scancode) { throw "glfwGetKeyName not implemented."; }, - glfwGetKeyScancode__sig: 'ii', glfwGetKeyScancode: function(key) { throw "glfwGetKeyScancode not implemented."; }, - glfwGetMouseButton__sig: 'iii', glfwGetMouseButton: function(winid, button) { return GLFW.getMouseButton(winid, button); }, - glfwGetCursorPos__sig: 'viii', glfwGetCursorPos: function(winid, x, y) { GLFW.getCursorPos(winid, x, y); }, // I believe it is not possible to move the mouse with javascript - glfwSetCursorPos__sig: 'vidd', glfwSetCursorPos: function(winid, x, y) { GLFW.setCursorPos(winid, x, y); }, - glfwSetKeyCallback__sig: 'iii', glfwSetKeyCallback: function(winid, cbfun) { return GLFW.setKeyCallback(winid, cbfun); }, - glfwSetCharCallback__sig: 'iii', glfwSetCharCallback: function(winid, cbfun) { return GLFW.setCharCallback(winid, cbfun); }, - glfwSetCharModsCallback__sig: 'iii', glfwSetCharModsCallback: function(winid, cbfun) { throw "glfwSetCharModsCallback not implemented."; }, - glfwSetMouseButtonCallback__sig: 'iii', glfwSetMouseButtonCallback: function(winid, cbfun) { return GLFW.setMouseButtonCallback(winid, cbfun); }, - glfwSetCursorPosCallback__sig: 'iii', glfwSetCursorPosCallback: function(winid, cbfun) { return GLFW.setCursorPosCallback(winid, cbfun); }, - glfwSetCursorEnterCallback__sig: 'iii', glfwSetCursorEnterCallback: function(winid, cbfun) { var win = GLFW.WindowFromId(winid); if (!win) return null; @@ -1709,38 +1622,30 @@ var LibraryGLFW = { return prevcbfun; }, - glfwSetScrollCallback__sig: 'iii', glfwSetScrollCallback: function(winid, cbfun) { return GLFW.setScrollCallback(winid, cbfun); }, - glfwVulkanSupported__sig: 'i', glfwVulkanSupported: function() { return 0; }, - glfwSetDropCallback__sig: 'iii', glfwSetDropCallback: function(winid, cbfun) { return GLFW.setDropCallback(winid, cbfun); }, - glfwGetTimerValue__sig: 'j', glfwGetTimerValue: function() { throw "glfwGetTimerValue is not implemented."; }, - glfwGetTimerFrequency__sig: 'j', glfwGetTimerFrequency: function() { throw "glfwGetTimerFrequency is not implemented."; }, - glfwGetRequiredInstanceExtensions__sig: 'ii', glfwGetRequiredInstanceExtensions: function(count) { throw "glfwGetRequiredInstanceExtensions is not implemented."; }, - glfwJoystickPresent__sig: 'ii', glfwJoystickPresent: function(joy) { GLFW.refreshJoysticks(); return GLFW.joys[joy] !== undefined; }, - glfwGetJoystickAxes__sig: 'iii', glfwGetJoystickAxes: function(joy, count) { GLFW.refreshJoysticks(); @@ -1754,7 +1659,6 @@ var LibraryGLFW = { return state.axes; }, - glfwGetJoystickButtons__sig: 'iii', glfwGetJoystickButtons: function(joy, count) { GLFW.refreshJoysticks(); @@ -1768,12 +1672,10 @@ var LibraryGLFW = { return state.buttons; }, - glfwGetJoystickHats__sig: 'iii', glfwGetJoystickHats: function(joy, count) { throw "glfwGetJoystickHats is not implemented"; }, - glfwGetJoystickName__sig: 'ii', glfwGetJoystickName: function(joy) { if (GLFW.joys[joy]) { return GLFW.joys[joy].id; @@ -1781,46 +1683,36 @@ var LibraryGLFW = { return 0; }, - glfwGetJoystickGUID__sig: 'ii', glfwGetJoystickGUID: function(jid) { throw "glfwGetJoystickGUID not implemented"; }, - glfwSetJoystickUserPointer__sig: 'vii', glfwSetJoystickUserPointer: function(jid, ptr) { throw "glfwSetJoystickUserPointer not implemented"; }, - glfwGetJoystickUserPointer__sig: 'ii', glfwGetJoystickUserPointer: function(jid) { throw "glfwGetJoystickUserPointer not implemented"; }, - glfwJoystickIsGamepad__sig: 'ii', glfwJoystickIsGamepad: function(jid) { throw "glfwJoystickIsGamepad not implemented"; }, - glfwSetJoystickCallback__sig: 'ii', glfwSetJoystickCallback: function(cbfun) { GLFW.setJoystickCallback(cbfun); }, - glfwSetClipboardString__sig: 'vii', glfwSetClipboardString: function(win, string) {}, - glfwGetClipboardString__sig: 'ii', glfwGetClipboardString: function(win) {}, - glfwMakeContextCurrent__sig: 'vi', glfwMakeContextCurrent: function(winid) {}, - glfwGetCurrentContext__sig: 'i', glfwGetCurrentContext: function() { return GLFW.active ? GLFW.active.id : 0; }, - glfwSwapBuffers__sig: 'vi', glfwSwapBuffers: function(winid) { GLFW.swapBuffers(winid); }, @@ -1846,39 +1738,35 @@ var LibraryGLFW = { GLFW.hints[target] = hint; }, - glfwGetWindowSize: function(width, height) { + glfwGetWindowSize_v2: function(width, height) { GLFW.getWindowSize(GLFW.active.id, width, height); }, - glfwSetWindowSize: function(width, height) { + glfwSetWindowSize_v2: function(width, height) { GLFW.setWindowSize(GLFW.active.id, width, height); }, - glfwGetWindowPos: function(x, y) { - GLFW.getWindowPos(GLFW.active.id, x, y); - }, - - glfwSetWindowPos: function(x, y) { + glfwSetWindowPos_v2: function(x, y) { GLFW.setWindowPos(GLFW.active.id, x, y); }, - glfwSetWindowTitle: function(title) { + glfwSetWindowTitle_v2: function(title) { GLFW.setWindowTitle(GLFW.active.id, title); }, - glfwIconifyWindow: function() { + glfwIconifyWindow_v2: function() { #if ASSERTIONS warnOnce('glfwIconifyWindow is not implemented'); #endif }, - glfwRestoreWindow: function() { + glfwRestoreWindow_v2: function() { #if ASSERTIONS warnOnce('glfwRestoreWindow is not implemented'); #endif }, - glfwSwapBuffers: function() { + glfwSwapBuffers_v2: function() { GLFW.swapBuffers(GLFW.active.id); }, @@ -1887,23 +1775,23 @@ var LibraryGLFW = { return GLFW.hints[param]; }, - glfwSetWindowSizeCallback: function(cbfun) { + glfwSetWindowSizeCallback_v2: function(cbfun) { GLFW.setWindowSizeCallback(GLFW.active.id, cbfun); }, - glfwSetWindowCloseCallback: function(cbfun) { + glfwSetWindowCloseCallback_v2: function(cbfun) { GLFW.setWindowCloseCallback(GLFW.active.id, cbfun); }, - glfwSetWindowRefreshCallback: function(cbfun) { + glfwSetWindowRefreshCallback_v2: function(cbfun) { GLFW.setWindowRefreshCallback(GLFW.active.id, cbfun); }, - glfwGetKey: function(key) { + glfwGetKey_v2: function(key) { return GLFW.getKey(GLFW.active.id, key); }, - glfwGetMouseButton: function(button) { + glfwGetMouseButton_v2: function(button) { return GLFW.getMouseButton(GLFW.active.id, button); }, @@ -1922,15 +1810,15 @@ var LibraryGLFW = { glfwSetMouseWheel: function(pos) { }, - glfwSetKeyCallback: function(cbfun) { + glfwSetKeyCallback_v2: function(cbfun) { GLFW.setKeyCallback(GLFW.active.id, cbfun); }, - glfwSetCharCallback: function(cbfun) { + glfwSetCharCallback_v2: function(cbfun) { GLFW.setCharCallback(GLFW.active.id, cbfun); }, - glfwSetMouseButtonCallback: function(cbfun) { + glfwSetMouseButtonCallback_v2: function(cbfun) { GLFW.setMouseButtonCallback(GLFW.active.id, cbfun); }, diff --git a/src/library_sigs.js b/src/library_sigs.js index 519c72e0f2aa7..88a1aec459745 100644 --- a/src/library_sigs.js +++ b/src/library_sigs.js @@ -1139,6 +1139,164 @@ sigs = { glewGetString__sig: 'pi', glewInit__sig: 'i', glewIsSupported__sig: 'ip', + glfwBroadcastCond__sig: 'vp', + glfwCloseWindow__sig: 'v', + glfwCreateCond__sig: 'p', + glfwCreateCursor__sig: 'ppii', + glfwCreateMutex__sig: 'p', + glfwCreateStandardCursor__sig: 'pi', + glfwCreateThread__sig: 'ipp', + glfwCreateWindow__sig: 'piippp', + glfwDefaultWindowHints__sig: 'v', + glfwDestroyCond__sig: 'vp', + glfwDestroyCursor__sig: 'vp', + glfwDestroyMutex__sig: 'vp', + glfwDestroyThread__sig: 'vi', + glfwDestroyWindow__sig: 'vp', + glfwDisable__sig: 'vi', + glfwEnable__sig: 'vi', + glfwExtensionSupported__sig: 'ip', + glfwFocusWindow__sig: 'vp', + glfwFreeImage__sig: 'vp', + glfwGetClipboardString__sig: 'pp', + glfwGetCurrentContext__sig: 'p', + glfwGetCursorPos__sig: 'vppp', + glfwGetDesktopMode__sig: 'vp', + glfwGetFramebufferSize__sig: 'vppp', + glfwGetGLVersion__sig: 'vppp', + glfwGetGammaRamp__sig: 'pp', + glfwGetInputMode__sig: 'ipi', + glfwGetJoystickAxes__sig: 'pip', + glfwGetJoystickButtons__sig: 'pip', + glfwGetJoystickGUID__sig: 'pi', + glfwGetJoystickHats__sig: 'pip', + glfwGetJoystickName__sig: 'pi', + glfwGetJoystickUserPointer__sig: 'pi', + glfwGetKey__sig: 'ipi', + glfwGetKeyName__sig: 'pii', + glfwGetKeyScancode__sig: 'ii', + glfwGetKey_v2__sig: 'ii', + glfwGetMonitorContentScale__sig: 'vppp', + glfwGetMonitorName__sig: 'pp', + glfwGetMonitorPhysicalSize__sig: 'vppp', + glfwGetMonitorPos__sig: 'vppp', + glfwGetMonitorWorkarea__sig: 'vppppp', + glfwGetMonitors__sig: 'pp', + glfwGetMouseButton__sig: 'ipi', + glfwGetMouseButton_v2__sig: 'ii', + glfwGetMousePos__sig: 'vpp', + glfwGetMouseWheel__sig: 'i', + glfwGetNumberOfProcessors__sig: 'i', + glfwGetPrimaryMonitor__sig: 'p', + glfwGetRequiredInstanceExtensions__sig: 'pp', + glfwGetThreadID__sig: 'i', + glfwGetTime__sig: 'd', + glfwGetTimerFrequency__sig: 'j', + glfwGetTimerValue__sig: 'j', + glfwGetVersion__sig: 'vppp', + glfwGetVersionString__sig: 'p', + glfwGetVideoMode__sig: 'pp', + glfwGetVideoModes__sig: 'ppp', + glfwGetWindowAttrib__sig: 'ipi', + glfwGetWindowContentScale__sig: 'vppp', + glfwGetWindowFrameSize__sig: 'vppppp', + glfwGetWindowMonitor__sig: 'pp', + glfwGetWindowOpacity__sig: 'fp', + glfwGetWindowParam__sig: 'ii', + glfwGetWindowPos__sig: 'vppp', + glfwGetWindowSize__sig: 'vppp', + glfwGetWindowSize_v2__sig: 'vpp', + glfwGetWindowUserPointer__sig: 'pp', + glfwHideWindow__sig: 'vp', + glfwIconifyWindow__sig: 'vp', + glfwIconifyWindow_v2__sig: 'v', + glfwInit__sig: 'i', + glfwJoystickIsGamepad__sig: 'ii', + glfwJoystickPresent__sig: 'ii', + glfwLoadMemoryTexture2D__sig: 'ippi', + glfwLoadTexture2D__sig: 'ipi', + glfwLoadTextureImage2D__sig: 'ipi', + glfwLockMutex__sig: 'vp', + glfwMakeContextCurrent__sig: 'vp', + glfwMaximizeWindow__sig: 'vp', + glfwOpenWindow__sig: 'iiiiiiiiii', + glfwOpenWindowHint__sig: 'vii', + glfwPollEvents__sig: 'v', + glfwPostEmptyEvent__sig: 'v', + glfwRawMouseMotionSupported__sig: 'i', + glfwReadImage__sig: 'ippi', + glfwReadMemoryImage__sig: 'ipppi', + glfwRequestWindowAttention__sig: 'vp', + glfwRestoreWindow__sig: 'vp', + glfwRestoreWindow_v2__sig: 'v', + glfwSetCharCallback__sig: 'ppp', + glfwSetCharCallback_v2__sig: 'vp', + glfwSetCharModsCallback__sig: 'ppp', + glfwSetClipboardString__sig: 'vpp', + glfwSetCursor__sig: 'vpp', + glfwSetCursorEnterCallback__sig: 'ppp', + glfwSetCursorPos__sig: 'vpdd', + glfwSetCursorPosCallback__sig: 'ppp', + glfwSetDropCallback__sig: 'ppp', + glfwSetErrorCallback__sig: 'pp', + glfwSetFramebufferSizeCallback__sig: 'ppp', + glfwSetGamma__sig: 'vpf', + glfwSetGammaRamp__sig: 'vpp', + glfwSetInputMode__sig: 'vpii', + glfwSetJoystickCallback__sig: 'pp', + glfwSetJoystickUserPointer__sig: 'vip', + glfwSetKeyCallback__sig: 'ppp', + glfwSetKeyCallback_v2__sig: 'vp', + glfwSetMonitorCallback__sig: 'pp', + glfwSetMouseButtonCallback__sig: 'ppp', + glfwSetMouseButtonCallback_v2__sig: 'vp', + glfwSetMousePos__sig: 'vii', + glfwSetMousePosCallback__sig: 'vp', + glfwSetMouseWheel__sig: 'vi', + glfwSetMouseWheelCallback__sig: 'vp', + glfwSetScrollCallback__sig: 'ppp', + glfwSetTime__sig: 'vd', + glfwSetWindowAspectRatio__sig: 'vpii', + glfwSetWindowAttrib__sig: 'vpii', + glfwSetWindowCloseCallback__sig: 'ppp', + glfwSetWindowCloseCallback_v2__sig: 'vp', + glfwSetWindowContentScaleCallback__sig: 'ppp', + glfwSetWindowFocusCallback__sig: 'ppp', + glfwSetWindowIcon__sig: 'vpip', + glfwSetWindowIconifyCallback__sig: 'ppp', + glfwSetWindowMaximizeCallback__sig: 'ppp', + glfwSetWindowMonitor__sig: 'vppiiiii', + glfwSetWindowOpacity__sig: 'vpf', + glfwSetWindowPos__sig: 'vpii', + glfwSetWindowPosCallback__sig: 'ppp', + glfwSetWindowPos_v2__sig: 'vii', + glfwSetWindowRefreshCallback__sig: 'ppp', + glfwSetWindowRefreshCallback_v2__sig: 'vp', + glfwSetWindowShouldClose__sig: 'vpi', + glfwSetWindowSize__sig: 'vpii', + glfwSetWindowSizeCallback__sig: 'ppp', + glfwSetWindowSizeCallback_v2__sig: 'vp', + glfwSetWindowSizeLimits__sig: 'vpiiii', + glfwSetWindowSize_v2__sig: 'vii', + glfwSetWindowTitle__sig: 'vpp', + glfwSetWindowTitle_v2__sig: 'vp', + glfwSetWindowUserPointer__sig: 'vpp', + glfwShowWindow__sig: 'vp', + glfwSignalCond__sig: 'vp', + glfwSleep__sig: 'vd', + glfwSwapBuffers__sig: 'vp', + glfwSwapBuffers_v2__sig: 'v', + glfwSwapInterval__sig: 'vi', + glfwTerminate__sig: 'v', + glfwUnlockMutex__sig: 'vp', + glfwVulkanSupported__sig: 'i', + glfwWaitCond__sig: 'vppd', + glfwWaitEvents__sig: 'v', + glfwWaitEventsTimeout__sig: 'vd', + glfwWaitThread__sig: 'iii', + glfwWindowHint__sig: 'vii', + glfwWindowHintString__sig: 'vip', + glfwWindowShouldClose__sig: 'ip', gluLookAt__sig: 'vddddddddd', gluOrtho2D__sig: 'vdddd', gluPerspective__sig: 'vdddd', diff --git a/system/include/GL/glfw.h b/system/include/GL/glfw.h index e20552e47dd00..e7dd09db8921b 100644 --- a/system/include/GL/glfw.h +++ b/system/include/GL/glfw.h @@ -425,6 +425,27 @@ typedef void (GLFWCALL * GLFWthreadfun)(void *); * Prototypes *************************************************************************/ +#ifdef __EMSCRIPTEN__ +// Redirect GLFW2 symbols when they have different signatures under GLFW3. +// This avoids the problem of JS symbols having different signatures in +// different configurations. +#define glfwGetWindowSize glfwGetWindowSize_v2 +#define glfwSetWindowSize glfwSetWindowSize_v2 +#define glfwSetWindowPos glfwSetWindowPos_v2 +#define glfwSetWindowTitle glfwSetWindowTitle_v2 +#define glfwIconifyWindow glfwIconifyWindow_v2 +#define glfwRestoreWindow glfwRestoreWindow_v2 +#define glfwSetWindowSizeCallback glfwSetWindowSizeCallback_v2 +#define glfwSetWindowCloseCallback glfwSetWindowCloseCallback_v2 +#define glfwSetWindowRefreshCallback glfwSetWindowRefreshCallback_v2 +#define glfwGetKey glfwGetKey_v2 +#define glfwGetMouseButton glfwGetMouseButton_v2 +#define glfwSetKeyCallback glfwSetKeyCallback_v2 +#define glfwSetCharCallback glfwSetCharCallback_v2 +#define glfwSetMouseButtonCallback glfwSetMouseButtonCallback_v2 +#define glfwSwapBuffers glfwSwapBuffers_v2 +#endif + /* GLFW initialization, termination and version querying */ GLFWAPI int GLFWAPIENTRY glfwInit( void ); GLFWAPI void GLFWAPIENTRY glfwTerminate( void ); @@ -509,7 +530,6 @@ GLFWAPI int GLFWAPIENTRY glfwLoadTexture2D( const char *name, int flags ); GLFWAPI int GLFWAPIENTRY glfwLoadMemoryTexture2D( const void *data, long size, int flags ); GLFWAPI int GLFWAPIENTRY glfwLoadTextureImage2D( GLFWimage *img, int flags ); - #ifdef __cplusplus } #endif diff --git a/tools/gen_sig_info.py b/tools/gen_sig_info.py index 1b7c3d9338cb3..a207181867b49 100755 --- a/tools/gen_sig_info.py +++ b/tools/gen_sig_info.py @@ -73,6 +73,11 @@ #include #include #endif +#if GLFW3 +#include +#else +#include +#endif #include #include #include @@ -272,10 +277,6 @@ def extract_sig_info(sig_info, extra_settings=None, extra_cflags=None, cxx=False 'SHARED_MEMORY': 1, 'AUDIO_WORKLET': 1, 'WASM_WORKERS': 1, - # Currently GLFW symbols have different sigs for the same symbol because the - # signatures changed between v2 and v3, so for now we continue to maintain - # them by hand. - 'USE_GLFW': 0, 'JS_LIBRARIES': [ 'src/library_websocket.js', 'src/library_webaudio.js', @@ -350,8 +351,10 @@ def main(args): print('generating signatures ...') sig_info = {} + extract_sig_info(sig_info, {'USE_GLFW': 3}, ['-DGLFW3']) extract_sig_info(sig_info, {'JS_LIBRARIES': ['src/embind/embind.js', 'src/embind/emval.js'], 'USE_SDL': 0, + 'USE_GLFW': 0, 'MAX_WEBGL_VERSION': 0, 'AUTO_JS_LIBRARIES': 0}, cxx=True) extract_sig_info(sig_info, {'LEGACY_GL_EMULATION': 1}, ['-DGLES']) From 57c5ae6d52a50ea601165e7949126a19133f0988 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 28 Apr 2023 14:43:07 -0700 Subject: [PATCH 0181/1523] Rebaseline codesize expectations. NFC --- test/code_size/hello_webgl2_wasm.json | 8 ++++---- test/code_size/hello_webgl2_wasm2js.json | 8 ++++---- test/code_size/hello_webgl_wasm.json | 8 ++++---- test/code_size/hello_webgl_wasm2js.json | 8 ++++---- test/other/metadce/test_metadce_cxx_ctors1.jssize | 2 +- test/other/metadce/test_metadce_cxx_ctors1.size | 2 +- test/other/metadce/test_metadce_cxx_ctors2.jssize | 2 +- test/other/metadce/test_metadce_cxx_ctors2.size | 2 +- test/other/metadce/test_metadce_cxx_except.jssize | 2 +- test/other/metadce/test_metadce_cxx_except.size | 2 +- test/other/metadce/test_metadce_cxx_except_wasm.jssize | 2 +- test/other/metadce/test_metadce_cxx_except_wasm.size | 2 +- test/other/metadce/test_metadce_cxx_mangle.size | 2 +- test/other/metadce/test_metadce_cxx_noexcept.jssize | 2 +- test/other/metadce/test_metadce_cxx_noexcept.size | 2 +- test/other/metadce/test_metadce_hello_O1.size | 2 +- test/other/metadce/test_metadce_hello_O2.size | 2 +- test/other/metadce/test_metadce_hello_O3.size | 2 +- test/other/metadce/test_metadce_hello_Os.size | 2 +- test/other/metadce/test_metadce_hello_Oz.size | 2 +- test/other/metadce/test_metadce_hello_dylink.size | 2 +- 21 files changed, 33 insertions(+), 33 deletions(-) diff --git a/test/code_size/hello_webgl2_wasm.json b/test/code_size/hello_webgl2_wasm.json index 69df7d2928d07..073bec23267cf 100644 --- a/test/code_size/hello_webgl2_wasm.json +++ b/test/code_size/hello_webgl2_wasm.json @@ -3,8 +3,8 @@ "a.html.gz": 379, "a.js": 4971, "a.js.gz": 2430, - "a.wasm": 10459, - "a.wasm.gz": 6689, - "total": 15999, - "total_gz": 9498 + "a.wasm": 10479, + "a.wasm.gz": 6697, + "total": 16019, + "total_gz": 9506 } diff --git a/test/code_size/hello_webgl2_wasm2js.json b/test/code_size/hello_webgl2_wasm2js.json index 17ddaf74b7b1d..c62a0f4be66c1 100644 --- a/test/code_size/hello_webgl2_wasm2js.json +++ b/test/code_size/hello_webgl2_wasm2js.json @@ -1,10 +1,10 @@ { "a.html": 567, "a.html.gz": 379, - "a.js": 18219, - "a.js.gz": 8059, + "a.js": 18253, + "a.js.gz": 8058, "a.mem": 3171, "a.mem.gz": 2713, - "total": 21957, - "total_gz": 11151 + "total": 21991, + "total_gz": 11150 } diff --git a/test/code_size/hello_webgl_wasm.json b/test/code_size/hello_webgl_wasm.json index 71d230beea6b4..cd1bb453d009e 100644 --- a/test/code_size/hello_webgl_wasm.json +++ b/test/code_size/hello_webgl_wasm.json @@ -3,8 +3,8 @@ "a.html.gz": 379, "a.js": 4450, "a.js.gz": 2250, - "a.wasm": 10459, - "a.wasm.gz": 6689, - "total": 15478, - "total_gz": 9318 + "a.wasm": 10479, + "a.wasm.gz": 6697, + "total": 15498, + "total_gz": 9326 } diff --git a/test/code_size/hello_webgl_wasm2js.json b/test/code_size/hello_webgl_wasm2js.json index f67f4f18bae42..74fb2b630b8d8 100644 --- a/test/code_size/hello_webgl_wasm2js.json +++ b/test/code_size/hello_webgl_wasm2js.json @@ -1,10 +1,10 @@ { "a.html": 567, "a.html.gz": 379, - "a.js": 17691, - "a.js.gz": 7882, + "a.js": 17725, + "a.js.gz": 7875, "a.mem": 3171, "a.mem.gz": 2713, - "total": 21429, - "total_gz": 10974 + "total": 21463, + "total_gz": 10967 } diff --git a/test/other/metadce/test_metadce_cxx_ctors1.jssize b/test/other/metadce/test_metadce_cxx_ctors1.jssize index cfd500263a04b..9afc428a72117 100644 --- a/test/other/metadce/test_metadce_cxx_ctors1.jssize +++ b/test/other/metadce/test_metadce_cxx_ctors1.jssize @@ -1 +1 @@ -25914 +25919 diff --git a/test/other/metadce/test_metadce_cxx_ctors1.size b/test/other/metadce/test_metadce_cxx_ctors1.size index 926498087fac1..f1e0faa629f7e 100644 --- a/test/other/metadce/test_metadce_cxx_ctors1.size +++ b/test/other/metadce/test_metadce_cxx_ctors1.size @@ -1 +1 @@ -123438 +123448 diff --git a/test/other/metadce/test_metadce_cxx_ctors2.jssize b/test/other/metadce/test_metadce_cxx_ctors2.jssize index ad29f7c112c4a..61e72300e5b81 100644 --- a/test/other/metadce/test_metadce_cxx_ctors2.jssize +++ b/test/other/metadce/test_metadce_cxx_ctors2.jssize @@ -1 +1 @@ -25878 +25883 diff --git a/test/other/metadce/test_metadce_cxx_ctors2.size b/test/other/metadce/test_metadce_cxx_ctors2.size index f8ee7683ac499..8cf21bb95112e 100644 --- a/test/other/metadce/test_metadce_cxx_ctors2.size +++ b/test/other/metadce/test_metadce_cxx_ctors2.size @@ -1 +1 @@ -123332 +123342 diff --git a/test/other/metadce/test_metadce_cxx_except.jssize b/test/other/metadce/test_metadce_cxx_except.jssize index ab4fd0a0713ae..64a8b2b5043a1 100644 --- a/test/other/metadce/test_metadce_cxx_except.jssize +++ b/test/other/metadce/test_metadce_cxx_except.jssize @@ -1 +1 @@ -30428 +30433 diff --git a/test/other/metadce/test_metadce_cxx_except.size b/test/other/metadce/test_metadce_cxx_except.size index 24bc171ec8d9a..2b9a778eec432 100644 --- a/test/other/metadce/test_metadce_cxx_except.size +++ b/test/other/metadce/test_metadce_cxx_except.size @@ -1 +1 @@ -166210 +166213 diff --git a/test/other/metadce/test_metadce_cxx_except_wasm.jssize b/test/other/metadce/test_metadce_cxx_except_wasm.jssize index 4cb8626753a4f..d2e929faedc49 100644 --- a/test/other/metadce/test_metadce_cxx_except_wasm.jssize +++ b/test/other/metadce/test_metadce_cxx_except_wasm.jssize @@ -1 +1 @@ -25723 +25728 diff --git a/test/other/metadce/test_metadce_cxx_except_wasm.size b/test/other/metadce/test_metadce_cxx_except_wasm.size index 23414de4bbcef..b7369b6b82070 100644 --- a/test/other/metadce/test_metadce_cxx_except_wasm.size +++ b/test/other/metadce/test_metadce_cxx_except_wasm.size @@ -1 +1 @@ -137008 +137011 diff --git a/test/other/metadce/test_metadce_cxx_mangle.size b/test/other/metadce/test_metadce_cxx_mangle.size index 010c68af7f9e6..fc909cbf0f37f 100644 --- a/test/other/metadce/test_metadce_cxx_mangle.size +++ b/test/other/metadce/test_metadce_cxx_mangle.size @@ -1 +1 @@ -219392 +219395 diff --git a/test/other/metadce/test_metadce_cxx_noexcept.jssize b/test/other/metadce/test_metadce_cxx_noexcept.jssize index cfd500263a04b..9afc428a72117 100644 --- a/test/other/metadce/test_metadce_cxx_noexcept.jssize +++ b/test/other/metadce/test_metadce_cxx_noexcept.jssize @@ -1 +1 @@ -25914 +25919 diff --git a/test/other/metadce/test_metadce_cxx_noexcept.size b/test/other/metadce/test_metadce_cxx_noexcept.size index 3b99dcaf0173e..61be1734935b4 100644 --- a/test/other/metadce/test_metadce_cxx_noexcept.size +++ b/test/other/metadce/test_metadce_cxx_noexcept.size @@ -1 +1 @@ -126231 +126241 diff --git a/test/other/metadce/test_metadce_hello_O1.size b/test/other/metadce/test_metadce_hello_O1.size index 6726ecf8dcdce..49ce078f63b5e 100644 --- a/test/other/metadce/test_metadce_hello_O1.size +++ b/test/other/metadce/test_metadce_hello_O1.size @@ -1 +1 @@ -2393 +2413 diff --git a/test/other/metadce/test_metadce_hello_O2.size b/test/other/metadce/test_metadce_hello_O2.size index b92935d9e1c94..fc7bdcf6f40e7 100644 --- a/test/other/metadce/test_metadce_hello_O2.size +++ b/test/other/metadce/test_metadce_hello_O2.size @@ -1 +1 @@ -2035 +2055 diff --git a/test/other/metadce/test_metadce_hello_O3.size b/test/other/metadce/test_metadce_hello_O3.size index b0539e90d9ac1..2358ac3b44c5e 100644 --- a/test/other/metadce/test_metadce_hello_O3.size +++ b/test/other/metadce/test_metadce_hello_O3.size @@ -1 +1 @@ -1735 +1755 diff --git a/test/other/metadce/test_metadce_hello_Os.size b/test/other/metadce/test_metadce_hello_Os.size index 57bf58ca801bf..c439d95d8e000 100644 --- a/test/other/metadce/test_metadce_hello_Os.size +++ b/test/other/metadce/test_metadce_hello_Os.size @@ -1 +1 @@ -1727 +1747 diff --git a/test/other/metadce/test_metadce_hello_Oz.size b/test/other/metadce/test_metadce_hello_Oz.size index 67d0dae572cc5..fb814da09665a 100644 --- a/test/other/metadce/test_metadce_hello_Oz.size +++ b/test/other/metadce/test_metadce_hello_Oz.size @@ -1 +1 @@ -1287 +1307 diff --git a/test/other/metadce/test_metadce_hello_dylink.size b/test/other/metadce/test_metadce_hello_dylink.size index 22e75887797fe..44339efbd26d2 100644 --- a/test/other/metadce/test_metadce_hello_dylink.size +++ b/test/other/metadce/test_metadce_hello_dylink.size @@ -1 +1 @@ -9488 +9507 From 9ffc8573a4c5963961f8bb8bee8e180a8a40be47 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 28 Apr 2023 15:53:37 -0700 Subject: [PATCH 0182/1523] Add auto-generated sigs for src/library_egl.js. NFC (#19259) --- src/library_egl.js | 27 +-------------------------- src/library_sigs.js | 26 ++++++++++++++++++++++++++ tools/gen_sig_info.py | 7 +++---- 3 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/library_egl.js b/src/library_egl.js index f4b6071b3b9e5..423479536bcb1 100644 --- a/src/library_egl.js +++ b/src/library_egl.js @@ -91,7 +91,6 @@ var LibraryEGL = { // EGLAPI EGLDisplay EGLAPIENTRY eglGetDisplay(EGLNativeDisplayType display_id); eglGetDisplay__proxy: 'sync', - eglGetDisplay__sig: 'ii', eglGetDisplay: function(nativeDisplayType) { EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); // Note: As a 'conformant' implementation of EGL, we would prefer to init here only if the user @@ -110,7 +109,6 @@ var LibraryEGL = { // EGLAPI EGLBoolean EGLAPIENTRY eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor); eglInitialize__proxy: 'sync', - eglInitialize__sig: 'iiii', eglInitialize: function(display, majorVersion, minorVersion) { if (display != 62000 /* Magic ID for Emscripten 'default display' */) { EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); @@ -129,7 +127,6 @@ var LibraryEGL = { // EGLAPI EGLBoolean EGLAPIENTRY eglTerminate(EGLDisplay dpy); eglTerminate__proxy: 'sync', - eglTerminate__sig: 'ii', eglTerminate: function(display) { if (display != 62000 /* Magic ID for Emscripten 'default display' */) { EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); @@ -145,21 +142,18 @@ var LibraryEGL = { // EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config); eglGetConfigs__proxy: 'sync', - eglGetConfigs__sig: 'iiiii', eglGetConfigs: function(display, configs, config_size, numConfigs) { return EGL.chooseConfig(display, 0, configs, config_size, numConfigs); }, // EGLAPI EGLBoolean EGLAPIENTRY eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config); eglChooseConfig__proxy: 'sync', - eglChooseConfig__sig: 'iiiiii', eglChooseConfig: function(display, attrib_list, configs, config_size, numConfigs) { return EGL.chooseConfig(display, attrib_list, configs, config_size, numConfigs); }, // EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value); eglGetConfigAttrib__proxy: 'sync', - eglGetConfigAttrib__sig: 'iiiii', eglGetConfigAttrib: function(display, config, attribute, value) { if (display != 62000 /* Magic ID for Emscripten 'default display' */) { EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); @@ -277,7 +271,6 @@ var LibraryEGL = { // EGLAPI EGLSurface EGLAPIENTRY eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list); eglCreateWindowSurface__proxy: 'sync', - eglCreateWindowSurface__sig: 'iiiii', eglCreateWindowSurface: function(display, config, win, attrib_list) { if (display != 62000 /* Magic ID for Emscripten 'default display' */) { EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); @@ -297,7 +290,6 @@ var LibraryEGL = { // EGLAPI EGLBoolean EGLAPIENTRY eglDestroySurface(EGLDisplay display, EGLSurface surface); eglDestroySurface__proxy: 'sync', - eglDestroySurface__sig: 'iii', eglDestroySurface: function(display, surface) { if (display != 62000 /* Magic ID for Emscripten 'default display' */) { EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); @@ -321,7 +313,6 @@ var LibraryEGL = { // EGLAPI EGLContext EGLAPIENTRY eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list); eglCreateContext__proxy: 'sync', - eglCreateContext__sig: 'iiiii', eglCreateContext: function(display, config, hmm, contextAttribs) { if (display != 62000 /* Magic ID for Emscripten 'default display' */) { EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); @@ -386,7 +377,6 @@ var LibraryEGL = { // EGLAPI EGLBoolean EGLAPIENTRY eglDestroyContext(EGLDisplay dpy, EGLContext context); eglDestroyContext__proxy: 'sync', - eglDestroyContext__sig: 'iii', eglDestroyContext: function(display, context) { if (display != 62000 /* Magic ID for Emscripten 'default display' */) { EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); @@ -407,7 +397,6 @@ var LibraryEGL = { // EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value); eglQuerySurface__proxy: 'sync', - eglQuerySurface__sig: 'iiiii', eglQuerySurface: function(display, surface, attribute, value) { if (display != 62000 /* Magic ID for Emscripten 'default display' */) { EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); @@ -474,7 +463,6 @@ var LibraryEGL = { // EGLAPI EGLBoolean EGLAPIENTRY eglQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value); eglQueryContext__proxy: 'sync', - eglQueryContext__sig: 'iiiii', eglQueryContext: function(display, context, attribute, value) { if (display != 62000 /* Magic ID for Emscripten 'default display' */) { EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); @@ -514,7 +502,6 @@ var LibraryEGL = { // EGLAPI EGLint EGLAPIENTRY eglGetError(void); eglGetError__proxy: 'sync', - eglGetError__sig: 'i', eglGetError: function() { return EGL.errorCode; }, @@ -522,7 +509,6 @@ var LibraryEGL = { // EGLAPI const char * EGLAPIENTRY eglQueryString(EGLDisplay dpy, EGLint name); eglQueryString__deps: ['$stringToNewUTF8'], eglQueryString__proxy: 'sync', - eglQueryString__sig: 'iii', eglQueryString: function(display, name) { if (display != 62000 /* Magic ID for Emscripten 'default display' */) { EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); @@ -547,7 +533,6 @@ var LibraryEGL = { // EGLAPI EGLBoolean EGLAPIENTRY eglBindAPI(EGLenum api); eglBindAPI__proxy: 'sync', - eglBindAPI__sig: 'ii', eglBindAPI: function(api) { if (api == 0x30A0 /* EGL_OPENGL_ES_API */) { EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); @@ -560,7 +545,6 @@ var LibraryEGL = { // EGLAPI EGLenum EGLAPIENTRY eglQueryAPI(void); eglQueryAPI__proxy: 'sync', - eglQueryAPI__sig: 'i', eglQueryAPI: function() { EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); return 0x30A0; // EGL_OPENGL_ES_API @@ -568,7 +552,6 @@ var LibraryEGL = { // EGLAPI EGLBoolean EGLAPIENTRY eglWaitClient(void); eglWaitClient__proxy: 'sync', - eglWaitClient__sig: 'i', eglWaitClient: function() { EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); return 1; @@ -576,7 +559,6 @@ var LibraryEGL = { // EGLAPI EGLBoolean EGLAPIENTRY eglWaitNative(EGLint engine); eglWaitNative__proxy: 'sync', - eglWaitNative__sig: 'ii', eglWaitNative: function(nativeEngineId) { EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); return 1; @@ -589,7 +571,6 @@ var LibraryEGL = { // EGLAPI EGLBoolean EGLAPIENTRY eglSwapInterval(EGLDisplay dpy, EGLint interval); eglSwapInterval__deps: ['emscripten_set_main_loop_timing'], eglSwapInterval__proxy: 'sync', - eglSwapInterval__sig: 'iii', eglSwapInterval: function(display, interval) { if (display != 62000 /* Magic ID for Emscripten 'default display' */) { EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); @@ -605,7 +586,6 @@ var LibraryEGL = { // EGLAPI EGLBoolean EGLAPIENTRY eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx); eglMakeCurrent__deps: ['$GL'], eglMakeCurrent__proxy: 'sync', - eglMakeCurrent__sig: 'iiiii', eglMakeCurrent: function(display, draw, read, context) { if (display != 62000 /* Magic ID for Emscripten 'default display' */) { EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); @@ -632,14 +612,12 @@ var LibraryEGL = { // EGLAPI EGLContext EGLAPIENTRY eglGetCurrentContext(void); eglGetCurrentContext__proxy: 'sync', - eglGetCurrentContext__sig: 'i', eglGetCurrentContext: function() { return EGL.currentContext; }, // EGLAPI EGLSurface EGLAPIENTRY eglGetCurrentSurface(EGLint readdraw); eglGetCurrentSurface__proxy: 'sync', - eglGetCurrentSurface__sig: 'ii', eglGetCurrentSurface: function(readdraw) { if (readdraw == 0x305A /* EGL_READ */) { return EGL.currentReadSurface; @@ -653,15 +631,13 @@ var LibraryEGL = { // EGLAPI EGLDisplay EGLAPIENTRY eglGetCurrentDisplay(void); eglGetCurrentDisplay__proxy: 'sync', - eglGetCurrentDisplay__sig: 'i', eglGetCurrentDisplay: function() { return EGL.currentContext ? 62000 /* Magic ID for Emscripten 'default display' */ : 0; }, // EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffers(EGLDisplay dpy, EGLSurface surface); eglSwapBuffers__proxy: 'sync', - eglSwapBuffers__sig: 'iii', - eglSwapBuffers: function() { + eglSwapBuffers: function(dpy, surface) { #if PROXY_TO_WORKER if (Browser.doSwapBuffers) Browser.doSwapBuffers(); #endif @@ -684,7 +660,6 @@ var LibraryEGL = { }, eglReleaseThread__proxy: 'sync', - eglReleaseThread__sig: 'i', eglReleaseThread: function() { // Equivalent to eglMakeCurrent with EGL_NO_CONTEXT and EGL_NO_SURFACE. EGL.currentContext = 0; diff --git a/src/library_sigs.js b/src/library_sigs.js index 88a1aec459745..c2eac9d1ba79b 100644 --- a/src/library_sigs.js +++ b/src/library_sigs.js @@ -463,6 +463,32 @@ sigs = { clock_time_get__sig: 'iijp', dladdr__sig: 'ipp', dlopen__sig: 'ppi', + eglBindAPI__sig: 'ii', + eglChooseConfig__sig: 'ipppip', + eglCreateContext__sig: 'ppppp', + eglCreateWindowSurface__sig: 'pppip', + eglDestroyContext__sig: 'ipp', + eglDestroySurface__sig: 'ipp', + eglGetConfigAttrib__sig: 'ippip', + eglGetConfigs__sig: 'ippip', + eglGetCurrentContext__sig: 'p', + eglGetCurrentDisplay__sig: 'p', + eglGetCurrentSurface__sig: 'pi', + eglGetDisplay__sig: 'pi', + eglGetError__sig: 'i', + eglInitialize__sig: 'ippp', + eglMakeCurrent__sig: 'ipppp', + eglQueryAPI__sig: 'i', + eglQueryContext__sig: 'ippip', + eglQueryString__sig: 'ppi', + eglQuerySurface__sig: 'ippip', + eglReleaseThread__sig: 'i', + eglSwapBuffers__sig: 'ipp', + eglSwapInterval__sig: 'ipi', + eglTerminate__sig: 'ip', + eglWaitClient__sig: 'i', + eglWaitGL__sig: 'i', + eglWaitNative__sig: 'ii', ellipseColor__sig: 'ipiiiii', ellipseRGBA__sig: 'ipiiiiiiii', emscripten_SDL_SetEventHandler__sig: 'vpp', diff --git a/tools/gen_sig_info.py b/tools/gen_sig_info.py index a207181867b49..2ea855db3de34 100755 --- a/tools/gen_sig_info.py +++ b/tools/gen_sig_info.py @@ -78,6 +78,7 @@ #else #include #endif +#include #include #include #include @@ -153,8 +154,6 @@ def ignore_symbol(s, cxx): return True if s.startswith('emscripten_gl') or s.startswith('emscripten_alc'): return True - if s.startswith('egl'): - return True if s.startswith('gl') and any(s.endswith(x) for x in ('NV', 'EXT', 'WEBGL', 'ARB', 'ANGLE')): return True if cxx and s in ('__dlsym', '__asctime_r'): @@ -272,6 +271,7 @@ def extract_sig_info(sig_info, extra_settings=None, extra_cflags=None, cxx=False # of JS symbols are included. 'STACK_OVERFLOW_CHECK': 1, 'USE_SDL': 1, + 'USE_GLFW': 0, 'FETCH': 1, 'PTHREADS': 1, 'SHARED_MEMORY': 1, @@ -354,11 +354,10 @@ def main(args): extract_sig_info(sig_info, {'USE_GLFW': 3}, ['-DGLFW3']) extract_sig_info(sig_info, {'JS_LIBRARIES': ['src/embind/embind.js', 'src/embind/emval.js'], 'USE_SDL': 0, - 'USE_GLFW': 0, 'MAX_WEBGL_VERSION': 0, 'AUTO_JS_LIBRARIES': 0}, cxx=True) extract_sig_info(sig_info, {'LEGACY_GL_EMULATION': 1}, ['-DGLES']) - extract_sig_info(sig_info, {'FULL_ES3': 1, 'MAX_WEBGL_VERSION': 2}) + extract_sig_info(sig_info, {'USE_GLFW': 2, 'FULL_ES3': 1, 'MAX_WEBGL_VERSION': 2}) extract_sig_info(sig_info, {'STANDALONE_WASM': 1}) extract_sig_info(sig_info, {'MAIN_MODULE': 2}) From f3ac5f4c906b0518baf5dd432dd4c19373d6987a Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 28 Apr 2023 15:54:56 -0700 Subject: [PATCH 0183/1523] Update .github/workflows/scorecards.yml. NFC (#19260) --- .github/workflows/scorecards.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml index 6bd21dfa895eb..77a261f40a999 100644 --- a/.github/workflows/scorecards.yml +++ b/.github/workflows/scorecards.yml @@ -22,12 +22,12 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@ec3a7ce113134d7a93b817d10a8272cb61118579 # v2.4.0 + uses: actions/checkout@a12a3943b4bdde767164f792f33f40b04645d846 # tag=v3.0.0 with: persist-credentials: false - name: "Run analysis" - uses: ossf/scorecard-action@c1aec4ac820532bab364f02a81873c555a0ba3a1 # v1.0.4 + uses: ossf/scorecard-action@3e15ea8318eee9b333819ec77a36aca8d39df13e # tag=v1.1.1 with: results_file: results.sarif results_format: sarif @@ -42,7 +42,7 @@ jobs: # Upload the results as artifacts (optional). - name: "Upload artifact" - uses: actions/upload-artifact@82c141cc518b40d92cc801eee768e7aafc9c2fa2 # v2.3.1 + uses: actions/upload-artifact@6673cd052c4cd6fcf4b4e6e60ea986c889389535 # tag=v3.0.0 with: name: SARIF file path: results.sarif @@ -50,6 +50,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@5f532563584d71fdef14ee64d17bafb34f751ce5 # v1.0.26 + uses: github/codeql-action/upload-sarif@5f532563584d71fdef14ee64d17bafb34f751ce5 # tag=v1.0.26 with: sarif_file: results.sarif From ba2633b798da2e66f62e1d2b09d77f37807a8674 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 28 Apr 2023 18:00:54 -0700 Subject: [PATCH 0184/1523] Add debug range checks for makeSetValue (#19251) Trying to store a value outside the range of the type being stored to can result in unexpected behaviour. For example, storing 256 to a u8 will end up storing 1. Adding these checks discovered real bug in out library code in `getaddrinfo`. I ran the full other and core test suite with these checks enabled at ASSERTIONS=1 before deciding to use ASSERTIONS=2, at least for now. --- src/library.js | 2 +- src/parseTools.js | 24 ++++++++++++++++++++---- src/runtime_debug.js | 32 +++++++++++++++++++++++++++++++- test/test_other.py | 12 +++++++++--- 4 files changed, 61 insertions(+), 9 deletions(-) diff --git a/src/library.js b/src/library.js index 4702f1f5c1d1b..f7aff0cfd95b4 100644 --- a/src/library.js +++ b/src/library.js @@ -1899,7 +1899,7 @@ mergeInto(LibraryManager.library, { {{{ makeSetValue('ai', C_STRUCTS.addrinfo.ai_family, 'family', 'i32') }}}; {{{ makeSetValue('ai', C_STRUCTS.addrinfo.ai_socktype, 'type', 'i32') }}}; {{{ makeSetValue('ai', C_STRUCTS.addrinfo.ai_protocol, 'proto', 'i32') }}}; - {{{ makeSetValue('ai', C_STRUCTS.addrinfo.ai_canonname, 'canon', 'i32') }}}; + {{{ makeSetValue('ai', C_STRUCTS.addrinfo.ai_canonname, 'canon', '*') }}}; {{{ makeSetValue('ai', C_STRUCTS.addrinfo.ai_addr, 'sa', '*') }}}; if (family === {{{ cDefs.AF_INET6 }}}) { {{{ makeSetValue('ai', C_STRUCTS.addrinfo.ai_addrlen, C_STRUCTS.sockaddr_in6.__size__, 'i32') }}}; diff --git a/src/parseTools.js b/src/parseTools.js index 299c7b40facd2..a3d951edba9ed 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -205,13 +205,13 @@ function makeInlineCalculation(expression, value, tempVar) { // Splits a number (an integer in a double, possibly > 32 bits) into an i64 // value, represented by a low and high i32 pair. -// Will suffer from rounding. +// Will suffer from rounding and truncation. function splitI64(value) { // general idea: // // $1$0 = ~~$d >>> 0; // $1$1 = Math.abs($d) >= 1 ? ( - // $d > 0 ? Math.floor(($d)/ 4294967296.0) >>> 0, + // $d > 0 ? Math.floor(($d)/ 4294967296.0) >>> 0 // : Math.ceil(Math.min(-4294967296.0, $d - $1$0)/ 4294967296.0) // ) : 0; // @@ -357,12 +357,22 @@ function makeGetValue(ptr, pos, type, noNeedFirst, unsigned, ignore, align) { * @return {string} JS code for performing the memory set operation */ function makeSetValue(ptr, pos, value, type) { + var rtn = makeSetValueImpl(ptr, pos, value, type); + if (ASSERTIONS == 2 && (type.startsWith('i') || type.startsWith('u'))) { + const width = getBitWidth(type); + const assertion = `checkInt${width}(${value})`; + rtn += ';' + assertion + } + return rtn; +} + +function makeSetValueImpl(ptr, pos, value, type) { if (type == 'i64' && !WASM_BIGINT) { // If we lack BigInt support we must fall back to an reading a pair of I32 // values. return '(tempI64 = [' + splitI64(value) + '], ' + - makeSetValue(ptr, pos, 'tempI64[0]', 'i32') + ',' + - makeSetValue(ptr, getFastValue(pos, '+', getNativeTypeSize('i32')), 'tempI64[1]', 'i32') + ')'; + makeSetValueImpl(ptr, pos, 'tempI64[0]', 'i32') + ',' + + makeSetValueImpl(ptr, getFastValue(pos, '+', getNativeTypeSize('i32')), 'tempI64[1]', 'i32') + ')'; } const offset = calcFastOffset(ptr, pos); @@ -442,6 +452,12 @@ function calcFastOffset(ptr, pos) { return getFastValue(ptr, '+', pos); } +function getBitWidth(type) { + if (type == 'i53' || type == 'u53') + return 53; + return getNativeTypeSize(type) * 8; +} + function getHeapForType(type) { assert(type); if (isPointerType(type)) { diff --git a/src/runtime_debug.js b/src/runtime_debug.js index 5a627a2634561..c062e1c70ada6 100644 --- a/src/runtime_debug.js +++ b/src/runtime_debug.js @@ -95,7 +95,37 @@ function unexportedRuntimeSymbol(sym) { }); } } -#endif + +#if ASSERTIONS == 2 + +var MAX_UINT8 = (2 ** 8) - 1; +var MAX_UINT16 = (2 ** 16) - 1; +var MAX_UINT32 = (2 ** 32) - 1; +var MAX_UINT53 = (2 ** 53) - 1; +var MAX_UINT64 = (2 ** 64) - 1; + +var MIN_INT8 = - (2 ** ( 8 - 1)) + 1; +var MIN_INT16 = - (2 ** (16 - 1)) + 1; +var MIN_INT32 = - (2 ** (32 - 1)) + 1; +var MIN_INT53 = - (2 ** (53 - 1)) + 1; +var MIN_INT64 = - (2 ** (64 - 1)) + 1; + +function checkInt(value, bits, min, max) { + assert(Number.isInteger(Number(value)), "attempt to write non-integer (" + value + ") into integer heap"); + assert(value <= max, "value (" + value + ") too large to write as " + bits +"-bit value"); + assert(value >= min, "value (" + value + ") too small to write as " + bits +"-bit value"); +} + +var checkInt1 = (value) => checkInt(value, 1, 1); +var checkInt8 = (value) => checkInt(value, 8, MIN_INT8, MAX_UINT8); +var checkInt16 = (value) => checkInt(value, 16, MIN_INT16, MAX_UINT16); +var checkInt32 = (value) => checkInt(value, 32, MIN_INT32, MAX_UINT32); +var checkInt53 = (value) => checkInt(value, 53, MIN_INT53, MAX_UINT53); +var checkInt64 = (value) => checkInt(value, 64, MIN_INT64, MAX_UINT64); + +#endif // ASSERTIONS == 2 + +#endif // ASSERTIONS #if RUNTIME_DEBUG var runtimeDebug = true; // Switch to false at runtime to disable logging at the right times diff --git a/test/test_other.py b/test/test_other.py index f3128024aad5b..d8e1916d2e203 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -12892,7 +12892,13 @@ def test_no_cfi(self): @also_with_wasm_bigint def test_parseTools(self): - self.do_other_test('test_parseTools.c', emcc_args=['--js-library', test_file('other/test_parseTools.js')]) + self.emcc_args += ['--js-library', test_file('other/test_parseTools.js')] + self.do_other_test('test_parseTools.c') + + # If we run ths same test with -sASSERTIONS=2 we expect it to fail because it + # involves writing numbers that are exceed the side of the type. + expected = 'Aborted(Assertion failed: value (316059037807746200000) too large to write as 64-bit value)' + self.do_runf(test_file('other/test_parseTools.c'), expected, emcc_args=['-sASSERTIONS=2'], assert_returncode=NON_ZERO) def test_lto_atexit(self): self.emcc_args.append('-flto') @@ -13200,8 +13206,8 @@ def test_parseTools_legacy(self): create_file('lib.js', ''' mergeInto(LibraryManager.library, { foo: function() { - return {{{ Runtime.POINTER_SIZE }}}; - } + return {{{ Runtime.POINTER_SIZE }}}; + } }); ''') self.set_setting('DEFAULT_LIBRARY_FUNCS_TO_INCLUDE', 'foo') From 9154b00a14c3c9b6a4802aae5dfe236bb6c3bbe2 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 28 Apr 2023 18:29:25 -0700 Subject: [PATCH 0185/1523] Auto-generate sigs for src/library_trace.js (#19261) --- src/library.js | 2 +- src/library_sigs.js | 25 +++++++++++++++++++++++++ src/library_trace.js | 26 +++++++++++--------------- tools/gen_sig_info.py | 3 +++ 4 files changed, 40 insertions(+), 16 deletions(-) diff --git a/src/library.js b/src/library.js index f7aff0cfd95b4..7eebb214b0d89 100644 --- a/src/library.js +++ b/src/library.js @@ -281,7 +281,7 @@ mergeInto(LibraryManager.library, { #endif #if EMSCRIPTEN_TRACING - _emscripten_trace_js_log_message("Emscripten", "Enlarging memory arrays from " + oldSize + " to " + newSize); + traceLogMessage("Emscripten", "Enlarging memory arrays from " + oldSize + " to " + newSize); // And now report the new layout _emscripten_trace_report_memory_layout(); #endif diff --git a/src/library_sigs.js b/src/library_sigs.js index c2eac9d1ba79b..f1ea60b5ec53b 100644 --- a/src/library_sigs.js +++ b/src/library_sigs.js @@ -717,6 +717,31 @@ sigs = { emscripten_supports_offscreencanvas__sig: 'i', emscripten_throw_number__sig: 'vd', emscripten_throw_string__sig: 'vp', + emscripten_trace_annotate_address_type__sig: 'vpp', + emscripten_trace_associate_storage_size__sig: 'vpi', + emscripten_trace_close__sig: 'v', + emscripten_trace_configure__sig: 'vpp', + emscripten_trace_configure_for_google_wtf__sig: 'v', + emscripten_trace_configure_for_test__sig: 'v', + emscripten_trace_enter_context__sig: 'vp', + emscripten_trace_exit_context__sig: 'v', + emscripten_trace_log_message__sig: 'vpp', + emscripten_trace_mark__sig: 'vp', + emscripten_trace_record_allocation__sig: 'vpi', + emscripten_trace_record_frame_end__sig: 'v', + emscripten_trace_record_frame_start__sig: 'v', + emscripten_trace_record_free__sig: 'vp', + emscripten_trace_record_reallocation__sig: 'vppi', + emscripten_trace_report_error__sig: 'vp', + emscripten_trace_report_memory_layout__sig: 'v', + emscripten_trace_report_off_heap_data__sig: 'v', + emscripten_trace_set_enabled__sig: 'vi', + emscripten_trace_set_session_username__sig: 'vp', + emscripten_trace_task_associate_data__sig: 'vpp', + emscripten_trace_task_end__sig: 'v', + emscripten_trace_task_resume__sig: 'vip', + emscripten_trace_task_start__sig: 'vip', + emscripten_trace_task_suspend__sig: 'vp', emscripten_unlock_orientation__sig: 'i', emscripten_unwind_to_js_event_loop__sig: 'v', emscripten_vibrate__sig: 'ii', diff --git a/src/library_trace.js b/src/library_trace.js index 7bd0c9ad92a35..781bb5f66d489 100644 --- a/src/library_trace.js +++ b/src/library_trace.js @@ -6,9 +6,9 @@ var LibraryTracing = { $EmscriptenTrace__deps: [ - 'emscripten_trace_js_configure', 'emscripten_trace_configure_for_google_wtf', - 'emscripten_trace_js_enter_context', 'emscripten_trace_exit_context', - 'emscripten_trace_js_log_message', 'emscripten_trace_js_mark', + '$traceConfigure', 'emscripten_trace_configure_for_google_wtf', + '$traceEnterContext', 'emscripten_trace_exit_context', + '$traceLogMessage', '$traceMark', 'emscripten_get_now' ], $EmscriptenTrace__postset: 'EmscriptenTrace.init()', @@ -49,12 +49,12 @@ var LibraryTracing = { EVENT_USER_NAME: 'user-name', init: function() { - Module['emscripten_trace_configure'] = _emscripten_trace_js_configure; + Module['emscripten_trace_configure'] = traceConfigure; Module['emscripten_trace_configure_for_google_wtf'] = _emscripten_trace_configure_for_google_wtf; - Module['emscripten_trace_enter_context'] = _emscripten_trace_js_enter_context; + Module['emscripten_trace_enter_context'] = traceEnterContext; Module['emscripten_trace_exit_context'] = _emscripten_trace_exit_context; - Module['emscripten_trace_log_message'] = _emscripten_trace_js_log_message; - Module['emscripten_trace_mark'] = _emscripten_trace_js_mark; + Module['emscripten_trace_log_message'] = traceLogMessage; + Module['emscripten_trace_mark'] = traceMark; }, // Work around CORS issues ... @@ -133,7 +133,7 @@ var LibraryTracing = { } }, - emscripten_trace_js_configure: function(collector_url, application) { + $traceConfigure: function(collector_url, application) { EmscriptenTrace.configure(collector_url, application); }, @@ -172,7 +172,7 @@ var LibraryTracing = { } }, - emscripten_trace_js_log_message: function(channel, message) { + $traceLogMessage: function(channel, message) { if (EmscriptenTrace.postEnabled) { var now = EmscriptenTrace.now(); EmscriptenTrace.post([EmscriptenTrace.EVENT_LOG_MESSAGE, now, @@ -180,7 +180,6 @@ var LibraryTracing = { } }, - emscripten_trace_log_message__sig: 'vpp', emscripten_trace_log_message: function(channel, message) { if (EmscriptenTrace.postEnabled) { var now = EmscriptenTrace.now(); @@ -190,7 +189,7 @@ var LibraryTracing = { } }, - emscripten_trace_js_mark: function(message) { + $traceMark: function(message) { if (EmscriptenTrace.postEnabled) { var now = EmscriptenTrace.now(); EmscriptenTrace.post([EmscriptenTrace.EVENT_LOG_MESSAGE, now, @@ -201,7 +200,6 @@ var LibraryTracing = { } }, - emscripten_trace_mark__sig: 'vp', emscripten_trace_mark: function(message) { if (EmscriptenTrace.postEnabled) { var now = EmscriptenTrace.now(); @@ -300,7 +298,7 @@ var LibraryTracing = { } }, - emscripten_trace_js_enter_context: function(name) { + $traceEnterContext: function(name) { if (EmscriptenTrace.postEnabled) { var now = EmscriptenTrace.now(); EmscriptenTrace.post([EmscriptenTrace.EVENT_ENTER_CONTEXT, @@ -311,7 +309,6 @@ var LibraryTracing = { } }, - emscripten_trace_enter_context__sig: 'vp', emscripten_trace_enter_context: function(name) { if (EmscriptenTrace.postEnabled) { var now = EmscriptenTrace.now(); @@ -333,7 +330,6 @@ var LibraryTracing = { } }, - emscripten_trace_task_start__sig: 'vip', emscripten_trace_task_start: function(task_id, name) { if (EmscriptenTrace.postEnabled) { var now = EmscriptenTrace.now(); diff --git a/tools/gen_sig_info.py b/tools/gen_sig_info.py index 2ea855db3de34..2d4efdd9d4aa5 100755 --- a/tools/gen_sig_info.py +++ b/tools/gen_sig_info.py @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -282,6 +283,7 @@ def extract_sig_info(sig_info, extra_settings=None, extra_cflags=None, cxx=False 'src/library_webaudio.js', 'src/library_fetch.js', 'src/library_pthread.js', + 'src/library_trace.js', ], 'SUPPORT_LONGJMP': 'emscripten' } @@ -311,6 +313,7 @@ def extract_sig_info(sig_info, extra_settings=None, extra_cflags=None, cxx=False # or `size_t` types. These get marked as `p` in the `__sig`. obj_file = 'out.o' cmd = [compiler, c_file, '-c', '-pthread', + '--tracing', '-Wno-deprecated-declarations', '-I' + utils.path_from_root('system/lib/libc'), '-o', obj_file] From b1fbec18442635058b362d36bc613ed9cecd5f17 Mon Sep 17 00:00:00 2001 From: Pavel Medvedev <1122386+pmed@users.noreply.github.com> Date: Sun, 30 Apr 2023 05:08:29 +0200 Subject: [PATCH 0186/1523] Enable `embuilder.py` targets mixed with predefined aliases (e.g. SYSTEM or MINIMAL) (#19180) --- embuilder.py | 54 +++++++++++++++++++++++++++------------------ test/test_sanity.py | 9 ++++++++ 2 files changed, 42 insertions(+), 21 deletions(-) diff --git a/embuilder.py b/embuilder.py index c8e65d03d265d..d1d363b1a6724 100755 --- a/embuilder.py +++ b/embuilder.py @@ -208,31 +208,43 @@ def main(): if args.force: do_clear = True + system_libraries, system_tasks = get_system_tasks() + # process tasks auto_tasks = False - tasks = args.targets - system_libraries, system_tasks = get_system_tasks() - if 'SYSTEM' in tasks: - tasks = system_tasks - auto_tasks = True - elif 'USER' in tasks: - tasks = PORTS - auto_tasks = True - elif 'MINIMAL' in tasks: - tasks = MINIMAL_TASKS - auto_tasks = True - elif 'MINIMAL_PIC' in tasks: - tasks = MINIMAL_PIC_TASKS - auto_tasks = True - elif 'ALL' in tasks: - tasks = system_tasks + PORTS - auto_tasks = True + task_targets = dict.fromkeys(args.targets) # use dict to keep targets order + + # subsitute + predefined_tasks = { + 'SYSTEM': system_tasks, + 'USER': PORTS, + 'MINIMAL': MINIMAL_TASKS, + 'MINIMAL_PIC': MINIMAL_PIC_TASKS, + 'ALL': system_tasks + PORTS, + } + for name, tasks in predefined_tasks.items(): + if name in task_targets: + task_targets[name] = tasks + auto_tasks = True + + # flatten tasks + tasks = [] + for name, targets in task_targets.items(): + if targets is None: + # Use target name as task + tasks.append(name) + else: + # There are some ports that we don't want to build as part + # of ALL since the are not well tested or widely used: + if 'cocos2d' in targets: + targets.remove('cocos2d') + + # Use targets from predefined_tasks + tasks.extend(targets) + if auto_tasks: - # There are some ports that we don't want to build as part - # of ALL since the are not well tested or widely used: - skip_tasks = ['cocos2d'] - tasks = [x for x in tasks if x not in skip_tasks] print('Building targets: %s' % ' '.join(tasks)) + for what in tasks: for old, new in legacy_prefixes.items(): if what.startswith(old): diff --git a/test/test_sanity.py b/test/test_sanity.py index 345346256a086..828cd550d5b6a 100644 --- a/test/test_sanity.py +++ b/test/test_sanity.py @@ -707,6 +707,15 @@ def test_embuilder_force_port(self): # Unless --force is specified self.assertContained('generating port', self.do([EMBUILDER, 'build', 'zlib', '--force'])) + def test_embuilder_auto_tasks(self): + restore_and_set_up() + self.assertContained('Building targets: zlib', self.do([EMBUILDER, 'build', 'zlib', 'MINIMAL'])) + # Second time it should not generate anything + self.assertNotContained('generating port', self.do([EMBUILDER, 'build', 'zlib'])) + self.assertNotContained('generating system library', self.do([EMBUILDER, 'build', 'libemmalloc'])) + # Unless --force is specified + self.assertContained('Building targets: zlib', self.do([EMBUILDER, 'build', 'zlib', 'MINIMAL', '--force'])) + def test_embuilder_wasm_backend(self): restore_and_set_up() # the --lto flag makes us build wasm-bc From dc4d654d4021d32cd85cc15d4ab7a01a92f6fac2 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 1 May 2023 10:19:53 -0700 Subject: [PATCH 0187/1523] [Wasm64] Enable emescipten exceptions and SjLj (#19262) Whatever was preventing this from working previously must have been fixed by all the work we have done in the mean time on wasm64 support more generally. --- emcc.py | 2 -- emscripten.py | 2 ++ src/library_exceptions.js | 18 +++++++++++++----- test/test_core.py | 16 ---------------- 4 files changed, 15 insertions(+), 23 deletions(-) diff --git a/emcc.py b/emcc.py index 781132126d8fb..bc46dea83c50f 100755 --- a/emcc.py +++ b/emcc.py @@ -2424,8 +2424,6 @@ def phase_linker_setup(options, state, newargs): if settings.MEMORY64: if settings.ASYNCIFY and settings.MEMORY64 == 1: exit_with_error('MEMORY64=1 is not compatible with ASYNCIFY') - if not settings.DISABLE_EXCEPTION_CATCHING: - exit_with_error('MEMORY64 is not compatible with DISABLE_EXCEPTION_CATCHING=0') # Any "pointers" passed to JS will now be i64's, in both modes. settings.WASM_BIGINT = 1 diff --git a/emscripten.py b/emscripten.py index aff41acd2ed3a..66d6b785b8733 100644 --- a/emscripten.py +++ b/emscripten.py @@ -886,6 +886,8 @@ def create_wasm64_wrappers(metadata): 'emscripten_stack_set_limits': '_pp', '__set_stack_limits': '_pp', '__cxa_can_catch': '_ppp', + '__cxa_increment_exception_refcount': '_p', + '__cxa_decrement_exception_refcount': '_p', '_wasmfs_write_file': '_ppp', '__dl_seterr': '_pp', '_emscripten_run_in_main_runtime_thread_js': '___p_', diff --git a/src/library_exceptions.js b/src/library_exceptions.js index 0672aca7b018b..17b9d2d986ae5 100644 --- a/src/library_exceptions.js +++ b/src/library_exceptions.js @@ -213,6 +213,7 @@ var LibraryExceptions = { }, __cxa_current_primary_exception__deps: ['$exceptionCaught', '__cxa_increment_exception_refcount'], + __cxa_current_primary_exception__sig: 'p', __cxa_current_primary_exception: function() { if (!exceptionCaught.length) { return 0; @@ -223,6 +224,7 @@ var LibraryExceptions = { }, __cxa_rethrow_primary_exception__deps: ['$ExceptionInfo', '$exceptionCaught', '__cxa_rethrow'], + __cxa_rethrow_primary_exception__sig: 'vp', __cxa_rethrow_primary_exception: function(ptr) { if (!ptr) return; var info = new ExceptionInfo(ptr); @@ -242,7 +244,11 @@ var LibraryExceptions = { // We'll do that here, instead, to keep things simpler. __cxa_find_matching_catch__deps: ['$exceptionLast', '$ExceptionInfo', '__resumeException', '__cxa_can_catch', 'setTempRet0'], __cxa_find_matching_catch: function() { - var thrown = + // Here we use explicit calls to `from64`/`to64` rather then using the + // `__sig` attribute to perform these automatically. This is because the + // `__sig` wrapper uses arrow function notation, which is not compatible + // with the use of `arguments` in this function. + var thrown = #if EXCEPTION_STACK_TRACES exceptionLast && exceptionLast.excPtr; #else @@ -251,7 +257,7 @@ var LibraryExceptions = { if (!thrown) { // just pass through the null ptr setTempRet0(0); - return 0; + return {{{ to64(0) }}}; } var info = new ExceptionInfo(thrown); info.set_adjusted_ptr(thrown); @@ -259,7 +265,7 @@ var LibraryExceptions = { if (!thrownType) { // just pass through the thrown ptr setTempRet0(0); - return thrown; + return {{{ to64('thrown') }}}; } // can_catch receives a **, add indirection @@ -272,6 +278,8 @@ var LibraryExceptions = { // return the type of the catch block which should be called. for (var i = 0; i < arguments.length; i++) { var caughtType = arguments[i]; + {{{ from64('caughtType') }}}; + if (caughtType === 0 || caughtType === thrownType) { // Catch all clause matched or exactly the same type is caught break; @@ -282,11 +290,11 @@ var LibraryExceptions = { dbg(" __cxa_find_matching_catch found " + [ptrToString(info.get_adjusted_ptr()), caughtType]); #endif setTempRet0(caughtType); - return thrown; + return {{{ to64('thrown') }}}; } } setTempRet0(thrownType); - return thrown; + return {{{ to64('thrown') }}}; }, __resumeException__deps: ['$exceptionLast'], diff --git a/test/test_core.py b/test/test_core.py index 524985a6cc532..45964cbc6929d 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -109,8 +109,6 @@ def metafunc(self, is_native): self.set_setting('SUPPORT_LONGJMP', 'wasm') f(self) else: - if self.get_setting('MEMORY64'): - self.skipTest('MEMORY64 does not yet support emscripten EH/SjLj') self.set_setting('DISABLE_EXCEPTION_CATCHING', 0) self.set_setting('SUPPORT_LONGJMP', 'emscripten') # DISABLE_EXCEPTION_CATCHING=0 exports __cxa_can_catch and @@ -549,7 +547,6 @@ def test_i64_varargs(self): self.do_core_test('test_i64_varargs.c', args='waka fleefl asdfasdfasdfasdf'.split()) @no_wasm2js('wasm_bigint') - @no_wasm64('MEMORY64 does not yet support exceptions') @requires_node def test_i64_invoke_bigint(self): self.set_setting('WASM_BIGINT') @@ -1100,7 +1097,6 @@ def test_longjmp_standalone(self): def test_longjmp(self): self.do_core_test('test_longjmp.c') - @no_wasm64('MEMORY64 does not yet support SJLJ') def test_longjmp_with_and_without_exceptions(self): # Emscripten SjLj with and without Emscripten EH support self.set_setting('SUPPORT_LONGJMP', 'emscripten') @@ -1157,7 +1153,6 @@ def test_longjmp_stacked(self): def test_longjmp_exc(self): self.do_core_test('test_longjmp_exc.c', assert_returncode=NON_ZERO) - @no_wasm64('MEMORY64 does not yet support exception handling') def test_longjmp_throw(self): for disable_throw in [0, 1]: print(disable_throw) @@ -1237,7 +1232,6 @@ def test_exceptions(self): self.maybe_closure() self.do_run_from_file(test_file('core/test_exceptions.cpp'), test_file('core/test_exceptions_caught.out')) - @no_wasm64('MEMORY64 does not yet support exceptions') def test_exceptions_with_and_without_longjmp(self): self.set_setting('EXCEPTION_DEBUG') self.maybe_closure() @@ -1267,7 +1261,6 @@ def test_exceptions_off(self): @no_wasmfs('https://github.com/emscripten-core/emscripten/issues/16816') @no_asan('TODO: ASan support in minimal runtime') - @no_wasm64('MEMORY64 does not yet support exceptions') def test_exceptions_minimal_runtime(self): self.set_setting('EXIT_RUNTIME') self.maybe_closure() @@ -1373,7 +1366,6 @@ def test_exceptions_3(self): print('2') self.do_run('src.js', 'Caught exception: Hello\nDone.', args=['2'], no_build=True) - @no_wasm64('MEMORY64 does not yet support exceptions') def test_exceptions_allowed(self): self.set_setting('EXCEPTION_CATCHING_ALLOWED', ["_Z12somefunctionv"]) # otherwise it is inlined and not identified @@ -1425,7 +1417,6 @@ def test_exceptions_allowed(self): if not any(o in self.emcc_args for o in ('-O3', '-Oz', '-Os')): self.assertLess(disabled_size, fake_size) - @no_wasm64('MEMORY64 does not yet support exceptions') def test_exceptions_allowed_2(self): self.set_setting('EXCEPTION_CATCHING_ALLOWED', ["main"]) # otherwise it is inlined and not identified @@ -1437,7 +1428,6 @@ def test_exceptions_allowed_2(self): self.emcc_args += ['-DMAIN_NO_SIGNATURE'] self.do_core_test('test_exceptions_allowed_2.cpp') - @no_wasm64('MEMORY64 does not yet support exceptions') def test_exceptions_allowed_uncaught(self): self.emcc_args += ['-std=c++11'] self.set_setting('EXCEPTION_CATCHING_ALLOWED', ["_Z4testv"]) @@ -1446,7 +1436,6 @@ def test_exceptions_allowed_uncaught(self): self.do_core_test('test_exceptions_allowed_uncaught.cpp') - @no_wasm64('MEMORY64 does not yet support exceptions') def test_exceptions_allowed_misuse(self): self.set_setting('EXCEPTION_CATCHING_ALLOWED', ['foo']) @@ -1608,7 +1597,6 @@ def test_exceptions_rethrow_missing(self): create_file('main.cpp', 'int main() { throw; }') self.do_runf('main.cpp', None, assert_returncode=NON_ZERO) - @no_wasm64('MEMORY64 does not yet support exceptions') @with_both_eh_sjlj def test_EXPORT_EXCEPTION_HANDLING_HELPERS(self): self.set_setting('ASSERTIONS', 0) @@ -2471,7 +2459,6 @@ def test_memorygrowth_3_force_fail_reallocBuffer(self): }) @no_asan('requires more memory when growing') @no_lsan('requires more memory when growing') - @no_wasm64('does not fail under wasm64') def test_aborting_new(self, args): # test that C++ new properly errors if we fail to malloc when growth is # enabled, with or without growth @@ -4636,7 +4623,6 @@ def test_dylink_i64_c(self): @needs_dylink @also_with_wasm_bigint - @no_wasm64('MEMORY64 does not yet support exceptions') def test_dylink_i64_invoke(self): self.set_setting('DISABLE_EXCEPTION_CATCHING', 0) self.dylink_test(r'''\ @@ -9350,7 +9336,6 @@ def test_pthread_create_embind_stack_check(self): self.do_run_in_out_file_test('core/pthread/create.cpp') @node_pthreads - @no_wasm64('MEMORY64 does not yet support exceptions') def test_pthread_exceptions(self): self.set_setting('PTHREAD_POOL_SIZE', 2) self.set_setting('EXIT_RUNTIME') @@ -9469,7 +9454,6 @@ def test_pthread_dylink_entry_point(self, args): @needs_dylink @node_pthreads - @no_wasm64('MEMORY64 does not yet support exceptions') def test_pthread_dylink_exceptions(self): self.emcc_args += ['-Wno-experimental', '-pthread'] self.emcc_args.append('-fexceptions') From 90732f878376a177f2daf109852b57c3d6863a91 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 1 May 2023 14:30:53 -0700 Subject: [PATCH 0188/1523] Assert if splitI64 used when WASM_BIGINT is enabled. NFC (#19269) At least today, the idea is that this should never be used when WASM_BIGINT is enabled. --- src/parseTools.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/parseTools.js b/src/parseTools.js index a3d951edba9ed..715b7228a3f51 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -223,6 +223,7 @@ function splitI64(value) { // For negatives, we need to ensure a -1 if the value is overall negative, // even if not significant negative component + assert(!WASM_BIGINT, 'splitI64 should not be used when WASM_BIGINT is enabled'); const low = value + '>>>0'; const high = makeInlineCalculation( asmCoercion('Math.abs(VALUE)', 'double') + ' >= ' + asmEnsureFloat('1', 'double') + ' ? ' + From 3130e06428b40426be1f371fa443232e258ada81 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 2 May 2023 14:51:14 -0700 Subject: [PATCH 0189/1523] Remove fallback to BlobBuilder if Blob constructor is missing (#19277) This code for handling the absence of Blob constructor goes back to 2012: a97aab0522858f3e24ab96fe93e7be9e2b976878 I'm pretty there is nobody depending on this today. I think we would have to go back to chrome 32 or firefox 14 or safari 6 in order to actually need this: https://caniuse.com/blobbuilder I noticed this looked like it should be removed when following the link in tools/file_packager.py to https://crbug.com/124926, which was marked as WontFix over 10 years ago. --- ChangeLog.md | 3 + src/closure-externs/closure-externs.js | 4 - src/headless.js | 13 --- src/library_browser.js | 113 +++++++++---------------- tools/file_packager.py | 6 +- 5 files changed, 46 insertions(+), 93 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 4fe05c3e71c13..cfbda677d95d8 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -20,6 +20,9 @@ See docs/process.md for more on how version tagging works. 3.1.38 (in development) ----------------------- +- Remove extra code for falling back to long-deprecated BlobBuilder browser API + when Blob constructor is missing. This was a fix for an issue that has long + been fixed. (#19277) 3.1.37 - 04/26/23 ----------------- diff --git a/src/closure-externs/closure-externs.js b/src/closure-externs/closure-externs.js index 9c25e396287aa..e8bee73aae629 100644 --- a/src/closure-externs/closure-externs.js +++ b/src/closure-externs/closure-externs.js @@ -171,10 +171,6 @@ var wakaUnknownAfter; * @suppress {undefinedVars} */ var wakaUnknownBefore; -/** - * @suppress {undefinedVars} - */ -var MozBlobBuilder; // Module loaders externs, for AMD etc. diff --git a/src/headless.js b/src/headless.js index 93ac6b8a90f1b..130e948c0ceb1 100644 --- a/src/headless.js +++ b/src/headless.js @@ -295,19 +295,6 @@ if (typeof console == "undefined") { } }; } -var MozBlobBuilder = () => { - this.data = new Uint8Array(0); - this.append = function(buffer) { - var data = new Uint8Array(buffer); - var combined = new Uint8Array(this.data.length + data.length); - combined.set(this.data); - combined.set(data, this.data.length); - this.data = combined; - }; - this.getBlob = function() { - return this.data.buffer; // return the buffer as a "blob". XXX We might need to change this if it is not opaque - }; -}; // additional setup if (!Module['canvas']) { diff --git a/src/library_browser.js b/src/library_browser.js index 675a0011ae718..140919a6502c9 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -105,15 +105,6 @@ var LibraryBrowser = { if (Browser.initted) return; Browser.initted = true; - - try { - new Blob(); - Browser.hasBlobConstructor = true; - } catch(e) { - Browser.hasBlobConstructor = false; - err("warning: no blob constructor, cannot create blobs with mimetypes"); - } - Browser.BlobBuilder = typeof MozBlobBuilder != "undefined" ? MozBlobBuilder : (typeof WebKitBlobBuilder != "undefined" ? WebKitBlobBuilder : (!Browser.hasBlobConstructor ? err("warning: no BlobBuilder") : null)); Browser.URLObject = typeof window != "undefined" ? (window.URL ? window.URL : window.webkitURL) : undefined; if (!Module.noImageDecoding && typeof Browser.URLObject == 'undefined') { err("warning: Browser does not support creating object URLs. Built-in browser image decoding will not be available."); @@ -133,22 +124,10 @@ var LibraryBrowser = { return !Module.noImageDecoding && /\.(jpg|jpeg|png|bmp)$/i.test(name); }; imagePlugin['handle'] = function imagePlugin_handle(byteArray, name, onload, onerror) { - var b = null; - if (Browser.hasBlobConstructor) { - try { - b = new Blob([byteArray], { type: Browser.getMimetype(name) }); - if (b.size !== byteArray.length) { // Safari bug #118630 - // Safari's Blob can only take an ArrayBuffer - b = new Blob([(new Uint8Array(byteArray)).buffer], { type: Browser.getMimetype(name) }); - } - } catch(e) { - warnOnce('Blob constructor present but fails: ' + e + '; falling back to blob builder'); - } - } - if (!b) { - var bb = new Browser.BlobBuilder(); - bb.append((new Uint8Array(byteArray)).buffer); // we need to pass a buffer, and must copy the array to get the right data range - b = bb.getBlob(); + var b = new Blob([byteArray], { type: Browser.getMimetype(name) }); + if (b.size !== byteArray.length) { // Safari bug #118630 + // Safari's Blob can only take an ArrayBuffer + b = new Blob([(new Uint8Array(byteArray)).buffer], { type: Browser.getMimetype(name) }); } var url = Browser.URLObject.createObjectURL(b); #if ASSERTIONS @@ -192,56 +171,48 @@ var LibraryBrowser = { preloadedAudios[name] = new Audio(); // empty shim if (onerror) onerror(); } - if (Browser.hasBlobConstructor) { - try { - var b = new Blob([byteArray], { type: Browser.getMimetype(name) }); - } catch(e) { - return fail(); - } - var url = Browser.URLObject.createObjectURL(b); // XXX we never revoke this! + var b = new Blob([byteArray], { type: Browser.getMimetype(name) }); + var url = Browser.URLObject.createObjectURL(b); // XXX we never revoke this! #if ASSERTIONS - assert(typeof url == 'string', 'createObjectURL must return a url as a string'); + assert(typeof url == 'string', 'createObjectURL must return a url as a string'); #endif - var audio = new Audio(); - audio.addEventListener('canplaythrough', () => finish(audio), false); // use addEventListener due to chromium bug 124926 - audio.onerror = function audio_onerror(event) { - if (done) return; - err('warning: browser could not fully decode audio ' + name + ', trying slower base64 approach'); - function encode64(data) { - var BASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; - var PAD = '='; - var ret = ''; - var leftchar = 0; - var leftbits = 0; - for (var i = 0; i < data.length; i++) { - leftchar = (leftchar << 8) | data[i]; - leftbits += 8; - while (leftbits >= 6) { - var curr = (leftchar >> (leftbits-6)) & 0x3f; - leftbits -= 6; - ret += BASE[curr]; - } - } - if (leftbits == 2) { - ret += BASE[(leftchar&3) << 4]; - ret += PAD + PAD; - } else if (leftbits == 4) { - ret += BASE[(leftchar&0xf) << 2]; - ret += PAD; + var audio = new Audio(); + audio.addEventListener('canplaythrough', () => finish(audio), false); // use addEventListener due to chromium bug 124926 + audio.onerror = function audio_onerror(event) { + if (done) return; + err('warning: browser could not fully decode audio ' + name + ', trying slower base64 approach'); + function encode64(data) { + var BASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; + var PAD = '='; + var ret = ''; + var leftchar = 0; + var leftbits = 0; + for (var i = 0; i < data.length; i++) { + leftchar = (leftchar << 8) | data[i]; + leftbits += 8; + while (leftbits >= 6) { + var curr = (leftchar >> (leftbits-6)) & 0x3f; + leftbits -= 6; + ret += BASE[curr]; } - return ret; } - audio.src = 'data:audio/x-' + name.substr(-3) + ';base64,' + encode64(byteArray); - finish(audio); // we don't wait for confirmation this worked - but it's worth trying - }; - audio.src = url; - // workaround for chrome bug 124926 - we do not always get oncanplaythrough or onerror - safeSetTimeout(() => { - finish(audio); // try to use it even though it is not necessarily ready to play - }, 10000); - } else { - return fail(); - } + if (leftbits == 2) { + ret += BASE[(leftchar&3) << 4]; + ret += PAD + PAD; + } else if (leftbits == 4) { + ret += BASE[(leftchar&0xf) << 2]; + ret += PAD; + } + return ret; + } + audio.src = 'data:audio/x-' + name.substr(-3) + ';base64,' + encode64(byteArray); + finish(audio); // we don't wait for confirmation this worked - but it's worth trying + }; + audio.src = url; + // workaround for chrome bug 124926 - we do not always get oncanplaythrough or onerror + safeSetTimeout(() => { + finish(audio); // try to use it even though it is not necessarily ready to play + }, 10000); }; Module['preloadPlugins'].push(audioPlugin); diff --git a/tools/file_packager.py b/tools/file_packager.py index 9ee8e4d2e90c9..7d6d9c0faa66b 100755 --- a/tools/file_packager.py +++ b/tools/file_packager.py @@ -635,11 +635,7 @@ def generate_js(data_target, data_files, metadata): Module['FS_createPreloadedFile'](this.name, null, byteArray, true, true, function() { Module['removeRunDependency']('fp ' + that.name); }, function() { - if (that.audio) { - Module['removeRunDependency']('fp ' + that.name); // workaround for chromium bug 124926 (still no audio with this, but at least we don't hang) - } else { - err('Preloading file ' + that.name + ' failed'); - } + err('Preloading file ' + that.name + ' failed'); }, false, true); // canOwn this data in the filesystem, it is a slide into the heap that will never change\n''' create_data = '''// canOwn this data in the filesystem, it is a slide into the heap that will never change Module['FS_createDataFile'](this.name, null, byteArray, true, true, true); From b4e0f5c06bc2d8cec0bb7082d58706b47f596825 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 2 May 2023 15:23:08 -0700 Subject: [PATCH 0190/1523] [Wasm64] Better support + testing for fetch API (#19276) --- src/Fetch.js | 30 ++++++++++++++--------------- src/generated_struct_info64.json | 22 ++++++++++----------- system/include/emscripten/fetch.h | 2 +- test/test_browser.py | 32 ++++++++++++++++++++++++++----- 4 files changed, 54 insertions(+), 32 deletions(-) diff --git a/src/Fetch.js b/src/Fetch.js index ed8970ffd4669..ef52028a8ec9b 100644 --- a/src/Fetch.js +++ b/src/Fetch.js @@ -241,17 +241,17 @@ function fetchXHR(fetch, onsuccess, onerror, onprogress, onreadystatechange) { var fetch_attr = fetch + {{{ C_STRUCTS.emscripten_fetch_t.__attributes }}}; var requestMethod = UTF8ToString(fetch_attr); if (!requestMethod) requestMethod = 'GET'; - var userData = HEAPU32[fetch + {{{ C_STRUCTS.emscripten_fetch_t.userData }}} >> 2]; - var fetchAttributes = HEAPU32[fetch_attr + {{{ C_STRUCTS.emscripten_fetch_attr_t.attributes }}} >> 2]; - var timeoutMsecs = HEAPU32[fetch_attr + {{{ C_STRUCTS.emscripten_fetch_attr_t.timeoutMSecs }}} >> 2]; - var withCredentials = !!HEAPU32[fetch_attr + {{{ C_STRUCTS.emscripten_fetch_attr_t.withCredentials }}} >> 2]; - var destinationPath = HEAPU32[fetch_attr + {{{ C_STRUCTS.emscripten_fetch_attr_t.destinationPath }}} >> 2]; - var userName = HEAPU32[fetch_attr + {{{ C_STRUCTS.emscripten_fetch_attr_t.userName }}} >> 2]; - var password = HEAPU32[fetch_attr + {{{ C_STRUCTS.emscripten_fetch_attr_t.password }}} >> 2]; - var requestHeaders = HEAPU32[fetch_attr + {{{ C_STRUCTS.emscripten_fetch_attr_t.requestHeaders }}} >> 2]; - var overriddenMimeType = HEAPU32[fetch_attr + {{{ C_STRUCTS.emscripten_fetch_attr_t.overriddenMimeType }}} >> 2]; - var dataPtr = HEAPU32[fetch_attr + {{{ C_STRUCTS.emscripten_fetch_attr_t.requestData }}} >> 2]; - var dataLength = HEAPU32[fetch_attr + {{{ C_STRUCTS.emscripten_fetch_attr_t.requestDataSize }}} >> 2]; + var userData = {{{ makeGetValue('fetch_attr', C_STRUCTS.emscripten_fetch_t.userData, '*') }}}; + var fetchAttributes = {{{ makeGetValue('fetch_attr', C_STRUCTS.emscripten_fetch_attr_t.attributes, 'u32') }}}; + var timeoutMsecs = {{{ makeGetValue('fetch_attr', C_STRUCTS.emscripten_fetch_attr_t.timeoutMSecs, 'u32') }}}; + var withCredentials = !!{{{ makeGetValue('fetch_attr', C_STRUCTS.emscripten_fetch_attr_t.withCredentials, 'u8') }}}; + var destinationPath = {{{ makeGetValue('fetch_attr', C_STRUCTS.emscripten_fetch_attr_t.destinationPath, '*') }}}; + var userName = {{{ makeGetValue('fetch_attr', C_STRUCTS.emscripten_fetch_attr_t.userName, '*') }}}; + var password = {{{ makeGetValue('fetch_attr', C_STRUCTS.emscripten_fetch_attr_t.password, '*') }}}; + var requestHeaders = {{{ makeGetValue('fetch_attr', C_STRUCTS.emscripten_fetch_attr_t.requestHeaders, '*') }}}; + var overriddenMimeType = {{{ makeGetValue('fetch_attr', C_STRUCTS.emscripten_fetch_attr_t.overriddenMimeType, '*') }}}; + var dataPtr = {{{ makeGetValue('fetch_attr', C_STRUCTS.emscripten_fetch_attr_t.requestData, '*') }}}; + var dataLength = {{{ makeGetValue('fetch_attr', C_STRUCTS.emscripten_fetch_attr_t.requestDataSize, '*') }}}; var fetchAttrLoadToMemory = !!(fetchAttributes & {{{ cDefs.EMSCRIPTEN_FETCH_LOAD_TO_MEMORY }}}); var fetchAttrStreamData = !!(fetchAttributes & {{{ cDefs.EMSCRIPTEN_FETCH_STREAM_DATA }}}); @@ -289,11 +289,11 @@ function fetchXHR(fetch, onsuccess, onerror, onprogress, onreadystatechange) { } if (requestHeaders) { for (;;) { - var key = HEAPU32[requestHeaders >> 2]; + var key = {{{ makeGetValue('requestHeaders', 0, '*') }}}; if (!key) break; - var value = HEAPU32[requestHeaders + 4 >> 2]; + var value = {{{ makeGetValue('requestHeaders', POINTER_SIZE, '*') }}}; if (!value) break; - requestHeaders += 8; + requestHeaders += {{{ 2 * POINTER_SIZE }}}; var keyStr = UTF8ToString(key); var valueStr = UTF8ToString(value); #if FETCH_DEBUG @@ -302,7 +302,7 @@ function fetchXHR(fetch, onsuccess, onerror, onprogress, onreadystatechange) { xhr.setRequestHeader(keyStr, valueStr); } } - var id = HEAPU32[fetch + {{{ C_STRUCTS.emscripten_fetch_t.id }}} >> 2]; + var id = {{{ makeGetValue('fetch', C_STRUCTS.emscripten_fetch_t.id, 'u32') }}}; Fetch.xhrs[id] = xhr; var data = (dataPtr && dataLength) ? HEAPU8.slice(dataPtr, dataPtr + dataLength) : null; // TODO: Support specifying custom headers to the request. diff --git a/src/generated_struct_info64.json b/src/generated_struct_info64.json index cc1d801fe6355..4a8b96dd5f6bc 100644 --- a/src/generated_struct_info64.json +++ b/src/generated_struct_info64.json @@ -1336,28 +1336,28 @@ "value": 8 }, "emscripten_fetch_attr_t": { - "__size__": 152, + "__size__": 144, "attributes": 72, - "destinationPath": 96, + "destinationPath": 88, "onerror": 48, "onprogress": 56, "onreadystatechange": 64, "onsuccess": 40, - "overriddenMimeType": 128, - "password": 112, - "requestData": 136, - "requestDataSize": 144, - "requestHeaders": 120, + "overriddenMimeType": 120, + "password": 104, + "requestData": 128, + "requestDataSize": 136, + "requestHeaders": 112, "requestMethod": 0, - "timeoutMSecs": 80, + "timeoutMSecs": 76, "userData": 32, - "userName": 104, - "withCredentials": 88 + "userName": 96, + "withCredentials": 80 }, "emscripten_fetch_t": { "__attributes": 128, "__proxyState": 124, - "__size__": 280, + "__size__": 272, "data": 24, "dataOffset": 40, "id": 0, diff --git a/system/include/emscripten/fetch.h b/system/include/emscripten/fetch.h index e87843f7b96e4..07147de8adce0 100644 --- a/system/include/emscripten/fetch.h +++ b/system/include/emscripten/fetch.h @@ -85,7 +85,7 @@ typedef struct emscripten_fetch_attr_t { // Specifies the amount of time the request can take before failing due to a // timeout. - unsigned long timeoutMSecs; + uint32_t timeoutMSecs; // Indicates whether cross-site access control requests should be made using // credentials. diff --git a/test/test_browser.py b/test/test_browser.py index 7cf8cd999665e..33653fd6c288a 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -124,6 +124,26 @@ def metafunc(self, with_wasm64): return metafunc +def also_with_wasm2js_or_wasm64(f): + assert callable(f) + + def metafunc(self, with_wasm2js, with_wasm64): + if with_wasm2js: + self.set_setting('WASM', 0) + f(self) + elif with_wasm64: + self.set_setting('MEMORY64') + self.emcc_args.append('-Wno-experimental') + f(self) + else: + f(self) + + metafunc._parameterize = {'': (False, False), + 'wasm2js': (True, False), + 'wasm64': (False, True)} + return metafunc + + def shell_with_script(shell_file, output_file, replacement): shell = read_file(path_from_root('src', shell_file)) create_file(output_file, shell.replace('{{{ SCRIPT }}}', replacement)) @@ -4602,7 +4622,7 @@ def test_preallocated_heap(self): self.btest_exit('test_preallocated_heap.cpp', args=['-sWASM=0', '-sINITIAL_MEMORY=16MB', '-sABORTING_MALLOC=0', '--shell-file', test_file('test_preallocated_heap_shell.html')]) # Tests emscripten_fetch() usage to XHR data directly to memory without persisting results to IndexedDB. - @also_with_wasm2js + @also_with_wasm2js_or_wasm64 def test_fetch_to_memory(self): # Test error reporting in the negative case when the file URL doesn't exist. (http 404) self.btest_exit('fetch/to_memory.cpp', @@ -4626,14 +4646,14 @@ def test_fetch_from_thread(self, args): args=args + ['-pthread', '-sPROXY_TO_PTHREAD', '-sFETCH_DEBUG', '-sFETCH', '-DFILE_DOES_NOT_EXIST'], also_wasm2js=True) - @also_with_wasm2js + @also_with_wasm2js_or_wasm64 def test_fetch_to_indexdb(self): shutil.copyfile(test_file('gears.png'), 'gears.png') self.btest_exit('fetch/to_indexeddb.cpp', args=['-sFETCH_DEBUG', '-sFETCH']) # Tests emscripten_fetch() usage to persist an XHR into IndexedDB and subsequently load up from there. - @also_with_wasm2js + @also_with_wasm2js_or_wasm64 def test_fetch_cached_xhr(self): shutil.copyfile(test_file('gears.png'), 'gears.png') self.btest_exit('fetch/cached_xhr.cpp', @@ -4641,14 +4661,14 @@ def test_fetch_cached_xhr(self): # Tests that response headers get set on emscripten_fetch_t values. @no_firefox('https://github.com/emscripten-core/emscripten/issues/16868') - @also_with_wasm2js + @also_with_wasm2js_or_wasm64 @requires_threads def test_fetch_response_headers(self): shutil.copyfile(test_file('gears.png'), 'gears.png') self.btest_exit('fetch/response_headers.cpp', args=['-sFETCH_DEBUG', '-sFETCH', '-pthread', '-sPROXY_TO_PTHREAD']) # Test emscripten_fetch() usage to stream a XHR in to memory without storing the full file in memory - @also_with_wasm2js + @also_with_wasm2js_or_wasm64 def test_fetch_stream_file(self): self.skipTest('moz-chunked-arraybuffer was firefox-only and has been removed') # Strategy: create a large 128MB file, and compile with a small 16MB Emscripten heap, so that the tested file @@ -4674,6 +4694,7 @@ def test_fetch_xhr_abort(self): # Tests emscripten_fetch() usage in synchronous mode when used from the main # thread proxied to a Worker with -sPROXY_TO_PTHREAD option. @no_firefox('https://github.com/emscripten-core/emscripten/issues/16868') + @also_with_wasm64 @requires_threads def test_fetch_sync_xhr(self): shutil.copyfile(test_file('gears.png'), 'gears.png') @@ -4682,6 +4703,7 @@ def test_fetch_sync_xhr(self): # Tests emscripten_fetch() usage when user passes none of the main 3 flags (append/replace/no_download). # In that case, in append is implicitly understood. @no_firefox('https://github.com/emscripten-core/emscripten/issues/16868') + @also_with_wasm64 @requires_threads def test_fetch_implicit_append(self): shutil.copyfile(test_file('gears.png'), 'gears.png') From 6a546c283980a161f17076628d82824c96bb4a36 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 2 May 2023 15:46:07 -0700 Subject: [PATCH 0191/1523] Rebaseline codesize expectations. NFC --- test/code_size/hello_wasm_worker_wasm.json | 8 ++++---- test/code_size/hello_webgl2_wasm.json | 8 ++++---- test/code_size/hello_webgl2_wasm2js.json | 8 ++++---- test/code_size/hello_webgl_wasm.json | 8 ++++---- test/code_size/hello_webgl_wasm2js.json | 8 ++++---- test/other/metadce/test_metadce_cxx_ctors1.size | 2 +- test/other/metadce/test_metadce_cxx_ctors2.size | 2 +- test/other/metadce/test_metadce_cxx_except.size | 2 +- test/other/metadce/test_metadce_cxx_except_wasm.size | 2 +- test/other/metadce/test_metadce_cxx_mangle.size | 2 +- test/other/metadce/test_metadce_cxx_noexcept.size | 2 +- test/other/metadce/test_metadce_hello_dylink.size | 2 +- test/other/metadce/test_metadce_mem_O3.size | 2 +- test/other/metadce/test_metadce_mem_O3_grow.size | 2 +- .../metadce/test_metadce_mem_O3_grow_standalone.size | 2 +- test/other/metadce/test_metadce_mem_O3_standalone.size | 2 +- .../other/metadce/test_metadce_mem_O3_standalone_lib.size | 2 +- .../metadce/test_metadce_mem_O3_standalone_narg.size | 2 +- .../metadce/test_metadce_mem_O3_standalone_narg_flto.size | 2 +- test/other/metadce/test_metadce_minimal_pthreads.size | 2 +- 20 files changed, 35 insertions(+), 35 deletions(-) diff --git a/test/code_size/hello_wasm_worker_wasm.json b/test/code_size/hello_wasm_worker_wasm.json index 1c477feb0bcd4..54299179b6e15 100644 --- a/test/code_size/hello_wasm_worker_wasm.json +++ b/test/code_size/hello_wasm_worker_wasm.json @@ -3,8 +3,8 @@ "a.html.gz": 433, "a.js": 733, "a.js.gz": 463, - "a.wasm": 1859, - "a.wasm.gz": 1033, - "total": 3329, - "total_gz": 1929 + "a.wasm": 1862, + "a.wasm.gz": 1040, + "total": 3332, + "total_gz": 1936 } diff --git a/test/code_size/hello_webgl2_wasm.json b/test/code_size/hello_webgl2_wasm.json index 073bec23267cf..d15f161407b87 100644 --- a/test/code_size/hello_webgl2_wasm.json +++ b/test/code_size/hello_webgl2_wasm.json @@ -3,8 +3,8 @@ "a.html.gz": 379, "a.js": 4971, "a.js.gz": 2430, - "a.wasm": 10479, - "a.wasm.gz": 6697, - "total": 16019, - "total_gz": 9506 + "a.wasm": 10482, + "a.wasm.gz": 6707, + "total": 16022, + "total_gz": 9516 } diff --git a/test/code_size/hello_webgl2_wasm2js.json b/test/code_size/hello_webgl2_wasm2js.json index c62a0f4be66c1..c7c3da01de188 100644 --- a/test/code_size/hello_webgl2_wasm2js.json +++ b/test/code_size/hello_webgl2_wasm2js.json @@ -1,10 +1,10 @@ { "a.html": 567, "a.html.gz": 379, - "a.js": 18253, - "a.js.gz": 8058, + "a.js": 18252, + "a.js.gz": 8055, "a.mem": 3171, "a.mem.gz": 2713, - "total": 21991, - "total_gz": 11150 + "total": 21990, + "total_gz": 11147 } diff --git a/test/code_size/hello_webgl_wasm.json b/test/code_size/hello_webgl_wasm.json index cd1bb453d009e..86d566419f1a9 100644 --- a/test/code_size/hello_webgl_wasm.json +++ b/test/code_size/hello_webgl_wasm.json @@ -3,8 +3,8 @@ "a.html.gz": 379, "a.js": 4450, "a.js.gz": 2250, - "a.wasm": 10479, - "a.wasm.gz": 6697, - "total": 15498, - "total_gz": 9326 + "a.wasm": 10482, + "a.wasm.gz": 6707, + "total": 15501, + "total_gz": 9336 } diff --git a/test/code_size/hello_webgl_wasm2js.json b/test/code_size/hello_webgl_wasm2js.json index 74fb2b630b8d8..0ce1b1997c10a 100644 --- a/test/code_size/hello_webgl_wasm2js.json +++ b/test/code_size/hello_webgl_wasm2js.json @@ -1,10 +1,10 @@ { "a.html": 567, "a.html.gz": 379, - "a.js": 17725, - "a.js.gz": 7875, + "a.js": 17724, + "a.js.gz": 7870, "a.mem": 3171, "a.mem.gz": 2713, - "total": 21463, - "total_gz": 10967 + "total": 21462, + "total_gz": 10962 } diff --git a/test/other/metadce/test_metadce_cxx_ctors1.size b/test/other/metadce/test_metadce_cxx_ctors1.size index f1e0faa629f7e..7cb7cf00d785b 100644 --- a/test/other/metadce/test_metadce_cxx_ctors1.size +++ b/test/other/metadce/test_metadce_cxx_ctors1.size @@ -1 +1 @@ -123448 +123479 diff --git a/test/other/metadce/test_metadce_cxx_ctors2.size b/test/other/metadce/test_metadce_cxx_ctors2.size index 8cf21bb95112e..7a2e462123ec6 100644 --- a/test/other/metadce/test_metadce_cxx_ctors2.size +++ b/test/other/metadce/test_metadce_cxx_ctors2.size @@ -1 +1 @@ -123342 +123373 diff --git a/test/other/metadce/test_metadce_cxx_except.size b/test/other/metadce/test_metadce_cxx_except.size index 2b9a778eec432..27e59ea3c5748 100644 --- a/test/other/metadce/test_metadce_cxx_except.size +++ b/test/other/metadce/test_metadce_cxx_except.size @@ -1 +1 @@ -166213 +166244 diff --git a/test/other/metadce/test_metadce_cxx_except_wasm.size b/test/other/metadce/test_metadce_cxx_except_wasm.size index b7369b6b82070..c2edb388c6c10 100644 --- a/test/other/metadce/test_metadce_cxx_except_wasm.size +++ b/test/other/metadce/test_metadce_cxx_except_wasm.size @@ -1 +1 @@ -137011 +137042 diff --git a/test/other/metadce/test_metadce_cxx_mangle.size b/test/other/metadce/test_metadce_cxx_mangle.size index fc909cbf0f37f..4cc57b2d3f06f 100644 --- a/test/other/metadce/test_metadce_cxx_mangle.size +++ b/test/other/metadce/test_metadce_cxx_mangle.size @@ -1 +1 @@ -219395 +219427 diff --git a/test/other/metadce/test_metadce_cxx_noexcept.size b/test/other/metadce/test_metadce_cxx_noexcept.size index 61be1734935b4..b8f5d0b10a39e 100644 --- a/test/other/metadce/test_metadce_cxx_noexcept.size +++ b/test/other/metadce/test_metadce_cxx_noexcept.size @@ -1 +1 @@ -126241 +126272 diff --git a/test/other/metadce/test_metadce_hello_dylink.size b/test/other/metadce/test_metadce_hello_dylink.size index 44339efbd26d2..6b4f6ad29f670 100644 --- a/test/other/metadce/test_metadce_hello_dylink.size +++ b/test/other/metadce/test_metadce_hello_dylink.size @@ -1 +1 @@ -9507 +9514 diff --git a/test/other/metadce/test_metadce_mem_O3.size b/test/other/metadce/test_metadce_mem_O3.size index 242bb0eacfe3a..57e22dba433ab 100644 --- a/test/other/metadce/test_metadce_mem_O3.size +++ b/test/other/metadce/test_metadce_mem_O3.size @@ -1 +1 @@ -5351 +5358 diff --git a/test/other/metadce/test_metadce_mem_O3_grow.size b/test/other/metadce/test_metadce_mem_O3_grow.size index 5fa867355346a..0da0b6c62ca1d 100644 --- a/test/other/metadce/test_metadce_mem_O3_grow.size +++ b/test/other/metadce/test_metadce_mem_O3_grow.size @@ -1 +1 @@ -5352 +5359 diff --git a/test/other/metadce/test_metadce_mem_O3_grow_standalone.size b/test/other/metadce/test_metadce_mem_O3_grow_standalone.size index d0872d0d9e75a..943b0641b04bf 100644 --- a/test/other/metadce/test_metadce_mem_O3_grow_standalone.size +++ b/test/other/metadce/test_metadce_mem_O3_grow_standalone.size @@ -1 +1 @@ -5665 +5672 diff --git a/test/other/metadce/test_metadce_mem_O3_standalone.size b/test/other/metadce/test_metadce_mem_O3_standalone.size index 4362efad08806..10a409ec845ab 100644 --- a/test/other/metadce/test_metadce_mem_O3_standalone.size +++ b/test/other/metadce/test_metadce_mem_O3_standalone.size @@ -1 +1 @@ -5588 +5595 diff --git a/test/other/metadce/test_metadce_mem_O3_standalone_lib.size b/test/other/metadce/test_metadce_mem_O3_standalone_lib.size index 35014c71983c6..5f7d333c97804 100644 --- a/test/other/metadce/test_metadce_mem_O3_standalone_lib.size +++ b/test/other/metadce/test_metadce_mem_O3_standalone_lib.size @@ -1 +1 @@ -5354 +5361 diff --git a/test/other/metadce/test_metadce_mem_O3_standalone_narg.size b/test/other/metadce/test_metadce_mem_O3_standalone_narg.size index 70bea13d82fe5..3833169846893 100644 --- a/test/other/metadce/test_metadce_mem_O3_standalone_narg.size +++ b/test/other/metadce/test_metadce_mem_O3_standalone_narg.size @@ -1 +1 @@ -5384 +5391 diff --git a/test/other/metadce/test_metadce_mem_O3_standalone_narg_flto.size b/test/other/metadce/test_metadce_mem_O3_standalone_narg_flto.size index 8df1f3688fac0..58109dfb98baf 100644 --- a/test/other/metadce/test_metadce_mem_O3_standalone_narg_flto.size +++ b/test/other/metadce/test_metadce_mem_O3_standalone_narg_flto.size @@ -1 +1 @@ -4195 +4202 diff --git a/test/other/metadce/test_metadce_minimal_pthreads.size b/test/other/metadce/test_metadce_minimal_pthreads.size index 78ae000359105..1350e12aa189f 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.size +++ b/test/other/metadce/test_metadce_minimal_pthreads.size @@ -1 +1 @@ -19019 +19050 From 9d036213d1f13f3a6d2b6daef8069a93b66e1eda Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 2 May 2023 20:16:35 -0700 Subject: [PATCH 0192/1523] Use JS string.startsWith. NFC (#19278) --- src/modules.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/modules.js b/src/modules.js index 613a836b0975a..e99c72b679136 100644 --- a/src/modules.js +++ b/src/modules.js @@ -283,10 +283,6 @@ function cDefine(key) { return cDefs[key]; } -function isFSPrefixed(name) { - return name.length > 3 && name[0] === 'F' && name[1] === 'S' && name[2] === '_'; -} - function isInternalSymbol(ident) { return ident + '__internal' in LibraryManager.library; } @@ -342,7 +338,7 @@ function exportRuntime() { if (EXPORTED_RUNTIME_METHODS_SET.has(name)) { let exported = name; // the exported name may differ from the internal name - if (isFSPrefixed(exported)) { + if (exported.startsWith('FS_')) { // this is a filesystem value, FS.x exported as FS_x exported = 'FS.' + exported.substr(3); } else if (legacyRuntimeElements.has(exported)) { From e278cb5e748ccc50957ac4474afd6b34af67e9df Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 3 May 2023 10:42:38 -0700 Subject: [PATCH 0193/1523] Remove code duplication between library_wasmfs.js and library_fs.js (#19279) --- src/library_fs.js | 80 +++++----------------------------------- src/library_fs_shared.js | 79 +++++++++++++++++++++++++++++++++++++++ src/library_noderawfs.js | 4 +- src/library_wasmfs.js | 75 ++++++------------------------------- src/modules.js | 17 +++++---- 5 files changed, 112 insertions(+), 143 deletions(-) create mode 100644 src/library_fs_shared.js diff --git a/src/library_fs.js b/src/library_fs.js index 5c7864e3f48f8..ce9c739f59f1a 100644 --- a/src/library_fs.js +++ b/src/library_fs.js @@ -5,7 +5,10 @@ */ mergeInto(LibraryManager.library, { - $FS__deps: ['$randomFill', '$PATH', '$PATH_FS', '$TTY', '$MEMFS', '$asyncLoad', + $FS__deps: ['$randomFill', '$PATH', '$PATH_FS', '$TTY', '$MEMFS', + '$FS_createPreloadedFile', + '$FS_modeStringToFlags', + '$FS_getMode', '$intArrayFromString', '$stringToUTF8Array', '$lengthBytesUTF8', @@ -88,6 +91,7 @@ Object.defineProperties(FSNode.prototype, { } }); FS.FSNode = FSNode; +FS.createPreloadedFile = FS_createPreloadedFile; FS.staticInit();` + #if USE_CLOSURE_COMPILER // Declare variable for Closure, FS.createPreloadedFile() below calls Browser.handledByPreloadPlugin() @@ -293,25 +297,6 @@ FS.staticInit();` + // // permissions // - flagModes: { - // Extra quotes used here on the keys to this object otherwise jsifier will - // erase them in the process of reading and then writing the JS library - // code. - '"r"': {{{ cDefs.O_RDONLY }}}, - '"r+"': {{{ cDefs.O_RDWR }}}, - '"w"': {{{ cDefs.O_TRUNC }}} | {{{ cDefs.O_CREAT }}} | {{{ cDefs.O_WRONLY }}}, - '"w+"': {{{ cDefs.O_TRUNC }}} | {{{ cDefs.O_CREAT }}} | {{{ cDefs.O_RDWR }}}, - '"a"': {{{ cDefs.O_APPEND }}} | {{{ cDefs.O_CREAT }}} | {{{ cDefs.O_WRONLY }}}, - '"a+"': {{{ cDefs.O_APPEND }}} | {{{ cDefs.O_CREAT }}} | {{{ cDefs.O_RDWR }}}, - }, - // convert the 'r', 'r+', etc. to it's corresponding set of O_* flags - modeStringToFlags: (str) => { - var flags = FS.flagModes[str]; - if (typeof flags == 'undefined') { - throw new Error('Unknown file open mode: ' + str); - } - return flags; - }, // convert O_* bitmask to a string for nodePermissions flagsToPermissionString: (flag) => { var perms = ['r', 'w', 'rw'][flag & 3]; @@ -1010,7 +995,7 @@ FS.staticInit();` + if (path === "") { throw new FS.ErrnoError({{{ cDefs.ENOENT }}}); } - flags = typeof flags == 'string' ? FS.modeStringToFlags(flags) : flags; + flags = typeof flags == 'string' ? FS_modeStringToFlags(flags) : flags; mode = typeof mode == 'undefined' ? 438 /* 0666 */ : mode; if ((flags & {{{ cDefs.O_CREAT }}})) { mode = (mode & {{{ cDefs.S_IALLUGO }}}) | {{{ cDefs.S_IFREG }}}; @@ -1536,12 +1521,6 @@ FS.staticInit();` + // // old v1 compatibility functions // - getMode: (canRead, canWrite) => { - var mode = 0; - if (canRead) mode |= {{{ cDefs.S_IRUGO }}} | {{{ cDefs.S_IXUGO }}}; - if (canWrite) mode |= {{{ cDefs.S_IWUGO }}}; - return mode; - }, findObject: (path, dontResolveLastLink) => { var ret = FS.analyzePath(path, dontResolveLastLink); if (!ret.exists) { @@ -1595,7 +1574,7 @@ FS.staticInit();` + }, createFile: (parent, name, properties, canRead, canWrite) => { var path = PATH.join2(typeof parent == 'string' ? parent : FS.getPath(parent), name); - var mode = FS.getMode(canRead, canWrite); + var mode = FS_getMode(canRead, canWrite); return FS.create(path, mode); }, createDataFile: (parent, name, data, canRead, canWrite, canOwn) => { @@ -1604,7 +1583,7 @@ FS.staticInit();` + parent = typeof parent == 'string' ? parent : FS.getPath(parent); path = name ? PATH.join2(parent, name) : parent; } - var mode = FS.getMode(canRead, canWrite); + var mode = FS_getMode(canRead, canWrite); var node = FS.create(path, mode); if (data) { if (typeof data == 'string') { @@ -1623,7 +1602,7 @@ FS.staticInit();` + }, createDevice: (parent, name, input, output) => { var path = PATH.join2(typeof parent == 'string' ? parent : FS.getPath(parent), name); - var mode = FS.getMode(!!input, !!output); + var mode = FS_getMode(!!input, !!output); if (!FS.createDevice.major) FS.createDevice.major = 64; var dev = FS.makedev(FS.createDevice.major++, 0); // Create a fake device that a set of stream ops to emulate @@ -1872,47 +1851,6 @@ FS.staticInit();` + node.stream_ops = stream_ops; return node; }, - // Preloads a file asynchronously. You can call this before run, for example in - // preRun. run will be delayed until this file arrives and is set up. - // If you call it after run(), you may want to pause the main loop until it - // completes, if so, you can use the onload parameter to be notified when - // that happens. - // In addition to normally creating the file, we also asynchronously preload - // the browser-friendly versions of it: For an image, we preload an Image - // element and for an audio, and Audio. These are necessary for SDL_Image - // and _Mixer to find the files in preloadedImages/Audios. - // You can also call this with a typed array instead of a url. It will then - // do preloading for the Image/Audio part, as if the typed array were the - // result of an XHR that you did manually. - createPreloadedFile: (parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile, canOwn, preFinish) => { - // TODO we should allow people to just pass in a complete filename instead - // of parent and name being that we just join them anyways - var fullname = name ? PATH_FS.resolve(PATH.join2(parent, name)) : parent; - var dep = getUniqueRunDependency('cp ' + fullname); // might have several active requests for the same fullname - function processData(byteArray) { - function finish(byteArray) { - if (preFinish) preFinish(); - if (!dontCreateFile) { - FS.createDataFile(parent, name, byteArray, canRead, canWrite, canOwn); - } - if (onload) onload(); - removeRunDependency(dep); - } - if (Browser.handledByPreloadPlugin(byteArray, fullname, finish, () => { - if (onerror) onerror(); - removeRunDependency(dep); - })) { - return; - } - finish(byteArray); - } - addRunDependency(dep); - if (typeof url == 'string') { - asyncLoad(url, (byteArray) => processData(byteArray), onerror); - } else { - processData(url); - } - }, // Removed v1 functions #if ASSERTIONS diff --git a/src/library_fs_shared.js b/src/library_fs_shared.js new file mode 100644 index 0000000000000..1d7336d64b6c1 --- /dev/null +++ b/src/library_fs_shared.js @@ -0,0 +1,79 @@ +/** + * @license + * Copyright 2032 The Emscripten Authors + * SPDX-License-Identifier: MIT + */ + +mergeInto(LibraryManager.library, { + // Preloads a file asynchronously. You can call this before run, for example in + // preRun. run will be delayed until this file arrives and is set up. + // If you call it after run(), you may want to pause the main loop until it + // completes, if so, you can use the onload parameter to be notified when + // that happens. + // In addition to normally creating the file, we also asynchronously preload + // the browser-friendly versions of it: For an image, we preload an Image + // element and for an audio, and Audio. These are necessary for SDL_Image + // and _Mixer to find the files in preloadedImages/Audios. + // You can also call this with a typed array instead of a url. It will then + // do preloading for the Image/Audio part, as if the typed array were the + // result of an XHR that you did manually. + $FS_createPreloadedFile__deps: ['$asyncLoad'], + $FS_createPreloadedFile: function(parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile, canOwn, preFinish) { +#if WASMFS + // TODO: use WasmFS code to resolve and join the path here? + var fullname = name ? parent + '/' + name : parent; +#else + // TODO we should allow people to just pass in a complete filename instead + // of parent and name being that we just join them anyways + var fullname = name ? PATH_FS.resolve(PATH.join2(parent, name)) : parent; +#endif + var dep = getUniqueRunDependency('cp ' + fullname); // might have several active requests for the same fullname + function processData(byteArray) { + function finish(byteArray) { + if (preFinish) preFinish(); + if (!dontCreateFile) { + FS.createDataFile(parent, name, byteArray, canRead, canWrite, canOwn); + } + if (onload) onload(); + removeRunDependency(dep); + } +#if !MINIMAL_RUNTIME + if (Browser.handledByPreloadPlugin(byteArray, fullname, finish, () => { + if (onerror) onerror(); + removeRunDependency(dep); + })) { + return; + } +#endif + finish(byteArray); + } + addRunDependency(dep); + if (typeof url == 'string') { + asyncLoad(url, (byteArray) => processData(byteArray), onerror); + } else { + processData(url); + } + }, + // convert the 'r', 'r+', etc. to it's corresponding set of O_* flags + $FS_modeStringToFlags: function(str) { + var flagModes = { + 'r': {{{ cDefs.O_RDONLY }}}, + 'r+': {{{ cDefs.O_RDWR }}}, + 'w': {{{ cDefs.O_TRUNC }}} | {{{ cDefs.O_CREAT }}} | {{{ cDefs.O_WRONLY }}}, + 'w+': {{{ cDefs.O_TRUNC }}} | {{{ cDefs.O_CREAT }}} | {{{ cDefs.O_RDWR }}}, + 'a': {{{ cDefs.O_APPEND }}} | {{{ cDefs.O_CREAT }}} | {{{ cDefs.O_WRONLY }}}, + 'a+': {{{ cDefs.O_APPEND }}} | {{{ cDefs.O_CREAT }}} | {{{ cDefs.O_RDWR }}}, + }; + var flags = flagModes[str]; + if (typeof flags == 'undefined') { + throw new Error('Unknown file open mode: ' + str); + } + return flags; + }, + $FS_getMode: function(canRead, canWrite) { + var mode = 0; + if (canRead) mode |= {{{ cDefs.S_IRUGO }}} | {{{ cDefs.S_IXUGO }}}; + if (canWrite) mode |= {{{ cDefs.S_IWUGO }}}; + return mode; + }, +}); diff --git a/src/library_noderawfs.js b/src/library_noderawfs.js index 3bb943febe1cf..f3e9ecb848b5e 100644 --- a/src/library_noderawfs.js +++ b/src/library_noderawfs.js @@ -5,7 +5,7 @@ */ mergeInto(LibraryManager.library, { - $NODERAWFS__deps: ['$ERRNO_CODES', '$FS', '$NODEFS', '$mmapAlloc'], + $NODERAWFS__deps: ['$ERRNO_CODES', '$FS', '$NODEFS', '$mmapAlloc', '$FS_modeStringToFlags'], $NODERAWFS__postset: ` if (ENVIRONMENT_IS_NODE) { var _wrapNodeError = function(func) { @@ -83,7 +83,7 @@ mergeInto(LibraryManager.library, { utime: function(path, atime, mtime) { fs.utimesSync(path, atime/1000, mtime/1000); }, open: function(path, flags, mode, suggestFD) { if (typeof flags == "string") { - flags = VFS.modeStringToFlags(flags) + flags = FS_modeStringToFlags(flags) } var pathTruncated = path.split('/').map(function(s) { return s.substr(0, 255); }).join('/'); var nfd = fs.openSync(pathTruncated, NODEFS.flagsForNode(flags), mode); diff --git a/src/library_wasmfs.js b/src/library_wasmfs.js index 84b4ee70c9138..3e39b150ac2c3 100644 --- a/src/library_wasmfs.js +++ b/src/library_wasmfs.js @@ -7,82 +7,31 @@ mergeInto(LibraryManager.library, { $wasmFSPreloadedFiles: [], $wasmFSPreloadedDirs: [], -#if USE_CLOSURE_COMPILER // Declare variable for Closure, FS.createPreloadedFile() below calls Browser.handledByPreloadPlugin() - $FS__postset: '/**@suppress {duplicate, undefinedVars}*/var Browser;', + $FS__postset: ` +#if USE_CLOSURE_COMPILER +/**@suppress {duplicate, undefinedVars}*/var Browser; #endif +FS.createPreloadedFile = FS_createPreloadedFile; +`, $FS__deps: [ '$wasmFSPreloadedFiles', '$wasmFSPreloadedDirs', - '$asyncLoad', '$PATH', '$stringToNewUTF8', '$stringToUTF8OnStack', '$withStackSave', '$readI53FromI64', + '$FS_createPreloadedFile', + '$FS_getMode', +#if FORCE_FILESYSTEM + '$FS_modeStringToFlags', +#endif ], $FS : { - // TODO: Clean up the following functions - currently copied from library_fs.js directly. - createPreloadedFile: (parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile, canOwn, preFinish) => { - // TODO: use WasmFS code to resolve and join the path here? - var fullname = name ? parent + '/' + name : parent; - var dep = getUniqueRunDependency('cp ' + fullname); // might have several active requests for the same fullname - function processData(byteArray) { - function finish(byteArray) { - if (preFinish) preFinish(); - if (!dontCreateFile) { - FS.createDataFile(parent, name, byteArray, canRead, canWrite, canOwn); - } - if (onload) onload(); - removeRunDependency(dep); - } -#if !MINIMAL_RUNTIME - if (Browser.handledByPreloadPlugin(byteArray, fullname, finish, () => { - if (onerror) onerror(); - removeRunDependency(dep); - })) { - return; - } -#endif - finish(byteArray); - } - addRunDependency(dep); - if (typeof url == 'string') { - asyncLoad(url, (byteArray) => { - processData(byteArray); - }, onerror); - } else { - processData(url); - } - }, - getMode: (canRead, canWrite) => { - var mode = 0; - if (canRead) mode |= {{{ cDefs.S_IRUGO }}} | {{{ cDefs.S_IXUGO }}}; - if (canWrite) mode |= {{{ cDefs.S_IWUGO }}}; - return mode; - }, - modeStringToFlags: (str) => { - var flags = FS.flagModes[str]; - if (typeof flags == 'undefined') { - throw new Error('Unknown file open mode: ' + str); - } - return flags; - }, - flagModes: { - // copied directly from library_fs.js - // Extra quotes used here on the keys to this object otherwise jsifier will - // erase them in the process of reading and then writing the JS library - // code. - '"r"': {{{ cDefs.O_RDONLY }}}, - '"r+"': {{{ cDefs.O_RDWR }}}, - '"w"': {{{ cDefs.O_TRUNC }}} | {{{ cDefs.O_CREAT }}} | {{{ cDefs.O_WRONLY }}}, - '"w+"': {{{ cDefs.O_TRUNC }}} | {{{ cDefs.O_CREAT }}} | {{{ cDefs.O_RDWR }}}, - '"a"': {{{ cDefs.O_APPEND }}} | {{{ cDefs.O_CREAT }}} | {{{ cDefs.O_WRONLY }}}, - '"a+"': {{{ cDefs.O_APPEND }}} | {{{ cDefs.O_CREAT }}} | {{{ cDefs.O_RDWR }}}, - }, createDataFile: (parent, name, data, canRead, canWrite, canOwn) => { // Data files must be cached until the file system itself has been initialized. - var mode = FS.getMode(canRead, canWrite); + var mode = FS_getMode(canRead, canWrite); var pathName = name ? parent + '/' + name : parent; wasmFSPreloadedFiles.push({pathName: pathName, fileData: data, mode: mode}); }, @@ -148,7 +97,7 @@ mergeInto(LibraryManager.library, { }, // TODO: open open: (path, flags, mode) => { - flags = typeof flags == 'string' ? FS.modeStringToFlags(flags) : flags; + flags = typeof flags == 'string' ? FS_modeStringToFlags(flags) : flags; mode = typeof mode == 'undefined' ? 438 /* 0666 */ : mode; return withStackSave(() => { var buffer = stringToUTF8OnStack(path); diff --git a/src/modules.js b/src/modules.js index e99c72b679136..16f46ecb6b875 100644 --- a/src/modules.js +++ b/src/modules.js @@ -80,6 +80,7 @@ global.LibraryManager = { if (FILESYSTEM) { // Core filesystem libraries (always linked against, unless -sFILESYSTEM=0 is specified) libraries = libraries.concat([ + 'library_fs_shared.js', 'library_fs.js', 'library_memfs.js', 'library_tty.js', @@ -97,12 +98,15 @@ global.LibraryManager = { libraries.push('library_nodepath.js'); } } else if (WASMFS) { - libraries.push('library_wasmfs.js'); - libraries.push('library_wasmfs_js_file.js'); - libraries.push('library_wasmfs_jsimpl.js'); - libraries.push('library_wasmfs_fetch.js'); - libraries.push('library_wasmfs_node.js'); - libraries.push('library_wasmfs_opfs.js'); + libraries = libraries.concat([ + 'library_fs_shared.js', + 'library_wasmfs.js', + 'library_wasmfs_js_file.js', + 'library_wasmfs_jsimpl.js', + 'library_wasmfs_fetch.js', + 'library_wasmfs_node.js', + 'library_wasmfs_opfs.js', + ]); } // Additional JS libraries (without AUTO_JS_LIBRARIES, link to these explicitly via -lxxx.js) @@ -361,7 +365,6 @@ function exportRuntime() { 'FS_createFolder', 'FS_createPath', 'FS_createDataFile', - 'FS_createPreloadedFile', 'FS_createLazyFile', 'FS_createLink', 'FS_createDevice', From b72453cc5bdb047917ce35c02359a819c9169617 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 3 May 2023 11:00:55 -0700 Subject: [PATCH 0194/1523] Rebaseline codesize expectations. NFC --- test/other/metadce/test_metadce_cxx_ctors1.jssize | 2 +- test/other/metadce/test_metadce_cxx_ctors2.jssize | 2 +- test/other/metadce/test_metadce_cxx_except.jssize | 2 +- test/other/metadce/test_metadce_cxx_except_wasm.jssize | 2 +- test/other/metadce/test_metadce_cxx_mangle.jssize | 2 +- test/other/metadce/test_metadce_cxx_noexcept.jssize | 2 +- test/other/metadce/test_metadce_hello_O0.jssize | 2 +- test/other/metadce/test_metadce_hello_dylink.jssize | 2 +- test/other/metadce/test_metadce_minimal_O0.jssize | 2 +- test/other/test_unoptimized_code_size.js.size | 2 +- test/other/test_unoptimized_code_size_strict.js.size | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/test/other/metadce/test_metadce_cxx_ctors1.jssize b/test/other/metadce/test_metadce_cxx_ctors1.jssize index 9afc428a72117..e64ca67cf3c41 100644 --- a/test/other/metadce/test_metadce_cxx_ctors1.jssize +++ b/test/other/metadce/test_metadce_cxx_ctors1.jssize @@ -1 +1 @@ -25919 +25922 diff --git a/test/other/metadce/test_metadce_cxx_ctors2.jssize b/test/other/metadce/test_metadce_cxx_ctors2.jssize index 61e72300e5b81..20a238310a29c 100644 --- a/test/other/metadce/test_metadce_cxx_ctors2.jssize +++ b/test/other/metadce/test_metadce_cxx_ctors2.jssize @@ -1 +1 @@ -25883 +25886 diff --git a/test/other/metadce/test_metadce_cxx_except.jssize b/test/other/metadce/test_metadce_cxx_except.jssize index 64a8b2b5043a1..c9e2df1f45fcf 100644 --- a/test/other/metadce/test_metadce_cxx_except.jssize +++ b/test/other/metadce/test_metadce_cxx_except.jssize @@ -1 +1 @@ -30433 +30436 diff --git a/test/other/metadce/test_metadce_cxx_except_wasm.jssize b/test/other/metadce/test_metadce_cxx_except_wasm.jssize index d2e929faedc49..832a59a4fbb2b 100644 --- a/test/other/metadce/test_metadce_cxx_except_wasm.jssize +++ b/test/other/metadce/test_metadce_cxx_except_wasm.jssize @@ -1 +1 @@ -25728 +25731 diff --git a/test/other/metadce/test_metadce_cxx_mangle.jssize b/test/other/metadce/test_metadce_cxx_mangle.jssize index 3a436364b573f..73d9a9794b958 100644 --- a/test/other/metadce/test_metadce_cxx_mangle.jssize +++ b/test/other/metadce/test_metadce_cxx_mangle.jssize @@ -1 +1 @@ -30432 +30435 diff --git a/test/other/metadce/test_metadce_cxx_noexcept.jssize b/test/other/metadce/test_metadce_cxx_noexcept.jssize index 9afc428a72117..e64ca67cf3c41 100644 --- a/test/other/metadce/test_metadce_cxx_noexcept.jssize +++ b/test/other/metadce/test_metadce_cxx_noexcept.jssize @@ -1 +1 @@ -25919 +25922 diff --git a/test/other/metadce/test_metadce_hello_O0.jssize b/test/other/metadce/test_metadce_hello_O0.jssize index c5c5bf593e07c..24a44d0d1ceae 100644 --- a/test/other/metadce/test_metadce_hello_O0.jssize +++ b/test/other/metadce/test_metadce_hello_O0.jssize @@ -1 +1 @@ -23795 +23827 diff --git a/test/other/metadce/test_metadce_hello_dylink.jssize b/test/other/metadce/test_metadce_hello_dylink.jssize index 1f68fb0a193ea..005f3bc6c8629 100644 --- a/test/other/metadce/test_metadce_hello_dylink.jssize +++ b/test/other/metadce/test_metadce_hello_dylink.jssize @@ -1 +1 @@ -27884 +27887 diff --git a/test/other/metadce/test_metadce_minimal_O0.jssize b/test/other/metadce/test_metadce_minimal_O0.jssize index 276217eb048bd..55ec08fe69674 100644 --- a/test/other/metadce/test_metadce_minimal_O0.jssize +++ b/test/other/metadce/test_metadce_minimal_O0.jssize @@ -1 +1 @@ -20044 +20076 diff --git a/test/other/test_unoptimized_code_size.js.size b/test/other/test_unoptimized_code_size.js.size index 8e0545a3a593b..77888a8cbbf48 100644 --- a/test/other/test_unoptimized_code_size.js.size +++ b/test/other/test_unoptimized_code_size.js.size @@ -1 +1 @@ -59584 +59626 diff --git a/test/other/test_unoptimized_code_size_strict.js.size b/test/other/test_unoptimized_code_size_strict.js.size index 32993c88f3353..ea43e56b33d17 100644 --- a/test/other/test_unoptimized_code_size_strict.js.size +++ b/test/other/test_unoptimized_code_size_strict.js.size @@ -1 +1 @@ -58526 +58568 From 5aee12332365b6a1a36254605edab065542da937 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 3 May 2023 12:06:30 -0700 Subject: [PATCH 0195/1523] Assume that browser has working URL object (#19283) Perhaps 10 years ago there was possibility that the URL object didn't exist, but today we don't support such browsers See https://caniuse.com/url. This is a followup to #19277 which did the same for the Blob constructor. --- src/library_browser.js | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/library_browser.js b/src/library_browser.js index 140919a6502c9..5a4d234070547 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -105,11 +105,6 @@ var LibraryBrowser = { if (Browser.initted) return; Browser.initted = true; - Browser.URLObject = typeof window != "undefined" ? (window.URL ? window.URL : window.webkitURL) : undefined; - if (!Module.noImageDecoding && typeof Browser.URLObject == 'undefined') { - err("warning: Browser does not support creating object URLs. Built-in browser image decoding will not be available."); - Module.noImageDecoding = true; - } // Support for plugins that can process preloaded files. You can add more of these to // your app by creating and appending to Module.preloadPlugins. @@ -129,7 +124,7 @@ var LibraryBrowser = { // Safari's Blob can only take an ArrayBuffer b = new Blob([(new Uint8Array(byteArray)).buffer], { type: Browser.getMimetype(name) }); } - var url = Browser.URLObject.createObjectURL(b); + var url = URL.createObjectURL(b); #if ASSERTIONS assert(typeof url == 'string', 'createObjectURL must return a url as a string'); #endif @@ -142,7 +137,7 @@ var LibraryBrowser = { var ctx = canvas.getContext('2d'); ctx.drawImage(img, 0, 0); preloadedImages[name] = canvas; - Browser.URLObject.revokeObjectURL(url); + URL.revokeObjectURL(url); if (onload) onload(byteArray); }; img.onerror = (event) => { @@ -172,7 +167,7 @@ var LibraryBrowser = { if (onerror) onerror(); } var b = new Blob([byteArray], { type: Browser.getMimetype(name) }); - var url = Browser.URLObject.createObjectURL(b); // XXX we never revoke this! + var url = URL.createObjectURL(b); // XXX we never revoke this! #if ASSERTIONS assert(typeof url == 'string', 'createObjectURL must return a url as a string'); #endif From c513aed3f247ef4c040f4b61b3f04f3030117df0 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 3 May 2023 15:58:07 -0700 Subject: [PATCH 0196/1523] Use JS Set rather than list for ALL_INCOMING_MODULE_JS_API. NFC (#19286) The only use of this setting was checking for membership so this should be faster. --- src/compiler.js | 1 + src/parseTools.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/compiler.js b/src/compiler.js index de46f3396e024..6176da18a09e6 100755 --- a/src/compiler.js +++ b/src/compiler.js @@ -68,6 +68,7 @@ EXPORTED_FUNCTIONS = new Set(EXPORTED_FUNCTIONS); WASM_EXPORTS = new Set(WASM_EXPORTS); SIDE_MODULE_EXPORTS = new Set(SIDE_MODULE_EXPORTS); INCOMING_MODULE_JS_API = new Set(INCOMING_MODULE_JS_API); +ALL_INCOMING_MODULE_JS_API = new Set(ALL_INCOMING_MODULE_JS_API); WEAK_IMPORTS = new Set(WEAK_IMPORTS); if (symbolsOnly) { INCLUDE_FULL_LIBRARY = 1; diff --git a/src/parseTools.js b/src/parseTools.js index 715b7228a3f51..91608eef8da34 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -732,7 +732,7 @@ function makeRemovedModuleAPIAssert(moduleName, localName) { function checkReceiving(name) { // ALL_INCOMING_MODULE_JS_API contains all valid incoming module API symbols // so calling makeModuleReceive* with a symbol not in this list is an error - assert(ALL_INCOMING_MODULE_JS_API.includes(name)); + assert(ALL_INCOMING_MODULE_JS_API.has(name)); } // Make code to receive a value on the incoming Module object. From 9dff99d6a303c7987fe195a53c883b1c1b390b70 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 4 May 2023 08:21:04 -0700 Subject: [PATCH 0197/1523] Use write_file/read_file in file_packager.py. NFC (#19290) --- tools/file_packager.py | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/tools/file_packager.py b/tools/file_packager.py index 7d6d9c0faa66b..748a6c7060552 100755 --- a/tools/file_packager.py +++ b/tools/file_packager.py @@ -410,8 +410,7 @@ def main(): options.from_emcc = True leading = '' elif arg.startswith('--plugin'): - with open(arg.split('=', 1)[1]) as f: - plugin = f.read() + plugin = utils.read_file(arg.split('=', 1)[1]) eval(plugin) # should append itself to plugins leading = '' elif leading == 'preload' or leading == 'embed': @@ -556,17 +555,13 @@ def was_seen(name): # differs from the current generated one, otherwise leave the file # untouched preserving its old timestamp if os.path.isfile(options.jsoutput): - with open(options.jsoutput) as f: - old = f.read() + old = utils.read_file(options.jsoutput) if old != ret: - with open(options.jsoutput, 'w') as f: - f.write(ret) + utils.write_file(options.jsoutput, ret) else: - with open(options.jsoutput, 'w') as f: - f.write(ret) + utils.write_file(options.jsoutput, ret) if options.separate_metadata: - with open(options.jsoutput + '.metadata', 'w') as f: - json.dump(metadata, f, separators=(',', ':')) + utils.write_file(options.jsoutput + '.metadata', json.dumps(metadata, separators=(',', ':'))) return 0 @@ -617,8 +612,7 @@ def generate_js(data_target, data_files, metadata): with open(data_target, 'wb') as data: for file_ in data_files: file_.data_start = start - with open(file_.srcpath, 'rb') as f: - curr = f.read() + curr = utils.read_binary(file_.srcpath) file_.data_end = start + len(curr) if AV_WORKAROUND: curr += '\x00' From e102f6fa5a04640a50bc8a7e9fbd26b7adcb889d Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 4 May 2023 13:40:41 -0700 Subject: [PATCH 0198/1523] Add test for `--preload-file` + `--closure=1`. NFC (#19294) I ran into the lack of testing (at least under node) of this config recently. In this case the output of file_packager is include as a pre-js so it ends up going through closure compiler. --- test/test_other.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test_other.py b/test/test_other.py index d8e1916d2e203..b119585c33a05 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -1743,6 +1743,7 @@ def test_export_from_archive(self): 'embed': (['--embed-file', 'somefile.txt'],), 'embed_twice': (['--embed-file', 'somefile.txt', '--embed-file', 'somefile.txt'],), 'preload': (['--preload-file', 'somefile.txt'],), + 'preload_closure': (['--preload-file', 'somefile.txt', '-O2', '--closure=1'],), 'preload_and_embed': (['--preload-file', 'somefile.txt', '--embed-file', 'hello.txt'],) }) @requires_node From 29cb1f5ad50c5e2b4dd521e137ca0499bbd9efb3 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 4 May 2023 15:24:32 -0700 Subject: [PATCH 0199/1523] Stop requiring DYNAMIC_EXECUTION when building with RELOCATABLE (#19295) I tracked this error all the way back to when it was first added back in 2015: 38157ef59e42b01078164098154baf78afbf8fc7. Its not longer true that `loadDynamicLibrary` requires `eval()`. It is true that if you have EM_ASM in your side modules that would require `eval()` but that usage is guarded using the `makeEval` helper (and also not common). --- ChangeLog.md | 4 ++++ emcc.py | 3 --- test/test_other.py | 6 ++---- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index cfbda677d95d8..dce73b8ce0606 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -20,6 +20,10 @@ See docs/process.md for more on how version tagging works. 3.1.38 (in development) ----------------------- +- The restriction preventing the use of dynamic linking in combination with + `-sDYNAMIC_EXECUTION=0` was removed. This restriction was being enforced + unnecessarily since dynamic linking has not depended on `eval()` for a while + now. - Remove extra code for falling back to long-deprecated BlobBuilder browser API when Blob constructor is missing. This was a fix for an issue that has long been fixed. (#19277) diff --git a/emcc.py b/emcc.py index bc46dea83c50f..92c1134ddda4f 100755 --- a/emcc.py +++ b/emcc.py @@ -2359,9 +2359,6 @@ def phase_linker_setup(options, state, newargs): # llvm change lands settings.EXPORT_IF_DEFINED.append('__wasm_apply_data_relocs') - if settings.RELOCATABLE and not settings.DYNAMIC_EXECUTION: - exit_with_error('cannot have both DYNAMIC_EXECUTION=0 and RELOCATABLE enabled at the same time, since RELOCATABLE needs to eval()') - if settings.SIDE_MODULE and 'GLOBAL_BASE' in user_settings: exit_with_error('GLOBAL_BASE is not compatible with SIDE_MODULE') diff --git a/test/test_other.py b/test/test_other.py index b119585c33a05..90cf5f3000db1 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -4585,10 +4585,8 @@ def test_no_dynamic_execution(self): self.assertNotContained('new Function', src) delete_file('a.out.js') - # Test that -sDYNAMIC_EXECUTION and -sRELOCATABLE are not allowed together. - self.expect_fail([EMCC, test_file('hello_world.c'), '-O1', - '-sDYNAMIC_EXECUTION=0', '-sRELOCATABLE']) - delete_file('a.out.js') + # Test that -sDYNAMIC_EXECUTION=0 and -sRELOCATABLE are allowed together. + self.do_runf(test_file('hello_world.c'), emcc_args=['-O1', '-sDYNAMIC_EXECUTION=0', '-sRELOCATABLE']) create_file('test.c', r''' #include From f642503af8ed1b0fc9489638ded078087c742711 Mon Sep 17 00:00:00 2001 From: mboc-qt <132437722+mboc-qt@users.noreply.github.com> Date: Fri, 5 May 2023 23:49:14 +0200 Subject: [PATCH 0200/1523] Correctly instrument ASYNCIFY_IMPORTS with a wildcard (#19280) Wildcard was incorrectly handled, as only verbatim matches were accepted in Asyncify.instrumentWasmImports for imports listed in ASYNCIFY_IMPORTS, even though the collection also contains wildcards. Those were ignored, but are now transformed to suitable RegExes. Also, don't single out __asyncjs__ as __asyncjs__* is already added as a default to ASYNCIFY_IMPORTS by emcc.py. Since now the wildcard will work correctly, there's no need to double-check for the prefix when determining if an import is an asyncify import. --- src/library_async.js | 6 +++--- test/test_browser.py | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/library_async.js b/src/library_async.js index d808eecc19997..a995dc01e2e73 100644 --- a/src/library_async.js +++ b/src/library_async.js @@ -38,15 +38,15 @@ mergeInto(LibraryManager.library, { #if ASYNCIFY_DEBUG dbg('asyncify instrumenting imports'); #endif - var ASYNCIFY_IMPORTS = {{{ JSON.stringify(ASYNCIFY_IMPORTS.map((x) => x.split('.')[1])) }}}; + var importPatterns = [{{{ ASYNCIFY_IMPORTS.map(x => new RegExp('^' + x.split('.')[1].replaceAll('*', '.*') + '$')) }}}]; + for (var x in imports) { (function(x) { var original = imports[x]; var sig = original.sig; if (typeof original == 'function') { var isAsyncifyImport = original.isAsync || - ASYNCIFY_IMPORTS.indexOf(x) >= 0 || - x.startsWith('__asyncjs__'); + importPatterns.some(pattern => !!x.match(pattern)); #if ASYNCIFY == 2 // Wrap async imports with a suspending WebAssembly function. if (isAsyncifyImport) { diff --git a/test/test_browser.py b/test/test_browser.py index 33653fd6c288a..df459f0e4f4e4 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -3412,6 +3412,7 @@ def test_async_iostream(self): # To make the test more precise we also use ASYNCIFY_IGNORE_INDIRECT here. @parameterized({ 'normal': (['-sASYNCIFY_IMPORTS=[sync_tunnel, sync_tunnel_bool]'],), # noqa + 'pattern_imports': (['-sASYNCIFY_IMPORTS=[sync_tun*]'],), # noqa 'response': (['-sASYNCIFY_IMPORTS=@filey.txt'],), # noqa 'nothing': (['-DBAD'],), # noqa 'empty_list': (['-DBAD', '-sASYNCIFY_IMPORTS=[]'],), # noqa From 7eacfcc18e083e19e90a8b2c9cee897816a4fbc2 Mon Sep 17 00:00:00 2001 From: juj Date: Mon, 8 May 2023 14:17:46 +0300 Subject: [PATCH 0201/1523] Optimize code size of dynCall() when MEMORY64 is used, and add a memory size limit check. (#19288) * Optimize code size of dynCall() when MEMORY64 is used, and add a memory size limit check. * Do not use 'let' or '...args' spread * Fix typo * Address review --- emcc.py | 2 ++ src/library.js | 25 +++++++++---------------- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/emcc.py b/emcc.py index 92c1134ddda4f..5ae47aaab53ec 100755 --- a/emcc.py +++ b/emcc.py @@ -2483,6 +2483,8 @@ def phase_linker_setup(options, state, newargs): def check_memory_setting(setting): if settings[setting] % webassembly.WASM_PAGE_SIZE != 0: exit_with_error(f'{setting} must be a multiple of WebAssembly page size (64KiB), was {settings[setting]}') + if settings[setting] >= 2**53: + exit_with_error(f'{setting} must be smaller than 2^53 bytes due to JS Numbers (doubles) being used to hold pointer addresses in JS side') check_memory_setting('INITIAL_MEMORY') check_memory_setting('MAXIMUM_MEMORY') diff --git a/src/library.js b/src/library.js index 7eebb214b0d89..33b2bb1da8474 100644 --- a/src/library.js +++ b/src/library.js @@ -248,7 +248,7 @@ mergeInto(LibraryManager.library, { #endif } - let alignUp = (x, multiple) => x + (multiple - x % multiple) % multiple; + var alignUp = (x, multiple) => x + (multiple - x % multiple) % multiple; // Loop through potential heap size increases. If we attempt a too eager // reservation that fails, cut down on the attempted size and reserve a @@ -3252,27 +3252,20 @@ mergeInto(LibraryManager.library, { assert(getWasmTableEntry(ptr), 'missing table entry in dynCall: ' + ptr); #endif #if MEMORY64 - // With MEMORY64 we have an additional step to covert `p` arguments to + // With MEMORY64 we have an additional step to convert `p` arguments to // bigint. This is the runtime equivalent of the wrappers we create for wasm // exports in `emscripten.py:create_wasm64_wrappers`. - if (sig.includes('p')) { - var new_args = []; - args.forEach((arg, index) => { - if (sig[index + 1] == 'p') { - arg = BigInt(arg); - } - new_args.push(arg); - }); - args = new_args; + for (var i = 1; i < sig.length; ++i) { + if (sig[i] == 'p') args[i-1] = BigInt(args[i-1]); } #endif var rtn = getWasmTableEntry(ptr).apply(null, args); #if MEMORY64 - if (sig[0] == 'p') { - rtn = Number(rtn); - } -#endif + return sig[0] == 'p' ? Number(rtn) : rtn; +#else return rtn; +#endif + #endif }, @@ -3675,7 +3668,7 @@ mergeInto(LibraryManager.library, { return this.allocated[id]; }; this.allocate = function(handle) { - let id = this.freelist.pop() || this.allocated.length; + var id = this.freelist.pop() || this.allocated.length; this.allocated[id] = handle; return id; }; From b6d5f3b3db669612a635afe8c9e8f157377df898 Mon Sep 17 00:00:00 2001 From: juj Date: Mon, 8 May 2023 16:48:23 +0300 Subject: [PATCH 0202/1523] Fix void in headers (#18913) * Fix C function declarations to state (void). * Fix emscripten_trace_*() no-op definition macros to behave well as statements in macro expansion. --- system/include/AL/alc.h | 2 +- system/include/emscripten/emmalloc.h | 4 +-- system/include/emscripten/eventloop.h | 6 ++-- system/include/emscripten/proxying.h | 4 +-- system/include/emscripten/trace.h | 50 +++++++++++++-------------- system/include/emscripten/val.h | 4 +-- 6 files changed, 35 insertions(+), 35 deletions(-) diff --git a/system/include/AL/alc.h b/system/include/AL/alc.h index 6ff7cb9b0ff61..ad24c8e6804fc 100644 --- a/system/include/AL/alc.h +++ b/system/include/AL/alc.h @@ -61,7 +61,7 @@ extern ALCboolean alcCloseDevice(ALCdevice *device); extern ALCboolean alcIsExtensionPresent(ALCdevice *device, const ALCchar *extname); extern ALCboolean alcMakeContextCurrent(ALCcontext *context); extern ALCcontext *alcCreateContext(ALCdevice *device, const ALCint *attrlist); -extern ALCcontext *alcGetCurrentContext(); +extern ALCcontext *alcGetCurrentContext(void); extern ALCdevice *alcCaptureOpenDevice(const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize); extern ALCdevice *alcGetContextsDevice(ALCcontext *context); extern ALCdevice *alcOpenDevice(const ALCchar *devicename); diff --git a/system/include/emscripten/emmalloc.h b/system/include/emscripten/emmalloc.h index d2a51e781458f..14d9b360ea52d 100644 --- a/system/include/emscripten/emmalloc.h +++ b/system/include/emscripten/emmalloc.h @@ -84,8 +84,8 @@ void *emmalloc_calloc(size_t num, size_t size); // mallinfo() returns information about current emmalloc allocation state. This function // is very slow, only good for debugging. Avoid calling it for "routine" diagnostics. -struct mallinfo mallinfo(); -struct mallinfo emmalloc_mallinfo(); +struct mallinfo mallinfo(void); +struct mallinfo emmalloc_mallinfo(void); // malloc_trim() returns unused dynamic memory back to the WebAssembly heap. Returns 1 if it // actually freed any memory, and 0 if not. Note: this function does not release memory back to diff --git a/system/include/emscripten/eventloop.h b/system/include/emscripten/eventloop.h index 7bcb34325a51b..74c2ca1a0ee48 100644 --- a/system/include/emscripten/eventloop.h +++ b/system/include/emscripten/eventloop.h @@ -26,9 +26,9 @@ void emscripten_set_immediate_loop(EM_BOOL (*cb)(void *user_data), void *user_da int emscripten_set_interval(void (*cb)(void *user_data) __attribute__((nonnull)), double interval_ms, void *user_data); void emscripten_clear_interval(int id); -void emscripten_runtime_keepalive_push(); -void emscripten_runtime_keepalive_pop(); -EM_BOOL emscripten_runtime_keepalive_check(); +void emscripten_runtime_keepalive_push(void); +void emscripten_runtime_keepalive_pop(void); +EM_BOOL emscripten_runtime_keepalive_check(void); #ifdef __cplusplus } diff --git a/system/include/emscripten/proxying.h b/system/include/emscripten/proxying.h index db58f27386049..5a082000e6d32 100644 --- a/system/include/emscripten/proxying.h +++ b/system/include/emscripten/proxying.h @@ -27,13 +27,13 @@ extern "C" { typedef struct em_proxying_queue em_proxying_queue; // Create and destroy proxying queues. -em_proxying_queue* em_proxying_queue_create(); +em_proxying_queue* em_proxying_queue_create(void); void em_proxying_queue_destroy(em_proxying_queue* q); // Get the queue used for proxying low-level runtime work. Work on this queue // may be processed at any time inside system functions, so it must be // nonblocking and safe to run at any time, similar to a native signal handler. -em_proxying_queue* emscripten_proxy_get_system_queue(); +em_proxying_queue* emscripten_proxy_get_system_queue(void); // Execute all the tasks enqueued for the current thread on the given queue. New // tasks that are enqueued concurrently with this execution will be executed as diff --git a/system/include/emscripten/trace.h b/system/include/emscripten/trace.h index 366067f2a7634..79a76613c89d3 100644 --- a/system/include/emscripten/trace.h +++ b/system/include/emscripten/trace.h @@ -68,31 +68,31 @@ void emscripten_trace_close(void); #else -#define emscripten_trace_configure(collector_url, application) -#define emscripten_trace_configure_for_google_wtf() -#define emscripten_trace_configure_for_test() -#define emscripten_trace_set_enabled(enabled) -#define emscripten_trace_set_session_username(username) -#define emscripten_trace_record_frame_start() -#define emscripten_trace_record_frame_end() -#define emscripten_trace_mark(message) -#define emscripten_trace_log_message(channel, message) -#define emscripten_trace_report_error(error) -#define emscripten_trace_record_allocation(address, size) -#define emscripten_trace_record_reallocation(old_address, new_address, size) -#define emscripten_trace_record_free(address) -#define emscripten_trace_annotate_address_type(address, type) -#define emscripten_trace_associate_storage_size(address, size) -#define emscripten_trace_report_memory_layout() -#define emscripten_trace_report_off_heap_data() -#define emscripten_trace_enter_context(name) -#define emscripten_trace_exit_context() -#define emscripten_trace_task_start(task_id, taskname) -#define emscripten_trace_task_associate_data(key, value); -#define emscripten_trace_task_suspend(explanation); -#define emscripten_trace_task_resume(task_id, explanation); -#define emscripten_trace_task_end(); -#define emscripten_trace_close() +#define emscripten_trace_configure(collector_url, application) ((void)0) +#define emscripten_trace_configure_for_google_wtf() ((void)0) +#define emscripten_trace_configure_for_test() ((void)0) +#define emscripten_trace_set_enabled(enabled) ((void)0) +#define emscripten_trace_set_session_username(username) ((void)0) +#define emscripten_trace_record_frame_start() ((void)0) +#define emscripten_trace_record_frame_end() ((void)0) +#define emscripten_trace_mark(message) ((void)0) +#define emscripten_trace_log_message(channel, message) ((void)0) +#define emscripten_trace_report_error(error) ((void)0) +#define emscripten_trace_record_allocation(address, size) ((void)0) +#define emscripten_trace_record_reallocation(old_address, new_address, size) ((void)0) +#define emscripten_trace_record_free(address) ((void)0) +#define emscripten_trace_annotate_address_type(address, type) ((void)0) +#define emscripten_trace_associate_storage_size(address, size) ((void)0) +#define emscripten_trace_report_memory_layout() ((void)0) +#define emscripten_trace_report_off_heap_data() ((void)0) +#define emscripten_trace_enter_context(name) ((void)0) +#define emscripten_trace_exit_context() ((void)0) +#define emscripten_trace_task_start(task_id, taskname) ((void)0) +#define emscripten_trace_task_associate_data(key, value) ((void)0) +#define emscripten_trace_task_suspend(explanation) ((void)0) +#define emscripten_trace_task_resume(task_id, explanation) ((void)0) +#define emscripten_trace_task_end() ((void)0) +#define emscripten_trace_close() ((void)0) #endif diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h index 1d32b6d68bf60..15b768c261c7f 100644 --- a/system/include/emscripten/val.h +++ b/system/include/emscripten/val.h @@ -52,9 +52,9 @@ void _emval_decref(EM_VAL value); void _emval_run_destructors(EM_DESTRUCTORS handle); -EM_VAL _emval_new_array(); +EM_VAL _emval_new_array(void); EM_VAL _emval_new_array_from_memory_view(EM_VAL mv); -EM_VAL _emval_new_object(); +EM_VAL _emval_new_object(void); EM_VAL _emval_new_cstring(const char*); EM_VAL _emval_new_u8string(const char*); EM_VAL _emval_new_u16string(const char16_t*); From 1386520f66df2ba704a3e0eae02713e3289fdcbc Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 8 May 2023 13:36:15 -0700 Subject: [PATCH 0203/1523] Move wasm module preload plugin out of library_browser.js. NFC (#18963) Also test the preload plugin system under node. It was working previously but not covered by any of the test we run in CI. I'm hoping to unify this preloading system with the one planned as part of #18552. --- src/compiler.js | 6 ++ src/library_browser.js | 59 +++---------------- src/library_dylink.js | 42 ++++++++++++- src/library_fs.js | 4 -- src/library_fs_shared.js | 34 ++++++++++- src/library_lz4.js | 4 +- src/library_wasmfs.js | 4 -- .../metadce/test_metadce_hello_O0.jssize | 2 +- .../metadce/test_metadce_hello_dylink.jssize | 2 +- .../metadce/test_metadce_minimal_O0.jssize | 2 +- test/other/test_unoptimized_code_size.js.size | 2 +- .../test_unoptimized_code_size_strict.js.size | 2 +- test/test_other.py | 32 ++++++++++ 13 files changed, 124 insertions(+), 71 deletions(-) diff --git a/src/compiler.js b/src/compiler.js index 6176da18a09e6..976cd55527cc8 100755 --- a/src/compiler.js +++ b/src/compiler.js @@ -64,6 +64,12 @@ Object.assign(global, settings); global.symbolsOnly = symbolsOnlyArg != -1; +// In case compiler.js is run directly (as in gen_sig_info) +// ALL_INCOMING_MODULE_JS_API might not be populated yet. +if (!ALL_INCOMING_MODULE_JS_API.length) { + ALL_INCOMING_MODULE_JS_API = INCOMING_MODULE_JS_API +} + EXPORTED_FUNCTIONS = new Set(EXPORTED_FUNCTIONS); WASM_EXPORTS = new Set(WASM_EXPORTS); SIDE_MODULE_EXPORTS = new Set(SIDE_MODULE_EXPORTS); diff --git a/src/library_browser.js b/src/library_browser.js index 5a4d234070547..df6b6a9ee41cf 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -12,6 +12,10 @@ var LibraryBrowser = { '$safeSetTimeout', '$warnOnce', 'emscripten_set_main_loop_timing', + '$preloadPlugins', +#if MAIN_MODULE + '$preloadedWasm', +#endif ], $Browser__postset: ` // exports @@ -25,9 +29,6 @@ var LibraryBrowser = { Module["resumeMainLoop"] = function Module_resumeMainLoop() { Browser.mainLoop.resume() }; Module["getUserMedia"] = function Module_getUserMedia() { Browser.getUserMedia() }; Module["createContext"] = function Module_createContext(canvas, useWebGL, setInModule, webGLContextAttributes) { return Browser.createContext(canvas, useWebGL, setInModule, webGLContextAttributes) }; -#if MAIN_MODULE - var preloadedWasm = {}; -#endif var preloadedImages = {}; var preloadedAudios = {};`, @@ -101,13 +102,11 @@ var LibraryBrowser = { workers: [], init: function() { - if (!Module["preloadPlugins"]) Module["preloadPlugins"] = []; // needs to exist even in workers - if (Browser.initted) return; Browser.initted = true; // Support for plugins that can process preloaded files. You can add more of these to - // your app by creating and appending to Module.preloadPlugins. + // your app by creating and appending to preloadPlugins. // // Each plugin is asked if it can handle a file based on the file's name. If it can, // it is given the file's raw data. When it is done, it calls a callback with the file's @@ -146,7 +145,7 @@ var LibraryBrowser = { }; img.src = url; }; - Module['preloadPlugins'].push(imagePlugin); + preloadPlugins.push(imagePlugin); var audioPlugin = {}; audioPlugin['canHandle'] = function audioPlugin_canHandle(name) { @@ -209,34 +208,7 @@ var LibraryBrowser = { finish(audio); // try to use it even though it is not necessarily ready to play }, 10000); }; - Module['preloadPlugins'].push(audioPlugin); - -#if MAIN_MODULE - // Use string keys here to avoid minification since the plugin consumer - // also uses string keys. - var wasmPlugin = { - 'promiseChainEnd': Promise.resolve(), - 'canHandle': function(name) { - return !Module.noWasmDecoding && name.endsWith('.so') - }, - 'handle': function(byteArray, name, onload, onerror) { - // loadWebAssemblyModule can not load modules out-of-order, so rather - // than just running the promises in parallel, this makes a chain of - // promises to run in series. - wasmPlugin['promiseChainEnd'] = wasmPlugin['promiseChainEnd'].then( - () => loadWebAssemblyModule(byteArray, {loadAsync: true, nodelete: true})).then( - (module) => { - preloadedWasm[name] = module; - onload(); - }, - (err) => { - console.warn("Couldn't instantiate wasm: " + name + " '" + err + "'"); - onerror(); - }); - } - }; - Module['preloadPlugins'].push(wasmPlugin); -#endif // MAIN_MODULE + preloadPlugins.push(audioPlugin); // Canvas event setup @@ -279,23 +251,6 @@ var LibraryBrowser = { } }, - // Tries to handle an input byteArray using preload plugins. Returns true if - // it was handled. - handledByPreloadPlugin: function(byteArray, fullname, finish, onerror) { - // Ensure plugins are ready. - Browser.init(); - - var handled = false; - Module['preloadPlugins'].forEach((plugin) => { - if (handled) return; - if (plugin['canHandle'](fullname)) { - plugin['handle'](byteArray, fullname, finish, onerror); - handled = true; - } - }); - return handled; - }, - createContext: function(/** @type {HTMLCanvasElement} */ canvas, useWebGL, setInModule, webGLContextAttributes) { if (useWebGL && Module.ctx && canvas == Module.canvas) return Module.ctx; // no need to recreate GL context if it's already been created for this canvas. diff --git a/src/library_dylink.js b/src/library_dylink.js index 91691a4303c99..471f73cf84ab4 100644 --- a/src/library_dylink.js +++ b/src/library_dylink.js @@ -10,6 +10,39 @@ var dlopenMissingError = "'To use dlopen, you need enable dynamic linking, see h var LibraryDylink = { #if RELOCATABLE + $registerWasmPlugin__deps: ['$preloadPlugins'], + $registerWasmPlugin: function() { + // Use string keys here to avoid minification since the plugin consumer + // also uses string keys. + var wasmPlugin = { + 'promiseChainEnd': Promise.resolve(), + 'canHandle': function(name) { + return !Module.noWasmDecoding && name.endsWith('.so') + }, + 'handle': function(byteArray, name, onload, onerror) { + // loadWebAssemblyModule can not load modules out-of-order, so rather + // than just running the promises in parallel, this makes a chain of + // promises to run in series. + wasmPlugin['promiseChainEnd'] = wasmPlugin['promiseChainEnd'].then( + () => loadWebAssemblyModule(byteArray, {loadAsync: true, nodelete: true})).then( + (module) => { + preloadedWasm[name] = module; + onload(); + }, + (error) => { + err('failed to instantiate wasm: ' + name + ': ' + error); + onerror(); + }); + } + }; + preloadPlugins.push(wasmPlugin); + }, + + $preloadedWasm__deps: ['$registerWasmPlugin'], + $preloadedWasm__postset: ` + registerWasmPlugin(); + `, + $preloadedWasm: {}, $isSymbolDefined: function(symName) { // Ignore 'stub' symbols that are auto-generated as part of the original @@ -884,7 +917,9 @@ var LibraryDylink = { // If a library was already loaded, it is not loaded a second time. However // flags.global and flags.nodelete are handled every time a load request is made. // Once a library becomes "global" or "nodelete", it cannot be removed or unloaded. - $loadDynamicLibrary__deps: ['$LDSO', '$loadWebAssemblyModule', '$isInternalSym', '$mergeLibSymbols', '$newDSO', '$asyncLoad'], + $loadDynamicLibrary__deps: ['$LDSO', '$loadWebAssemblyModule', + '$isInternalSym', '$mergeLibSymbols', '$newDSO', + '$asyncLoad', '$preloadedWasm'], $loadDynamicLibrary__docs: ` /** * @param {number=} handle @@ -955,7 +990,10 @@ var LibraryDylink = { // libName -> exports function getExports() { // lookup preloaded cache first - if (typeof preloadedWasm != 'undefined' && preloadedWasm[libName]) { + if (preloadedWasm[libName]) { +#if DYLINK_DEBUG + err('using preloaded module for: ' + libName); +#endif var libModule = preloadedWasm[libName]; return flags.loadAsync ? Promise.resolve(libModule) : libModule; } diff --git a/src/library_fs.js b/src/library_fs.js index ce9c739f59f1a..bd432c991f25c 100644 --- a/src/library_fs.js +++ b/src/library_fs.js @@ -93,10 +93,6 @@ Object.defineProperties(FSNode.prototype, { FS.FSNode = FSNode; FS.createPreloadedFile = FS_createPreloadedFile; FS.staticInit();` + -#if USE_CLOSURE_COMPILER - // Declare variable for Closure, FS.createPreloadedFile() below calls Browser.handledByPreloadPlugin() - '/**@suppress {duplicate, undefinedVars}*/var Browser;' + -#endif // Get module methods from settings '{{{ EXPORTED_RUNTIME_METHODS.filter(function(func) { return func.substr(0, 3) === 'FS_' }).map(function(func){return 'Module["' + func + '"] = FS.' + func.substr(3) + ";"}).reduce(function(str, func){return str + func;}, '') }}}'; }, diff --git a/src/library_fs_shared.js b/src/library_fs_shared.js index 1d7336d64b6c1..e595fb3fe2c7a 100644 --- a/src/library_fs_shared.js +++ b/src/library_fs_shared.js @@ -5,6 +5,31 @@ */ mergeInto(LibraryManager.library, { + $preloadPlugins: "{{{ makeModuleReceiveExpr('preloadPlugins', '[]') }}}", + +#if !MINIMAL_RUNTIME + // Tries to handle an input byteArray using preload plugins. Returns true if + // it was handled. + $FS_handledByPreloadPlugin__internal: true, + $FS_handledByPreloadPlugin__deps: ['$preloadPlugins'], + $FS_handledByPreloadPlugin: function(byteArray, fullname, finish, onerror) { +#if LibraryManager.has('library_browser.js') + // Ensure plugins are ready. + if (typeof Browser != 'undefined') Browser.init(); +#endif + + var handled = false; + preloadPlugins.forEach(function(plugin) { + if (handled) return; + if (plugin['canHandle'](fullname)) { + plugin['handle'](byteArray, fullname, finish, onerror); + handled = true; + } + }); + return handled; + }, +#endif + // Preloads a file asynchronously. You can call this before run, for example in // preRun. run will be delayed until this file arrives and is set up. // If you call it after run(), you may want to pause the main loop until it @@ -17,7 +42,11 @@ mergeInto(LibraryManager.library, { // You can also call this with a typed array instead of a url. It will then // do preloading for the Image/Audio part, as if the typed array were the // result of an XHR that you did manually. - $FS_createPreloadedFile__deps: ['$asyncLoad'], + $FS_createPreloadedFile__deps: ['$asyncLoad', +#if !MINIMAL_RUNTIME + '$FS_handledByPreloadPlugin', +#endif + ], $FS_createPreloadedFile: function(parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile, canOwn, preFinish) { #if WASMFS // TODO: use WasmFS code to resolve and join the path here? @@ -38,7 +67,7 @@ mergeInto(LibraryManager.library, { removeRunDependency(dep); } #if !MINIMAL_RUNTIME - if (Browser.handledByPreloadPlugin(byteArray, fullname, finish, () => { + if (FS_handledByPreloadPlugin(byteArray, fullname, finish, () => { if (onerror) onerror(); removeRunDependency(dep); })) { @@ -76,4 +105,5 @@ mergeInto(LibraryManager.library, { if (canWrite) mode |= {{{ cDefs.S_IWUGO }}}; return mode; }, + }); diff --git a/src/library_lz4.js b/src/library_lz4.js index 60fe36ff84374..94d565c667931 100644 --- a/src/library_lz4.js +++ b/src/library_lz4.js @@ -6,7 +6,7 @@ #if LZ4 mergeInto(LibraryManager.library, { - $LZ4__deps: ['$FS'], + $LZ4__deps: ['$FS', '$preloadPlugins'], $LZ4: { DIR_MODE: {{{ cDefs.S_IFDIR }}} | 511 /* 0777 */, FILE_MODE: {{{ cDefs.S_IFREG }}} | 511 /* 0777 */, @@ -52,7 +52,7 @@ mergeInto(LibraryManager.library, { pack['metadata'].files.forEach(function(file) { var handled = false; var fullname = file.filename; - Module['preloadPlugins'].forEach(function(plugin) { + preloadPlugins.forEach(function(plugin) { if (handled) return; if (plugin['canHandle'](fullname)) { var dep = getUniqueRunDependency('fp ' + fullname); diff --git a/src/library_wasmfs.js b/src/library_wasmfs.js index 3e39b150ac2c3..fc05172dd8d5b 100644 --- a/src/library_wasmfs.js +++ b/src/library_wasmfs.js @@ -7,11 +7,7 @@ mergeInto(LibraryManager.library, { $wasmFSPreloadedFiles: [], $wasmFSPreloadedDirs: [], - // Declare variable for Closure, FS.createPreloadedFile() below calls Browser.handledByPreloadPlugin() $FS__postset: ` -#if USE_CLOSURE_COMPILER -/**@suppress {duplicate, undefinedVars}*/var Browser; -#endif FS.createPreloadedFile = FS_createPreloadedFile; `, $FS__deps: [ diff --git a/test/other/metadce/test_metadce_hello_O0.jssize b/test/other/metadce/test_metadce_hello_O0.jssize index 24a44d0d1ceae..a17534e412b0e 100644 --- a/test/other/metadce/test_metadce_hello_O0.jssize +++ b/test/other/metadce/test_metadce_hello_O0.jssize @@ -1 +1 @@ -23827 +23842 diff --git a/test/other/metadce/test_metadce_hello_dylink.jssize b/test/other/metadce/test_metadce_hello_dylink.jssize index 005f3bc6c8629..bc6d98594e845 100644 --- a/test/other/metadce/test_metadce_hello_dylink.jssize +++ b/test/other/metadce/test_metadce_hello_dylink.jssize @@ -1 +1 @@ -27887 +28153 diff --git a/test/other/metadce/test_metadce_minimal_O0.jssize b/test/other/metadce/test_metadce_minimal_O0.jssize index 55ec08fe69674..ee2c9295201b2 100644 --- a/test/other/metadce/test_metadce_minimal_O0.jssize +++ b/test/other/metadce/test_metadce_minimal_O0.jssize @@ -1 +1 @@ -20076 +20091 diff --git a/test/other/test_unoptimized_code_size.js.size b/test/other/test_unoptimized_code_size.js.size index 77888a8cbbf48..10afb236d5a46 100644 --- a/test/other/test_unoptimized_code_size.js.size +++ b/test/other/test_unoptimized_code_size.js.size @@ -1 +1 @@ -59626 +59646 diff --git a/test/other/test_unoptimized_code_size_strict.js.size b/test/other/test_unoptimized_code_size_strict.js.size index ea43e56b33d17..0049768cac040 100644 --- a/test/other/test_unoptimized_code_size_strict.js.size +++ b/test/other/test_unoptimized_code_size_strict.js.size @@ -1 +1 @@ -58568 +58588 diff --git a/test/test_other.py b/test/test_other.py index 90cf5f3000db1..aecd266dab506 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -13389,3 +13389,35 @@ def test_node_pthreads_err_out(self): def test_windows_batch_file_dp0_expansion_bug(self): create_file('build_with_quotes.bat', f'@"emcc" {test_file("hello_world.c")}') self.run_process(['build_with_quotes.bat']) + + def test_preload_module(self): + # TODO(sbc): This test is copyied from test_browser.py. Perhaps find a better way to + # share code between them. + create_file('library.c', r''' + #include + int library_func() { + return 42; + } + ''') + self.run_process([EMCC, 'library.c', '-sSIDE_MODULE', '-o', 'library.so']) + create_file('main.c', r''' + #include + #include + #include + #include + int main() { + int found = EM_ASM_INT( + return preloadedWasm['/library.so'] !== undefined; + ); + assert(found); + void *lib_handle = dlopen("/library.so", RTLD_NOW); + assert(lib_handle); + typedef int (*voidfunc)(); + voidfunc x = (voidfunc)dlsym(lib_handle, "library_func"); + assert(x); + assert(x() == 42); + printf("done\n"); + return 0; + } + ''') + self.do_runf('main.c', 'done\n', emcc_args=['-sMAIN_MODULE=2', '--preload-file', '.@/', '--use-preload-plugins']) From d1530e7dd9c1d309fddd51b7d4b7201ec2cf3fd6 Mon Sep 17 00:00:00 2001 From: Armstrong Date: Tue, 9 May 2023 12:45:58 +0800 Subject: [PATCH 0204/1523] Fix websocket in shared memory environment (#19247) --- src/library_websocket.js | 2 +- test/test_sockets.py | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/library_websocket.js b/src/library_websocket.js index a8d83212457ac..736894584247f 100644 --- a/src/library_websocket.js +++ b/src/library_websocket.js @@ -347,7 +347,7 @@ var LibraryWebSocket = { dbg('emscripten_websocket_send_binary(socketId='+socketId+',binaryData='+binaryData+ ',dataLength='+dataLength+'), ' + s); #endif -#if PTHREADS +#if SHARED_MEMORY // TODO: This is temporary to cast a shared Uint8Array to a non-shared Uint8Array. This could be removed if WebSocket API is improved // to allow passing in views to SharedArrayBuffers socket.send(new Uint8Array({{{ makeHEAPView('U8', 'binaryData', 'binaryData+dataLength') }}})); diff --git a/test/test_sockets.py b/test/test_sockets.py index 12abd2c3cd28d..7bee567e8daa6 100644 --- a/test/test_sockets.py +++ b/test/test_sockets.py @@ -325,9 +325,14 @@ def test_nodejs_sockets_echo_subprotocol(self): # Test Emscripten WebSockets API to send and receive text and binary messages against an echo server. # N.B. running this test requires 'npm install ws' in Emscripten root directory - def test_websocket_send(self): + # NOTE: Shared buffer is not allowed for websocket sending. + @parameterized({ + '': [[]], + 'shared': [['-sSHARED_MEMORY']], + }) + def test_websocket_send(self, args): with NodeJsWebSocketEchoServerProcess(): - self.btest_exit(test_file('websocket/test_websocket_send.c'), args=['-lwebsocket', '-sNO_EXIT_RUNTIME', '-sWEBSOCKET_DEBUG']) + self.btest_exit(test_file('websocket/test_websocket_send.c'), args=['-lwebsocket', '-sNO_EXIT_RUNTIME', '-sWEBSOCKET_DEBUG'] + args) # Test that native POSIX sockets API can be used by proxying calls to an intermediate WebSockets # -> POSIX sockets bridge server From c8f3ea70602cc8e72bc5cb2b35cd2cbd9db3cabd Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 9 May 2023 09:39:37 -0700 Subject: [PATCH 0205/1523] [Docs] Update a mention of the spidermonkey shell in tests. See #19264 (#19271) --- .../docs/building_from_source/toolchain_what_is_needed.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/source/docs/building_from_source/toolchain_what_is_needed.rst b/site/source/docs/building_from_source/toolchain_what_is_needed.rst index b8c448fcf86a2..a6246732e80e6 100644 --- a/site/source/docs/building_from_source/toolchain_what_is_needed.rst +++ b/site/source/docs/building_from_source/toolchain_what_is_needed.rst @@ -32,7 +32,7 @@ In general a complete Emscripten environment requires the following tools. First .. note: 64-bit versions of all needed dependencies are preferred, and may be required if you are building large projects. -.. note:: The `Spidermonkey shell `_ is also required if you want to run **100%** of the tests in the test suite. Most developers will not need this, and should instead use *node.js*. +.. note:: The `d8 shell `_ is also required if you want to run **100%** of the tests in the test suite (in particular, tests for extremely new features that are only present in d8 so far). Most developers will not need this, and should instead use *node.js*. .. _compiler-toolchain: From 3c822ef6ba6b3be58b73fd8dde4422538fdbe3dc Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 9 May 2023 10:23:06 -0700 Subject: [PATCH 0206/1523] Start using JS string template in JS code (#19285) It looks like these have been implements for a very long time in all the engines: https://caniuse.com/template-literals I just chose of libraries to start with, and will continue with others if there are no objections. --- src/embind/embind.js | 92 +++++++++---------- src/library.js | 42 ++++----- src/runtime_safe_heap.js | 28 +++--- .../metadce/test_metadce_hello_dylink.jssize | 2 +- test/other/test_unoptimized_code_size.js.size | 2 +- .../test_unoptimized_code_size_strict.js.size | 2 +- 6 files changed, 83 insertions(+), 85 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index f4c7ca2fa0563..8ee41866e6f71 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -93,7 +93,7 @@ var LibraryEmbind = { proto[methodName] = function() { // TODO This check can be removed in -O3 level "unsafe" optimizations. if (!proto[methodName].overloadTable.hasOwnProperty(arguments.length)) { - throwBindingError("Function '" + humanName + "' called with an invalid number of arguments (" + arguments.length + ") - expects one of (" + proto[methodName].overloadTable + ")!"); + throwBindingError(`Function '${humanName}' called with an invalid number of arguments (${arguments.length}) - expects one of (${proto[methodName].overloadTable})!`); } return proto[methodName].overloadTable[arguments.length].apply(this, arguments); }; @@ -118,14 +118,14 @@ var LibraryEmbind = { $exposePublicSymbol: function(name, value, numArguments) { if (Module.hasOwnProperty(name)) { if (undefined === numArguments || (undefined !== Module[name].overloadTable && undefined !== Module[name].overloadTable[numArguments])) { - throwBindingError("Cannot register public name '" + name + "' twice"); + throwBindingError(`Cannot register public name '${name}' twice`); } // We are exposing a function with the same name as an existing function. Create an overload table and a function selector // that routes between the two. ensureOverloadTable(Module, name, name); if (Module.hasOwnProperty(numArguments)) { - throwBindingError("Cannot register multiple overloads of a function with the same number of arguments (" + numArguments + ")!"); + throwBindingError(`Cannot register multiple overloads of a function with the same number of arguments (${numArguments})!`); } // Add the new function into the overload table. Module[name].overloadTable[numArguments] = value; @@ -282,19 +282,19 @@ var LibraryEmbind = { $registerType__docs: '/** @param {Object=} options */', $registerType: function(rawType, registeredInstance, options = {}) { if (!('argPackAdvance' in registeredInstance)) { - throw new TypeError('registerType registeredInstance requires argPackAdvance'); + throw new TypeError('registerType registeredInstance requires argPackAdvance'); } var name = registeredInstance.name; if (!rawType) { - throwBindingError('type "' + name + '" must have a positive integer typeid pointer'); + throwBindingError(`type "${name}" must have a positive integer typeid pointer`); } if (registeredTypes.hasOwnProperty(rawType)) { - if (options.ignoreDuplicateRegistrations) { - return; - } else { - throwBindingError("Cannot register type '" + name + "' twice"); - } + if (options.ignoreDuplicateRegistrations) { + return; + } else { + throwBindingError(`Cannot register type '${name}' twice`); + } } registeredTypes[rawType] = registeredInstance; @@ -546,10 +546,10 @@ var LibraryEmbind = { var checkAssertions = (value, toTypeName) => { #if ASSERTIONS if (typeof value != "number" && typeof value != "boolean") { - throw new TypeError('Cannot convert "' + embindRepr(value) + '" to ' + toTypeName); + throw new TypeError(`Cannot convert "${embindRepr(value)}" to ${toTypeName}`); } if (value < minRange || value > maxRange) { - throw new TypeError('Passing a number "' + embindRepr(value) + '" from JS side to C/C++ side to an argument of type "' + name + '", which is outside the valid range [' + minRange + ', ' + maxRange + ']!'); + throw new TypeError(`Passing a number "${embindRepr(value)}" from JS side to C/C++ side to an argument of type "${name}", which is outside the valid range [${minRange}, ${maxRange}]!`); } #endif } @@ -599,10 +599,10 @@ var LibraryEmbind = { }, 'toWireType': function (destructors, value) { if (typeof value != "bigint" && typeof value != "number") { - throw new TypeError('Cannot convert "' + embindRepr(value) + '" to ' + this.name); + throw new TypeError(`Cannot convert "${embindRepr(value)}" to ${this.name}`); } if (value < minRange || value > maxRange) { - throw new TypeError('Passing a number "' + embindRepr(value) + '" from JS side to C/C++ side to an argument of type "' + name + '", which is outside the valid range [' + minRange + ', ' + maxRange + ']!'); + throw new TypeError(`Passing a number "${embindRepr(value)}" from JS side to C/C++ side to an argument of type "${name}", which is outside the valid range [${minRange}, ${maxRange}]!`); } return value; }, @@ -630,7 +630,7 @@ var LibraryEmbind = { 'toWireType': function(destructors, value) { #if ASSERTIONS if (typeof value != "number" && typeof value != "boolean") { - throw new TypeError('Cannot convert "' + embindRepr(value) + '" to ' + this.name); + throw new TypeError(`Cannot convert ${embindRepr(value)} to ${this.name}`); } #endif // The VM will perform JS to Wasm value conversion, according to the spec: @@ -902,7 +902,7 @@ var LibraryEmbind = { $newFunc__deps: ['$createNamedFunction'], $newFunc: function(constructor, argumentList) { if (!(constructor instanceof Function)) { - throw new TypeError('new_ called with constructor type ' + typeof(constructor) + " which is not a function"); + throw new TypeError(`new_ called with constructor type ${typeof(constructor)} which is not a function`); } /* * Previously, the following line was just: @@ -990,9 +990,7 @@ var LibraryEmbind = { var destructors = []; return function() { if (arguments.length !== expectedArgCount) { - throwBindingError('function ' + humanName + ' called with ' + - arguments.length + ' arguments, expected ' + expectedArgCount + - ' args!'); + throwBindingError(`function ${humanName} called with ${arguments.length} arguments, expected ${expectedArgCount} args!`); } #if EMSCRIPTEN_TRACING Module.emscripten_trace_enter_context('embind::' + humanName); @@ -1060,7 +1058,7 @@ var LibraryEmbind = { "}\n"; #if EMSCRIPTEN_TRACING - invokerFnBody += "Module.emscripten_trace_enter_context('embind::" + humanName + "');\n"; + invokerFnBody += `Module.emscripten_trace_enter_context('embind::${humanName}');\n`; #endif if (needsDestructorStack) { @@ -1169,7 +1167,7 @@ var LibraryEmbind = { var fp = makeDynCaller(); if (typeof fp != "function") { - throwBindingError("unknown function pointer with signature " + signature + ": " + rawFunction); + throwBindingError(`unknown function pointer with signature ${signature}: ${rawFunction}`); } return fp; }, @@ -1185,7 +1183,7 @@ var LibraryEmbind = { rawInvoker = embind__requireFunction(signature, rawInvoker); exposePublicSymbol(name, function() { - throwUnboundTypeError('Cannot call ' + name + ' due to unbound types', argTypes); + throwUnboundTypeError(`Cannot call ${name} due to unbound types`, argTypes); }, argCount - 1); whenDependentTypesAreResolved([], argTypes, function(argTypes) { @@ -1282,7 +1280,7 @@ var LibraryEmbind = { }, 'toWireType': function(destructors, o) { if (elementsLength !== o.length) { - throw new TypeError("Incorrect number of tuple elements for " + reg.name + ": expected=" + elementsLength + ", actual=" + o.length); + throw new TypeError(`Incorrect number of tuple elements for ${reg.name}: expected=${elementsLength}, actual=${o.length}`); } var ptr = rawConstructor(); for (var i = 0; i < elementsLength; ++i) { @@ -1395,7 +1393,7 @@ var LibraryEmbind = { // assume all fields are present without checking. for (var fieldName in fields) { if (!(fieldName in o)) { - throw new TypeError('Missing field: "' + fieldName + '"'); + throw new TypeError(`Missing field: "${fieldName}"`); } } var ptr = rawConstructor(); @@ -1434,13 +1432,13 @@ var LibraryEmbind = { } if (!handle.$$) { - throwBindingError('Cannot pass "' + embindRepr(handle) + '" as a ' + this.name); + throwBindingError(`Cannot pass "${embindRepr(handle)}" as a ${this.name}`); } if (!handle.$$.ptr) { - throwBindingError('Cannot pass deleted object as a pointer of type ' + this.name); + throwBindingError(`Cannot pass deleted object as a pointer of type ${this.name}`); } if (!this.isConst && handle.$$.ptrType.isConst) { - throwBindingError('Cannot convert argument of type ' + (handle.$$.smartPtrType ? handle.$$.smartPtrType.name : handle.$$.ptrType.name) + ' to parameter type ' + this.name); + throwBindingError(`Cannot convert argument of type ${(handle.$$.smartPtrType ? handle.$$.smartPtrType.name : handle.$$.ptrType.name)} to parameter type ${this.name}`); } var handleClass = handle.$$.ptrType.registeredClass; ptr = upcastPointer(handle.$$.ptr, handleClass, this.registeredClass); @@ -1459,7 +1457,7 @@ var LibraryEmbind = { if (handle.$$.smartPtrType === this) { ptr = handle.$$.smartPtr; } else { - throwBindingError('Cannot convert argument of type ' + (handle.$$.smartPtrType ? handle.$$.smartPtrType.name : handle.$$.ptrType.name) + ' to parameter type ' + this.name); + throwBindingError(`Cannot convert argument of type ${(handle.$$.smartPtrType ? handle.$$.smartPtrType.name : handle.$$.ptrType.name)} to parameter type ${this.name}`); } break; @@ -1503,7 +1501,7 @@ var LibraryEmbind = { } if (!handle.$$) { - throwBindingError('Cannot pass "' + embindRepr(handle) + '" as a ' + this.name); + throwBindingError(`Cannot pass "${embindRepr(handle)}" as a ${this.name}`); } if (!handle.$$.ptr) { throwBindingError('Cannot pass deleted object as a pointer of type ' + this.name); @@ -1525,13 +1523,13 @@ var LibraryEmbind = { } if (!handle.$$) { - throwBindingError('Cannot pass "' + embindRepr(handle) + '" as a ' + this.name); + throwBindingError(`Cannot pass "${embindRepr(handle)}" as a ${this.name}`); } if (!handle.$$.ptr) { - throwBindingError('Cannot pass deleted object as a pointer of type ' + this.name); + throwBindingError(`Cannot pass deleted object as a pointer of type ${this.name}`); } if (handle.$$.ptrType.isConst) { - throwBindingError('Cannot convert argument of type ' + handle.$$.ptrType.name + ' to parameter type ' + this.name); + throwBindingError(`Cannot convert argument of type ${handle.$$.ptrType.name} to parameter type ${this.name}`); } var handleClass = handle.$$.ptrType.registeredClass; var ptr = upcastPointer(handle.$$.ptr, handleClass, this.registeredClass); @@ -1768,7 +1766,7 @@ var LibraryEmbind = { // This is more useful than the empty stacktrace of `FinalizationRegistry` // callback. var cls = $$.ptrType.registeredClass; - info.leakWarning = new Error("Embind found a leaked C++ instance " + cls.name + " <" + ptrToString($$.ptr) + ">.\n" + + info.leakWarning = new Error(`Embind found a leaked C++ instance ${cls.name} <${ptrToString($$.ptr)}>.\n` + "We'll free it automatically in this case, but this functionality is not reliable across various environments.\n" + "Make sure to invoke .delete() manually once you're done with the instance instead.\n" + "Originally allocated"); // `.stack` will add "at ..." after this sentence @@ -2002,7 +2000,7 @@ var LibraryEmbind = { exposePublicSymbol(legalFunctionName, function() { // this code cannot run if baseClassRawType is zero - throwUnboundTypeError('Cannot construct ' + name + ' due to unbound types', [baseClassRawType]); + throwUnboundTypeError(`Cannot construct ${name} due to unbound types`, [baseClassRawType]); }); whenDependentTypesAreResolved( @@ -2029,7 +2027,7 @@ var LibraryEmbind = { } var body = registeredClass.constructor_body[arguments.length]; if (undefined === body) { - throw new BindingError("Tried to invoke ctor of " + name + " with invalid number of parameters (" + arguments.length + ") - expected (" + Object.keys(registeredClass.constructor_body).toString() + ") parameters instead!"); + throw new BindingError(`Tried to invoke ctor of ${name} with invalid number of parameters (${arguments.length}) - expected (${Object.keys(registeredClass.constructor_body).toString()}) parameters instead!`); } return body.apply(this, arguments); }); @@ -2105,10 +2103,10 @@ var LibraryEmbind = { classType.registeredClass.constructor_body = []; } if (undefined !== classType.registeredClass.constructor_body[argCount - 1]) { - throw new BindingError("Cannot register multiple constructors with identical number of parameters (" + (argCount-1) + ") for class '" + classType.name + "'! Overload resolution is currently only performed using the parameter count, not actual type info!"); + throw new BindingError(`Cannot register multiple constructors with identical number of parameters (${argCount-1}) for class '${classType.name}'! Overload resolution is currently only performed using the parameter count, not actual type info!`); } classType.registeredClass.constructor_body[argCount - 1] = () => { - throwUnboundTypeError('Cannot construct ' + classType.name + ' due to unbound types', rawArgTypes); + throwUnboundTypeError(`Cannot construct ${classType.name} due to unbound types`, rawArgTypes); }; whenDependentTypesAreResolved([], rawArgTypes, function(argTypes) { @@ -2140,7 +2138,7 @@ var LibraryEmbind = { $upcastPointer: function(ptr, ptrClass, desiredClass) { while (ptrClass !== desiredClass) { if (!ptrClass.upcast) { - throwBindingError("Expected null or instance of " + desiredClass.name + ", got an instance of " + ptrClass.name); + throwBindingError(`Expected null or instance of ${desiredClass.name}, got an instance of ${ptrClass.name}`); } ptr = ptrClass.upcast(ptr); ptrClass = ptrClass.baseClass; @@ -2157,7 +2155,7 @@ var LibraryEmbind = { throwBindingError(humanName + ' incompatible with "this" of type ' + this_.constructor.name); } if (!this_.$$.ptr) { - throwBindingError('cannot call emscripten binding method ' + humanName + ' on deleted object'); + throwBindingError(`cannot call emscripten binding method ${humanName} on deleted object`); } // todo: kill this @@ -2196,7 +2194,7 @@ var LibraryEmbind = { } function unboundTypesHandler() { - throwUnboundTypeError('Cannot call ' + humanName + ' due to unbound types', rawArgTypes); + throwUnboundTypeError(`Cannot call ${humanName} due to unbound types`, rawArgTypes); } var proto = classType.registeredClass.instancePrototype; @@ -2255,14 +2253,14 @@ var LibraryEmbind = { var humanName = classType.name + '.' + fieldName; var desc = { get: function() { - throwUnboundTypeError('Cannot access ' + humanName + ' due to unbound types', [getterReturnType, setterArgumentType]); + throwUnboundTypeError(`Cannot access ${humanName} due to unbound types`, [getterReturnType, setterArgumentType]); }, enumerable: true, configurable: true }; if (setter) { desc.set = () => { - throwUnboundTypeError('Cannot access ' + humanName + ' due to unbound types', [getterReturnType, setterArgumentType]); + throwUnboundTypeError(`Cannot access ${humanName} due to unbound types`, [getterReturnType, setterArgumentType]); }; } else { desc.set = (v) => { @@ -2324,7 +2322,7 @@ var LibraryEmbind = { var humanName = classType.name + '.' + methodName; function unboundTypesHandler() { - throwUnboundTypeError('Cannot call ' + humanName + ' due to unbound types', rawArgTypes); + throwUnboundTypeError(`Cannot call ${humanName} due to unbound types`, rawArgTypes); } if (methodName.startsWith("@@")) { @@ -2381,18 +2379,18 @@ var LibraryEmbind = { var humanName = classType.name + '.' + fieldName; var desc = { get: function() { - throwUnboundTypeError('Cannot access ' + humanName + ' due to unbound types', [rawFieldType]); + throwUnboundTypeError(`Cannot access ${humanName} due to unbound types`, [rawFieldType]); }, enumerable: true, configurable: true }; if (setter) { desc.set = () => { - throwUnboundTypeError('Cannot access ' + humanName + ' due to unbound types', [rawFieldType]); + throwUnboundTypeError(`Cannot access ${humanName} due to unbound types`, [rawFieldType]); }; } else { desc.set = (v) => { - throwBindingError(humanName + ' is a read-only property'); + throwBindingError(`${humanName} is a read-only property`); }; } @@ -2445,7 +2443,7 @@ var LibraryEmbind = { var ctor = createNamedFunction(constructorName, function() { registeredClass.baseClass.pureVirtualFunctions.forEach(function(name) { if (this[name] === baseClassPrototype[name]) { - throw new PureVirtualError('Pure virtual function ' + name + ' must be implemented in JavaScript'); + throw new PureVirtualError(`Pure virtual function ${name} must be implemented in JavaScript`); } }.bind(this)); diff --git a/src/library.js b/src/library.js index 33b2bb1da8474..5192b952fe183 100644 --- a/src/library.js +++ b/src/library.js @@ -69,7 +69,7 @@ mergeInto(LibraryManager.library, { assert(!implicit); #endif #if PTHREADS_DEBUG - dbg('Pthread ' + ptrToString(_pthread_self()) + ' called exit(), posting exitOnMainThread.'); + dbg(`Pthread ${ptrToString(_pthread_self())} called exit(), posting exitOnMainThread.`); #endif // When running in a pthread we propagate the exit back to the main thread // where it can decide if the whole process should be shut down or not. @@ -79,7 +79,7 @@ mergeInto(LibraryManager.library, { throw 'unwind'; } #if PTHREADS_DEBUG - err('main thread called exit: keepRuntimeAlive=' + keepRuntimeAlive() + ' (counter=' + runtimeKeepaliveCounter + ')'); + err(`main thread called exit: keepRuntimeAlive=${keepRuntimeAlive()} (counter=${runtimeKeepaliveCounter})`); #endif // PTHREADS_DEBUG #endif // PTHREADS @@ -92,7 +92,7 @@ mergeInto(LibraryManager.library, { #if ASSERTIONS // if exit() was called explicitly, warn the user if the runtime isn't actually being shut down if (keepRuntimeAlive() && !implicit) { - var msg = 'program exited (with status: ' + status + '), but keepRuntimeAlive() is set (counter=' + runtimeKeepaliveCounter + ') due to an async operation, so halting execution but not exiting the runtime or preventing further async execution (you can use emscripten_force_exit, if you want to force a true shutdown)'; + var msg = `program exited (with status: ${status}), but keepRuntimeAlive() is set (counter=${runtimeKeepaliveCounter}) due to an async operation, so halting execution but not exiting the runtime or preventing further async execution (you can use emscripten_force_exit, if you want to force a true shutdown)`; #if MODULARIZE readyPromiseReject(msg); #endif // MODULARIZE @@ -136,9 +136,9 @@ mergeInto(LibraryManager.library, { $abortOnCannotGrowMemory: function(requestedSize) { #if ASSERTIONS #if ALLOW_MEMORY_GROWTH - abort('Cannot enlarge memory arrays to size ' + requestedSize + ' bytes (OOM). If you want malloc to return NULL (0) instead of this abort, do not link with -sABORTING_MALLOC (that is, the default when growth is enabled is to not abort, but you have overridden that)'); + abort(`Cannot enlarge memory arrays to size ${requestedSize} bytes (OOM). If you want malloc to return NULL (0) instead of this abort, do not link with -sABORTING_MALLOC (that is, the default when growth is enabled is to not abort, but you have overridden that)`); #else // ALLOW_MEMORY_GROWTH - abort('Cannot enlarge memory arrays to size ' + requestedSize + ' bytes (OOM). Either (1) compile with -sINITIAL_MEMORY=X with X higher than the current value ' + HEAP8.length + ', (2) compile with -sALLOW_MEMORY_GROWTH which allows increasing the size at runtime, or (3) if you want malloc to return NULL (0) instead of this abort, compile with -sABORTING_MALLOC=0'); + abort(`Cannot enlarge memory arrays to size ${requestedSize} bytes (OOM). Either (1) compile with -sINITIAL_MEMORY=X with X higher than the current value ${HEAP8.length}, (2) compile with -sALLOW_MEMORY_GROWTH which allows increasing the size at runtime, or (3) if you want malloc to return NULL (0) instead of this abort, compile with -sABORTING_MALLOC=0`); #endif // ALLOW_MEMORY_GROWTH #else // ASSERTIONS abort('OOM'); @@ -171,7 +171,7 @@ mergeInto(LibraryManager.library, { return 1 /*success*/; } catch(e) { #if ASSERTIONS - err('emscripten_realloc_buffer: Attempted to grow heap from ' + b.byteLength + ' bytes to ' + size + ' bytes, but got error: ' + e); + err(`emscripten_realloc_buffer: Attempted to grow heap from ${b.byteLength} bytes to ${size} bytes, but got error: ${e}`); #endif } // implicit 0 return to save code size (caller will cast "undefined" into 0 @@ -239,7 +239,7 @@ mergeInto(LibraryManager.library, { var maxHeapSize = getHeapMax(); if (requestedSize > maxHeapSize) { #if ASSERTIONS - err('Cannot enlarge memory, asked to go up to ' + requestedSize + ' bytes, but the limit is ' + maxHeapSize + ' bytes!'); + err(`Cannot enlarge memory, asked to go up to ${requestedSize} bytes, but the limit is ${maxHeapSize} bytes!`); #endif #if ABORTING_MALLOC abortOnCannotGrowMemory(requestedSize); @@ -273,7 +273,7 @@ mergeInto(LibraryManager.library, { var replacement = emscripten_realloc_buffer(newSize); #if ASSERTIONS == 2 var t1 = _emscripten_get_now(); - out('Heap resize call from ' + oldSize + ' to ' + newSize + ' took ' + (t1 - t0) + ' msecs. Success: ' + !!replacement); + out(`Heap resize call from ${oldSize} to ${newSize} took ${(t1 - t0)} msecs. Success: ${!!replacement}`); #endif if (replacement) { #if ASSERTIONS && WASM2JS @@ -281,7 +281,7 @@ mergeInto(LibraryManager.library, { #endif #if EMSCRIPTEN_TRACING - traceLogMessage("Emscripten", "Enlarging memory arrays from " + oldSize + " to " + newSize); + traceLogMessage("Emscripten", `Enlarging memory arrays from ${oldSize} to ${newSize}`); // And now report the new layout _emscripten_trace_report_memory_layout(); #endif @@ -289,7 +289,7 @@ mergeInto(LibraryManager.library, { } } #if ASSERTIONS - err('Failed to grow the heap from ' + oldSize + ' bytes to ' + newSize + ' bytes, not enough memory!'); + err(`Failed to grow the heap from ${oldSize} bytes to ${newSize} bytes, not enough memory!`); #endif #if ABORTING_MALLOC abortOnCannotGrowMemory(requestedSize); @@ -424,7 +424,7 @@ mergeInto(LibraryManager.library, { // ========================================================================== __assert_fail: function(condition, filename, line, func) { - abort('Assertion failed: ' + UTF8ToString(condition) + ', at: ' + [filename ? UTF8ToString(filename) : 'unknown filename', line, func ? UTF8ToString(func) : 'unknown function']); + abort(`Assertion failed: ${UTF8ToString(condition)}, at: ` + [filename ? UTF8ToString(filename) : 'unknown filename', line, func ? UTF8ToString(func) : 'unknown function']); }, // ========================================================================== @@ -2266,7 +2266,7 @@ mergeInto(LibraryManager.library, { '_emscripten_timeout', 'emscripten_get_now'], _setitimer_js: function(which, timeout_ms) { #if RUNTIME_DEBUG - dbg('setitimer_js ' + which + ' timeout=' + timeout_ms); + dbg(`setitimer_js ${which} timeout=${timeout_ms}`); #endif // First, clear any existing timer. if (timers[which]) { @@ -2550,14 +2550,14 @@ mergeInto(LibraryManager.library, { if (flags & {{{ cDefs.EM_LOG_NO_PATHS }}}) { orig.source = orig.source.substring(orig.source.replace(/\\/g, "/").lastIndexOf('/')+1); } - callstack += ' at ' + symbolName + ' (' + orig.source + ':' + orig.line + ':' + orig.column + ')\n'; + callstack += ` at ${symbolName} (${orig.source}:${orig.line}:${orig.column})\n`; } } if ((flags & {{{ cDefs.EM_LOG_JS_STACK }}}) || !haveSourceMap) { if (flags & {{{ cDefs.EM_LOG_NO_PATHS }}}) { file = file.substring(file.replace(/\\/g, "/").lastIndexOf('/')+1); } - callstack += (haveSourceMap ? (' = ' + symbolName) : (' at '+ symbolName)) + ' (' + file + ':' + lineno + ':' + column + ')\n'; + callstack += (haveSourceMap ? (` = ${symbolName}`) : (` at ${symbolName}`)) + ` (${file}:${lineno}:${column})\n`; } // If we are still keeping track with the callstack by traversing via @@ -2962,7 +2962,7 @@ mergeInto(LibraryManager.library, { // get automatically converted to int53/Double. validChars.push('p'); #endif - assert(validChars.includes(chr), 'Invalid character ' + ch + '("' + chr + '") in readEmAsmArgs! Use only [' + validChars + '], and do not specify "v" for void return argument.'); + assert(validChars.includes(chr), `Invalid character ${ch}("${chr}") in readEmAsmArgs! Use only [${validChars}], and do not specify "v" for void return argument.`); #endif // Floats are always passed as doubles, and doubles and int64s take up 8 // bytes (two 32-bit slots) in memory, align reads to these: @@ -3131,8 +3131,8 @@ mergeInto(LibraryManager.library, { requested = requested >>> 0; var base = _emscripten_stack_get_base(); var end = _emscripten_stack_get_end(); - abort('stack overflow (Attempt to set SP to ' + ptrToString(requested) + - ', with stack limits [' + ptrToString(end) + ' - ' + ptrToString(base) + + abort(`stack overflow (Attempt to set SP to ${ptrToString(requested)}` + + `, with stack limits [${ptrToString(end)} - ${ptrToString(base)}` + ']). If you require more stack space build with -sSTACK_SIZE='); }, #endif @@ -3193,9 +3193,9 @@ mergeInto(LibraryManager.library, { #if ASSERTIONS #if MINIMAL_RUNTIME assert(typeof dynCalls != 'undefined', 'Global dynCalls dictionary was not generated in the build! Pass -sDEFAULT_LIBRARY_FUNCS_TO_INCLUDE=$dynCall linker flag to include it!'); - assert(sig in dynCalls, 'bad function pointer type - sig is not in dynCalls: \'' + sig + '\''); + assert(sig in dynCalls, `bad function pointer type - sig is not in dynCalls: '${sig}'`); #else - assert(('dynCall_' + sig) in Module, 'bad function pointer type - dynCall function not found for sig \'' + sig + '\''); + assert(('dynCall_' + sig) in Module, `bad function pointer type - dynCall function not found for sig '${sig}'`); #endif if (args && args.length) { // j (64-bit integer) must be passed in as two numbers [low 32, high 32]. @@ -3559,14 +3559,14 @@ mergeInto(LibraryManager.library, { $asyncLoad: function(url, onload, onerror, noRunDep) { var dep = !noRunDep ? getUniqueRunDependency('al ' + url) : ''; readAsync(url, (arrayBuffer) => { - assert(arrayBuffer, 'Loading data file "' + url + '" failed (no arrayBuffer).'); + assert(arrayBuffer, `Loading data file "${url}" failed (no arrayBuffer).`); onload(new Uint8Array(arrayBuffer)); if (dep) removeRunDependency(dep); }, (event) => { if (onerror) { onerror(); } else { - throw 'Loading data file "' + url + '" failed.'; + throw `Loading data file "${url}" failed.`; } }); if (dep) addRunDependency(dep); diff --git a/src/runtime_safe_heap.js b/src/runtime_safe_heap.js index 3ca4ea2c43b2f..dbb91468b2121 100644 --- a/src/runtime_safe_heap.js +++ b/src/runtime_safe_heap.js @@ -15,7 +15,7 @@ function getSafeHeapType(bytes, isFloat) { case 2: return 'i16'; case 4: return isFloat ? 'float' : 'i32'; case 8: return isFloat ? 'double' : 'i64'; - default: assert(0, 'getSafeHeapType() invalid bytes=' + bytes); + default: assert(0, `getSafeHeapType() invalid bytes=${bytes}`); } } @@ -31,11 +31,11 @@ function SAFE_HEAP_STORE(dest, value, bytes, isFloat) { #if SAFE_HEAP_LOG out('SAFE_HEAP store: ' + [dest, value, bytes, isFloat, SAFE_HEAP_COUNTER++]); #endif - if (dest <= 0) abort('segmentation fault storing ' + bytes + ' bytes to address ' + dest); + if (dest <= 0) abort(`segmentation fault storing ${bytes} bytes to address ${dest}`); #if SAFE_HEAP == 1 - if (dest % bytes !== 0) abort('alignment error storing to address ' + dest + ', which was expected to be aligned to a multiple of ' + bytes); + if (dest % bytes !== 0) abort(`alignment error storing to address ${dest}, which was expected to be aligned to a multiple of ${bytes}`); #else - if (dest % bytes !== 0) warnOnce('alignment error in a memory store operation, alignment was a multiple of ' + (((dest ^ (dest-1)) >> 1) + 1) + ', but was was expected to be aligned to a multiple of ' + bytes); + if (dest % bytes !== 0) warnOnce(`alignment error in a memory store operation, alignment was a multiple of ${(((dest ^ (dest-1)) >> 1) + 1)}, but was was expected to be aligned to a multiple of ${bytes}`); #endif #if EXIT_RUNTIME if (runtimeInitialized && !runtimeExited) { @@ -43,9 +43,9 @@ function SAFE_HEAP_STORE(dest, value, bytes, isFloat) { if (runtimeInitialized) { #endif var brk = _sbrk() >>> 0; - if (dest + bytes > brk) abort('segmentation fault, exceeded the top of the available dynamic heap when storing ' + bytes + ' bytes to address ' + dest + '. DYNAMICTOP=' + brk); - assert(brk >= _emscripten_stack_get_base(), "brk >= _emscripten_stack_get_base() (brk=" + brk + ", _emscripten_stack_get_base()=" + _emscripten_stack_get_base() + ')'); // sbrk-managed memory must be above the stack - assert(brk <= wasmMemory.buffer.byteLength, "brk <= wasmMemory.buffer.byteLength (brk=" + brk + ', wasmMemory.buffer.byteLength=' + wasmMemory.buffer.byteLength + ')'); + if (dest + bytes > brk) abort(`segmentation fault, exceeded the top of the available dynamic heap when storing ${bytes} bytes to address ${dest}. DYNAMICTOP=${brk}`); + assert(brk >= _emscripten_stack_get_base(), `brk >= _emscripten_stack_get_base() (brk=${brk}, _emscripten_stack_get_base()=${_emscripten_stack_get_base()})`); // sbrk-managed memory must be above the stack + assert(brk <= wasmMemory.buffer.byteLength, `brk <= wasmMemory.buffer.byteLength (brk=${brk}, wasmMemory.buffer.byteLength=${wasmMemory.buffer.byteLength})`); } setValue_safe(dest, value, getSafeHeapType(bytes, isFloat)); return value; @@ -59,11 +59,11 @@ function SAFE_HEAP_LOAD(dest, bytes, unsigned, isFloat) { #if CAN_ADDRESS_2GB dest >>>= 0; #endif - if (dest <= 0) abort('segmentation fault loading ' + bytes + ' bytes from address ' + dest); + if (dest <= 0) abort(`segmentation fault loading ${bytes} bytes from address ${dest}`); #if SAFE_HEAP == 1 - if (dest % bytes !== 0) abort('alignment error loading from address ' + dest + ', which was expected to be aligned to a multiple of ' + bytes); + if (dest % bytes !== 0) abort(`alignment error loading from address ${dest}, which was expected to be aligned to a multiple of ${bytes}`); #else - if (dest % bytes !== 0) warnOnce('alignment error in a memory load operation, alignment was a multiple of ' + (((dest ^ (dest-1)) >> 1) + 1) + ', but was was expected to be aligned to a multiple of ' + bytes); + if (dest % bytes !== 0) warnOnce(`alignment error in a memory load operation, alignment was a multiple of ${(((dest ^ (dest-1)) >> 1) + 1)}, but was was expected to be aligned to a multiple of ${bytes}`); #endif #if EXIT_RUNTIME if (runtimeInitialized && !runtimeExited) { @@ -71,9 +71,9 @@ function SAFE_HEAP_LOAD(dest, bytes, unsigned, isFloat) { if (runtimeInitialized) { #endif var brk = _sbrk() >>> 0; - if (dest + bytes > brk) abort('segmentation fault, exceeded the top of the available dynamic heap when loading ' + bytes + ' bytes from address ' + dest + '. DYNAMICTOP=' + brk); - assert(brk >= _emscripten_stack_get_base(), "brk >= _emscripten_stack_get_base() (brk=" + brk + ", _emscripten_stack_get_base()=" + _emscripten_stack_get_base() + ')'); // sbrk-managed memory must be above the stack - assert(brk <= wasmMemory.buffer.byteLength, "brk <= wasmMemory.buffer.byteLength (brk=" + brk + ', wasmMemory.buffer.byteLength=' + wasmMemory.buffer.byteLength + ')'); + if (dest + bytes > brk) abort(`segmentation fault, exceeded the top of the available dynamic heap when loading ${bytes} bytes from address ${dest}. DYNAMICTOP=${brk}`); + assert(brk >= _emscripten_stack_get_base(), `brk >= _emscripten_stack_get_base() (brk=${brk}, _emscripten_stack_get_base()=${_emscripten_stack_get_base()})`); // sbrk-managed memory must be above the stack + assert(brk <= wasmMemory.buffer.byteLength, `brk <= wasmMemory.buffer.byteLength (brk=${brk}, wasmMemory.buffer.byteLength=${wasmMemory.buffer.byteLength})`); } var type = getSafeHeapType(bytes, isFloat); var ret = getValue_safe(dest, type); @@ -90,7 +90,7 @@ function SAFE_HEAP_LOAD_D(dest, bytes, unsigned) { function SAFE_FT_MASK(value, mask) { var ret = value & mask; if (ret !== value) { - abort('Function table mask error: function pointer is ' + value + ' which is masked by ' + mask + ', the likely cause of this is that the function pointer is being called by the wrong type.'); + abort(`Function table mask error: function pointer is ${value} which is masked by ${mask}, the likely cause of this is that the function pointer is being called by the wrong type.`); } return ret; } diff --git a/test/other/metadce/test_metadce_hello_dylink.jssize b/test/other/metadce/test_metadce_hello_dylink.jssize index bc6d98594e845..fb3b566636284 100644 --- a/test/other/metadce/test_metadce_hello_dylink.jssize +++ b/test/other/metadce/test_metadce_hello_dylink.jssize @@ -1 +1 @@ -28153 +28151 diff --git a/test/other/test_unoptimized_code_size.js.size b/test/other/test_unoptimized_code_size.js.size index 10afb236d5a46..adf34be9a2082 100644 --- a/test/other/test_unoptimized_code_size.js.size +++ b/test/other/test_unoptimized_code_size.js.size @@ -1 +1 @@ -59646 +59636 diff --git a/test/other/test_unoptimized_code_size_strict.js.size b/test/other/test_unoptimized_code_size_strict.js.size index 0049768cac040..76e26a7c5e517 100644 --- a/test/other/test_unoptimized_code_size_strict.js.size +++ b/test/other/test_unoptimized_code_size_strict.js.size @@ -1 +1 @@ -58588 +58578 From 4874997d6a99af3b88de50fdae6e2c005536bf20 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 9 May 2023 12:40:41 -0700 Subject: [PATCH 0207/1523] Remove some hardcoded exports that can now be handled by JS __deps. NFC (#19313) See #18849 --- emcc.py | 26 +++++++------------ src/embind/embind.js | 4 +-- src/library_dylink.js | 2 +- src/library_fetch.js | 2 ++ src/library_webgl.js | 5 ++-- src/library_webgpu.js | 6 ++--- .../metadce/test_metadce_cxx_mangle.exports | 1 - .../metadce/test_metadce_cxx_mangle.size | 2 +- 8 files changed, 21 insertions(+), 27 deletions(-) diff --git a/emcc.py b/emcc.py index 5ae47aaab53ec..4eb50e9988563 100755 --- a/emcc.py +++ b/emcc.py @@ -2087,6 +2087,7 @@ def phase_linker_setup(options, state, newargs): if settings.MAIN_MODULE == 1: settings.INCLUDE_FULL_LIBRARY = 1 settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['$loadDylibs'] + settings.REQUIRED_EXPORTS += ['malloc'] if settings.MAIN_MODULE == 1 or settings.SIDE_MODULE == 1: settings.LINKABLE = 1 @@ -2339,7 +2340,7 @@ def phase_linker_setup(options, state, newargs): settings.FETCH_WORKER_FILE = unsuffixed_basename(target) + '.fetch.js' if settings.DEMANGLE_SUPPORT: - settings.REQUIRED_EXPORTS += ['__cxa_demangle'] + settings.REQUIRED_EXPORTS += ['__cxa_demangle', 'free'] settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['$demangle', '$stackTrace'] if settings.FULL_ES3: @@ -2413,11 +2414,6 @@ def phase_linker_setup(options, state, newargs): exit_with_error('-sPROXY_TO_PTHREAD requires -pthread to work!') settings.JS_LIBRARIES.append((0, 'library_pthread_stub.js')) - # TODO: Move this into the library JS file once it becomes possible. - # See https://github.com/emscripten-core/emscripten/pull/15982 - if settings.INCLUDE_FULL_LIBRARY and not settings.DISABLE_EXCEPTION_CATCHING: - settings.EXPORTED_FUNCTIONS += ['___get_exception_message', '_free'] - if settings.MEMORY64: if settings.ASYNCIFY and settings.MEMORY64 == 1: exit_with_error('MEMORY64=1 is not compatible with ASYNCIFY') @@ -2760,20 +2756,16 @@ def check_memory_setting(setting): # need to be able to call these explicitly. settings.REQUIRED_EXPORTS += ['__funcs_on_exit'] - # various settings require malloc/free support from JS - if settings.RELOCATABLE or \ - settings.BUILD_AS_WORKER or \ - settings.USE_WEBGPU or \ - settings.OFFSCREENCANVAS_SUPPORT or \ - settings.LEGACY_GL_EMULATION or \ + # Some settings require malloc/free to be exported explictly. + # In most cases, the inclustion of native symbols like malloc and free + # is taken care of by wasm-ld use its normal symbol resolution process. + # However, when JS symbols are exported explictly via + # DEFAULT_LIBRARY_FUNCS_TO_INCLUDE and they depend on native symbols + # we need to explictly require those exports. + if settings.BUILD_AS_WORKER or \ settings.ASYNCIFY or \ settings.WASMFS or \ - settings.DEMANGLE_SUPPORT or \ settings.FORCE_FILESYSTEM or \ - settings.STB_IMAGE or \ - settings.EMBIND or \ - settings.FETCH or \ - settings.PROXY_POSIX_SOCKETS or \ options.memory_profiler or \ sanitize: settings.REQUIRED_EXPORTS += ['malloc', 'free'] diff --git a/src/embind/embind.js b/src/embind/embind.js index 8ee41866e6f71..c3f4fa33b26c4 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -371,7 +371,7 @@ var LibraryEmbind = { return ret; }, - $getTypeName__deps: ['$readLatin1String', '__getTypeName'], + $getTypeName__deps: ['$readLatin1String', '__getTypeName', 'free'], $getTypeName: function(type) { var ptr = ___getTypeName(type); var rv = readLatin1String(ptr); @@ -651,7 +651,7 @@ var LibraryEmbind = { _embind_register_std_string__deps: [ '$readLatin1String', '$registerType', '$simpleReadValueFromPointer', '$throwBindingError', - '$stringToUTF8', '$lengthBytesUTF8'], + '$stringToUTF8', '$lengthBytesUTF8', 'malloc', 'free'], _embind_register_std_string: function(rawType, name) { name = readLatin1String(name); var stdStringIsUTF8 diff --git a/src/library_dylink.js b/src/library_dylink.js index 471f73cf84ab4..f3ae85930657f 100644 --- a/src/library_dylink.js +++ b/src/library_dylink.js @@ -379,7 +379,7 @@ var LibraryDylink = { // Allocate memory even if malloc isn't ready yet. The allocated memory here // must be zero initialized since its used for all static data, including bss. $getMemory__noleakcheck: true, - $getMemory__deps: ['$GOT', '__heap_base', '$zeroMemory'], + $getMemory__deps: ['$GOT', '__heap_base', '$zeroMemory', 'malloc'], $getMemory: function(size) { // After the runtime is initialized, we must only use sbrk() normally. #if DYLINK_DEBUG diff --git a/src/library_fetch.js b/src/library_fetch.js index f2d470ff03f34..5b6ba93dddf8e 100644 --- a/src/library_fetch.js +++ b/src/library_fetch.js @@ -28,6 +28,8 @@ var LibraryFetch = { emscripten_start_fetch: startFetch, emscripten_start_fetch__deps: [ + 'malloc', + 'free', '$Fetch', '$fetchXHR', '$callUserCallback', diff --git a/src/library_webgl.js b/src/library_webgl.js index 0350f6236c435..ebf20a9e155e7 100644 --- a/src/library_webgl.js +++ b/src/library_webgl.js @@ -152,6 +152,7 @@ var LibraryGL = { $GL__deps: [ #if PTHREADS 'malloc', // Needed by registerContext + 'free', // Needed by deleteContext #endif #if MIN_WEBGL_VERSION == 1 '$webgl_enable_ANGLE_instanced_arrays', @@ -3933,7 +3934,7 @@ var LibraryGL = { } }, - glMapBufferRange__deps: ['$emscriptenWebGLGetBufferBinding', '$emscriptenWebGLValidateMapBufferTarget'], + glMapBufferRange__deps: ['$emscriptenWebGLGetBufferBinding', '$emscriptenWebGLValidateMapBufferTarget', 'malloc'], glMapBufferRange: function(target, offset, length, access) { if ((access & (0x1/*GL_MAP_READ_BIT*/ | 0x20/*GL_MAP_UNSYNCHRONIZED_BIT*/)) != 0) { err("glMapBufferRange access does not support MAP_READ or MAP_UNSYNCHRONIZED"); @@ -4015,7 +4016,7 @@ var LibraryGL = { HEAPU8.subarray(mapping.mem + offset, mapping.mem + offset + length)); }, - glUnmapBuffer__deps: ['$emscriptenWebGLGetBufferBinding', '$emscriptenWebGLValidateMapBufferTarget'], + glUnmapBuffer__deps: ['$emscriptenWebGLGetBufferBinding', '$emscriptenWebGLValidateMapBufferTarget', 'free'], glUnmapBuffer: function(target) { if (!emscriptenWebGLValidateMapBufferTarget(target)) { GL.recordError(0x500/*GL_INVALID_ENUM*/); diff --git a/src/library_webgpu.js b/src/library_webgpu.js index 47f1954530497..4eeff83cea1ef 100644 --- a/src/library_webgpu.js +++ b/src/library_webgpu.js @@ -810,7 +810,7 @@ var LibraryWebGPU = { device.label = UTF8ToString(labelPtr); }, - wgpuDeviceSetDeviceLostCallback__deps: ['$callUserCallback', '$stringToNewUTF8'], + wgpuDeviceSetDeviceLostCallback__deps: ['$callUserCallback', '$stringToNewUTF8', 'free'], wgpuDeviceSetDeviceLostCallback: function(deviceId, callback, userdata) { var deviceWrapper = WebGPU.mgrDevice.objects[deviceId]; {{{ gpu.makeCheckDefined('deviceWrapper') }}} @@ -2432,7 +2432,7 @@ var LibraryWebGPU = { #endif }, - wgpuInstanceRequestAdapter__deps: ['$callUserCallback', '$stringToNewUTF8'], + wgpuInstanceRequestAdapter__deps: ['$callUserCallback', '$stringToNewUTF8', 'free'], wgpuInstanceRequestAdapter: function(instanceId, options, callback, userdata) { {{{ gpu.makeCheck('instanceId === 0, "WGPUInstance is ignored"') }}} @@ -2513,7 +2513,7 @@ var LibraryWebGPU = { return adapter.features.has(WebGPU.FeatureName[featureEnumValue]); }, - wgpuAdapterRequestDevice__deps: ['$callUserCallback', '$stringToNewUTF8'], + wgpuAdapterRequestDevice__deps: ['$callUserCallback', '$stringToNewUTF8', 'free'], wgpuAdapterRequestDevice: function(adapterId, descriptor, callback, userdata) { var adapter = WebGPU.mgrAdapter.get(adapterId); diff --git a/test/other/metadce/test_metadce_cxx_mangle.exports b/test/other/metadce/test_metadce_cxx_mangle.exports index 2a14e2cb1fbda..33a07671bf2f2 100644 --- a/test/other/metadce/test_metadce_cxx_mangle.exports +++ b/test/other/metadce/test_metadce_cxx_mangle.exports @@ -16,7 +16,6 @@ dynCall_viijii free getTempRet0 main -malloc memory setTempRet0 setThrew diff --git a/test/other/metadce/test_metadce_cxx_mangle.size b/test/other/metadce/test_metadce_cxx_mangle.size index 4cc57b2d3f06f..d310455c80818 100644 --- a/test/other/metadce/test_metadce_cxx_mangle.size +++ b/test/other/metadce/test_metadce_cxx_mangle.size @@ -1 +1 @@ -219427 +219418 From 344f0774c4b0c17ec9039d9eea221667a6220ba1 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Morin <38703886+JeanChristopheMorinPerso@users.noreply.github.com> Date: Tue, 9 May 2023 16:37:38 -0400 Subject: [PATCH 0208/1523] Embind: Make subclasses inherit class functions (#18794) --- src/embind/embind.js | 19 +++++++++++++++++++ test/embind/embind.test.js | 6 ++++++ test/embind/embind_test.cpp | 8 ++++++++ 3 files changed, 33 insertions(+) diff --git a/src/embind/embind.js b/src/embind/embind.js index c3f4fa33b26c4..15c021ab7ce14 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -2047,6 +2047,15 @@ var LibraryEmbind = { upcast, downcast); + if (registeredClass.baseClass) { + // Keep track of class hierarchy. Used to allow sub-classes to inherit class functions. + if (registeredClass.baseClass.__derivedClasses === undefined) { + registeredClass.baseClass.__derivedClasses = []; + } + + registeredClass.baseClass.__derivedClasses.push(registeredClass); + } + var referenceConverter = new RegisteredPointer(name, registeredClass, true, @@ -2353,6 +2362,16 @@ var LibraryEmbind = { } else { proto[methodName].overloadTable[argCount-1] = func; } + + if (classType.registeredClass.__derivedClasses) { + for (const derivedClass of classType.registeredClass.__derivedClasses) { + if (!derivedClass.constructor.hasOwnProperty(methodName)) { + // TODO: Add support for overloads + derivedClass.constructor[methodName] = func; + } + } + } + return []; }); return []; diff --git a/test/embind/embind.test.js b/test/embind/embind.test.js index 5578350e2099f..141fa4f1c0ec3 100644 --- a/test/embind/embind.test.js +++ b/test/embind/embind.test.js @@ -111,6 +111,12 @@ module({ derived.delete(); }); + test("class functions are inherited in subclasses", function() { + assert.equal("Base", cm.Base.classFunction()); + assert.equal("Derived", cm.Derived.classFunction()); + assert.equal("Derived", cm.DerivedTwice.classFunction()); + }); + test("calling method on unrelated class throws error", function() { var a = new cm.HasTwoBases; var e = assert.throws(cm.BindingError, function() { diff --git a/test/embind/embind_test.cpp b/test/embind/embind_test.cpp index 8000425b6db19..2897adaabf0ec 100644 --- a/test/embind/embind_test.cpp +++ b/test/embind/embind_test.cpp @@ -490,6 +490,9 @@ class Base { int getBaseMember() { return baseMember; } + static std::string classFunction() { + return "Base"; + }; std::string name; int member; int baseMember; @@ -546,6 +549,9 @@ class Derived : public Base{ int getMember() { return member; } + static std::string classFunction() { + return "Derived"; + } int member; private: std::string name_; @@ -2019,6 +2025,7 @@ EMSCRIPTEN_BINDINGS(tests) { .function("getMember", &Derived::getMember) .function("setMember", &Derived::setMember) .property("member", &Derived::member) + .class_function("classFunction", &Derived::classFunction) ; class_("Base") @@ -2033,6 +2040,7 @@ EMSCRIPTEN_BINDINGS(tests) { .function("setBaseMember", &Base::setBaseMember) .property("member", &Base::member) .property("baseMember", &Base::baseMember) + .class_function("classFunction", &Base::classFunction) ; class_("SecondBase") From b280116b23ca8b734f18bac34994df5b767d9ef6 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 9 May 2023 13:50:08 -0700 Subject: [PATCH 0209/1523] Avoid using String.replaceAll at compile time. NFC (#19314) This requires node v15, and we still support running on older versions. See #19280 --- .circleci/config.yml | 1 + src/library_async.js | 2 +- test/test_other.py | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index ffd8a4ce41e27..6a0e118f66c16 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -577,6 +577,7 @@ jobs: other.test_gen_struct_info other.test_native_call_before_init other.test_node_unhandled_rejection + other.test_full_js_library core2.test_hello_world" # Run a few test with the most recent version of node # In particular we have some tests that require node flags on older diff --git a/src/library_async.js b/src/library_async.js index a995dc01e2e73..541cc04d06ed5 100644 --- a/src/library_async.js +++ b/src/library_async.js @@ -38,7 +38,7 @@ mergeInto(LibraryManager.library, { #if ASYNCIFY_DEBUG dbg('asyncify instrumenting imports'); #endif - var importPatterns = [{{{ ASYNCIFY_IMPORTS.map(x => new RegExp('^' + x.split('.')[1].replaceAll('*', '.*') + '$')) }}}]; + var importPatterns = [{{{ ASYNCIFY_IMPORTS.map(x => '/^' + x.split('.')[1].replace(new RegExp('\\*', 'g'), '.*') + '$/') }}}]; for (var x in imports) { (function(x) { diff --git a/test/test_other.py b/test/test_other.py index aecd266dab506..f721de4d4cb6e 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -8666,7 +8666,7 @@ def test(check, extra): self.assertNotContained(WARNING, proc.stderr) def test_full_js_library(self): - self.run_process([EMCC, test_file('hello_world.c'), '-sSTRICT_JS', '-sINCLUDE_FULL_LIBRARY']) + self.run_process([EMCC, test_file('hello_world.c'), '-sSTRICT_JS', '-sINCLUDE_FULL_LIBRARY', '-sASYNCIFY']) def test_full_js_library_undefined(self): create_file('main.c', 'void foo(); int main() { foo(); return 0; }') From 2749bae2374668a3a38f0866eaf7eb2e73c23c65 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 9 May 2023 15:08:17 -0700 Subject: [PATCH 0210/1523] Feedback from #19314 (#19318) --- .circleci/config.yml | 2 +- test/test_other.py | 20 +++++++++----------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 6a0e118f66c16..3e1da78df32f5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -577,7 +577,7 @@ jobs: other.test_gen_struct_info other.test_native_call_before_init other.test_node_unhandled_rejection - other.test_full_js_library + other.test_full_js_library* core2.test_hello_world" # Run a few test with the most recent version of node # In particular we have some tests that require node flags on older diff --git a/test/test_other.py b/test/test_other.py index f721de4d4cb6e..88a25c67274ca 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -8665,8 +8665,15 @@ def test(check, extra): proc = test(check=True, extra=['-sIGNORE_CLOSURE_COMPILER_ERRORS']) self.assertNotContained(WARNING, proc.stderr) - def test_full_js_library(self): - self.run_process([EMCC, test_file('hello_world.c'), '-sSTRICT_JS', '-sINCLUDE_FULL_LIBRARY', '-sASYNCIFY']) + @parameterized({ + '': ([],), + 'asyncify': (['-sASYNCIFY'],), + 'gl_emu': (['-sLEGACY_GL_EMULATION'],), + 'no_exception_throwing': (['-sDISABLE_EXCEPTION_THROWING'],), + 'minimal_runtime': (['-sMINIMAL_RUNTIME'],), + }) + def test_full_js_library(self, args): + self.run_process([EMCC, test_file('hello_world.c'), '-sSTRICT_JS', '-sINCLUDE_FULL_LIBRARY'] + args) def test_full_js_library_undefined(self): create_file('main.c', 'void foo(); int main() { foo(); return 0; }') @@ -8678,15 +8685,6 @@ def test_full_js_library_except(self): self.set_setting('DISABLE_EXCEPTION_CATCHING', 0) self.do_other_test('test_full_js_library_except.cpp') - def test_full_js_library_gl_emu(self): - self.run_process([EMCC, test_file('hello_world.c'), '-sSTRICT_JS', '-sINCLUDE_FULL_LIBRARY', '-sLEGACY_GL_EMULATION']) - - def test_full_js_library_no_exception_throwing(self): - self.run_process([EMCC, test_file('hello_world.c'), '-sSTRICT_JS', '-sINCLUDE_FULL_LIBRARY', '-sDISABLE_EXCEPTION_THROWING']) - - def test_full_js_library_minimal_runtime(self): - self.run_process([EMCC, test_file('hello_world.c'), '-sSTRICT_JS', '-sINCLUDE_FULL_LIBRARY', '-sMINIMAL_RUNTIME']) - @crossplatform @parameterized({ '': [[]], From d9a6a12076aafeda9067241c2ddad773db224e5b Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 9 May 2023 15:54:25 -0700 Subject: [PATCH 0211/1523] Minor cleanups to library_webgpu.js (#19316) - Use arrow functions. - Use stack space for error messages --- src/library_webgpu.js | 119 +++++++++++++++++++++--------------------- 1 file changed, 59 insertions(+), 60 deletions(-) diff --git a/src/library_webgpu.js b/src/library_webgpu.js index 4eeff83cea1ef..f09e57eebb878 100644 --- a/src/library_webgpu.js +++ b/src/library_webgpu.js @@ -162,7 +162,15 @@ var LibraryWebGPU = { $WebGPU__postset: 'WebGPU.initManagers();', + $WebGPU__deps: ['$withStackSave', '$stringToUTF8OnStack'], $WebGPU: { + errorCallback: function(callback, type, message, userdata) { + withStackSave(() => { + var messagePtr = stringToUTF8OnStack(message); + {{{ makeDynCall('viii', 'callback') }}}(type, messagePtr, userdata); + }); + }, + initManagers: function() { if (WebGPU.mgrDevice) return; @@ -770,13 +778,13 @@ var LibraryWebGPU = { device["pushErrorScope"](WebGPU.ErrorFilter[filter]); }, - wgpuDevicePopErrorScope__deps: ['$callUserCallback', '$stringToNewUTF8'], + wgpuDevicePopErrorScope__deps: ['$callUserCallback'], wgpuDevicePopErrorScope: function(deviceId, callback, userdata) { var device = WebGPU.mgrDevice.get(deviceId); {{{ runtimeKeepalivePush() }}} - device["popErrorScope"]().then(function(gpuError) { + device["popErrorScope"]().then((gpuError) => { {{{ runtimeKeepalivePop() }}} - callUserCallback(function() { + callUserCallback(() => { if (!gpuError) { {{{ makeDynCall('viii', 'callback') }}}( {{{ gpu.ErrorType.NoError }}}, 0, userdata); @@ -787,20 +795,16 @@ var LibraryWebGPU = { #if ASSERTIONS assert(gpuError instanceof GPUValidationError); #endif - var messagePtr = stringToNewUTF8(gpuError.message); - {{{ makeDynCall('viii', 'callback') }}}({{{ gpu.ErrorType.Validation }}}, messagePtr, userdata); - _free(messagePtr); + WebGPU.errorCallback(callback, {{{ gpu.ErrorType.Validation }}}, gpuError.message, userdata); } }); - }, function(ex) { + }, (ex) => { {{{ runtimeKeepalivePop() }}} - callUserCallback(function() { - var messagePtr = stringToNewUTF8(ex.message); + callUserCallback(() => { // TODO: This can mean either the device was lost or the error scope stack was empty. Figure // out how to synthesize the DeviceLost error type. (Could be by simply tracking the error // scope depth, but that isn't ideal.) - {{{ makeDynCall('viii', 'callback') }}}({{{ gpu.ErrorType.Unknown }}}, messagePtr, userdata); - _free(messagePtr); + WebGPU.errorCallback(callback, {{{ gpu.ErrorType.Unknown }}}, ex.message, userdata); }); }); }, @@ -810,32 +814,27 @@ var LibraryWebGPU = { device.label = UTF8ToString(labelPtr); }, - wgpuDeviceSetDeviceLostCallback__deps: ['$callUserCallback', '$stringToNewUTF8', 'free'], + wgpuDeviceSetDeviceLostCallback__deps: ['$callUserCallback'], wgpuDeviceSetDeviceLostCallback: function(deviceId, callback, userdata) { var deviceWrapper = WebGPU.mgrDevice.objects[deviceId]; {{{ gpu.makeCheckDefined('deviceWrapper') }}} if (!deviceWrapper.lostCallback) { // device.lost hasn't been registered yet - register it. - deviceWrapper.object["lost"].then(function(info) { - deviceWrapper.lostCallback(info); - }); + deviceWrapper.object["lost"].then((info) => deviceWrapper.lostCallback(info)); } - deviceWrapper.lostCallback = function(info) { + deviceWrapper.lostCallback = (info) => { // This will skip the callback if the runtime is no longer alive. - callUserCallback(function() { - var messagePtr = stringToNewUTF8(info.message); - {{{ makeDynCall('viii', 'callback') }}}(WebGPU.DeviceLostReason[info.reason], messagePtr, userdata); - _free(messagePtr); - }); + callUserCallback(() => WebGPU.errorCallback(callback, WebGPU.DeviceLostReason[info.reason], + info.message, userdata)); }; }, - wgpuDeviceSetUncapturedErrorCallback__deps: ['$callUserCallback', '$stringToNewUTF8'], + wgpuDeviceSetUncapturedErrorCallback__deps: ['$callUserCallback'], wgpuDeviceSetUncapturedErrorCallback: function(deviceId, callback, userdata) { var device = WebGPU.mgrDevice.get(deviceId); device["onuncapturederror"] = function(ev) { // This will skip the callback if the runtime is no longer alive. - callUserCallback(function() { + callUserCallback(() => { // WGPUErrorType type, const char* message, void* userdata var Validation = 0x00000001; var OutOfMemory = 0x00000002; @@ -847,9 +846,7 @@ var LibraryWebGPU = { if (ev.error instanceof GPUValidationError) type = Validation; else if (ev.error instanceof GPUOutOfMemoryError) type = OutOfMemory; - var messagePtr = stringToNewUTF8(ev.error.message); - {{{ makeDynCall('viii', 'callback') }}}(type, messagePtr, userdata); - _free(messagePtr); + WebGPU.errorCallback(callback, type, ev.error.message, userdata); }); }; }, @@ -1506,14 +1503,14 @@ var LibraryWebGPU = { #endif {{{ runtimeKeepalivePush() }}} - queue["onSubmittedWorkDone"]().then(function() { + queue["onSubmittedWorkDone"]().then(() => { {{{ runtimeKeepalivePop() }}} - callUserCallback(function() { + callUserCallback(() => { {{{ makeDynCall('vii', 'callback') }}}({{{ gpu.QueueWorkDoneStatus.Success }}}, userdata); }); - }, function() { + }, () => { {{{ runtimeKeepalivePop() }}} - callUserCallback(function() { + callUserCallback(() => { {{{ makeDynCall('vii', 'callback') }}}({{{ gpu.QueueWorkDoneStatus.Error }}}, userdata); }); }); @@ -1885,9 +1882,7 @@ var LibraryWebGPU = { var data = _malloc(mapped.byteLength); HEAPU8.set(new Uint8Array(mapped), data); - bufferWrapper.onUnmap.push(function() { - _free(data); - }); + bufferWrapper.onUnmap.push(() => _free(data)); return data; }, @@ -1924,7 +1919,7 @@ var LibraryWebGPU = { var data = _malloc(mapped.byteLength); HEAPU8.fill(0, data, mapped.byteLength); - bufferWrapper.onUnmap.push(function() { + bufferWrapper.onUnmap.push(() => { new Uint8Array(mapped).set(HEAPU8.subarray(data, data + mapped.byteLength)); _free(data); }); @@ -1947,14 +1942,14 @@ var LibraryWebGPU = { // `callback` takes (WGPUBufferMapAsyncStatus status, void * userdata) {{{ runtimeKeepalivePush() }}} - buffer["mapAsync"](mode, offset, size).then(function() { + buffer["mapAsync"](mode, offset, size).then(() => { {{{ runtimeKeepalivePop() }}} - callUserCallback(function() { + callUserCallback(() => { {{{ makeDynCall('vii', 'callback') }}}({{{ gpu.BufferMapAsyncStatus.Success }}}, userdata); }); - }, function() { + }, () => { {{{ runtimeKeepalivePop() }}} - callUserCallback(function() { + callUserCallback(() => { // TODO(kainino0x): Figure out how to pick other error status values. {{{ makeDynCall('vii', 'callback') }}}({{{ gpu.BufferMapAsyncStatus.Error }}}, userdata); }); @@ -2432,7 +2427,7 @@ var LibraryWebGPU = { #endif }, - wgpuInstanceRequestAdapter__deps: ['$callUserCallback', '$stringToNewUTF8', 'free'], + wgpuInstanceRequestAdapter__deps: ['$callUserCallback', '$stringToUTF8OnStack'], wgpuInstanceRequestAdapter: function(instanceId, options, callback, userdata) { {{{ gpu.makeCheck('instanceId === 0, "WGPUInstance is ignored"') }}} @@ -2448,31 +2443,34 @@ var LibraryWebGPU = { } if (!('gpu' in navigator)) { - var messagePtr = stringToNewUTF8('WebGPU not available on this browser (navigator.gpu is not available)'); - {{{ makeDynCall('viiii', 'callback') }}}({{{ gpu.RequestAdapterStatus.Unavailable }}}, 0, messagePtr, userdata); - _free(messagePtr); + withStackSave(() => { + var messagePtr = stringToUTF8OnStack('WebGPU not available on this browser (navigator.gpu is not available)'); + {{{ makeDynCall('viiii', 'callback') }}}({{{ gpu.RequestAdapterStatus.Unavailable }}}, 0, messagePtr, userdata); + }); return; } {{{ runtimeKeepalivePush() }}} - navigator["gpu"]["requestAdapter"](opts).then(function(adapter) { + navigator["gpu"]["requestAdapter"](opts).then((adapter) => { {{{ runtimeKeepalivePop() }}} - callUserCallback(function() { + callUserCallback(() => { if (adapter) { var adapterId = WebGPU.mgrAdapter.create(adapter); {{{ makeDynCall('viiii', 'callback') }}}({{{ gpu.RequestAdapterStatus.Success }}}, adapterId, 0, userdata); } else { - var messagePtr = stringToNewUTF8('WebGPU not available on this system (requestAdapter returned null)'); - {{{ makeDynCall('viiii', 'callback') }}}({{{ gpu.RequestAdapterStatus.Unavailable }}}, 0, messagePtr, userdata); - _free(messagePtr); + withStackSave(() => { + var messagePtr = stringToUTF8OnStack('WebGPU not available on this system (requestAdapter returned null)'); + {{{ makeDynCall('viiii', 'callback') }}}({{{ gpu.RequestAdapterStatus.Unavailable }}}, 0, messagePtr, userdata); + }); } }); - }, function(ex) { + }, (ex) => { {{{ runtimeKeepalivePop() }}} - callUserCallback(function() { - var messagePtr = stringToNewUTF8(ex.message); - {{{ makeDynCall('viiii', 'callback') }}}({{{ gpu.RequestAdapterStatus.Error }}}, 0, messagePtr, userdata); - _free(messagePtr); + callUserCallback(() => { + withStackSave(() => { + var messagePtr = stringToUTF8OnStack(ex.message); + {{{ makeDynCall('viiii', 'callback') }}}({{{ gpu.RequestAdapterStatus.Error }}}, 0, messagePtr, userdata); + }); }); }); }, @@ -2513,7 +2511,7 @@ var LibraryWebGPU = { return adapter.features.has(WebGPU.FeatureName[featureEnumValue]); }, - wgpuAdapterRequestDevice__deps: ['$callUserCallback', '$stringToNewUTF8', 'free'], + wgpuAdapterRequestDevice__deps: ['$callUserCallback', '$stringToUTF8OnStack'], wgpuAdapterRequestDevice: function(adapterId, descriptor, callback, userdata) { var adapter = WebGPU.mgrAdapter.get(adapterId); @@ -2524,7 +2522,7 @@ var LibraryWebGPU = { if (requiredFeaturesCount) { var requiredFeaturesPtr = {{{ makeGetValue('descriptor', C_STRUCTS.WGPUDeviceDescriptor.requiredFeatures, '*') }}}; desc["requiredFeatures"] = Array.from(HEAP32.subarray(requiredFeaturesPtr >> 2, (requiredFeaturesPtr >> 2) + requiredFeaturesCount), - function(feature) { return WebGPU.FeatureName[feature]; }); + (feature) => WebGPU.FeatureName[feature]); } var requiredLimitsPtr = {{{ makeGetValue('descriptor', C_STRUCTS.WGPUDeviceDescriptor.requiredLimits, '*') }}}; if (requiredLimitsPtr) { @@ -2592,19 +2590,20 @@ var LibraryWebGPU = { } {{{ runtimeKeepalivePush() }}} - adapter["requestDevice"](desc).then(function(device) { + adapter["requestDevice"](desc).then((device) => { {{{ runtimeKeepalivePop() }}} - callUserCallback(function() { + callUserCallback(() => { var deviceWrapper = { queueId: WebGPU.mgrQueue.create(device["queue"]) }; var deviceId = WebGPU.mgrDevice.create(device, deviceWrapper); {{{ makeDynCall('viiii', 'callback') }}}({{{ gpu.RequestDeviceStatus.Success }}}, deviceId, 0, userdata); }); }, function(ex) { {{{ runtimeKeepalivePop() }}} - callUserCallback(function() { - var messagePtr = stringToNewUTF8(ex.message); - {{{ makeDynCall('viiii', 'callback') }}}({{{ gpu.RequestDeviceStatus.Error }}}, 0, messagePtr, userdata); - _free(messagePtr); + callUserCallback(() => { + withStackSave(() => { + var messagePtr = stringToUTF8OnStack(ex.message); + {{{ makeDynCall('viiii', 'callback') }}}({{{ gpu.RequestDeviceStatus.Error }}}, 0, messagePtr, userdata); + }); }); }); }, From 91194285ea29eb56204cb26a897141977b53b5b5 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 9 May 2023 15:55:32 -0700 Subject: [PATCH 0212/1523] Remove references to RESERVED_FUNCTION_POINTERS. NFC (#19315) This setting was replaced by ALLOW_TABLE_GROWTH a long time ago. --- site/source/docs/compiling/WebAssembly.rst | 13 ------------- test/test_core.py | 18 +++++++----------- 2 files changed, 7 insertions(+), 24 deletions(-) diff --git a/site/source/docs/compiling/WebAssembly.rst b/site/source/docs/compiling/WebAssembly.rst index 80faf4ae99b2a..979855e8fbb4b 100644 --- a/site/source/docs/compiling/WebAssembly.rst +++ b/site/source/docs/compiling/WebAssembly.rst @@ -75,19 +75,6 @@ upgrade from fastcomp to upstream: `strip` on an archive file that contains WebAssembly object files it will remove the index which makes the archive unusable at link time. -* Fastcomp emits asm.js and so has some limitations on function pointers. For - example, the ``RESERVED_FUNCTION_POINTERS`` setting exists there to work - around the fact that we can't grow the table. In the upstream backend table - growth is easy, and you can just enable ``ALLOW_TABLE_GROWTH``. - -* Fastcomp and upstream use very different LLVM and clang versions (fastcomp - has been stuck on LLVM 6, upstream is many releases after). This affects - optimizations, usually by making the upstream version faster and smaller. - However, in rare cases you may see a regression (for example, in some cases - *UN*-optimized code may be - `less optimal in upstream `_, - so make sure to optimize both when compiling and when linking). - * Also see the `blocker bugs on the wasm backend `_, and the `wasm backend tagged issues `_. Trapping diff --git a/test/test_core.py b/test/test_core.py index 45964cbc6929d..d086326e639dd 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -7410,17 +7410,15 @@ def test_large_exported_response(self): def test_add_function(self): self.set_setting('INVOKE_RUN', 0) self.set_setting('WASM_ASYNC_COMPILATION', 0) - self.set_setting('RESERVED_FUNCTION_POINTERS') + self.set_setting('ALLOW_TABLE_GROWTH') self.set_setting('EXPORTED_RUNTIME_METHODS', ['callMain']) - src = test_file('interop/test_add_function.cpp') - post_js = test_file('interop/test_add_function_post.js') - self.emcc_args += ['--post-js', post_js] + self.emcc_args += ['--post-js', test_file('interop/test_add_function_post.js')] print('basics') self.do_run_in_out_file_test('interop/test_add_function.cpp') - print('with RESERVED_FUNCTION_POINTERS=0') - self.set_setting('RESERVED_FUNCTION_POINTERS', 0) + print('with ALLOW_TABLE_GROWTH=0') + self.set_setting('ALLOW_TABLE_GROWTH', 0) expected = 'Unable to grow wasm table' if self.is_wasm2js(): # in wasm2js the error message doesn't come from the VM, but from our @@ -7429,7 +7427,7 @@ def test_add_function(self): # shows a generic error. expected = 'wasmTable.grow is not a function' - self.do_runf(src, expected, assert_returncode=NON_ZERO) + self.do_runf(test_file('interop/test_add_function.cpp'), expected, assert_returncode=NON_ZERO) print('- with table growth') self.set_setting('ALLOW_TABLE_GROWTH') @@ -9573,16 +9571,14 @@ def test_Module_dynamicLibraries_pthreads(self): # Tests the emscripten_get_exported_function() API. def test_emscripten_get_exported_function(self): - # Could also test with -sALLOW_TABLE_GROWTH - self.set_setting('RESERVED_FUNCTION_POINTERS', 2) + self.set_setting('ALLOW_TABLE_GROWTH') self.emcc_args += ['-lexports.js'] self.do_core_test('test_get_exported_function.cpp') # Tests the emscripten_get_exported_function() API. @no_asan('TODO: ASan support in minimal runtime') def test_minimal_runtime_emscripten_get_exported_function(self): - # Could also test with -sALLOW_TABLE_GROWTH - self.set_setting('RESERVED_FUNCTION_POINTERS', 2) + self.set_setting('ALLOW_TABLE_GROWTH') self.set_setting('MINIMAL_RUNTIME') self.emcc_args += ['--pre-js', test_file('minimal_runtime_exit_handling.js')] self.emcc_args += ['-lexports.js'] From 75c7902f4768fe9951d8fcf6b479492bb6b86219 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 9 May 2023 17:55:07 -0700 Subject: [PATCH 0213/1523] Use musl's stub implementation of dladdr. NFC (#19319) --- ChangeLog.md | 2 ++ src/library_dylink.js | 5 ----- src/library_sigs.js | 1 - system/lib/libc/dynlink.c | 10 ---------- test/test_core.py | 9 ++------- test/test_other.py | 10 ++++++---- tools/system_libs.py | 2 +- 7 files changed, 11 insertions(+), 28 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index dce73b8ce0606..cb002a75f86e4 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -20,6 +20,8 @@ See docs/process.md for more on how version tagging works. 3.1.38 (in development) ----------------------- +- The `dladdr` function will now always return an error rather than filling in + dummy values. (#19319) - The restriction preventing the use of dynamic linking in combination with `-sDYNAMIC_EXECUTION=0` was removed. This restriction was being enforced unnecessarily since dynamic linking has not depended on `eval()` for a while diff --git a/src/library_dylink.js b/src/library_dylink.js index f3ae85930657f..69465884a85f5 100644 --- a/src/library_dylink.js +++ b/src/library_dylink.js @@ -281,7 +281,6 @@ var LibraryDylink = { dlopen__deps: [function() { error(dlopenMissingError); }], emscripten_dlopen__deps: [function() { error(dlopenMissingError); }], __dlsym__deps: [function() { error(dlopenMissingError); }], - dladdr__deps: [function() { error(dlopenMissingError); }], #else $dlopenMissingError: `= ${dlopenMissingError}`, _dlopen_js__deps: ['$dlopenMissingError'], @@ -291,7 +290,6 @@ var LibraryDylink = { dlopen__deps: ['$dlopenMissingError'], emscripten_dlopen__deps: ['$dlopenMissingError'], __dlsym__deps: ['$dlopenMissingError'], - dladdr__deps: ['$dlopenMissingError'], #endif _dlopen_js: function(handle) { abort(dlopenMissingError); @@ -314,9 +312,6 @@ var LibraryDylink = { __dlsym: function(handle, symbol) { abort(dlopenMissingError); }, - dladdr: function() { - abort(dlopenMissingError); - }, #else // MAIN_MODULE != 0 // dynamic linker/loader (a-la ld.so on ELF systems) $LDSO__deps: ['$newDSO'], diff --git a/src/library_sigs.js b/src/library_sigs.js index f1ea60b5ec53b..688854ff66566 100644 --- a/src/library_sigs.js +++ b/src/library_sigs.js @@ -461,7 +461,6 @@ sigs = { boxRGBA__sig: 'ipiiiiiiii', clock_res_get__sig: 'iip', clock_time_get__sig: 'iijp', - dladdr__sig: 'ipp', dlopen__sig: 'ppi', eglBindAPI__sig: 'ii', eglChooseConfig__sig: 'ipppip', diff --git a/system/lib/libc/dynlink.c b/system/lib/libc/dynlink.c index a5c19d977b738..4f98f3e3e67a7 100644 --- a/system/lib/libc/dynlink.c +++ b/system/lib/libc/dynlink.c @@ -584,13 +584,3 @@ void* __dlsym(void* restrict p, const char* restrict s, void* restrict ra) { do_write_unlock(); return res; } - -int dladdr(const void* addr, Dl_info* info) { - // report all function pointers as coming from this program itself XXX not - // really correct in any way - info->dli_fname = "unknown"; - info->dli_fbase = NULL; - info->dli_sname = NULL; - info->dli_saddr = NULL; - return 1; -} diff --git a/test/test_core.py b/test/test_core.py index d086326e639dd..f6956fb88aaf2 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -3671,17 +3671,12 @@ def test_dlfcn_info(self): /* Verify that we don't corrupt func_ptr when calling dladdr. */ Dl_info info; memset(&info, 0, sizeof(info)); - dladdr(func_ptr, &info); + int rtn = dladdr(func_ptr, &info); + assert(rtn == 0); assert(func_ptr != NULL); assert(func_ptr(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) == 13); - /* Verify something useful lives in info. */ - assert(info.dli_fname != NULL); - assert(info.dli_fbase == NULL); - assert(info.dli_sname == NULL); - assert(info.dli_saddr == NULL); - puts("success"); return 0; diff --git a/test/test_other.py b/test/test_other.py index 88a25c67274ca..05c62b3b201c3 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -12227,17 +12227,19 @@ def test_unimplemented_syscalls_dlopen(self): def test_unimplemented_syscalls_dladdr(self): create_file('main.c', ''' + #include #include int main() { - dladdr(0, 0); + Dl_info info; + int rtn = dladdr(&main, &info); + assert(rtn == 0); return 0; } ''') - self.run_process([EMCC, 'main.c']) - err = self.run_js('a.out.js', assert_returncode=NON_ZERO) - self.assertContained('Aborted(To use dlopen, you need enable dynamic linking, see https://emscripten.org/docs/compiling/Dynamic-Linking.html)', err) + self.do_runf('main.c') + self.do_runf('main.c', emcc_args=['-sMAIN_MODULE=2']) @requires_v8 def test_missing_shell_support(self): diff --git a/tools/system_libs.py b/tools/system_libs.py index c03ecf816a37a..37642b27b507c 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -1173,7 +1173,7 @@ def get_files(self): libc_files += files_in_path( path='system/lib/libc/musl/src/ldso', - filenames=['dlerror.c', 'dlsym.c', 'dlclose.c']) + filenames=['dladdr.c', 'dlerror.c', 'dlsym.c', 'dlclose.c']) libc_files += files_in_path( path='system/lib/libc/musl/src/signal', From f2cca1a33b29c120876e0286dfdaeeff4686c9cd Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Tue, 9 May 2023 20:54:06 -0500 Subject: [PATCH 0214/1523] [WasmFS] Gracefully error when moving OPFS directory (#19320) The OPFS API does not yet support moving directories. When user code tried to move a directory using the OPFS backend, we previously crashed because the backend implementation incorrectly assumed that the moved file was a data file. Fix the crash by returning EBUSY instead in that case. --- src/library_wasmfs_opfs.js | 11 +++++---- system/lib/wasmfs/backends/opfs_backend.cpp | 26 ++++++++++++++------- test/wasmfs/wasmfs_opfs_errors.c | 20 ++++++++++++++++ test/wasmfs/wasmfs_opfs_errors_post.js | 4 ++++ 4 files changed, 47 insertions(+), 14 deletions(-) diff --git a/src/library_wasmfs_opfs.js b/src/library_wasmfs_opfs.js index b1e1b39844ece..630fdd5004b1c 100644 --- a/src/library_wasmfs_opfs.js +++ b/src/library_wasmfs_opfs.js @@ -189,13 +189,14 @@ mergeInto(LibraryManager.library, { wasmfsOPFSProxyFinish(ctx); }, - _wasmfs_opfs_move__sig: 'vpiipp', - _wasmfs_opfs_move__deps: ['$wasmfsOPFSFileHandles', - '$wasmfsOPFSDirectoryHandles', '$wasmfsOPFSProxyFinish'], - _wasmfs_opfs_move: async function(ctx, fileID, newDirID, namePtr, errPtr) { + _wasmfs_opfs_move_file__sig: 'vpiipp', + _wasmfs_opfs_move_file__deps: ['$wasmfsOPFSFileHandles', + '$wasmfsOPFSDirectoryHandles', + '$wasmfsOPFSProxyFinish'], + _wasmfs_opfs_move_file: async function(ctx, fileID, newParentID, namePtr, errPtr) { let name = UTF8ToString(namePtr); let fileHandle = wasmfsOPFSFileHandles.get(fileID); - let newDirHandle = wasmfsOPFSDirectoryHandles.get(newDirID); + let newDirHandle = wasmfsOPFSDirectoryHandles.get(newParentID); try { await fileHandle.move(newDirHandle, name); } catch { diff --git a/system/lib/wasmfs/backends/opfs_backend.cpp b/system/lib/wasmfs/backends/opfs_backend.cpp index f089520a4f877..9245a393f9cea 100644 --- a/system/lib/wasmfs/backends/opfs_backend.cpp +++ b/system/lib/wasmfs/backends/opfs_backend.cpp @@ -41,11 +41,11 @@ void _wasmfs_opfs_insert_directory(em_proxying_ctx* ctx, const char* name, int* child_id); -void _wasmfs_opfs_move(em_proxying_ctx* ctx, - int file_id, - int new_dir_id, - const char* name, - int* err); +void _wasmfs_opfs_move_file(em_proxying_ctx* ctx, + int file_id, + int new_parent_id, + const char* name, + int* err); void _wasmfs_opfs_remove_child(em_proxying_ctx* ctx, int dir_id, @@ -431,11 +431,19 @@ class OPFSDirectory : public Directory { } int insertMove(const std::string& name, std::shared_ptr file) override { - auto old_file = std::static_pointer_cast(file); int err = 0; - proxy([&](auto ctx) { - _wasmfs_opfs_move(ctx.ctx, old_file->fileID, dirID, name.c_str(), &err); - }); + if (file->is()) { + auto opfsFile = std::static_pointer_cast(file); + proxy([&](auto ctx) { + _wasmfs_opfs_move_file( + ctx.ctx, opfsFile->fileID, dirID, name.c_str(), &err); + }); + } else { + // TODO: Support moving directories once OPFS supports that. + // EBUSY can be returned when the directory is "in use by the system," + // which can mean whatever we want. + err = -EBUSY; + } return err; } diff --git a/test/wasmfs/wasmfs_opfs_errors.c b/test/wasmfs/wasmfs_opfs_errors.c index defa0ce92cab8..65339b17af645 100644 --- a/test/wasmfs/wasmfs_opfs_errors.c +++ b/test/wasmfs/wasmfs_opfs_errors.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -121,6 +122,25 @@ int try_oob_write(void) { return 2; } +EMSCRIPTEN_KEEPALIVE +int try_rename_dir(void) { + int err = mkdir("/opfs/dir1", 0666); + if (err != 0) { + return 2; + } + err = rename("/opfs/dir1", "/opfs/dir2"); + if (err == 0) { + return 1; + } + if (errno == EBUSY) { + rmdir("/opfs/dir1"); + return 0; + } + emscripten_console_error(strerror(errno)); + rmdir("/opfs/dir1"); + return 2; +} + EMSCRIPTEN_KEEPALIVE void report_result(int result) { EM_ASM({ console.log(new Error().stack); }); diff --git a/test/wasmfs/wasmfs_opfs_errors_post.js b/test/wasmfs/wasmfs_opfs_errors_post.js index 49069cb7376d7..e76675a899898 100644 --- a/test/wasmfs/wasmfs_opfs_errors_post.js +++ b/test/wasmfs/wasmfs_opfs_errors_post.js @@ -66,5 +66,9 @@ async function run_test() { "nothing prevents it)"; } + if (Module._try_rename_dir() != 0) { + throw "Did not get expected EBUSY while renaming directory"; + } + Module._report_result(0); } From 9eff02bc816c50ab0e3b70a3bd5b72a8dc2893a2 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 9 May 2023 19:21:00 -0700 Subject: [PATCH 0215/1523] Move LD_LIBRARY_PATH handling to native code. NFC (#19321) Split out from #19310 --- src/library_dylink.js | 19 ------------------ system/lib/libc/dynlink.c | 42 +++++++++++++++++++++++++++++++++++++++ test/test_other.py | 29 +++++++++++++++++---------- 3 files changed, 61 insertions(+), 29 deletions(-) diff --git a/src/library_dylink.js b/src/library_dylink.js index 69465884a85f5..b897f5720a325 100644 --- a/src/library_dylink.js +++ b/src/library_dylink.js @@ -1071,25 +1071,6 @@ var LibraryDylink = { filename = PATH.normalize(filename); var searchpaths = []; - var isValidFile = (filename) => { - var target = FS.findObject(filename); - return target && !target.isFolder && !target.isDevice; - }; - - if (!isValidFile(filename)) { - if (ENV['LD_LIBRARY_PATH']) { - searchpaths = ENV['LD_LIBRARY_PATH'].split(':'); - } - - for (var ident in searchpaths) { - var searchfile = PATH.join2(searchpaths[ident], filename); - if (isValidFile(searchfile)) { - filename = searchfile; - break; - } - } - } - var global = Boolean(flags & {{{ cDefs.RTLD_GLOBAL }}}); var localScope = global ? null : {}; diff --git a/system/lib/libc/dynlink.c b/system/lib/libc/dynlink.c index 4f98f3e3e67a7..fea12b76fcd09 100644 --- a/system/lib/libc/dynlink.c +++ b/system/lib/libc/dynlink.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -441,6 +442,37 @@ static void dlopen_onerror(struct dso* dso, void* user_data) { free(data); } +// Modified version of path_open from musl/ldso/dynlink.c +static int path_find(const char *name, const char *s, char *buf, size_t buf_size) { + size_t l; + int fd; + for (;;) { + s += strspn(s, ":\n"); + l = strcspn(s, ":\n"); + if (l-1 >= INT_MAX) return -1; + if (snprintf(buf, buf_size, "%.*s/%s", (int)l, s, name) < buf_size) { + dbg("dlopen: path_find: %s", buf); + struct stat statbuf; + if (stat(buf, &statbuf) == 0 && S_ISREG(statbuf.st_mode)) { + return 0; + } + switch (errno) { + case ENOENT: + case ENOTDIR: + case EACCES: + case ENAMETOOLONG: + break; + default: + dbg("dlopen: path_find failed: %s", strerror(errno)); + /* Any negative value but -1 will inhibit + * futher path search. */ + return -2; + } + } + s += l; + } +} + // Internal version of dlopen with typed return value. // Without this, the compiler won't tell us if we have the wrong return type. static struct dso* _dlopen(const char* file, int flags) { @@ -462,6 +494,16 @@ static struct dso* _dlopen(const char* file, int flags) { struct dso* p; + /* Resolve filename using LD_LIBRARY_PATH */ + char buf[2*NAME_MAX+2]; + if (!strchr(file, '/')) { + const char* env_path = getenv("LD_LIBRARY_PATH"); + if (env_path && path_find(file, env_path, buf, sizeof buf) == 0) { + dbg("dlopen: found in LD_LIBRARY_PATH: %s", buf); + file = buf; + } + } + /* Search for the name to see if it's already loaded */ for (struct dlevent* e = head; e; e = e->next) { if (e->sym_index == -1 && !strcmp(e->dso->name, file)) { diff --git a/test/test_other.py b/test/test_other.py index 05c62b3b201c3..e6648fc7ca136 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -6407,10 +6407,11 @@ def test_ld_library_path(self): ''') create_file('pre.js', r''' Module['preRun'] = function () { - ENV['LD_LIBRARY_PATH']='/lib:/usr/lib'; + ENV['LD_LIBRARY_PATH']='/lib:/usr/lib:/usr/local/lib'; }; ''') create_file('main.c', r''' +#include #include #include #include @@ -6422,22 +6423,30 @@ def test_ld_library_path(self): double (*f2)(double); h = dlopen("libhello1.wasm", RTLD_NOW); + assert(h); f = dlsym(h, "hello1"); + assert(f); f(); dlclose(h); h = dlopen("libhello2.wasm", RTLD_NOW); + assert(h); f = dlsym(h, "hello2"); + assert(f); f(); dlclose(h); h = dlopen("libhello3.wasm", RTLD_NOW); + assert(h); f = dlsym(h, "hello3"); + assert(f); f(); dlclose(h); h = dlopen("/usr/local/lib/libhello4.wasm", RTLD_NOW); + assert(h); f2 = dlsym(h, "hello4"); + assert(f2); double result = f2(5.5); dlclose(h); @@ -6447,16 +6456,16 @@ def test_ld_library_path(self): return 0; } ''') - self.run_process([EMCC, '-o', 'libhello1.wasm', 'hello1.c', '-sSIDE_MODULE']) - self.run_process([EMCC, '-o', 'libhello2.wasm', 'hello2.c', '-sSIDE_MODULE']) - self.run_process([EMCC, '-o', 'libhello3.wasm', 'hello3.c', '-sSIDE_MODULE']) - self.run_process([EMCC, '-o', 'libhello4.wasm', 'hello4.c', '-sSIDE_MODULE']) + self.run_process([EMCC, '-o', 'hello1.wasm', 'hello1.c', '-sSIDE_MODULE']) + self.run_process([EMCC, '-o', 'hello2.wasm', 'hello2.c', '-sSIDE_MODULE']) + self.run_process([EMCC, '-o', 'hello3.wasm', 'hello3.c', '-sSIDE_MODULE']) + self.run_process([EMCC, '-o', 'hello4.wasm', 'hello4.c', '-sSIDE_MODULE']) self.run_process([EMCC, '--profiling-funcs', '-o', 'main.js', 'main.c', '-sMAIN_MODULE=2', '-sINITIAL_MEMORY=32Mb', - '--embed-file', 'libhello1.wasm@/lib/libhello1.wasm', - '--embed-file', 'libhello2.wasm@/usr/lib/libhello2.wasm', - '--embed-file', 'libhello3.wasm@/libhello3.wasm', - '--embed-file', 'libhello4.wasm@/usr/local/lib/libhello4.wasm', - 'libhello1.wasm', 'libhello2.wasm', 'libhello3.wasm', 'libhello4.wasm', '-sNO_AUTOLOAD_DYLIBS', + '--embed-file', 'hello1.wasm@/lib/libhello1.wasm', + '--embed-file', 'hello2.wasm@/usr/lib/libhello2.wasm', + '--embed-file', 'hello3.wasm@/libhello3.wasm', + '--embed-file', 'hello4.wasm@/usr/local/lib/libhello4.wasm', + 'hello1.wasm', 'hello2.wasm', 'hello3.wasm', 'hello4.wasm', '-sNO_AUTOLOAD_DYLIBS', '--pre-js', 'pre.js']) out = self.run_js('main.js') self.assertContained('Hello1', out) From ca1d374c624aba773b5c38ac5326e1fcb4add34b Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 10 May 2023 10:51:06 -0700 Subject: [PATCH 0216/1523] Enable wasm workers to run under node (#19322) This means we can run the tests without depending on the browser. --- src/library_wasm_worker.js | 2 +- src/shell.js | 2 +- test/code_size/hello_wasm_worker_wasm.js | 2 +- test/code_size/hello_wasm_worker_wasm.json | 8 ++++---- test/test_core.py | 8 ++++++++ 5 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/library_wasm_worker.js b/src/library_wasm_worker.js index e43a75eefdb06..a7f3a91f35963 100644 --- a/src/library_wasm_worker.js +++ b/src/library_wasm_worker.js @@ -139,7 +139,7 @@ mergeInto(LibraryManager.library, { 'sb': stackLowestAddress, // sb = stack bottom (lowest stack address, SP points at this when stack is full) 'sz': stackSize, // sz = stack size }); - worker.addEventListener('message', __wasm_worker_runPostMessage); + worker.onmessage = __wasm_worker_runPostMessage; return _wasm_workers_id++; }, diff --git a/src/shell.js b/src/shell.js index 8796c478b1046..d7899a6062c84 100644 --- a/src/shell.js +++ b/src/shell.js @@ -263,7 +263,7 @@ if (ENVIRONMENT_IS_NODE) { Module['inspect'] = () => '[Emscripten Module object]'; -#if PTHREADS +#if PTHREADS || WASM_WORKERS let nodeWorkerThreads; try { nodeWorkerThreads = require('worker_threads'); diff --git a/test/code_size/hello_wasm_worker_wasm.js b/test/code_size/hello_wasm_worker_wasm.js index 265efaab6c28c..6c2e59a08ac15 100644 --- a/test/code_size/hello_wasm_worker_wasm.js +++ b/test/code_size/hello_wasm_worker_wasm.js @@ -28,7 +28,7 @@ WebAssembly.instantiate(b.wasm, { sb: a, sz: d }); - r.addEventListener("message", n); + r.onmessage = n; return k++; }, c: function() { diff --git a/test/code_size/hello_wasm_worker_wasm.json b/test/code_size/hello_wasm_worker_wasm.json index 54299179b6e15..b8f284b88c113 100644 --- a/test/code_size/hello_wasm_worker_wasm.json +++ b/test/code_size/hello_wasm_worker_wasm.json @@ -1,10 +1,10 @@ { "a.html": 737, "a.html.gz": 433, - "a.js": 733, - "a.js.gz": 463, + "a.js": 715, + "a.js.gz": 465, "a.wasm": 1862, "a.wasm.gz": 1040, - "total": 3332, - "total_gz": 1936 + "total": 3314, + "total_gz": 1938 } diff --git a/test/test_core.py b/test/test_core.py index f6956fb88aaf2..38d15809665d7 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -9761,6 +9761,14 @@ def test_emscripten_async_load_script(self): self.run_process([FILE_PACKAGER, 'test.data', '--preload', 'file1.txt', 'file2.txt', '--from-emcc', '--js-output=script2.js']) self.do_runf(test_file('test_emscripten_async_load_script.c'), emcc_args=['-sFORCE_FILESYSTEM']) + @node_pthreads + def test_wasm_worker_hello(self): + self.do_runf(test_file('wasm_worker/hello_wasm_worker.c'), emcc_args=['-sWASM_WORKERS']) + + @node_pthreads + def test_wasm_worker_malloc(self): + self.do_runf(test_file('wasm_worker/malloc_wasm_worker.c'), emcc_args=['-sWASM_WORKERS']) + # Generate tests for everything def make_run(name, emcc_args, settings=None, env=None, From dd5ae0fec7e85e245ea78b50e228a819fc7e010c Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 10 May 2023 13:42:52 -0700 Subject: [PATCH 0217/1523] Remove EM_JS version of `console_log` in test code. NFC (#19329) These is no need to re-implement this everywhere since `emscripten_console_log` does just this. This pattern seems to have been copied around so removing it everywhere should avoid future copies. --- test/minimal_hello.c | 8 ++--- test/wasm_worker/cancel_all_wait_asyncs.c | 32 ++++++++--------- .../cancel_all_wait_asyncs_at_address.c | 34 ++++++++----------- test/wasm_worker/cancel_wait_async.c | 28 +++++++-------- test/wasm_worker/lock_async_acquire.c | 12 +++---- test/wasm_worker/lock_wait_acquire2.c | 22 +++++------- test/wasm_worker/malloc_wasm_worker.c | 6 +--- test/wasm_worker/post_function.c | 20 +++++------ .../post_function_to_main_thread.c | 8 ++--- test/wasm_worker/semaphore_try_acquire.c | 14 +++----- test/wasm_worker/semaphore_waitinf_acquire.c | 28 +++++++-------- test/wasm_worker/wait32_notify.c | 30 +++++++--------- test/wasm_worker/wait64_notify.c | 28 +++++++-------- test/wasm_worker/wait_async.c | 30 +++++++--------- test/wasm_worker/wasm_worker_self_id.c | 5 --- test/wasm_worker/wasm_worker_sleep.c | 6 +--- 16 files changed, 123 insertions(+), 188 deletions(-) diff --git a/test/minimal_hello.c b/test/minimal_hello.c index 62160142f380c..c7bd5ac4d3a6a 100644 --- a/test/minimal_hello.c +++ b/test/minimal_hello.c @@ -1,11 +1,7 @@ -#include - -EM_JS(void, console_log, (char* str), { - console.log(UTF8ToString(str)); -}); +#include int main() { - console_log("minimal hello!"); + emscripten_console_log("minimal hello!"); return 0; } diff --git a/test/wasm_worker/cancel_all_wait_asyncs.c b/test/wasm_worker/cancel_all_wait_asyncs.c index 4823cc165126a..735806067b0fd 100644 --- a/test/wasm_worker/cancel_all_wait_asyncs.c +++ b/test/wasm_worker/cancel_all_wait_asyncs.c @@ -5,24 +5,20 @@ // Test emscripten_atomic_cancel_all_wait_asyncs() function. -EM_JS(void, console_log, (char* str), { - console.log(UTF8ToString(str)); -}); - volatile int32_t addr = 1; EM_BOOL testSucceeded = 1; void asyncWaitFinishedShouldNotBeCalled(int32_t *ptr, uint32_t val, ATOMICS_WAIT_RESULT_T waitResult, void *userData) { - console_log("asyncWaitFinishedShouldNotBeCalled"); + emscripten_console_log("asyncWaitFinishedShouldNotBeCalled"); testSucceeded = 0; assert(0); // We should not reach here } void asyncWaitFinishedShouldBeCalled(int32_t *ptr, uint32_t val, ATOMICS_WAIT_RESULT_T waitResult, void *userData) { - console_log("asyncWaitFinishedShouldBeCalled"); + emscripten_console_log("asyncWaitFinishedShouldBeCalled"); #ifdef REPORT_RESULT REPORT_RESULT(testSucceeded); #endif @@ -30,51 +26,51 @@ void asyncWaitFinishedShouldBeCalled(int32_t *ptr, uint32_t val, ATOMICS_WAIT_RE int main() { - console_log("Async waiting on address should give a wait token"); + emscripten_console_log("Async waiting on address should give a wait token"); ATOMICS_WAIT_TOKEN_T ret = emscripten_atomic_wait_async((int32_t*)&addr, 1, asyncWaitFinishedShouldNotBeCalled, (void*)42, EMSCRIPTEN_WAIT_ASYNC_INFINITY); assert(EMSCRIPTEN_IS_VALID_WAIT_TOKEN(ret)); - console_log("Async waiting on address should give a wait token"); + emscripten_console_log("Async waiting on address should give a wait token"); ATOMICS_WAIT_TOKEN_T ret2 = emscripten_atomic_wait_async((int32_t*)&addr, 1, asyncWaitFinishedShouldNotBeCalled, (void*)42, EMSCRIPTEN_WAIT_ASYNC_INFINITY); assert(EMSCRIPTEN_IS_VALID_WAIT_TOKEN(ret2)); - console_log("Canceling all async waits should return the number of waits cancelled"); + emscripten_console_log("Canceling all async waits should return the number of waits cancelled"); int numCancelled = emscripten_atomic_cancel_all_wait_asyncs(); assert(numCancelled == 2); - console_log("Canceling an async wait that has already been cancelled should give an invalid param"); + emscripten_console_log("Canceling an async wait that has already been cancelled should give an invalid param"); EMSCRIPTEN_RESULT r = emscripten_atomic_cancel_wait_async(ret); assert(r == EMSCRIPTEN_RESULT_INVALID_PARAM); - console_log("Canceling an async wait that has already been cancelled should give an invalid param"); + emscripten_console_log("Canceling an async wait that has already been cancelled should give an invalid param"); r = emscripten_atomic_cancel_wait_async(ret2); assert(r == EMSCRIPTEN_RESULT_INVALID_PARAM); - console_log("Notifying an async wait should not trigger the callback function"); + emscripten_console_log("Notifying an async wait should not trigger the callback function"); int64_t numWoken = emscripten_wasm_notify((int32_t*)&addr, EMSCRIPTEN_NOTIFY_ALL_WAITERS); - console_log("Notifying an async wait should return 0 threads woken"); + emscripten_console_log("Notifying an async wait should return 0 threads woken"); assert(numWoken == 0); addr = 2; - console_log("Notifying an async wait even after changed value should not trigger the callback function"); + emscripten_console_log("Notifying an async wait even after changed value should not trigger the callback function"); numWoken = emscripten_wasm_notify((int32_t*)&addr, EMSCRIPTEN_NOTIFY_ALL_WAITERS); - console_log("Notifying an async wait should return 0 threads woken"); + emscripten_console_log("Notifying an async wait should return 0 threads woken"); assert(numWoken == 0); - console_log("Async waiting on address should give a wait token"); + emscripten_console_log("Async waiting on address should give a wait token"); ret = emscripten_atomic_wait_async((int32_t*)&addr, 2, asyncWaitFinishedShouldBeCalled, (void*)42, EMSCRIPTEN_WAIT_ASYNC_INFINITY); assert(EMSCRIPTEN_IS_VALID_WAIT_TOKEN(ret)); #if 0 - console_log("Notifying an async wait without value changing should still trigger the callback"); + emscripten_console_log("Notifying an async wait without value changing should still trigger the callback"); numWoken = emscripten_wasm_notify((int32_t*)&addr, EMSCRIPTEN_NOTIFY_ALL_WAITERS); assert(numWoken == 1); #else // TODO: Switch to the above test instead after the Atomics.waitAsync() polyfill is dropped. addr = 3; - console_log("Notifying an async wait after value changing should trigger the callback"); + emscripten_console_log("Notifying an async wait after value changing should trigger the callback"); numWoken = emscripten_wasm_notify((int32_t*)&addr, EMSCRIPTEN_NOTIFY_ALL_WAITERS); #endif } diff --git a/test/wasm_worker/cancel_all_wait_asyncs_at_address.c b/test/wasm_worker/cancel_all_wait_asyncs_at_address.c index c9192e796a349..7c859ffd8b032 100644 --- a/test/wasm_worker/cancel_all_wait_asyncs_at_address.c +++ b/test/wasm_worker/cancel_all_wait_asyncs_at_address.c @@ -5,24 +5,20 @@ // Test emscripten_atomic_cancel_all_wait_asyncs() function. -EM_JS(void, console_log, (char* str), { - console.log(UTF8ToString(str)); -}); - volatile int32_t addr = 1; EM_BOOL testSucceeded = 1; void asyncWaitFinishedShouldNotBeCalled(int32_t *ptr, uint32_t val, ATOMICS_WAIT_RESULT_T waitResult, void *userData) { - console_log("asyncWaitFinishedShouldNotBeCalled"); + emscripten_console_log("asyncWaitFinishedShouldNotBeCalled"); testSucceeded = 0; assert(0); // We should not reach here } void asyncWaitFinishedShouldBeCalled(int32_t *ptr, uint32_t val, ATOMICS_WAIT_RESULT_T waitResult, void *userData) { - console_log("asyncWaitFinishedShouldBeCalled"); + emscripten_console_log("asyncWaitFinishedShouldBeCalled"); #ifdef REPORT_RESULT REPORT_RESULT(testSucceeded); #endif @@ -30,55 +26,55 @@ void asyncWaitFinishedShouldBeCalled(int32_t *ptr, uint32_t val, ATOMICS_WAIT_RE int main() { - console_log("Async waiting on address should give a wait token"); + emscripten_console_log("Async waiting on address should give a wait token"); ATOMICS_WAIT_TOKEN_T ret = emscripten_atomic_wait_async((int32_t*)&addr, 1, asyncWaitFinishedShouldNotBeCalled, (void*)42, EMSCRIPTEN_WAIT_ASYNC_INFINITY); assert(EMSCRIPTEN_IS_VALID_WAIT_TOKEN(ret)); - console_log("Async waiting on address should give a wait token"); + emscripten_console_log("Async waiting on address should give a wait token"); ATOMICS_WAIT_TOKEN_T ret2 = emscripten_atomic_wait_async((int32_t*)&addr, 1, asyncWaitFinishedShouldNotBeCalled, (void*)42, EMSCRIPTEN_WAIT_ASYNC_INFINITY); assert(EMSCRIPTEN_IS_VALID_WAIT_TOKEN(ret2)); - console_log("Canceling all async waits at wait address should return the number of waits cancelled"); + emscripten_console_log("Canceling all async waits at wait address should return the number of waits cancelled"); int numCancelled = emscripten_atomic_cancel_all_wait_asyncs_at_address((int32_t*)&addr); assert(numCancelled == 2); - console_log("Canceling all async waits at some other address should return 0"); + emscripten_console_log("Canceling all async waits at some other address should return 0"); numCancelled = emscripten_atomic_cancel_all_wait_asyncs_at_address((int32_t*)0xbad); assert(numCancelled == 0); - console_log("Canceling an async wait that has already been cancelled should give an invalid param"); + emscripten_console_log("Canceling an async wait that has already been cancelled should give an invalid param"); EMSCRIPTEN_RESULT r = emscripten_atomic_cancel_wait_async(ret); assert(r == EMSCRIPTEN_RESULT_INVALID_PARAM); - console_log("Canceling an async wait that has already been cancelled should give an invalid param"); + emscripten_console_log("Canceling an async wait that has already been cancelled should give an invalid param"); r = emscripten_atomic_cancel_wait_async(ret2); assert(r == EMSCRIPTEN_RESULT_INVALID_PARAM); - console_log("Notifying an async wait should not trigger the callback function"); + emscripten_console_log("Notifying an async wait should not trigger the callback function"); int64_t numWoken = emscripten_wasm_notify((int32_t*)&addr, EMSCRIPTEN_NOTIFY_ALL_WAITERS); - console_log("Notifying an async wait should return 0 threads woken"); + emscripten_console_log("Notifying an async wait should return 0 threads woken"); assert(numWoken == 0); addr = 2; - console_log("Notifying an async wait even after changed value should not trigger the callback function"); + emscripten_console_log("Notifying an async wait even after changed value should not trigger the callback function"); numWoken = emscripten_wasm_notify((int32_t*)&addr, EMSCRIPTEN_NOTIFY_ALL_WAITERS); - console_log("Notifying an async wait should return 0 threads woken"); + emscripten_console_log("Notifying an async wait should return 0 threads woken"); assert(numWoken == 0); - console_log("Async waiting on address should give a wait token"); + emscripten_console_log("Async waiting on address should give a wait token"); ret = emscripten_atomic_wait_async((int32_t*)&addr, 2, asyncWaitFinishedShouldBeCalled, (void*)42, EMSCRIPTEN_WAIT_ASYNC_INFINITY); assert(EMSCRIPTEN_IS_VALID_WAIT_TOKEN(ret)); #if 0 - console_log("Notifying an async wait without value changing should still trigger the callback"); + emscripten_console_log("Notifying an async wait without value changing should still trigger the callback"); numWoken = emscripten_wasm_notify((int32_t*)&addr, EMSCRIPTEN_NOTIFY_ALL_WAITERS); assert(numWoken == 1); #else // TODO: Switch to the above test instead after the Atomics.waitAsync() polyfill is dropped. addr = 3; - console_log("Notifying an async wait after value changing should trigger the callback"); + emscripten_console_log("Notifying an async wait after value changing should trigger the callback"); numWoken = emscripten_wasm_notify((int32_t*)&addr, EMSCRIPTEN_NOTIFY_ALL_WAITERS); #endif } diff --git a/test/wasm_worker/cancel_wait_async.c b/test/wasm_worker/cancel_wait_async.c index c2822630791b6..bdb7e90e010d7 100644 --- a/test/wasm_worker/cancel_wait_async.c +++ b/test/wasm_worker/cancel_wait_async.c @@ -5,24 +5,20 @@ // Test emscripten_cancel_wait_async() function. -EM_JS(void, console_log, (char* str), { - console.log(UTF8ToString(str)); -}); - volatile int32_t addr = 1; EM_BOOL testSucceeded = 1; void asyncWaitFinishedShouldNotBeCalled(int32_t *ptr, uint32_t val, ATOMICS_WAIT_RESULT_T waitResult, void *userData) { - console_log("asyncWaitFinishedShouldNotBeCalled"); + emscripten_console_log("asyncWaitFinishedShouldNotBeCalled"); testSucceeded = 0; assert(0); // We should not reach here } void asyncWaitFinishedShouldBeCalled(int32_t *ptr, uint32_t val, ATOMICS_WAIT_RESULT_T waitResult, void *userData) { - console_log("asyncWaitFinishedShouldBeCalled"); + emscripten_console_log("asyncWaitFinishedShouldBeCalled"); #ifdef REPORT_RESULT REPORT_RESULT(testSucceeded); #endif @@ -30,43 +26,43 @@ void asyncWaitFinishedShouldBeCalled(int32_t *ptr, uint32_t val, ATOMICS_WAIT_RE int main() { - console_log("Async waiting on address should give a wait token"); + emscripten_console_log("Async waiting on address should give a wait token"); ATOMICS_WAIT_TOKEN_T ret = emscripten_atomic_wait_async((int32_t*)&addr, 1, asyncWaitFinishedShouldNotBeCalled, (void*)42, EMSCRIPTEN_WAIT_ASYNC_INFINITY); assert(EMSCRIPTEN_IS_VALID_WAIT_TOKEN(ret)); - console_log("Canceling an async wait should succeed"); + emscripten_console_log("Canceling an async wait should succeed"); EMSCRIPTEN_RESULT r = emscripten_atomic_cancel_wait_async(ret); assert(r == EMSCRIPTEN_RESULT_SUCCESS); - console_log("Canceling an async wait a second time should give invalid param"); + emscripten_console_log("Canceling an async wait a second time should give invalid param"); r = emscripten_atomic_cancel_wait_async(ret); assert(r == EMSCRIPTEN_RESULT_INVALID_PARAM); - console_log("Notifying an async wait should not trigger the callback function"); + emscripten_console_log("Notifying an async wait should not trigger the callback function"); int64_t numWoken = emscripten_wasm_notify((int32_t*)&addr, EMSCRIPTEN_NOTIFY_ALL_WAITERS); - console_log("Notifying an async wait should return 0 threads woken"); + emscripten_console_log("Notifying an async wait should return 0 threads woken"); assert(numWoken == 0); addr = 2; - console_log("Notifying an async wait even after changed value should not trigger the callback function"); + emscripten_console_log("Notifying an async wait even after changed value should not trigger the callback function"); numWoken = emscripten_wasm_notify((int32_t*)&addr, EMSCRIPTEN_NOTIFY_ALL_WAITERS); - console_log("Notifying an async wait should return 0 threads woken"); + emscripten_console_log("Notifying an async wait should return 0 threads woken"); assert(numWoken == 0); - console_log("Async waiting on address should give a wait token"); + emscripten_console_log("Async waiting on address should give a wait token"); ret = emscripten_atomic_wait_async((int32_t*)&addr, 2, asyncWaitFinishedShouldBeCalled, (void*)42, EMSCRIPTEN_WAIT_ASYNC_INFINITY); assert(EMSCRIPTEN_IS_VALID_WAIT_TOKEN(ret)); #if 0 - console_log("Notifying an async wait without value changing should still trigger the callback"); + emscripten_console_log("Notifying an async wait without value changing should still trigger the callback"); numWoken = emscripten_wasm_notify((int32_t*)&addr, EMSCRIPTEN_NOTIFY_ALL_WAITERS); assert(numWoken == 1); #else // TODO: Switch to the above test instead after the Atomics.waitAsync() polyfill is dropped. addr = 3; - console_log("Notifying an async wait after value changing should trigger the callback"); + emscripten_console_log("Notifying an async wait after value changing should trigger the callback"); numWoken = emscripten_wasm_notify((int32_t*)&addr, EMSCRIPTEN_NOTIFY_ALL_WAITERS); #endif } diff --git a/test/wasm_worker/lock_async_acquire.c b/test/wasm_worker/lock_async_acquire.c index 9a293a74ebcfe..2e81ffbd2b71a 100644 --- a/test/wasm_worker/lock_async_acquire.c +++ b/test/wasm_worker/lock_async_acquire.c @@ -6,10 +6,6 @@ // Tests emscripten_lock_async_acquire() function. -EM_JS(void, console_log, (char* str), { - console.log(UTF8ToString(str)); -}); - emscripten_lock_t lock = EMSCRIPTEN_LOCK_T_STATIC_INITIALIZER; // Two shared variables, always a delta distance of one from each other. @@ -23,7 +19,7 @@ int numTimesWasmWorkerAcquiredLock = 0; void work() { -// console_log("work"); +// emscripten_console_log("work"); volatile int x = sharedState0; volatile int y = sharedState1; assert(x == y+1 || y == x+1); @@ -51,7 +47,7 @@ void work() { if (!testFinished) { - console_log("test finished"); + emscripten_console_log("test finished"); #ifdef REPORT_RESULT REPORT_RESULT(0); #endif @@ -65,7 +61,7 @@ void schedule_work(void *userData); void lock_async_acquired(volatile void *addr, uint32_t val, ATOMICS_WAIT_RESULT_T waitResult, void *userData) { -// console_log("async lock acquired"); +// emscripten_console_log("async lock acquired"); assert(addr == &lock); assert(val == 0 || val == 1); assert(waitResult == ATOMICS_WAIT_OK); @@ -82,7 +78,7 @@ void schedule_work(void *userData) if (emscripten_current_thread_is_wasm_worker() && emscripten_random() > 0.5) { emscripten_lock_waitinf_acquire(&lock); -// console_log("sync lock acquired"); +// emscripten_console_log("sync lock acquired"); work(); emscripten_lock_release(&lock); if (!testFinished) diff --git a/test/wasm_worker/lock_wait_acquire2.c b/test/wasm_worker/lock_wait_acquire2.c index a4833a78f9b1c..7d14f32216b16 100644 --- a/test/wasm_worker/lock_wait_acquire2.c +++ b/test/wasm_worker/lock_wait_acquire2.c @@ -6,38 +6,34 @@ // Tests emscripten_lock_wait_acquire() between two Wasm Workers. -EM_JS(void, console_log, (char* str), { - console.log(UTF8ToString(str)); -}); - emscripten_lock_t lock = EMSCRIPTEN_LOCK_T_STATIC_INITIALIZER; void worker1_main() { - console_log("worker1 main try_acquiring lock"); + emscripten_console_log("worker1 main try_acquiring lock"); EM_BOOL success = emscripten_lock_try_acquire(&lock); // Expect no contention on free lock. - console_log("worker1 try_acquire lock finished"); + emscripten_console_log("worker1 try_acquire lock finished"); assert(success); - console_log("worker1 try_acquire lock success, sleeping 1000 msecs"); + emscripten_console_log("worker1 try_acquire lock success, sleeping 1000 msecs"); emscripten_wasm_worker_sleep(1000 * 1000000ull); - console_log("worker1 slept 1000 msecs, releasing lock"); + emscripten_console_log("worker1 slept 1000 msecs, releasing lock"); emscripten_lock_release(&lock); - console_log("worker1 released lock"); + emscripten_console_log("worker1 released lock"); } void worker2_main() { - console_log("worker2 main sleeping 500 msecs"); + emscripten_console_log("worker2 main sleeping 500 msecs"); emscripten_wasm_worker_sleep(500 * 1000000ull); - console_log("worker2 slept 500 msecs, try_acquiring lock"); + emscripten_console_log("worker2 slept 500 msecs, try_acquiring lock"); EM_BOOL success = emscripten_lock_try_acquire(&lock); // At this time, the other thread should have the lock. - console_log("worker2 try_acquire lock finished"); + emscripten_console_log("worker2 try_acquire lock finished"); assert(!success); // Wait enough time to cover over the time that the other thread held the lock. success = emscripten_lock_wait_acquire(&lock, 2000 * 1000000ull); - console_log("worker2 wait_acquired lock"); + emscripten_console_log("worker2 wait_acquired lock"); assert(success); #ifdef REPORT_RESULT diff --git a/test/wasm_worker/malloc_wasm_worker.c b/test/wasm_worker/malloc_wasm_worker.c index 10f5a8fda0330..0249e6c41dc30 100644 --- a/test/wasm_worker/malloc_wasm_worker.c +++ b/test/wasm_worker/malloc_wasm_worker.c @@ -4,13 +4,9 @@ // Test emscripten_malloc_wasm_worker() and emscripten_current_thread_is_wasm_worker() functions -EM_JS(void, console_log, (char* str), { - console.log(UTF8ToString(str)); -}); - void worker_main() { - console_log("Hello from wasm worker!"); + emscripten_console_log("Hello from wasm worker!"); assert(emscripten_current_thread_is_wasm_worker()); #ifdef REPORT_RESULT REPORT_RESULT(0); diff --git a/test/wasm_worker/post_function.c b/test/wasm_worker/post_function.c index 288d3610d9667..41cb82849ee56 100644 --- a/test/wasm_worker/post_function.c +++ b/test/wasm_worker/post_function.c @@ -4,28 +4,24 @@ // Test emscripten_wasm_worker_post_function_*() API -EM_JS(void, console_log, (char* str), { - console.log(UTF8ToString(str)); -}); - volatile int success = 0; void v() { - console_log("v"); + emscripten_console_log("v"); ++success; } void vi(int i) { - console_log("vi"); + emscripten_console_log("vi"); assert(i == 1); ++success; } void vii(int i, int j) { - console_log("vii"); + emscripten_console_log("vii"); assert(i == 2); assert(j == 3); ++success; @@ -33,7 +29,7 @@ void vii(int i, int j) void viii(int i, int j, int k) { - console_log("viii"); + emscripten_console_log("viii"); assert(i == 4); assert(j == 5); assert(k == 6); @@ -42,14 +38,14 @@ void viii(int i, int j, int k) void vd(double i) { - console_log("vd"); + emscripten_console_log("vd"); assert(i == 1.5); ++success; } void vdd(double i, double j) { - console_log("vdd"); + emscripten_console_log("vdd"); assert(i == 2.5); assert(j == 3.5); ++success; @@ -57,7 +53,7 @@ void vdd(double i, double j) void vddd(double i, double j, double k) { - console_log("vddd"); + emscripten_console_log("vddd"); assert(i == 4.5); assert(j == 5.5); assert(k == 6.5); @@ -66,7 +62,7 @@ void vddd(double i, double j, double k) void viiiiiidddddd(int a, int b, int c, int d, int e, int f, double g, double h, double i, double j, double k, double l) { - console_log("viiiiiidddddd"); + emscripten_console_log("viiiiiidddddd"); assert(a == 10); assert(b == 11); assert(c == 12); diff --git a/test/wasm_worker/post_function_to_main_thread.c b/test/wasm_worker/post_function_to_main_thread.c index 93aa2d3679c04..3ef342ad4372f 100644 --- a/test/wasm_worker/post_function_to_main_thread.c +++ b/test/wasm_worker/post_function_to_main_thread.c @@ -5,13 +5,9 @@ // Test emscripten_wasm_worker_post_function_*() API and EMSCRIPTEN_WASM_WORKER_ID_PARENT // to send a message back from Worker to its parent thread. -EM_JS(void, console_log, (char* str), { - console.log(UTF8ToString(str)); -}); - void test_success(int i, double d) { - console_log("test_success"); + emscripten_console_log("test_success"); assert(!emscripten_current_thread_is_wasm_worker()); assert(i == 10); assert(d == 0.5); @@ -22,7 +18,7 @@ void test_success(int i, double d) void worker_main() { - console_log("worker_main"); + emscripten_console_log("worker_main"); assert(emscripten_current_thread_is_wasm_worker()); emscripten_wasm_worker_post_function_sig(EMSCRIPTEN_WASM_WORKER_ID_PARENT, test_success, "id", 10, 0.5); } diff --git a/test/wasm_worker/semaphore_try_acquire.c b/test/wasm_worker/semaphore_try_acquire.c index 76f840e491c38..f3d656e2dcc2c 100644 --- a/test/wasm_worker/semaphore_try_acquire.c +++ b/test/wasm_worker/semaphore_try_acquire.c @@ -6,32 +6,28 @@ // Tests emscripten_semaphore_try_acquire() on the main thread -EM_JS(void, console_log, (char* str), { - console.log(UTF8ToString(str)); -}); - emscripten_semaphore_t unavailable = EMSCRIPTEN_SEMAPHORE_T_STATIC_INITIALIZER(0); emscripten_semaphore_t available = EMSCRIPTEN_SEMAPHORE_T_STATIC_INITIALIZER(1); int main() { - console_log("try_acquiring unavailable semaphore should fail"); + emscripten_console_log("try_acquiring unavailable semaphore should fail"); int idx = emscripten_semaphore_try_acquire(&unavailable, 1); assert(idx == -1); - console_log("try_acquiring too many resources from an available semaphore should fail"); + emscripten_console_log("try_acquiring too many resources from an available semaphore should fail"); idx = emscripten_semaphore_try_acquire(&available, 2); assert(idx == -1); - console_log("try_acquiring a resource from an available semaphore should succeed"); + emscripten_console_log("try_acquiring a resource from an available semaphore should succeed"); idx = emscripten_semaphore_try_acquire(&available, 1); assert(idx == 0); - console_log("releasing semaphore resources on main thread should succeed"); + emscripten_console_log("releasing semaphore resources on main thread should succeed"); idx = emscripten_semaphore_release(&available, 10); assert(idx == 0); - console_log("try_acquiring multiple resources from an available semaphore should succeed"); + emscripten_console_log("try_acquiring multiple resources from an available semaphore should succeed"); idx = emscripten_semaphore_try_acquire(&available, 9); assert(idx == 1); diff --git a/test/wasm_worker/semaphore_waitinf_acquire.c b/test/wasm_worker/semaphore_waitinf_acquire.c index eeabd9cfe3bf1..b7f04732ffdd3 100644 --- a/test/wasm_worker/semaphore_waitinf_acquire.c +++ b/test/wasm_worker/semaphore_waitinf_acquire.c @@ -6,10 +6,6 @@ // Tests emscripten_semaphore_init(), emscripten_semaphore_waitinf_acquire() and emscripten_semaphore_release() -EM_JS(void, console_log, (char* str), { - console.log(UTF8ToString(str)); -}); - emscripten_semaphore_t threadsWaiting = (emscripten_semaphore_t)12345315; // initialize with garbage emscripten_semaphore_t threadsRunning = EMSCRIPTEN_SEMAPHORE_T_STATIC_INITIALIZER(0); // initialize with static initializer emscripten_semaphore_t threadsCompleted = EMSCRIPTEN_SEMAPHORE_T_STATIC_INITIALIZER(0); @@ -18,56 +14,56 @@ int threadCounter = 0; void worker_main() { - console_log("worker_main"); + emscripten_console_log("worker_main"); // Increment semaphore to mark that this thread is waiting for a signal from control thread to start. emscripten_semaphore_release(&threadsWaiting, 1); // Acquire thread run semaphore once main thread has given this thread a go signal. - console_log("worker_main: waiting for thread run signal"); + emscripten_console_log("worker_main: waiting for thread run signal"); emscripten_semaphore_waitinf_acquire(&threadsRunning, 1); // Do heavy computation: - console_log("worker_main: incrementing work"); + emscripten_console_log("worker_main: incrementing work"); emscripten_atomic_add_u32((void*)&threadCounter, 1); // Increment semaphore to signal that this thread has finished. - console_log("worker_main: thread completed"); + emscripten_console_log("worker_main: thread completed"); emscripten_semaphore_release(&threadsCompleted, 1); } void control_thread() { // Wait until we have three threads available to start running. - console_log("control_thread: waiting for three threads to complete loading"); + emscripten_console_log("control_thread: waiting for three threads to complete loading"); emscripten_semaphore_waitinf_acquire(&threadsWaiting, 3); // Set the three waiting threads to run simultaneously. assert(threadCounter == 0); - console_log("control_thread: release three threads to run"); + emscripten_console_log("control_thread: release three threads to run"); emscripten_semaphore_release(&threadsRunning, 3); // Wait until we have 3 threads completed their run. - console_log("control_thread: waiting for three threads to complete"); + emscripten_console_log("control_thread: waiting for three threads to complete"); emscripten_semaphore_waitinf_acquire(&threadsCompleted, 3); assert(threadCounter == 3); // Wait until we have next 3 threads available to start running. - console_log("control_thread: waiting for next three threads to be ready"); + emscripten_console_log("control_thread: waiting for next three threads to be ready"); emscripten_semaphore_waitinf_acquire(&threadsWaiting, 3); // Set the three waiting threads to run simultaneously. assert(threadCounter == 3); - console_log("control_thread: setting next three threads go"); + emscripten_console_log("control_thread: setting next three threads go"); emscripten_semaphore_release(&threadsRunning, 3); // Wait until we have the final 3 threads completed their run. - console_log("control_thread: waiting for the last three threads to finish"); + emscripten_console_log("control_thread: waiting for the last three threads to finish"); emscripten_semaphore_waitinf_acquire(&threadsCompleted, 3); - console_log("control_thread: threads finished"); + emscripten_console_log("control_thread: threads finished"); assert(threadCounter == 6); - console_log("control_thread: test finished"); + emscripten_console_log("control_thread: test finished"); #ifdef REPORT_RESULT REPORT_RESULT(0); #endif diff --git a/test/wasm_worker/wait32_notify.c b/test/wasm_worker/wait32_notify.c index ab04be49bac5d..1476e43967249 100644 --- a/test/wasm_worker/wait32_notify.c +++ b/test/wasm_worker/wait32_notify.c @@ -1,42 +1,38 @@ -#include +#include #include #include #include // Test emscripten_wasm_wait_i32() and emscripten_wasm_notify() functions. -EM_JS(void, console_log, (char* str), { - console.log(UTF8ToString(str)); -}); - volatile int32_t addr = 0; void worker_main() { - console_log("worker_main"); + emscripten_console_log("worker_main"); emscripten_atomic_store_u32((void*)&addr, 1); - console_log("Waiting on address with unexpected value should return 'not-equal'"); + emscripten_console_log("Waiting on address with unexpected value should return 'not-equal'"); ATOMICS_WAIT_RESULT_T ret = emscripten_wasm_wait_i32((int32_t*)&addr, 2, /*timeout=*/-1); assert(ret == ATOMICS_WAIT_NOT_EQUAL); - console_log("Waiting on address with unexpected value should return 'not-equal' also if timeout==0"); + emscripten_console_log("Waiting on address with unexpected value should return 'not-equal' also if timeout==0"); ret = emscripten_wasm_wait_i32((int32_t*)&addr, 2, /*timeout=*/0); assert(ret == ATOMICS_WAIT_NOT_EQUAL); - console_log("Waiting for 0 nanoseconds should return 'timed-out'"); + emscripten_console_log("Waiting for 0 nanoseconds should return 'timed-out'"); ret = emscripten_wasm_wait_i32((int32_t*)&addr, 1, /*timeout=*/0); assert(ret == ATOMICS_WAIT_TIMED_OUT); - console_log("Waiting for >0 nanoseconds should return 'timed-out'"); + emscripten_console_log("Waiting for >0 nanoseconds should return 'timed-out'"); ret = emscripten_wasm_wait_i32((int32_t*)&addr, 1, /*timeout=*/1000); assert(ret == ATOMICS_WAIT_TIMED_OUT); - console_log("Waiting for infinitely long should return 'ok'"); + emscripten_console_log("Waiting for infinitely long should return 'ok'"); ret = emscripten_wasm_wait_i32((int32_t*)&addr, 1, /*timeout=*/-1); assert(ret == ATOMICS_WAIT_OK); - console_log("Test finished"); + emscripten_console_log("Test finished"); #ifdef REPORT_RESULT REPORT_RESULT(addr); @@ -50,12 +46,12 @@ EM_BOOL main_loop(double time, void *userData) if (addr == 1) { // Burn one second to make sure worker finishes its test. - console_log("main: seen worker running"); + emscripten_console_log("main: seen worker running"); double t0 = emscripten_performance_now(); while(emscripten_performance_now() < t0 + 1000); // Wake the waiter - console_log("main: waking worker"); + emscripten_console_log("main: waking worker"); addr = 2; emscripten_wasm_notify((int32_t*)&addr, 1); @@ -66,11 +62,11 @@ EM_BOOL main_loop(double time, void *userData) int main() { - console_log("main: creating worker"); + emscripten_console_log("main: creating worker"); emscripten_wasm_worker_t worker = emscripten_create_wasm_worker(stack, sizeof(stack)); - console_log("main: posting function"); + emscripten_console_log("main: posting function"); emscripten_wasm_worker_post_function_v(worker, worker_main); - console_log("main: entering timeout loop to wait for wasm worker to run"); + emscripten_console_log("main: entering timeout loop to wait for wasm worker to run"); emscripten_set_timeout_loop(main_loop, 1000, 0); } diff --git a/test/wasm_worker/wait64_notify.c b/test/wasm_worker/wait64_notify.c index 9c903978dc742..14af347ffcb69 100644 --- a/test/wasm_worker/wait64_notify.c +++ b/test/wasm_worker/wait64_notify.c @@ -5,38 +5,34 @@ // Test emscripten_wasm_wait_i64() and emscripten_wasm_notify() functions. -EM_JS(void, console_log, (char* str), { - console.log(UTF8ToString(str)); -}); - volatile int64_t addr = 0; void worker_main() { - console_log("worker_main"); + emscripten_console_log("worker_main"); emscripten_atomic_store_u64((void*)&addr, 0x100000000ull); - console_log("Waiting on address with unexpected value should return 'not-equal'"); + emscripten_console_log("Waiting on address with unexpected value should return 'not-equal'"); ATOMICS_WAIT_RESULT_T ret = emscripten_wasm_wait_i64((int64_t*)&addr, 0x200000000ull, /*timeout=*/-1); assert(ret == ATOMICS_WAIT_NOT_EQUAL); - console_log("Waiting on address with unexpected value should return 'not-equal' also if timeout==0"); + emscripten_console_log("Waiting on address with unexpected value should return 'not-equal' also if timeout==0"); ret = emscripten_wasm_wait_i64((int64_t*)&addr, 0x200000000ull, /*timeout=*/0); assert(ret == ATOMICS_WAIT_NOT_EQUAL); - console_log("Waiting for 0 nanoseconds should return 'timed-out'"); + emscripten_console_log("Waiting for 0 nanoseconds should return 'timed-out'"); ret = emscripten_wasm_wait_i64((int64_t*)&addr, 0x100000000ull, /*timeout=*/0); assert(ret == ATOMICS_WAIT_TIMED_OUT); - console_log("Waiting for >0 nanoseconds should return 'timed-out'"); + emscripten_console_log("Waiting for >0 nanoseconds should return 'timed-out'"); ret = emscripten_wasm_wait_i64((int64_t*)&addr, 0x100000000ull, /*timeout=*/1000); assert(ret == ATOMICS_WAIT_TIMED_OUT); - console_log("Waiting for infinitely long should return 'ok'"); + emscripten_console_log("Waiting for infinitely long should return 'ok'"); ret = emscripten_wasm_wait_i64((int64_t*)&addr, 0x100000000ull, /*timeout=*/-1); assert(ret == ATOMICS_WAIT_OK); - console_log("Test finished"); + emscripten_console_log("Test finished"); #ifdef REPORT_RESULT REPORT_RESULT(addr >> 32); @@ -50,12 +46,12 @@ EM_BOOL main_loop(double time, void *userData) if (addr == 0x100000000ull) { // Burn one second to make sure worker finishes its test. - console_log("main: seen worker running"); + emscripten_console_log("main: seen worker running"); double t0 = emscripten_performance_now(); while(emscripten_performance_now() < t0 + 1000); // Wake the waiter - console_log("main: waking worker"); + emscripten_console_log("main: waking worker"); addr = 0x200000000ull; emscripten_wasm_notify((int32_t*)&addr, 1); @@ -66,11 +62,11 @@ EM_BOOL main_loop(double time, void *userData) int main() { - console_log("main: creating worker"); + emscripten_console_log("main: creating worker"); emscripten_wasm_worker_t worker = emscripten_create_wasm_worker(stack, sizeof(stack)); - console_log("main: posting function"); + emscripten_console_log("main: posting function"); emscripten_wasm_worker_post_function_v(worker, worker_main); - console_log("main: entering timeout loop to wait for wasm worker to run"); + emscripten_console_log("main: entering timeout loop to wait for wasm worker to run"); emscripten_set_timeout_loop(main_loop, 1000, 0); } diff --git a/test/wasm_worker/wait_async.c b/test/wasm_worker/wait_async.c index 9ad0fe1fc6211..3d164d55430b6 100644 --- a/test/wasm_worker/wait_async.c +++ b/test/wasm_worker/wait_async.c @@ -5,19 +5,15 @@ // Test emscripten_wasm_wait_i64() and emscripten_wasm_notify() functions. -EM_JS(void, console_log, (char* str), { - console.log(UTF8ToString(str)); -}); - volatile int32_t addr = 0; void worker_main() { - console_log("worker_main"); + emscripten_console_log("worker_main"); emscripten_wasm_worker_sleep(1000 * 1000000ull); // Sleep one second. - console_log("worker: addr = 1234"); + emscripten_console_log("worker: addr = 1234"); emscripten_atomic_store_u32((void*)&addr, 1234); - console_log("worker: notify async waiting main thread"); + emscripten_console_log("worker: notify async waiting main thread"); emscripten_wasm_notify((int32_t*)&addr, 1); } @@ -27,7 +23,7 @@ int numCalled = 0; void asyncWaitShouldTimeout(int32_t *ptr, uint32_t val, ATOMICS_WAIT_RESULT_T waitResult, void *userData) { - console_log("main: asyncWaitShouldTimeout"); + emscripten_console_log("main: asyncWaitShouldTimeout"); ++numCalled; assert(numCalled == 1); assert(ptr == &addr); @@ -43,14 +39,14 @@ void asyncWaitFinishedShouldNotBeCalled(int32_t *ptr, uint32_t val, ATOMICS_WAIT void asyncWaitFinishedShouldBeOk(int32_t *ptr, uint32_t val, ATOMICS_WAIT_RESULT_T waitResult, void *userData) { - console_log("main: asyncWaitFinished"); + emscripten_console_log("main: asyncWaitFinished"); assert(ptr == &addr); assert(val == 1); assert(userData == (void*)42); ++numCalled; assert(numCalled == 2); assert(waitResult == ATOMICS_WAIT_OK); - console_log("test finished"); + emscripten_console_log("test finished"); #ifdef REPORT_RESULT REPORT_RESULT(0); #endif @@ -58,30 +54,30 @@ void asyncWaitFinishedShouldBeOk(int32_t *ptr, uint32_t val, ATOMICS_WAIT_RESULT int main() { - console_log("main: creating worker"); + emscripten_console_log("main: creating worker"); emscripten_wasm_worker_t worker = emscripten_create_wasm_worker(stack, sizeof(stack)); - console_log("main: posting function"); + emscripten_console_log("main: posting function"); emscripten_wasm_worker_post_function_v(worker, worker_main); addr = 1; - console_log("Async waiting on address with unexpected value should return 'not-equal'"); + emscripten_console_log("Async waiting on address with unexpected value should return 'not-equal'"); ATOMICS_WAIT_TOKEN_T ret = emscripten_atomic_wait_async((int32_t*)&addr, 2, asyncWaitFinishedShouldNotBeCalled, (void*)42, EMSCRIPTEN_WAIT_ASYNC_INFINITY); assert(ret == ATOMICS_WAIT_NOT_EQUAL); - console_log("Waiting on address with unexpected value should return 'not-equal' also if timeout==0"); + emscripten_console_log("Waiting on address with unexpected value should return 'not-equal' also if timeout==0"); ret = emscripten_atomic_wait_async((int32_t*)&addr, 2, asyncWaitFinishedShouldNotBeCalled, (void*)42, 0); assert(ret == ATOMICS_WAIT_NOT_EQUAL); - console_log("Waiting for 0 milliseconds should return 'timed-out'"); + emscripten_console_log("Waiting for 0 milliseconds should return 'timed-out'"); ret = emscripten_atomic_wait_async((int32_t*)&addr, 1, asyncWaitFinishedShouldNotBeCalled, (void*)42, 0); assert(ret == ATOMICS_WAIT_TIMED_OUT); - console_log("Waiting for >0 milliseconds should return 'ok' (but successfully time out in first call to asyncWaitFinished)"); + emscripten_console_log("Waiting for >0 milliseconds should return 'ok' (but successfully time out in first call to asyncWaitFinished)"); ret = emscripten_atomic_wait_async((int32_t*)&addr, 1, asyncWaitShouldTimeout, (void*)42, 10); assert(EMSCRIPTEN_IS_VALID_WAIT_TOKEN(ret)); - console_log("Waiting for infinitely long should return 'ok' (and return 'ok' in second call to asyncWaitFinished)"); + emscripten_console_log("Waiting for infinitely long should return 'ok' (and return 'ok' in second call to asyncWaitFinished)"); ret = emscripten_atomic_wait_async((int32_t*)&addr, 1, asyncWaitFinishedShouldBeOk, (void*)42, EMSCRIPTEN_WAIT_ASYNC_INFINITY); assert(EMSCRIPTEN_IS_VALID_WAIT_TOKEN(ret)); } diff --git a/test/wasm_worker/wasm_worker_self_id.c b/test/wasm_worker/wasm_worker_self_id.c index ade1232242c54..42ed57fce4f8d 100644 --- a/test/wasm_worker/wasm_worker_self_id.c +++ b/test/wasm_worker/wasm_worker_self_id.c @@ -1,13 +1,8 @@ -#include #include #include // Test the function emscripten_wasm_worker_self_id() -EM_JS(void, console_log, (char* str), { - console.log(UTF8ToString(str)); -}); - emscripten_wasm_worker_t worker1 = 0; emscripten_wasm_worker_t worker2 = 0; diff --git a/test/wasm_worker/wasm_worker_sleep.c b/test/wasm_worker/wasm_worker_sleep.c index 4285389b2e99b..e3b87d9421e1e 100644 --- a/test/wasm_worker/wasm_worker_sleep.c +++ b/test/wasm_worker/wasm_worker_sleep.c @@ -1,10 +1,6 @@ -#include +#include #include -EM_JS(void, console_log, (char* str), { - console.log(UTF8ToString(str)); -}); - void worker_main() { double t0 = emscripten_performance_now(); From 27bb0c1c9d4b77fbb8e40a06477b46602fc9e429 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 10 May 2023 14:17:06 -0700 Subject: [PATCH 0218/1523] Build libwasm_worker with standard cflags (#19317) Split out from #19263 --- system/lib/wasm_worker/library_wasm_worker.c | 2 ++ tools/system_libs.py | 15 +++++++++------ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/system/lib/wasm_worker/library_wasm_worker.c b/system/lib/wasm_worker/library_wasm_worker.c index 04ad072092c3e..275794f2a43f4 100644 --- a/system/lib/wasm_worker/library_wasm_worker.c +++ b/system/lib/wasm_worker/library_wasm_worker.c @@ -43,8 +43,10 @@ emscripten_wasm_worker_t emscripten_create_wasm_worker(void *stackLowestAddress, // We expect TLS area to need to be at most 16 bytes aligned assert(__builtin_wasm_tls_align() == 0 || 16 % __builtin_wasm_tls_align() == 0); +#ifndef NDEBUG uint32_t tlsSize = (__builtin_wasm_tls_size() + 15) & -16; assert(stackSize > tlsSize); +#endif return _emscripten_create_wasm_worker(stackLowestAddress, stackSize); } diff --git a/tools/system_libs.py b/tools/system_libs.py index 37642b27b507c..2a00813676e90 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -1333,22 +1333,25 @@ def can_use(self): class libwasm_workers(MTLibrary): + name = 'libwasm_workers' + def __init__(self, **kwargs): self.debug = kwargs.pop('debug') super().__init__(**kwargs) - name = 'libwasm_workers' - def get_cflags(self): - cflags = get_base_cflags() + ['-D_DEBUG' if self.debug else '-Oz'] + cflags = super().get_cflags() if self.debug: + cflags += ['-D_DEBUG'] # library_wasm_worker.c contains an assert that a nonnull paramater # is no NULL, which llvm now warns is redundant/tautological. cflags += ['-Wno-tautological-pointer-compare'] + # Override the `-O2` default. Building library_wasm_worker.c with + # `-O1` or `-O2` currently causes tests to fail. + # https://github.com/emscripten-core/emscripten/issues/19331 + cflags += ['-O0'] else: - cflags += ['-DNDEBUG'] - if self.is_ww or self.is_mt: - cflags += ['-pthread', '-sWASM_WORKERS'] + cflags += ['-DNDEBUG', '-Oz'] if settings.MAIN_MODULE: cflags += ['-fPIC'] return cflags From 0dcfc0f0607cf0e3678144b9b537f1d616cf563e Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 10 May 2023 15:37:40 -0700 Subject: [PATCH 0219/1523] Rebaseline codesize expectations. NFC --- test/other/metadce/test_metadce_cxx_ctors1.size | 2 +- test/other/metadce/test_metadce_cxx_ctors2.size | 2 +- test/other/metadce/test_metadce_cxx_except.size | 2 +- test/other/metadce/test_metadce_cxx_except_wasm.size | 2 +- test/other/metadce/test_metadce_cxx_mangle.size | 2 +- test/other/metadce/test_metadce_cxx_noexcept.size | 2 +- test/other/metadce/test_metadce_minimal_pthreads.size | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/test/other/metadce/test_metadce_cxx_ctors1.size b/test/other/metadce/test_metadce_cxx_ctors1.size index 7cb7cf00d785b..c3e6c8e8b8cec 100644 --- a/test/other/metadce/test_metadce_cxx_ctors1.size +++ b/test/other/metadce/test_metadce_cxx_ctors1.size @@ -1 +1 @@ -123479 +123502 diff --git a/test/other/metadce/test_metadce_cxx_ctors2.size b/test/other/metadce/test_metadce_cxx_ctors2.size index 7a2e462123ec6..e9659e9d95013 100644 --- a/test/other/metadce/test_metadce_cxx_ctors2.size +++ b/test/other/metadce/test_metadce_cxx_ctors2.size @@ -1 +1 @@ -123373 +123407 diff --git a/test/other/metadce/test_metadce_cxx_except.size b/test/other/metadce/test_metadce_cxx_except.size index 27e59ea3c5748..75ce5068ec801 100644 --- a/test/other/metadce/test_metadce_cxx_except.size +++ b/test/other/metadce/test_metadce_cxx_except.size @@ -1 +1 @@ -166244 +166271 diff --git a/test/other/metadce/test_metadce_cxx_except_wasm.size b/test/other/metadce/test_metadce_cxx_except_wasm.size index c2edb388c6c10..d1ea9f9b1f5fc 100644 --- a/test/other/metadce/test_metadce_cxx_except_wasm.size +++ b/test/other/metadce/test_metadce_cxx_except_wasm.size @@ -1 +1 @@ -137042 +137069 diff --git a/test/other/metadce/test_metadce_cxx_mangle.size b/test/other/metadce/test_metadce_cxx_mangle.size index d310455c80818..d3ad8dde956d8 100644 --- a/test/other/metadce/test_metadce_cxx_mangle.size +++ b/test/other/metadce/test_metadce_cxx_mangle.size @@ -1 +1 @@ -219418 +221359 diff --git a/test/other/metadce/test_metadce_cxx_noexcept.size b/test/other/metadce/test_metadce_cxx_noexcept.size index b8f5d0b10a39e..04a2ee6190e4b 100644 --- a/test/other/metadce/test_metadce_cxx_noexcept.size +++ b/test/other/metadce/test_metadce_cxx_noexcept.size @@ -1 +1 @@ -126272 +126299 diff --git a/test/other/metadce/test_metadce_minimal_pthreads.size b/test/other/metadce/test_metadce_minimal_pthreads.size index 1350e12aa189f..677ec1c885444 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.size +++ b/test/other/metadce/test_metadce_minimal_pthreads.size @@ -1 +1 @@ -19050 +19028 From ca69e264233460417e6247451ce1e63a0eca9a69 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 10 May 2023 15:54:45 -0700 Subject: [PATCH 0220/1523] Mark 3.1.38 as released (#19332) --- ChangeLog.md | 5 ++++- emscripten-version.txt | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index cb002a75f86e4..48593447f5eeb 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -18,8 +18,11 @@ to browse the changes between the tags. See docs/process.md for more on how version tagging works. -3.1.38 (in development) +3.1.39 (in development) ----------------------- + +3.1.38 - 05/10/23 +----------------- - The `dladdr` function will now always return an error rather than filling in dummy values. (#19319) - The restriction preventing the use of dynamic linking in combination with diff --git a/emscripten-version.txt b/emscripten-version.txt index 60a4a5635012d..a3355af430b15 100644 --- a/emscripten-version.txt +++ b/emscripten-version.txt @@ -1 +1 @@ -3.1.38-git +3.1.39-git From cb54282c665563bc41403036a53fa3c244f24657 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 10 May 2023 17:31:53 -0700 Subject: [PATCH 0221/1523] Use multi-line JS string in library_wasm_worker. NFC (#19330) --- src/library_wasm_worker.js | 66 +++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/src/library_wasm_worker.js b/src/library_wasm_worker.js index a7f3a91f35963..3a362c3321ce6 100644 --- a/src/library_wasm_worker.js +++ b/src/library_wasm_worker.js @@ -227,41 +227,41 @@ mergeInto(LibraryManager.library, { // see https://bugs.chromium.org/p/chromium/issues/detail?id=1167541 // https://github.com/tc39/proposal-atomics-wait-async/blob/master/PROPOSAL.md // This polyfill performs polling with setTimeout() to observe a change in the target memory location. - emscripten_atomic_wait_async__postset: "if (!Atomics['waitAsync'] || jstoi_q((navigator.userAgent.match(/Chrom(e|ium)\\/([0-9]+)\\./)||[])[2]) < 91) { \n"+ -"let __Atomics_waitAsyncAddresses = [/*[i32a, index, value, maxWaitMilliseconds, promiseResolve]*/];\n"+ -"function __Atomics_pollWaitAsyncAddresses() {\n"+ -" let now = performance.now();\n"+ -" let l = __Atomics_waitAsyncAddresses.length;\n"+ -" for(let i = 0; i < l; ++i) {\n"+ -" let a = __Atomics_waitAsyncAddresses[i];\n"+ -" let expired = (now > a[3]);\n"+ -" let awoken = (Atomics.load(a[0], a[1]) != a[2]);\n"+ -" if (expired || awoken) {\n"+ -" __Atomics_waitAsyncAddresses[i--] = __Atomics_waitAsyncAddresses[--l];\n"+ -" __Atomics_waitAsyncAddresses.length = l;\n"+ -" a[4](awoken ? 'ok': 'timed-out');\n"+ -" }\n"+ -" }\n"+ -" if (l) {\n"+ -" // If we still have addresses to wait, loop the timeout handler to continue polling.\n"+ -" setTimeout(__Atomics_pollWaitAsyncAddresses, 10);\n"+ -" }\n"+ -"}\n"+ + emscripten_atomic_wait_async__postset: `if (!Atomics['waitAsync'] || jstoi_q((navigator.userAgent.match(/Chrom(e|ium)\\/([0-9]+)\\./)||[])[2]) < 91) { +let __Atomics_waitAsyncAddresses = [/*[i32a, index, value, maxWaitMilliseconds, promiseResolve]*/]; +function __Atomics_pollWaitAsyncAddresses() { + let now = performance.now(); + let l = __Atomics_waitAsyncAddresses.length; + for(let i = 0; i < l; ++i) { + let a = __Atomics_waitAsyncAddresses[i]; + let expired = (now > a[3]); + let awoken = (Atomics.load(a[0], a[1]) != a[2]); + if (expired || awoken) { + __Atomics_waitAsyncAddresses[i--] = __Atomics_waitAsyncAddresses[--l]; + __Atomics_waitAsyncAddresses.length = l; + a[4](awoken ? 'ok': 'timed-out'); + } + } + if (l) { + // If we still have addresses to wait, loop the timeout handler to continue polling. + setTimeout(__Atomics_pollWaitAsyncAddresses, 10); + } +} #if ASSERTIONS -" if (!ENVIRONMENT_IS_WASM_WORKER) console.error('Current environment does not support Atomics.waitAsync(): polyfilling it, but this is going to be suboptimal.');\n"+ + if (!ENVIRONMENT_IS_WASM_WORKER) err('Current environment does not support Atomics.waitAsync(): polyfilling it, but this is going to be suboptimal.'); #endif -"Atomics['waitAsync'] = function(i32a, index, value, maxWaitMilliseconds) {\n"+ -" let val = Atomics.load(i32a, index);\n"+ -" if (val != value) return { async: false, value: 'not-equal' };\n"+ -" if (maxWaitMilliseconds <= 0) return { async: false, value: 'timed-out' };\n"+ -" maxWaitMilliseconds = performance.now() + (maxWaitMilliseconds || Infinity);\n"+ -" let promiseResolve;\n"+ -" let promise = new Promise((resolve) => { promiseResolve = resolve; });\n"+ -" if (!__Atomics_waitAsyncAddresses[0]) setTimeout(__Atomics_pollWaitAsyncAddresses, 10);\n"+ -" __Atomics_waitAsyncAddresses.push([i32a, index, value, maxWaitMilliseconds, promiseResolve]);\n"+ -" return { async: true, value: promise };\n"+ -"};\n"+ -"}", +Atomics['waitAsync'] = function(i32a, index, value, maxWaitMilliseconds) { + let val = Atomics.load(i32a, index); + if (val != value) return { async: false, value: 'not-equal' }; + if (maxWaitMilliseconds <= 0) return { async: false, value: 'timed-out' }; + maxWaitMilliseconds = performance.now() + (maxWaitMilliseconds || Infinity); + let promiseResolve; + let promise = new Promise((resolve) => { promiseResolve = resolve; }); + if (!__Atomics_waitAsyncAddresses[0]) setTimeout(__Atomics_pollWaitAsyncAddresses, 10); + __Atomics_waitAsyncAddresses.push([i32a, index, value, maxWaitMilliseconds, promiseResolve]); + return { async: true, value: promise }; +}; +}`, // These dependencies are artificial, issued so that we still get the waitAsync polyfill emitted // if code only calls emscripten_lock/semaphore_async_acquire() From ae8d76b29f181176d8258fd11a9899e25b42fe57 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 10 May 2023 19:22:39 -0700 Subject: [PATCH 0222/1523] Auto-generate sigs for `src/library_wasm_worker.js` (#19263) --- emcc.py | 2 +- src/library_sigs.js | 21 +++ src/library_wasm_worker.js | 134 +++++++++---------- src/library_webaudio.js | 4 +- src/postamble_minimal.js | 2 +- src/preamble.js | 2 +- system/lib/libc/emscripten_internal.h | 5 + system/lib/wasm_worker/library_wasm_worker.c | 6 +- test/code_size/hello_wasm_worker_wasm.js | 28 ++-- tools/gen_sig_info.py | 2 + tools/system_libs.py | 1 + 11 files changed, 116 insertions(+), 91 deletions(-) diff --git a/emcc.py b/emcc.py index 4eb50e9988563..d0d09f294acc3 100755 --- a/emcc.py +++ b/emcc.py @@ -2426,7 +2426,7 @@ def phase_linker_setup(options, state, newargs): wasm_worker_imports = ['_emscripten_wasm_worker_initialize', '___set_thread_state'] settings.EXPORTED_FUNCTIONS += wasm_worker_imports building.user_requested_exports.update(wasm_worker_imports) - settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['_wasm_worker_initializeRuntime'] + settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['$_wasmWorkerInitializeRuntime'] # set location of Wasm Worker bootstrap JS file if settings.WASM_WORKERS == 1: settings.WASM_WORKER_FILE = unsuffixed(os.path.basename(target)) + '.ww.js' diff --git a/src/library_sigs.js b/src/library_sigs.js index 688854ff66566..6ac5f18275d08 100644 --- a/src/library_sigs.js +++ b/src/library_sigs.js @@ -298,6 +298,7 @@ sigs = { _embind_register_value_object__sig: 'vpppppp', _embind_register_value_object_field__sig: 'vpppppppppp', _embind_register_void__sig: 'vpp', + _emscripten_create_wasm_worker__sig: 'ipi', _emscripten_dbg__sig: 'vp', _emscripten_default_pthread_stack_size__sig: 'i', _emscripten_dlopen_js__sig: 'vpppp', @@ -505,6 +506,11 @@ sigs = { emscripten_async_wget2_abort__sig: 'vi', emscripten_async_wget2_data__sig: 'ippppippp', emscripten_async_wget_data__sig: 'vpppp', + emscripten_atomic_cancel_all_wait_asyncs__sig: 'i', + emscripten_atomic_cancel_all_wait_asyncs_at_address__sig: 'ip', + emscripten_atomic_cancel_wait_async__sig: 'ii', + emscripten_atomic_wait_async__sig: 'ipippd', + emscripten_atomics_is_lock_free__sig: 'ii', emscripten_audio_context_state__sig: 'ii', emscripten_audio_worklet_post_function_sig__sig: 'vippp', emscripten_audio_worklet_post_function_v__sig: 'vip', @@ -529,6 +535,7 @@ sigs = { emscripten_create_wasm_audio_worklet_processor_async__sig: 'vippp', emscripten_create_worker__sig: 'ip', emscripten_current_thread_is_audio_worklet__sig: 'i', + emscripten_current_thread_is_wasm_worker__sig: 'i', emscripten_date_now__sig: 'd', emscripten_debugger__sig: 'v', emscripten_destroy_audio_context__sig: 'vi', @@ -583,6 +590,7 @@ sigs = { emscripten_idb_load__sig: 'vppppp', emscripten_idb_store__sig: 'vpppip', emscripten_is_webgl_context_lost__sig: 'ii', + emscripten_lock_async_acquire__sig: 'vpppd', emscripten_lock_orientation__sig: 'ii', emscripten_log__sig: 'vipp', emscripten_math_acos__sig: 'dd', @@ -613,6 +621,7 @@ sigs = { emscripten_math_tan__sig: 'dd', emscripten_math_tanh__sig: 'dd', emscripten_memcpy_big__sig: 'vppp', + emscripten_navigator_hardware_concurrency__sig: 'i', emscripten_notify_memory_growth__sig: 'vp', emscripten_num_logical_cores__sig: 'i', emscripten_pause_main_loop__sig: 'v', @@ -652,6 +661,7 @@ sigs = { emscripten_runtime_keepalive_push__sig: 'v', emscripten_sample_gamepad_data__sig: 'i', emscripten_scan_registers__sig: 'vp', + emscripten_semaphore_async_acquire__sig: 'vpippd', emscripten_set_batterychargingchange_callback_on_thread__sig: 'ippp', emscripten_set_batterylevelchange_callback_on_thread__sig: 'ippp', emscripten_set_beforeunload_callback_on_thread__sig: 'ippp', @@ -714,6 +724,8 @@ sigs = { emscripten_start_fetch__sig: 'vp', emscripten_start_wasm_audio_worklet_thread_async__sig: 'vipipp', emscripten_supports_offscreencanvas__sig: 'i', + emscripten_terminate_all_wasm_workers__sig: 'v', + emscripten_terminate_wasm_worker__sig: 'vi', emscripten_throw_number__sig: 'vd', emscripten_throw_string__sig: 'vp', emscripten_trace_annotate_address_type__sig: 'vpp', @@ -745,6 +757,15 @@ sigs = { emscripten_unwind_to_js_event_loop__sig: 'v', emscripten_vibrate__sig: 'ii', emscripten_vibrate_pattern__sig: 'ipi', + emscripten_wasm_worker_post_function_sig__sig: 'vippp', + emscripten_wasm_worker_post_function_v__sig: 'vip', + emscripten_wasm_worker_post_function_vd__sig: 'vipd', + emscripten_wasm_worker_post_function_vdd__sig: 'vipdd', + emscripten_wasm_worker_post_function_vddd__sig: 'vipddd', + emscripten_wasm_worker_post_function_vi__sig: 'vipi', + emscripten_wasm_worker_post_function_vii__sig: 'vipii', + emscripten_wasm_worker_post_function_viii__sig: 'vipiii', + emscripten_wasm_worker_self_id__sig: 'i', emscripten_webgl_commit_frame__sig: 'i', emscripten_webgl_create_context__sig: 'ipp', emscripten_webgl_destroy_context__sig: 'ii', diff --git a/src/library_wasm_worker.js b/src/library_wasm_worker.js index 3a362c3321ce6..6b0a47b4e5d3a 100644 --- a/src/library_wasm_worker.js +++ b/src/library_wasm_worker.js @@ -30,28 +30,28 @@ mergeInto(LibraryManager.library, { - wasm_workers: {}, - wasm_workers_id: 1, + $_wasmWorkers: {}, + $_wasmWorkersID: 1, // Starting up a Wasm Worker is an asynchronous operation, hence if the parent thread performs any // postMessage()-based wasm function calls s to the Worker, they must be delayed until the async // startup has finished, after which these postponed function calls can be dispatched. - _wasm_worker_delayedMessageQueue: [], + $_wasmWorkerDelayedMessageQueue: [], - _wasm_worker_appendToQueue: function(e) { - __wasm_worker_delayedMessageQueue.push(e); + $_wasmWorkerAppendToQueue: function(e) { + _wasmWorkerDelayedMessageQueue.push(e); }, // Executes a wasm function call received via a postMessage. - _wasm_worker_runPostMessage: function(e) { + $_wasmWorkerRunPostMessage: function(e) { let data = e.data, wasmCall = data['_wsc']; // '_wsc' is short for 'wasm call', trying to use an identifier name that will never conflict with user code wasmCall && getWasmTableEntry(wasmCall)(...data['x']); }, // src/postamble_minimal.js brings this symbol in to the build, and calls this function synchronously // from main JS file at the startup of each Worker. - _wasm_worker_initializeRuntime__deps: ['_wasm_worker_delayedMessageQueue', '_wasm_worker_runPostMessage', '_wasm_worker_appendToQueue'], - _wasm_worker_initializeRuntime: function() { + $_wasmWorkerInitializeRuntime__deps: ['$_wasmWorkerDelayedMessageQueue', '$_wasmWorkerRunPostMessage', '$_wasmWorkerAppendToQueue', 'emscripten_wasm_worker_initialize'], + $_wasmWorkerInitializeRuntime: function() { let m = Module; #if ASSERTIONS assert(m['sb'] % 16 == 0); @@ -87,13 +87,13 @@ mergeInto(LibraryManager.library, { // The Wasm Worker runtime is now up, so we can start processing // any postMessage function calls that have been received. Drop the temp // message handler that queued any pending incoming postMessage function calls ... - removeEventListener('message', __wasm_worker_appendToQueue); + removeEventListener('message', _wasmWorkerAppendToQueue); // ... then flush whatever messages we may have already gotten in the queue, - // and clear __wasm_worker_delayedMessageQueue to undefined ... - __wasm_worker_delayedMessageQueue = __wasm_worker_delayedMessageQueue.forEach(__wasm_worker_runPostMessage); + // and clear _wasmWorkerDelayedMessageQueue to undefined ... + _wasmWorkerDelayedMessageQueue = _wasmWorkerDelayedMessageQueue.forEach(_wasmWorkerRunPostMessage); // ... and finally register the proper postMessage handler that immediately // dispatches incoming function calls without queueing them. - addEventListener('message', __wasm_worker_runPostMessage); + addEventListener('message', _wasmWorkerRunPostMessage); #if AUDIO_WORKLET } #endif @@ -102,22 +102,22 @@ mergeInto(LibraryManager.library, { #if WASM_WORKERS == 2 // In WASM_WORKERS == 2 build mode, we create the Wasm Worker global scope script from a string bundled in the main application JS file. This simplifies the number of deployed JS files with the app, // but has a downside that the generated build output will no longer be csp-eval compliant. https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src#unsafe_eval_expressions - _wasmWorkerBlobUrl: "URL.createObjectURL(new Blob(['onmessage=function(d){onmessage=null;d=d.data;{{{ captureModuleArg() }}}{{{ instantiateWasm() }}}importScripts(d.js);{{{ instantiateModule() }}}d.wasm=d.mem=d.js=0;}'],{type:'application/javascript'}))", + $_wasmWorkerBlobUrl: "URL.createObjectURL(new Blob(['onmessage=function(d){onmessage=null;d=d.data;{{{ captureModuleArg() }}}{{{ instantiateWasm() }}}importScripts(d.js);{{{ instantiateModule() }}}d.wasm=d.mem=d.js=0;}'],{type:'application/javascript'}))", #endif - _emscripten_create_wasm_worker__deps: ['wasm_workers', 'wasm_workers_id', '_wasm_worker_appendToQueue', '_wasm_worker_runPostMessage' + _emscripten_create_wasm_worker__deps: ['$_wasmWorkers', '$_wasmWorkersID', '$_wasmWorkerAppendToQueue', '$_wasmWorkerRunPostMessage' #if WASM_WORKERS == 2 - , '_wasmWorkerBlobUrl' + , '$_wasmWorkerBlobUrl' #endif ], _emscripten_create_wasm_worker__postset: 'if (ENVIRONMENT_IS_WASM_WORKER) {\n' - + '_wasm_workers[0] = this;\n' - + 'addEventListener("message", __wasm_worker_appendToQueue);\n' + + '_wasmWorkers[0] = this;\n' + + 'addEventListener("message", _wasmWorkerAppendToQueue);\n' + '}\n', _emscripten_create_wasm_worker: function(stackLowestAddress, stackSize) { - let worker = _wasm_workers[_wasm_workers_id] = new Worker( + let worker = _wasmWorkers[_wasmWorkersID] = new Worker( #if WASM_WORKERS == 2 // WASM_WORKERS=2 mode embeds .ww.js file contents into the main .js file as a Blob URL. (convenient, but not CSP security safe, since this is eval-like) - __wasmWorkerBlobUrl + _wasmWorkerBlobUrl #elif MINIMAL_RUNTIME // MINIMAL_RUNTIME has a structure where the .ww.js file is loaded from the main HTML file in parallel to all other files for best performance Module['$wb'] // $wb="Wasm worker Blob", abbreviated since not DCEable #else // default runtime loads the .ww.js file on demand. @@ -126,7 +126,7 @@ mergeInto(LibraryManager.library, { ); // Craft the Module object for the Wasm Worker scope: worker.postMessage({ - '$ww': _wasm_workers_id, // Signal with a non-zero value that this Worker will be a Wasm Worker, and not the main browser thread. + '$ww': _wasmWorkersID, // Signal with a non-zero value that this Worker will be a Wasm Worker, and not the main browser thread. #if MINIMAL_RUNTIME 'wasm': Module['wasm'], 'js': Module['js'], @@ -139,17 +139,17 @@ mergeInto(LibraryManager.library, { 'sb': stackLowestAddress, // sb = stack bottom (lowest stack address, SP points at this when stack is full) 'sz': stackSize, // sz = stack size }); - worker.onmessage = __wasm_worker_runPostMessage; - return _wasm_workers_id++; + worker.onmessage = _wasmWorkerRunPostMessage; + return _wasmWorkersID++; }, emscripten_terminate_wasm_worker: function(id) { #if ASSERTIONS assert(id != 0, 'emscripten_terminate_wasm_worker() cannot be called with id=0!'); #endif - if (_wasm_workers[id]) { - _wasm_workers[id].terminate(); - delete _wasm_workers[id]; + if (_wasmWorkers[id]) { + _wasmWorkers[id].terminate(); + delete _wasmWorkers[id]; } }, @@ -157,10 +157,10 @@ mergeInto(LibraryManager.library, { #if ASSERTIONS assert(!ENVIRONMENT_IS_WASM_WORKER, 'emscripten_terminate_all_wasm_workers() cannot be called from a Wasm Worker: only the main browser thread has visibility to terminate all Workers!'); #endif - Object.values(_wasm_workers).forEach((worker) => { + Object.values(_wasmWorkers).forEach((worker) => { worker.terminate(); }); - _wasm_workers = {}; + _wasmWorkers = {}; }, emscripten_current_thread_is_wasm_worker: function() { @@ -175,35 +175,33 @@ mergeInto(LibraryManager.library, { return Module['$ww']; }, - emscripten_wasm_worker_post_function_v__sig: 'vip', emscripten_wasm_worker_post_function_v: function(id, funcPtr) { - _wasm_workers[id].postMessage({'_wsc': funcPtr, 'x': [] }); // "WaSm Call" + _wasmWorkers[id].postMessage({'_wsc': funcPtr, 'x': [] }); // "WaSm Call" }, - emscripten_wasm_worker_post_function_1__sig: 'vipd', - emscripten_wasm_worker_post_function_1: function(id, funcPtr, arg0) { - _wasm_workers[id].postMessage({'_wsc': funcPtr, 'x': [arg0] }); // "WaSm Call" + $_wasmWorkerPostFunction1__sig: 'vipd', + $_wasmWorkerPostFunction1: function(id, funcPtr, arg0) { + _wasmWorkers[id].postMessage({'_wsc': funcPtr, 'x': [arg0] }); // "WaSm Call" }, - emscripten_wasm_worker_post_function_vi: 'emscripten_wasm_worker_post_function_1', - emscripten_wasm_worker_post_function_vd: 'emscripten_wasm_worker_post_function_1', + emscripten_wasm_worker_post_function_vi: '$_wasmWorkerPostFunction1', + emscripten_wasm_worker_post_function_vd: '$_wasmWorkerPostFunction1', - emscripten_wasm_worker_post_function_2__sig: 'vipdd', - emscripten_wasm_worker_post_function_2: function(id, funcPtr, arg0, arg1) { - _wasm_workers[id].postMessage({'_wsc': funcPtr, 'x': [arg0, arg1] }); // "WaSm Call" + $_wasmWorkerPostFunction2__sig: 'vipdd', + $_wasmWorkerPostFunction2: function(id, funcPtr, arg0, arg1) { + _wasmWorkers[id].postMessage({'_wsc': funcPtr, 'x': [arg0, arg1] }); // "WaSm Call" }, - emscripten_wasm_worker_post_function_vii: 'emscripten_wasm_worker_post_function_2', - emscripten_wasm_worker_post_function_vdd: 'emscripten_wasm_worker_post_function_2', + emscripten_wasm_worker_post_function_vii: '$_wasmWorkerPostFunction2', + emscripten_wasm_worker_post_function_vdd: '$_wasmWorkerPostFunction2', - emscripten_wasm_worker_post_function_3__sig: 'vipddd', - emscripten_wasm_worker_post_function_3: function(id, funcPtr, arg0, arg1, arg2) { - _wasm_workers[id].postMessage({'_wsc': funcPtr, 'x': [arg0, arg1, arg2] }); // "WaSm Call" + $_wasmWorkerPostFunction3__sig: 'vipddd', + $_wasmWorkerPostFunction3: function(id, funcPtr, arg0, arg1, arg2) { + _wasmWorkers[id].postMessage({'_wsc': funcPtr, 'x': [arg0, arg1, arg2] }); // "WaSm Call" }, - emscripten_wasm_worker_post_function_viii: 'emscripten_wasm_worker_post_function_3', - emscripten_wasm_worker_post_function_vddd: 'emscripten_wasm_worker_post_function_3', + emscripten_wasm_worker_post_function_viii: '$_wasmWorkerPostFunction3', + emscripten_wasm_worker_post_function_vddd: '$_wasmWorkerPostFunction3', emscripten_wasm_worker_post_function_sig__deps: ['$readEmAsmArgs'], - emscripten_wasm_worker_post_function_sig__sig: 'vippp', emscripten_wasm_worker_post_function_sig: function(id, funcPtr, sigPtr, varargs) { #if ASSERTIONS assert(id >= 0); @@ -212,10 +210,10 @@ mergeInto(LibraryManager.library, { assert(UTF8ToString(sigPtr)[0] != 'v', 'Do NOT specify the return argument in the signature string for a call to emscripten_wasm_worker_post_function_sig(), just pass the function arguments.'); assert(varargs); #endif - _wasm_workers[id].postMessage({'_wsc': funcPtr, 'x': readEmAsmArgs(sigPtr, varargs) }); + _wasmWorkers[id].postMessage({'_wsc': funcPtr, 'x': readEmAsmArgs(sigPtr, varargs) }); }, - _emscripten_atomic_wait_states: "['ok', 'not-equal', 'timed-out']", + $atomicWaitStates: "['ok', 'not-equal', 'timed-out']", // Chrome 87 (and hence Edge 87) shipped Atomics.waitAsync (https://www.chromestatus.com/feature/6243382101803008) // However its implementation is faulty: https://bugs.chromium.org/p/chromium/issues/detail?id=1167541 @@ -271,65 +269,65 @@ Atomics['waitAsync'] = function(i32a, index, value, maxWaitMilliseconds) { #endif - _emscripten_atomic_live_wait_asyncs: '{}', - _emscripten_atomic_live_wait_asyncs_counter: '0', + $atomicLiveWaitAsyncs: '{}', + $atomicLiveWaitAsyncsCounter: '0', - emscripten_atomic_wait_async__deps: ['_emscripten_atomic_wait_states', '_emscripten_atomic_live_wait_asyncs', '_emscripten_atomic_live_wait_asyncs_counter', '$jstoi_q'], + emscripten_atomic_wait_async__deps: ['$atomicWaitStates', '$atomicLiveWaitAsyncs', '$atomicLiveWaitAsyncsCounter', '$jstoi_q'], emscripten_atomic_wait_async: function(addr, val, asyncWaitFinished, userData, maxWaitMilliseconds) { let wait = Atomics['waitAsync'](HEAP32, addr >> 2, val, maxWaitMilliseconds); - if (!wait.async) return __emscripten_atomic_wait_states.indexOf(wait.value); + if (!wait.async) return atomicWaitStates.indexOf(wait.value); // Increment waitAsync generation counter, account for wraparound in case application does huge amounts of waitAsyncs per second (not sure if possible?) // Valid counterrange: 0...2^31-1 - let counter = __emscripten_atomic_live_wait_asyncs_counter; - __emscripten_atomic_live_wait_asyncs_counter = Math.max(0, (__emscripten_atomic_live_wait_asyncs_counter+1)|0); - __emscripten_atomic_live_wait_asyncs[counter] = addr >> 2; + let counter = atomicLiveWaitAsyncsCounter; + atomicLiveWaitAsyncsCounter = Math.max(0, (atomicLiveWaitAsyncsCounter+1)|0); + atomicLiveWaitAsyncs[counter] = addr >> 2; wait.value.then((value) => { - if (__emscripten_atomic_live_wait_asyncs[counter]) { - delete __emscripten_atomic_live_wait_asyncs[counter]; - {{{ makeDynCall('viiii', 'asyncWaitFinished') }}}(addr, val, __emscripten_atomic_wait_states.indexOf(value), userData); + if (atomicLiveWaitAsyncs[counter]) { + delete atomicLiveWaitAsyncs[counter]; + {{{ makeDynCall('viiii', 'asyncWaitFinished') }}}(addr, val, atomicWaitStates.indexOf(value), userData); } }); return -counter; }, - emscripten_atomic_cancel_wait_async__deps: ['_emscripten_atomic_live_wait_asyncs'], + emscripten_atomic_cancel_wait_async__deps: ['$atomicLiveWaitAsyncs'], emscripten_atomic_cancel_wait_async: function(waitToken) { #if ASSERTIONS if (waitToken == 1 /* ATOMICS_WAIT_NOT_EQUAL */) warnOnce('Attempted to call emscripten_atomic_cancel_wait_async() with a value ATOMICS_WAIT_NOT_EQUAL (1) that is not a valid wait token! Check success in return value from call to emscripten_atomic_wait_async()'); else if (waitToken == 2 /* ATOMICS_WAIT_TIMED_OUT */) warnOnce('Attempted to call emscripten_atomic_cancel_wait_async() with a value ATOMICS_WAIT_TIMED_OUT (2) that is not a valid wait token! Check success in return value from call to emscripten_atomic_wait_async()'); else if (waitToken > 0) warnOnce('Attempted to call emscripten_atomic_cancel_wait_async() with an invalid wait token value ' + waitToken); #endif - if (__emscripten_atomic_live_wait_asyncs[waitToken]) { + if (atomicLiveWaitAsyncs[waitToken]) { // Notify the waitAsync waiters on the memory location, so that JavaScript garbage collection can occur // See https://github.com/WebAssembly/threads/issues/176 // This has the unfortunate effect of causing spurious wakeup of all other waiters at the address (which // causes a small performance loss) - Atomics.notify(HEAP32, __emscripten_atomic_live_wait_asyncs[waitToken]); - delete __emscripten_atomic_live_wait_asyncs[waitToken]; + Atomics.notify(HEAP32, atomicLiveWaitAsyncs[waitToken]); + delete atomicLiveWaitAsyncs[waitToken]; return 0 /* EMSCRIPTEN_RESULT_SUCCESS */; } // This waitToken does not exist. return -5 /* EMSCRIPTEN_RESULT_INVALID_PARAM */; }, - emscripten_atomic_cancel_all_wait_asyncs__deps: ['_emscripten_atomic_live_wait_asyncs'], + emscripten_atomic_cancel_all_wait_asyncs__deps: ['$atomicLiveWaitAsyncs'], emscripten_atomic_cancel_all_wait_asyncs: function() { - let waitAsyncs = Object.values(__emscripten_atomic_live_wait_asyncs); + let waitAsyncs = Object.values(atomicLiveWaitAsyncs); waitAsyncs.forEach((address) => { Atomics.notify(HEAP32, address); }); - __emscripten_atomic_live_wait_asyncs = {}; + atomicLiveWaitAsyncs = {}; return waitAsyncs.length; }, - emscripten_atomic_cancel_all_wait_asyncs_at_address__deps: ['_emscripten_atomic_live_wait_asyncs'], + emscripten_atomic_cancel_all_wait_asyncs_at_address__deps: ['$atomicLiveWaitAsyncs'], emscripten_atomic_cancel_all_wait_asyncs_at_address: function(address) { address >>= 2; let numCancelled = 0; - Object.keys(__emscripten_atomic_live_wait_asyncs).forEach((waitToken) => { - if (__emscripten_atomic_live_wait_asyncs[waitToken] == address) { + Object.keys(atomicLiveWaitAsyncs).forEach((waitToken) => { + if (atomicLiveWaitAsyncs[waitToken] == address) { Atomics.notify(HEAP32, address); - delete __emscripten_atomic_live_wait_asyncs[waitToken]; + delete atomicLiveWaitAsyncs[waitToken]; ++numCancelled; } }); diff --git a/src/library_webaudio.js b/src/library_webaudio.js index 9b4942f0aa472..aaf28d386fb45 100644 --- a/src/library_webaudio.js +++ b/src/library_webaudio.js @@ -123,7 +123,7 @@ let LibraryWebAudio = { #if AUDIO_WORKLET emscripten_start_wasm_audio_worklet_thread_async__deps: [ - 'wasm_workers_id', + '$_wasmWorkersID', '$_EmAudioDispatchProcessorCallback'], emscripten_start_wasm_audio_worklet_thread_async: function(contextHandle, stackLowestAddress, stackSize, callback, userData) { @@ -175,7 +175,7 @@ let LibraryWebAudio = { #endif audioWorklet.bootstrapMessage = new AudioWorkletNode(audioContext, 'message', { processorOptions: { - '$ww': _wasm_workers_id++, // Assign the loaded AudioWorkletGlobalScope a Wasm Worker ID so that it can utilized its own TLS slots, and it is recognized to not be the main browser thread. + '$ww': _wasmWorkersID++, // Assign the loaded AudioWorkletGlobalScope a Wasm Worker ID so that it can utilized its own TLS slots, and it is recognized to not be the main browser thread. #if MINIMAL_RUNTIME 'wasm': Module['wasm'], 'mem': wasmMemory, diff --git a/src/postamble_minimal.js b/src/postamble_minimal.js index 396d955b43ef6..e8d50122f579f 100644 --- a/src/postamble_minimal.js +++ b/src/postamble_minimal.js @@ -65,7 +65,7 @@ function initRuntime(asm) { #endif #if WASM_WORKERS - if (ENVIRONMENT_IS_WASM_WORKER) return __wasm_worker_initializeRuntime(); + if (ENVIRONMENT_IS_WASM_WORKER) return _wasmWorkerInitializeRuntime(); #endif #if STACK_OVERFLOW_CHECK diff --git a/src/preamble.js b/src/preamble.js index 55fb916518437..51783e5a5f386 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -221,7 +221,7 @@ function initRuntime() { runtimeInitialized = true; #if WASM_WORKERS - if (ENVIRONMENT_IS_WASM_WORKER) return __wasm_worker_initializeRuntime(); + if (ENVIRONMENT_IS_WASM_WORKER) return _wasmWorkerInitializeRuntime(); #endif #if PTHREADS diff --git a/system/lib/libc/emscripten_internal.h b/system/lib/libc/emscripten_internal.h index 4aff06e6b1a35..0d878c49ebe47 100644 --- a/system/lib/libc/emscripten_internal.h +++ b/system/lib/libc/emscripten_internal.h @@ -14,6 +14,7 @@ #include #include #include +#include #include // for `sighandler_t` #include // for `bool` @@ -132,6 +133,10 @@ void _emscripten_fetch_free(unsigned int); EMSCRIPTEN_RESULT _emscripten_set_offscreencanvas_size(const char *target, int width, int height); +// Internal implementation function in JavaScript side that emscripten_create_wasm_worker() calls to +// to perform the wasm worker creation. +emscripten_wasm_worker_t _emscripten_create_wasm_worker(void *stackLowestAddress, uint32_t stackSize); + #ifdef __cplusplus } #endif diff --git a/system/lib/wasm_worker/library_wasm_worker.c b/system/lib/wasm_worker/library_wasm_worker.c index 275794f2a43f4..b0007c6417e8b 100644 --- a/system/lib/wasm_worker/library_wasm_worker.c +++ b/system/lib/wasm_worker/library_wasm_worker.c @@ -5,6 +5,8 @@ #include #include +#include "emscripten_internal.h" + #ifndef __EMSCRIPTEN_WASM_WORKERS__ #error __EMSCRIPTEN_WASM_WORKERS__ should be defined when building this file! #endif @@ -12,10 +14,6 @@ // Options: // #define STACK_OVERFLOW_CHECK 0/1/2 : set to the current stack overflow check mode -// Internal implementation function in JavaScript side that emscripten_create_wasm_worker() calls to -// to perform the wasm worker creation. -emscripten_wasm_worker_t _emscripten_create_wasm_worker(void *stackLowestAddress, uint32_t stackSize); - void __wasm_init_tls(void *memory); __attribute__((constructor(48))) diff --git a/test/code_size/hello_wasm_worker_wasm.js b/test/code_size/hello_wasm_worker_wasm.js index 6c2e59a08ac15..77a6b5a4d9824 100644 --- a/test/code_size/hello_wasm_worker_wasm.js +++ b/test/code_size/hello_wasm_worker_wasm.js @@ -2,40 +2,40 @@ var b = Module, c = b.$ww, f, e = b.mem || new WebAssembly.Memory({ initial: 256, maximum: 256, shared: !0 -}), g = e.buffer, h = {}, k = 1, m = [], p, q; +}), g = e.buffer, h = [], m = {}, n = 1, p, q; -function l(a) { - m.push(a); -} - -function n(a) { +function k(a) { a = a.data; let d = a._wsc; d && f.get(d)(...a.x); } -c && (h[0] = this, addEventListener("message", l)); +function l(a) { + h.push(a); +} + +c && (m[0] = this, addEventListener("message", l)); WebAssembly.instantiate(b.wasm, { a: { b: function(a, d) { - let r = h[k] = new Worker(b.$wb); + let r = m[n] = new Worker(b.$wb); r.postMessage({ - $ww: k, + $ww: n, wasm: b.wasm, js: b.js, mem: e, sb: a, sz: d }); - r.onmessage = n; - return k++; + r.onmessage = k; + return n++; }, c: function() { return !1; }, d: function(a, d) { - h[a].postMessage({ + m[a].postMessage({ _wsc: d, x: [] }); @@ -50,7 +50,7 @@ WebAssembly.instantiate(b.wasm, { p = a.g; q = a.i; f = a.h; - c ? (a = b, q(a.sb, a.sz), removeEventListener("message", l), m = m.forEach(n), - addEventListener("message", n)) : a.f(); + c ? (a = b, q(a.sb, a.sz), removeEventListener("message", l), h = h.forEach(k), + addEventListener("message", k)) : a.f(); c || p(); })); \ No newline at end of file diff --git a/tools/gen_sig_info.py b/tools/gen_sig_info.py index 2d4efdd9d4aa5..a85bfcf72f942 100755 --- a/tools/gen_sig_info.py +++ b/tools/gen_sig_info.py @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -354,6 +355,7 @@ def main(args): print('generating signatures ...') sig_info = {} + extract_sig_info(sig_info, {'WASM_WORKERS': 1, 'JS_LIBRARIES': ['src/library_wasm_worker.js']}) extract_sig_info(sig_info, {'USE_GLFW': 3}, ['-DGLFW3']) extract_sig_info(sig_info, {'JS_LIBRARIES': ['src/embind/embind.js', 'src/embind/emval.js'], 'USE_SDL': 0, diff --git a/tools/system_libs.py b/tools/system_libs.py index 2a00813676e90..c8fd811c34494 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -1334,6 +1334,7 @@ def can_use(self): class libwasm_workers(MTLibrary): name = 'libwasm_workers' + includes = ['system/lib/libc'] def __init__(self, **kwargs): self.debug = kwargs.pop('debug') From a0d43fc3a07fa9161b41d030036695c24d25cb30 Mon Sep 17 00:00:00 2001 From: juj Date: Thu, 11 May 2023 16:12:02 +0300 Subject: [PATCH 0223/1523] Fix test_response_file to run correctly if invoked from an Emscripten directory cloned to a path that contains spaces in it. (#19220) --- test/test_core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_core.py b/test/test_core.py index 38d15809665d7..7d0d2226e6d7d 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -7326,7 +7326,7 @@ def test(expected, args=None, assert_returncode=0): test('|1|', args=['-DDIRECT']) def test_response_file(self): - response_data = '-o %s/response_file.js %s' % (self.get_dir(), test_file('hello_world.cpp')) + response_data = '-o "%s/response_file.js" "%s"' % (self.get_dir(), test_file('hello_world.cpp')) create_file('rsp_file', response_data.replace('\\', '\\\\')) self.run_process([EMCC, "@rsp_file"] + self.get_emcc_args()) self.do_run('response_file.js', 'hello, world', no_build=True) From ab6e3ee3810cc438aae4408021a030f8027cf422 Mon Sep 17 00:00:00 2001 From: mboc-qt <132437722+mboc-qt@users.noreply.github.com> Date: Thu, 11 May 2023 17:03:01 +0200 Subject: [PATCH 0224/1523] test: Add Opera & Edge to list of JSPI-supporting browsers (#19291) Opera and Edge are Chromium-based, so they also support JSPI (since O96). Use the current simple detection algorithm based on executable full path part pattern detection, but extend it with a new pattern for Opera and Edge. Also, print the available options for running test_async when a JSPI-capable browser was not provided. --- test/test_browser.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/test/test_browser.py b/test/test_browser.py index df459f0e4f4e4..6f84737413309 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -149,8 +149,11 @@ def shell_with_script(shell_file, output_file, replacement): create_file(output_file, shell.replace('{{{ SCRIPT }}}', replacement)) +CHROMIUM_BASED_BROWSERS = ['chrom', 'edge', 'opera'] + + def is_chrome(): - return EMTEST_BROWSER and 'chrom' in EMTEST_BROWSER.lower() + return EMTEST_BROWSER and any(pattern in EMTEST_BROWSER.lower() for pattern in CHROMIUM_BASED_BROWSERS) def no_chrome(note='chrome is not supported'): @@ -3350,7 +3353,7 @@ def test_cocos2d_hello(self): }) def test_async(self, args): if is_jspi(args) and not is_chrome(): - self.skipTest('only chrome supports jspi') + self.skipTest(f'Current browser ({EMTEST_BROWSER}) does not support JSPI. Only chromium-based browsers ({CHROMIUM_BASED_BROWSERS}) support JSPI today.') for opts in [0, 1, 2, 3]: print(opts) From 516060b9cbe61c06ce6ad88d59a10783220d9d9a Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 11 May 2023 09:34:12 -0700 Subject: [PATCH 0225/1523] Honor `DEFAULT_PTHREAD_STACK_SIZE` in `pthread_attr_init` (#19333) Also remove the extra `_emscripten_default_pthread_stack_size` import/call in favor of just passing this information in during `_emscripten_thread_init`. Fixes: #19302, #15101 --- emscripten.py | 2 +- src/library_pthread.js | 7 +------ src/library_sigs.js | 1 - system/lib/pthread/emscripten_thread_init.c | 5 +++++ system/lib/pthread/library_pthread_stub.c | 8 ++++---- system/lib/pthread/pthread_create.c | 4 ++-- .../metadce/test_metadce_minimal_pthreads.exports | 2 +- .../metadce/test_metadce_minimal_pthreads.imports | 1 - .../other/metadce/test_metadce_minimal_pthreads.jssize | 2 +- test/other/metadce/test_metadce_minimal_pthreads.sent | 1 - test/other/metadce/test_metadce_minimal_pthreads.size | 2 +- test/other/test_default_pthread_stack_size.c | 10 +++++++--- test/test_other.py | 9 +++++++-- tools/system_libs.py | 2 ++ 14 files changed, 32 insertions(+), 24 deletions(-) diff --git a/emscripten.py b/emscripten.py index 66d6b785b8733..16b5c28481354 100644 --- a/emscripten.py +++ b/emscripten.py @@ -893,7 +893,7 @@ def create_wasm64_wrappers(metadata): '_emscripten_run_in_main_runtime_thread_js': '___p_', '_emscripten_proxy_execute_task_queue': '_p', '_emscripten_thread_exit': '_p', - '_emscripten_thread_init': '_p____', + '_emscripten_thread_init': '_p_____', '_emscripten_thread_free_data': '_p', '_emscripten_dlsync_self_async': '_p', '_emscripten_proxy_dlsync_async': '_pp', diff --git a/src/library_pthread.js b/src/library_pthread.js index a630f0cd91240..3ead63051ca96 100644 --- a/src/library_pthread.js +++ b/src/library_pthread.js @@ -722,6 +722,7 @@ var LibraryPThread = { /*isMainBrowserThread=*/!ENVIRONMENT_IS_WORKER, /*isMainRuntimeThread=*/1, /*canBlock=*/!ENVIRONMENT_IS_WEB, + {{{ DEFAULT_PTHREAD_STACK_SIZE }}}, #if PTHREADS_PROFILING /*start_profiling=*/true #endif @@ -1042,12 +1043,6 @@ var LibraryPThread = { return func.apply(null, emscripten_receive_on_main_thread_js_callArgs); }, - // TODO(sbc): Do we really need this to be dynamically settable from JS like this? - // See https://github.com/emscripten-core/emscripten/issues/15101. - _emscripten_default_pthread_stack_size: function() { - return {{{ DEFAULT_PTHREAD_STACK_SIZE }}}; - }, - #if STACK_OVERFLOW_CHECK >= 2 && MAIN_MODULE $establishStackSpace__deps: ['$setDylinkStackLimits'], #endif diff --git a/src/library_sigs.js b/src/library_sigs.js index 6ac5f18275d08..18ad740b9689a 100644 --- a/src/library_sigs.js +++ b/src/library_sigs.js @@ -300,7 +300,6 @@ sigs = { _embind_register_void__sig: 'vpp', _emscripten_create_wasm_worker__sig: 'ipi', _emscripten_dbg__sig: 'vp', - _emscripten_default_pthread_stack_size__sig: 'i', _emscripten_dlopen_js__sig: 'vpppp', _emscripten_dlsync_threads__sig: 'v', _emscripten_dlsync_threads_async__sig: 'vppp', diff --git a/system/lib/pthread/emscripten_thread_init.c b/system/lib/pthread/emscripten_thread_init.c index 1c9933ba18cc9..ef4b17e7d8542 100644 --- a/system/lib/pthread/emscripten_thread_init.c +++ b/system/lib/pthread/emscripten_thread_init.c @@ -7,13 +7,18 @@ #include #include "emscripten/threading.h" #include "threading_internal.h" +#include "pthread_impl.h" void _emscripten_thread_init(pthread_t ptr, int is_main, int is_runtime, int can_block, + int default_stacksize, int start_profiling) { __set_thread_state(ptr, is_main, is_runtime, can_block); + if (is_main && default_stacksize) { + __default_stacksize = default_stacksize; + } #ifndef NDEBUG if (start_profiling) { _emscripten_thread_profiler_enable(); diff --git a/system/lib/pthread/library_pthread_stub.c b/system/lib/pthread/library_pthread_stub.c index ac67080fc8667..0e016d2995c6e 100644 --- a/system/lib/pthread/library_pthread_stub.c +++ b/system/lib/pthread/library_pthread_stub.c @@ -279,10 +279,6 @@ int pthread_condattr_setpshared(pthread_condattr_t *attr, int shared) { return 0; } -int pthread_attr_init(pthread_attr_t *attr) { - return 0; -} - int pthread_getattr_np(pthread_t thread, pthread_attr_t *attr) { return 0; } @@ -389,6 +385,10 @@ void __lock(void* ptr) {} void __unlock(void* ptr) {} +void __acquire_ptc() {} + +void __release_ptc() {} + // When pthreads is not enabled, we can't use the Atomics futex api to do // proper sleeps, so simulate a busy spin wait loop instead. void emscripten_thread_sleep(double msecs) { diff --git a/system/lib/pthread/pthread_create.c b/system/lib/pthread/pthread_create.c index 916368e634619..3d6f712387e91 100644 --- a/system/lib/pthread/pthread_create.c +++ b/system/lib/pthread/pthread_create.c @@ -140,7 +140,7 @@ int __pthread_create(pthread_t* restrict res, pthread_attr_t attr = { 0 }; if (attrp && attrp != __ATTRP_C11_THREAD) attr = *attrp; if (!attr._a_stacksize) { - attr._a_stacksize = _emscripten_default_pthread_stack_size(); + attr._a_stacksize = __default_stacksize; } // Allocate memory for new thread. The layout of the thread block is @@ -149,7 +149,7 @@ int __pthread_create(pthread_t* restrict res, // 1. pthread struct (sizeof struct pthread) // 2. tls data (__builtin_wasm_tls_size()) // 3. tsd pointers (__pthread_tsd_size) - // 4. stack (_emscripten_default_pthread_stack_size()) + // 4. stack (__default_stacksize AKA -sDEFAULT_PTHREAD_STACK_SIZE) size_t size = sizeof(struct pthread); if (__builtin_wasm_tls_size()) { size += __builtin_wasm_tls_size() + __builtin_wasm_tls_align() - 1; diff --git a/test/other/metadce/test_metadce_minimal_pthreads.exports b/test/other/metadce/test_metadce_minimal_pthreads.exports index fcb5627b2e747..9c917676e4d2a 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.exports +++ b/test/other/metadce/test_metadce_minimal_pthreads.exports @@ -4,7 +4,7 @@ C D E F -G +p q r s diff --git a/test/other/metadce/test_metadce_minimal_pthreads.imports b/test/other/metadce/test_metadce_minimal_pthreads.imports index 259d8061349ff..fcc5923256f40 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.imports +++ b/test/other/metadce/test_metadce_minimal_pthreads.imports @@ -13,4 +13,3 @@ a.l a.m a.n a.o -a.p diff --git a/test/other/metadce/test_metadce_minimal_pthreads.jssize b/test/other/metadce/test_metadce_minimal_pthreads.jssize index a8720b55c8c44..5c6c88b9001f7 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.jssize +++ b/test/other/metadce/test_metadce_minimal_pthreads.jssize @@ -1 +1 @@ -15448 +15425 diff --git a/test/other/metadce/test_metadce_minimal_pthreads.sent b/test/other/metadce/test_metadce_minimal_pthreads.sent index b03757ea914f6..f8c295c135e5d 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.sent +++ b/test/other/metadce/test_metadce_minimal_pthreads.sent @@ -13,4 +13,3 @@ l m n o -p diff --git a/test/other/metadce/test_metadce_minimal_pthreads.size b/test/other/metadce/test_metadce_minimal_pthreads.size index 677ec1c885444..a8093fa03841c 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.size +++ b/test/other/metadce/test_metadce_minimal_pthreads.size @@ -1 +1 @@ -19028 +19045 diff --git a/test/other/test_default_pthread_stack_size.c b/test/other/test_default_pthread_stack_size.c index b7af751db7760..0a5f2a7d67a3d 100644 --- a/test/other/test_default_pthread_stack_size.c +++ b/test/other/test_default_pthread_stack_size.c @@ -2,13 +2,17 @@ #include #include +#ifndef EXPECTED_STACK_SIZE +// Should match DEFAULT_PTHREAD_STACK_SIZE = 64*1024; +#define EXPECTED_STACK_SIZE (64*1024) +#endif + int main() { pthread_attr_t attr; pthread_attr_init(&attr); size_t stacksize; pthread_attr_getstacksize(&attr, &stacksize); - printf("%zu\n", stacksize); - // Should match DEFAULT_PTHREAD_STACK_SIZE = 64*1024; - assert(stacksize == 64*1024); + printf("expected: %d, actual: %zu\n", EXPECTED_STACK_SIZE, stacksize); + assert(stacksize == EXPECTED_STACK_SIZE); return 0; } diff --git a/test/test_other.py b/test/test_other.py index e6648fc7ca136..1ff46ad1097db 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -12367,10 +12367,15 @@ def test_node_unhandled_rejection(self): self.assertContained('ReferenceError: missing is not defined', output) self.assertContained('at foo (', output) - @node_pthreads def test_default_pthread_stack_size(self): self.do_runf(test_file('other/test_default_pthread_stack_size.c')) - self.emcc_args.append('-pthread') + + # Same again with pthreads enabled + self.setup_node_pthreads() + self.do_runf(test_file('other/test_default_pthread_stack_size.c')) + + # Same again but with a custom stack size + self.emcc_args += ['-DEXPECTED_STACK_SIZE=1024', '-sDEFAULT_PTHREAD_STACK_SIZE=1024'] self.do_runf(test_file('other/test_default_pthread_stack_size.c')) def test_emscripten_set_immediate(self): diff --git a/tools/system_libs.py b/tools/system_libs.py index c8fd811c34494..1485077d06f89 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -1074,6 +1074,7 @@ def get_files(self): filenames=[ 'pthread_self.c', 'pthread_cleanup_push.c', + 'pthread_attr_init.c', 'pthread_attr_destroy.c', 'pthread_attr_get.c', 'pthread_attr_setdetachstate.c', @@ -1089,6 +1090,7 @@ def get_files(self): 'pthread_getschedparam.c', 'pthread_setschedprio.c', 'pthread_setconcurrency.c', + 'default_attr.c', # C11 thread library functions 'call_once.c', 'tss_create.c', From 72db270718777a4e3a7b276520f7626b3bb0f680 Mon Sep 17 00:00:00 2001 From: juj Date: Thu, 11 May 2023 19:39:49 +0300 Subject: [PATCH 0226/1523] Fix emscripten_set_*_callback() to return EMSCRIPTEN_RESULT_UNKNOWN_TARGET if the target is not known. (#18977) * Fix issue https://github.com/jeffreylanters/react-unity-webgl/issues/250 where calling emscripten_set_wheel_callback() on an event target that does not exist would result in the page throwing an exception. After the change, an error diagnostic with callstack is logged when in ASSERTIONS builds, and the result EMSCRIPTEN_RESULT_UNKNOWN_TARGET is returned. * Update a couple of cDefs --- src/library_html5.js | 150 ++++++++++------------- test/test_browser.py | 3 + test/test_html5_unknown_event_target.cpp | 58 +++++++++ 3 files changed, 123 insertions(+), 88 deletions(-) create mode 100644 test/test_html5_unknown_event_target.cpp diff --git a/src/library_html5.js b/src/library_html5.js index ed6887011566d..319ebbc998289 100644 --- a/src/library_html5.js +++ b/src/library_html5.js @@ -152,6 +152,13 @@ var LibraryHTML5 = { }, registerOrRemoveHandler: function(eventHandler) { + if (!eventHandler.target) { +#if ASSERTIONS + err('registerOrRemoveHandler: the target element for event handler registration does not exist, when processing the following event handler registration:'); + console.dir(eventHandler); +#endif + return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}}; + } var jsEventHandler = function jsEventHandler(event) { #if HTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS // Increment nesting count for the event handler. @@ -185,6 +192,7 @@ var LibraryHTML5 = { } } } + return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; }, #if PTHREADS @@ -291,7 +299,7 @@ var LibraryHTML5 = { handlerFunc: keyEventHandlerFunc, useCapture: useCapture }; - JSEvents.registerOrRemoveHandler(eventHandler); + return JSEvents.registerOrRemoveHandler(eventHandler); }, // In DOM capturing and bubbling sequence, there are two special elements at the top of the event chain that can be of interest @@ -401,22 +409,19 @@ var LibraryHTML5 = { emscripten_set_keypress_callback_on_thread__proxy: 'sync', emscripten_set_keypress_callback_on_thread__deps: ['$registerKeyEventCallback'], emscripten_set_keypress_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerKeyEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_KEYPRESS }}}, "keypress", targetThread); - return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; + return registerKeyEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_KEYPRESS }}}, "keypress", targetThread); }, emscripten_set_keydown_callback_on_thread__proxy: 'sync', emscripten_set_keydown_callback_on_thread__deps: ['$registerKeyEventCallback'], emscripten_set_keydown_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerKeyEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_KEYDOWN }}}, "keydown", targetThread); - return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; + return registerKeyEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_KEYDOWN }}}, "keydown", targetThread); }, emscripten_set_keyup_callback_on_thread__proxy: 'sync', emscripten_set_keyup_callback_on_thread__deps: ['$registerKeyEventCallback'], emscripten_set_keyup_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerKeyEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_KEYUP }}}, "keyup", targetThread); - return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; + return registerKeyEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_KEYUP }}}, "keyup", targetThread); }, // Outline access to function .getBoundingClientRect() since it is a long string. Closure compiler does not outline access to it by itself, but it can inline access if @@ -539,70 +544,61 @@ var LibraryHTML5 = { // In IE, mousedown events don't either allow deferred calls to be run! if (JSEvents.isInternetExplorer() && eventTypeString == 'mousedown') eventHandler.allowsDeferredCalls = false; #endif - JSEvents.registerOrRemoveHandler(eventHandler); + return JSEvents.registerOrRemoveHandler(eventHandler); }, emscripten_set_click_callback_on_thread__proxy: 'sync', emscripten_set_click_callback_on_thread__deps: ['$registerMouseEventCallback'], emscripten_set_click_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_CLICK }}}, "click", targetThread); - return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; + return registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_CLICK }}}, "click", targetThread); }, emscripten_set_mousedown_callback_on_thread__proxy: 'sync', emscripten_set_mousedown_callback_on_thread__deps: ['$registerMouseEventCallback'], emscripten_set_mousedown_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_MOUSEDOWN }}}, "mousedown", targetThread); - return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; + return registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_MOUSEDOWN }}}, "mousedown", targetThread); }, emscripten_set_mouseup_callback_on_thread__proxy: 'sync', emscripten_set_mouseup_callback_on_thread__deps: ['$registerMouseEventCallback'], emscripten_set_mouseup_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_MOUSEUP }}}, "mouseup", targetThread); - return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; + return registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_MOUSEUP }}}, "mouseup", targetThread); }, emscripten_set_dblclick_callback_on_thread__proxy: 'sync', emscripten_set_dblclick_callback_on_thread__deps: ['$registerMouseEventCallback'], emscripten_set_dblclick_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_DBLCLICK }}}, "dblclick", targetThread); - return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; + return registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_DBLCLICK }}}, "dblclick", targetThread); }, emscripten_set_mousemove_callback_on_thread__proxy: 'sync', emscripten_set_mousemove_callback_on_thread__deps: ['$registerMouseEventCallback'], emscripten_set_mousemove_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_MOUSEMOVE }}}, "mousemove", targetThread); - return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; + return registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_MOUSEMOVE }}}, "mousemove", targetThread); }, emscripten_set_mouseenter_callback_on_thread__proxy: 'sync', emscripten_set_mouseenter_callback_on_thread__deps: ['$registerMouseEventCallback'], emscripten_set_mouseenter_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_MOUSEENTER }}}, "mouseenter", targetThread); - return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; + return registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_MOUSEENTER }}}, "mouseenter", targetThread); }, emscripten_set_mouseleave_callback_on_thread__proxy: 'sync', emscripten_set_mouseleave_callback_on_thread__deps: ['$registerMouseEventCallback'], emscripten_set_mouseleave_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_MOUSELEAVE }}}, "mouseleave", targetThread); - return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; + return registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_MOUSELEAVE }}}, "mouseleave", targetThread); }, emscripten_set_mouseover_callback_on_thread__proxy: 'sync', emscripten_set_mouseover_callback_on_thread__deps: ['$registerMouseEventCallback'], emscripten_set_mouseover_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_MOUSEOVER }}}, "mouseover", targetThread); - return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; + return registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_MOUSEOVER }}}, "mouseover", targetThread); }, emscripten_set_mouseout_callback_on_thread__proxy: 'sync', emscripten_set_mouseout_callback_on_thread__deps: ['$registerMouseEventCallback'], emscripten_set_mouseout_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_MOUSEOUT }}}, "mouseout", targetThread); - return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; + return registerMouseEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_MOUSEOUT }}}, "mouseout", targetThread); }, emscripten_get_mouse_status__proxy: 'sync', @@ -672,20 +668,19 @@ var LibraryHTML5 = { #endif useCapture: useCapture }; - JSEvents.registerOrRemoveHandler(eventHandler); + return JSEvents.registerOrRemoveHandler(eventHandler); }, emscripten_set_wheel_callback_on_thread__proxy: 'sync', emscripten_set_wheel_callback_on_thread__deps: ['$JSEvents', '$registerWheelEventCallback', '$findEventTarget'], emscripten_set_wheel_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { target = findEventTarget(target); + if (!target) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}}; if (typeof target.onwheel != 'undefined') { - registerWheelEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_WHEEL }}}, "wheel", targetThread); - return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; + return registerWheelEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_WHEEL }}}, "wheel", targetThread); #if MIN_IE_VERSION <= 8 || MIN_SAFARI_VERSION < 60100 // Browsers that do not support https://caniuse.com/#feat=mdn-api_wheelevent } else if (typeof target.onmousewheel != 'undefined') { - registerWheelEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_WHEEL }}}, "mousewheel", targetThread); - return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; + return registerWheelEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_WHEEL }}}, "mousewheel", targetThread); #endif } else { return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; @@ -751,21 +746,19 @@ var LibraryHTML5 = { handlerFunc: uiEventHandlerFunc, useCapture: useCapture }; - JSEvents.registerOrRemoveHandler(eventHandler); + return JSEvents.registerOrRemoveHandler(eventHandler); }, emscripten_set_resize_callback_on_thread__proxy: 'sync', emscripten_set_resize_callback_on_thread__deps: ['$registerUiEventCallback'], emscripten_set_resize_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerUiEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_RESIZE }}}, "resize", targetThread); - return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; + return registerUiEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_RESIZE }}}, "resize", targetThread); }, emscripten_set_scroll_callback_on_thread__proxy: 'sync', emscripten_set_scroll_callback_on_thread__deps: ['$registerUiEventCallback'], emscripten_set_scroll_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerUiEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_SCROLL }}}, "scroll", targetThread); - return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; + return registerUiEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_SCROLL }}}, "scroll", targetThread); }, $registerFocusEventCallback__deps: ['$JSEvents', '$findEventTarget', 'malloc', '$stringToUTF8'], @@ -801,35 +794,31 @@ var LibraryHTML5 = { handlerFunc: focusEventHandlerFunc, useCapture: useCapture }; - JSEvents.registerOrRemoveHandler(eventHandler); + return JSEvents.registerOrRemoveHandler(eventHandler); }, emscripten_set_blur_callback_on_thread__proxy: 'sync', emscripten_set_blur_callback_on_thread__deps: ['$registerFocusEventCallback'], emscripten_set_blur_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_BLUR }}}, "blur", targetThread); - return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; + return registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_BLUR }}}, "blur", targetThread); }, emscripten_set_focus_callback_on_thread__proxy: 'sync', emscripten_set_focus_callback_on_thread__deps: ['$registerFocusEventCallback'], emscripten_set_focus_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_FOCUS }}}, "focus", targetThread); - return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; + return registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_FOCUS }}}, "focus", targetThread); }, emscripten_set_focusin_callback_on_thread__proxy: 'sync', emscripten_set_focusin_callback_on_thread__deps: ['$registerFocusEventCallback'], emscripten_set_focusin_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_FOCUSIN }}}, "focusin", targetThread); - return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; + return registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_FOCUSIN }}}, "focusin", targetThread); }, emscripten_set_focusout_callback_on_thread__proxy: 'sync', emscripten_set_focusout_callback_on_thread__deps: ['$registerFocusEventCallback'], emscripten_set_focusout_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_FOCUSOUT }}}, "focusout", targetThread); - return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; + return registerFocusEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_FOCUSOUT }}}, "focusout", targetThread); }, $fillDeviceOrientationEventData__deps: ['$JSEvents'], @@ -867,14 +856,13 @@ var LibraryHTML5 = { handlerFunc: deviceOrientationEventHandlerFunc, useCapture: useCapture }; - JSEvents.registerOrRemoveHandler(eventHandler); + return JSEvents.registerOrRemoveHandler(eventHandler); }, emscripten_set_deviceorientation_callback_on_thread__proxy: 'sync', emscripten_set_deviceorientation_callback_on_thread__deps: ['$registerDeviceOrientationEventCallback'], emscripten_set_deviceorientation_callback_on_thread: function(userData, useCapture, callbackfunc, targetThread) { - registerDeviceOrientationEventCallback({{{ cDefs.EMSCRIPTEN_EVENT_TARGET_WINDOW }}}, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_DEVICEORIENTATION }}}, "deviceorientation", targetThread); - return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; + return registerDeviceOrientationEventCallback({{{ cDefs.EMSCRIPTEN_EVENT_TARGET_WINDOW }}}, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_DEVICEORIENTATION }}}, "deviceorientation", targetThread); }, emscripten_get_deviceorientation_status__proxy: 'sync', @@ -938,14 +926,13 @@ var LibraryHTML5 = { handlerFunc: deviceMotionEventHandlerFunc, useCapture: useCapture }; - JSEvents.registerOrRemoveHandler(eventHandler); + return JSEvents.registerOrRemoveHandler(eventHandler); }, emscripten_set_devicemotion_callback_on_thread__proxy: 'sync', emscripten_set_devicemotion_callback_on_thread__deps: ['$registerDeviceMotionEventCallback'], emscripten_set_devicemotion_callback_on_thread: function(userData, useCapture, callbackfunc, targetThread) { - registerDeviceMotionEventCallback({{{ cDefs.EMSCRIPTEN_EVENT_TARGET_WINDOW }}}, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_DEVICEMOTION }}}, "devicemotion", targetThread); - return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; + return registerDeviceMotionEventCallback({{{ cDefs.EMSCRIPTEN_EVENT_TARGET_WINDOW }}}, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_DEVICEMOTION }}}, "devicemotion", targetThread); }, emscripten_get_devicemotion_status__proxy: 'sync', @@ -1013,15 +1000,14 @@ var LibraryHTML5 = { handlerFunc: orientationChangeEventHandlerFunc, useCapture: useCapture }; - JSEvents.registerOrRemoveHandler(eventHandler); + return JSEvents.registerOrRemoveHandler(eventHandler); }, emscripten_set_orientationchange_callback_on_thread__proxy: 'sync', emscripten_set_orientationchange_callback_on_thread__deps: ['$registerOrientationChangeEventCallback'], emscripten_set_orientationchange_callback_on_thread: function(userData, useCapture, callbackfunc, targetThread) { if (!screen || !screen['addEventListener']) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; - registerOrientationChangeEventCallback(screen, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_ORIENTATIONCHANGE }}}, "orientationchange", targetThread); - return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; + return registerOrientationChangeEventCallback(screen, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_ORIENTATIONCHANGE }}}, "orientationchange", targetThread); }, emscripten_get_orientation_status__proxy: 'sync', @@ -1129,7 +1115,7 @@ var LibraryHTML5 = { handlerFunc: fullscreenChangeEventhandlerFunc, useCapture: useCapture }; - JSEvents.registerOrRemoveHandler(eventHandler); + return JSEvents.registerOrRemoveHandler(eventHandler); }, emscripten_set_fullscreenchange_callback_on_thread__proxy: 'sync', @@ -1142,7 +1128,6 @@ var LibraryHTML5 = { target = target ? findEventTarget(target) : specialHTMLTargets[{{{ cDefs.EMSCRIPTEN_EVENT_TARGET_DOCUMENT }}}]; #endif if (!target) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}}; - registerFullscreenChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_FULLSCREENCHANGE }}}, "fullscreenchange", targetThread); #if MIN_FIREFOX_VERSION <= 63 // https://caniuse.com/#feat=mdn-api_element_fullscreenchange_event registerFullscreenChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_FULLSCREENCHANGE }}}, "mozfullscreenchange", targetThread); @@ -1157,7 +1142,8 @@ var LibraryHTML5 = { #if MIN_IE_VERSION != TARGET_NOT_SUPPORTED // https://caniuse.com/#feat=mdn-api_document_fullscreenchange_event registerFullscreenChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_FULLSCREENCHANGE }}}, "MSFullscreenChange", targetThread); #endif - return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; + + return registerFullscreenChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_FULLSCREENCHANGE }}}, "fullscreenchange", targetThread); }, emscripten_get_fullscreen_status__proxy: 'sync', @@ -1706,7 +1692,7 @@ var LibraryHTML5 = { handlerFunc: pointerlockChangeEventHandlerFunc, useCapture: useCapture }; - JSEvents.registerOrRemoveHandler(eventHandler); + return JSEvents.registerOrRemoveHandler(eventHandler); }, emscripten_set_pointerlockchange_callback_on_thread__proxy: 'sync', @@ -1724,11 +1710,10 @@ var LibraryHTML5 = { target = target ? findEventTarget(target) : specialHTMLTargets[{{{ cDefs.EMSCRIPTEN_EVENT_TARGET_DOCUMENT }}}]; // Pointer lock change events need to be captured from 'document' by default instead of 'window' #endif if (!target) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}}; - registerPointerlockChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_POINTERLOCKCHANGE }}}, "pointerlockchange", targetThread); registerPointerlockChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_POINTERLOCKCHANGE }}}, "mozpointerlockchange", targetThread); registerPointerlockChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_POINTERLOCKCHANGE }}}, "webkitpointerlockchange", targetThread); registerPointerlockChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_POINTERLOCKCHANGE }}}, "mspointerlockchange", targetThread); - return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; + return registerPointerlockChangeEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_POINTERLOCKCHANGE }}}, "pointerlockchange", targetThread); }, $registerPointerlockErrorEventCallback__deps: ['$JSEvents', '$findEventTarget', '$specialHTMLTargets'], @@ -1752,7 +1737,7 @@ var LibraryHTML5 = { handlerFunc: pointerlockErrorEventHandlerFunc, useCapture: useCapture }; - JSEvents.registerOrRemoveHandler(eventHandler); + return JSEvents.registerOrRemoveHandler(eventHandler); }, emscripten_set_pointerlockerror_callback_on_thread__proxy: 'sync', @@ -1771,11 +1756,10 @@ var LibraryHTML5 = { #endif if (!target) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}}; - registerPointerlockErrorEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_POINTERLOCKERROR }}}, "pointerlockerror", targetThread); registerPointerlockErrorEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_POINTERLOCKERROR }}}, "mozpointerlockerror", targetThread); registerPointerlockErrorEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_POINTERLOCKERROR }}}, "webkitpointerlockerror", targetThread); registerPointerlockErrorEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_POINTERLOCKERROR }}}, "mspointerlockerror", targetThread); - return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; + return registerPointerlockErrorEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_POINTERLOCKERROR }}}, "pointerlockerror", targetThread); }, emscripten_get_pointerlock_status__proxy: 'sync', @@ -1953,7 +1937,7 @@ var LibraryHTML5 = { handlerFunc: visibilityChangeEventHandlerFunc, useCapture: useCapture }; - JSEvents.registerOrRemoveHandler(eventHandler); + return JSEvents.registerOrRemoveHandler(eventHandler); }, emscripten_set_visibilitychange_callback_on_thread__proxy: 'sync', @@ -1964,8 +1948,7 @@ var LibraryHTML5 = { return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}}; } #endif - registerVisibilityChangeEventCallback(specialHTMLTargets[{{{ cDefs.EMSCRIPTEN_EVENT_TARGET_DOCUMENT }}}], userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_VISIBILITYCHANGE }}}, "visibilitychange", targetThread); - return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; + return registerVisibilityChangeEventCallback(specialHTMLTargets[{{{ cDefs.EMSCRIPTEN_EVENT_TARGET_DOCUMENT }}}], userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_VISIBILITYCHANGE }}}, "visibilitychange", targetThread); }, emscripten_get_visibility_status__proxy: 'sync', @@ -2074,35 +2057,31 @@ var LibraryHTML5 = { handlerFunc: touchEventHandlerFunc, useCapture: useCapture }; - JSEvents.registerOrRemoveHandler(eventHandler); + return JSEvents.registerOrRemoveHandler(eventHandler); }, emscripten_set_touchstart_callback_on_thread__proxy: 'sync', emscripten_set_touchstart_callback_on_thread__deps: ['$registerTouchEventCallback'], emscripten_set_touchstart_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_TOUCHSTART }}}, "touchstart", targetThread); - return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; + return registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_TOUCHSTART }}}, "touchstart", targetThread); }, emscripten_set_touchend_callback_on_thread__proxy: 'sync', emscripten_set_touchend_callback_on_thread__deps: ['$registerTouchEventCallback'], emscripten_set_touchend_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_TOUCHEND }}}, "touchend", targetThread); - return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; + return registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_TOUCHEND }}}, "touchend", targetThread); }, emscripten_set_touchmove_callback_on_thread__proxy: 'sync', emscripten_set_touchmove_callback_on_thread__deps: ['$registerTouchEventCallback'], emscripten_set_touchmove_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_TOUCHMOVE }}}, "touchmove", targetThread); - return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; + return registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_TOUCHMOVE }}}, "touchmove", targetThread); }, emscripten_set_touchcancel_callback_on_thread__proxy: 'sync', emscripten_set_touchcancel_callback_on_thread__deps: ['$registerTouchEventCallback'], emscripten_set_touchcancel_callback_on_thread: function(target, userData, useCapture, callbackfunc, targetThread) { - registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_TOUCHCANCEL }}}, "touchcancel", targetThread); - return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; + return registerTouchEventCallback(target, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_TOUCHCANCEL }}}, "touchcancel", targetThread); }, $fillGamepadEventData__deps: ['$stringToUTF8'], @@ -2169,23 +2148,21 @@ var LibraryHTML5 = { handlerFunc: gamepadEventHandlerFunc, useCapture: useCapture }; - JSEvents.registerOrRemoveHandler(eventHandler); + return JSEvents.registerOrRemoveHandler(eventHandler); }, emscripten_set_gamepadconnected_callback_on_thread__proxy: 'sync', emscripten_set_gamepadconnected_callback_on_thread__deps: ['$registerGamepadEventCallback'], emscripten_set_gamepadconnected_callback_on_thread: function(userData, useCapture, callbackfunc, targetThread) { if (!navigator.getGamepads && !navigator.webkitGetGamepads) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; - registerGamepadEventCallback({{{ cDefs.EMSCRIPTEN_EVENT_TARGET_WINDOW }}}, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_GAMEPADCONNECTED }}}, "gamepadconnected", targetThread); - return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; + return registerGamepadEventCallback({{{ cDefs.EMSCRIPTEN_EVENT_TARGET_WINDOW }}}, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_GAMEPADCONNECTED }}}, "gamepadconnected", targetThread); }, emscripten_set_gamepaddisconnected_callback_on_thread__proxy: 'sync', emscripten_set_gamepaddisconnected_callback_on_thread__deps: ['$registerGamepadEventCallback'], emscripten_set_gamepaddisconnected_callback_on_thread: function(userData, useCapture, callbackfunc, targetThread) { if (!navigator.getGamepads && !navigator.webkitGetGamepads) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; - registerGamepadEventCallback({{{ cDefs.EMSCRIPTEN_EVENT_TARGET_WINDOW }}}, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_GAMEPADDISCONNECTED }}}, "gamepaddisconnected", targetThread); - return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; + return registerGamepadEventCallback({{{ cDefs.EMSCRIPTEN_EVENT_TARGET_WINDOW }}}, userData, useCapture, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_GAMEPADDISCONNECTED }}}, "gamepaddisconnected", targetThread); }, emscripten_sample_gamepad_data__proxy: 'sync', @@ -2249,7 +2226,7 @@ var LibraryHTML5 = { handlerFunc: beforeUnloadEventHandlerFunc, useCapture: useCapture }; - JSEvents.registerOrRemoveHandler(eventHandler); + return JSEvents.registerOrRemoveHandler(eventHandler); }, emscripten_set_beforeunload_callback_on_thread__proxy: 'sync', @@ -2259,8 +2236,7 @@ var LibraryHTML5 = { // beforeunload callback can only be registered on the main browser thread, because the page will go away immediately after returning from the handler, // and there is no time to start proxying it anywhere. if (targetThread !== {{{ cDefs.EM_CALLBACK_THREAD_CONTEXT_MAIN_RUNTIME_THREAD }}}) return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_PARAM }}}; - registerBeforeUnloadEventCallback({{{ cDefs.EMSCRIPTEN_EVENT_TARGET_WINDOW }}}, userData, true, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_BEFOREUNLOAD }}}, "beforeunload"); - return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; + return registerBeforeUnloadEventCallback({{{ cDefs.EMSCRIPTEN_EVENT_TARGET_WINDOW }}}, userData, true, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_BEFOREUNLOAD }}}, "beforeunload"); }, $fillBatteryEventData: function(eventStruct, e) { @@ -2301,23 +2277,21 @@ var LibraryHTML5 = { handlerFunc: batteryEventHandlerFunc, useCapture: useCapture }; - JSEvents.registerOrRemoveHandler(eventHandler); + return JSEvents.registerOrRemoveHandler(eventHandler); }, emscripten_set_batterychargingchange_callback_on_thread__proxy: 'sync', emscripten_set_batterychargingchange_callback_on_thread__deps: ['$registerBatteryEventCallback', '$battery'], emscripten_set_batterychargingchange_callback_on_thread: function(userData, callbackfunc, targetThread) { if (!battery()) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; - registerBatteryEventCallback(battery(), userData, true, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_BATTERYCHARGINGCHANGE }}}, "chargingchange", targetThread); - return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; + return registerBatteryEventCallback(battery(), userData, true, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_BATTERYCHARGINGCHANGE }}}, "chargingchange", targetThread); }, emscripten_set_batterylevelchange_callback_on_thread__proxy: 'sync', emscripten_set_batterylevelchange_callback_on_thread__deps: ['$registerBatteryEventCallback', '$battery'], emscripten_set_batterylevelchange_callback_on_thread: function(userData, callbackfunc, targetThread) { if (!battery()) return {{{ cDefs.EMSCRIPTEN_RESULT_NOT_SUPPORTED }}}; - registerBatteryEventCallback(battery(), userData, true, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_BATTERYLEVELCHANGE }}}, "levelchange", targetThread); - return {{{ cDefs.EMSCRIPTEN_RESULT_SUCCESS }}}; + return registerBatteryEventCallback(battery(), userData, true, callbackfunc, {{{ cDefs.EMSCRIPTEN_EVENT_BATTERYLEVELCHANGE }}}, "levelchange", targetThread); }, emscripten_get_battery_status__proxy: 'sync', diff --git a/test/test_browser.py b/test/test_browser.py index 6f84737413309..71c8914e50301 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -2662,6 +2662,9 @@ def test_html5_gamepad(self): print(opts) self.btest_exit(test_file('test_gamepad.c'), args=[] + opts) + def test_html5_unknown_event_target(self): + self.btest_exit(test_file('test_html5_unknown_event_target.cpp')) + @requires_graphics_hardware def test_html5_webgl_create_context_no_antialias(self): for opts in [[], ['-O2', '-g1', '--closure=1'], ['-sFULL_ES2']]: diff --git a/test/test_html5_unknown_event_target.cpp b/test/test_html5_unknown_event_target.cpp new file mode 100644 index 0000000000000..894d89c072b6e --- /dev/null +++ b/test/test_html5_unknown_event_target.cpp @@ -0,0 +1,58 @@ +// Copyright 2023 The Emscripten Authors. All rights reserved. +// Emscripten is available under two separate licenses, the MIT license and the +// University of Illinois/NCSA Open Source License. Both these licenses can be +// found in the LICENSE file. + +#include +#include +#include +#include + +EM_BOOL wheel_cb(int eventType, const EmscriptenWheelEvent *wheelEvent __attribute__((nonnull)), void *userData) { return EM_TRUE; } +EM_BOOL key_cb(int eventType, const EmscriptenKeyboardEvent *e, void *userData) { return EM_TRUE; } +EM_BOOL mouse_cb(int eventType, const EmscriptenMouseEvent *mouseEvent __attribute__((nonnull)), void *userData) { return EM_TRUE; } +EM_BOOL ui_cb(int eventType, const EmscriptenUiEvent *uiEvent __attribute__((nonnull)), void *userData) { return EM_TRUE; } +EM_BOOL focus_cb(int eventType, const EmscriptenFocusEvent *focusEvent __attribute__((nonnull)), void *userData) { return EM_TRUE; } +EM_BOOL fullscreenchange_cb(int eventType, const EmscriptenFullscreenChangeEvent *fullscreenChangeEvent __attribute__((nonnull)), void *userData) { return EM_TRUE; } +EM_BOOL pointerlockchange_cb(int eventType, const EmscriptenPointerlockChangeEvent *pointerlockChangeEvent __attribute__((nonnull)), void *userData) { return EM_TRUE; } +EM_BOOL pointerlockerror_cb(int eventType, const void *reserved, void *userData) { return EM_TRUE; } +EM_BOOL touch_cb(int eventType, const EmscriptenTouchEvent *touchEvent __attribute__((nonnull)), void *userData) { return EM_TRUE; } + +int main(int argc, char **argv) +{ + assert(emscripten_set_keypress_callback("this_dom_element_does_not_exist", 0, 0, key_cb) == EMSCRIPTEN_RESULT_UNKNOWN_TARGET); + assert(emscripten_set_keydown_callback("this_dom_element_does_not_exist", 0, 0, key_cb) == EMSCRIPTEN_RESULT_UNKNOWN_TARGET); + assert(emscripten_set_keyup_callback("this_dom_element_does_not_exist", 0, 0, key_cb) == EMSCRIPTEN_RESULT_UNKNOWN_TARGET); + + assert(emscripten_set_click_callback("this_dom_element_does_not_exist", 0, 0, mouse_cb) == EMSCRIPTEN_RESULT_UNKNOWN_TARGET); + assert(emscripten_set_mousedown_callback("this_dom_element_does_not_exist", 0, 0, mouse_cb) == EMSCRIPTEN_RESULT_UNKNOWN_TARGET); + assert(emscripten_set_mouseup_callback("this_dom_element_does_not_exist", 0, 0, mouse_cb) == EMSCRIPTEN_RESULT_UNKNOWN_TARGET); + assert(emscripten_set_dblclick_callback("this_dom_element_does_not_exist", 0, 0, mouse_cb) == EMSCRIPTEN_RESULT_UNKNOWN_TARGET); + assert(emscripten_set_mousemove_callback("this_dom_element_does_not_exist", 0, 0, mouse_cb) == EMSCRIPTEN_RESULT_UNKNOWN_TARGET); + assert(emscripten_set_mouseenter_callback("this_dom_element_does_not_exist", 0, 0, mouse_cb) == EMSCRIPTEN_RESULT_UNKNOWN_TARGET); + assert(emscripten_set_mouseleave_callback("this_dom_element_does_not_exist", 0, 0, mouse_cb) == EMSCRIPTEN_RESULT_UNKNOWN_TARGET); + assert(emscripten_set_mouseover_callback("this_dom_element_does_not_exist", 0, 0, mouse_cb) == EMSCRIPTEN_RESULT_UNKNOWN_TARGET); + assert(emscripten_set_mouseout_callback("this_dom_element_does_not_exist", 0, 0, mouse_cb) == EMSCRIPTEN_RESULT_UNKNOWN_TARGET); + + assert(emscripten_set_wheel_callback("this_dom_element_does_not_exist", 0, 1, wheel_cb) == EMSCRIPTEN_RESULT_UNKNOWN_TARGET); + + assert(emscripten_set_resize_callback("this_dom_element_does_not_exist", 0, 1, ui_cb) == EMSCRIPTEN_RESULT_UNKNOWN_TARGET); + assert(emscripten_set_scroll_callback("this_dom_element_does_not_exist", 0, 1, ui_cb) == EMSCRIPTEN_RESULT_UNKNOWN_TARGET); + + assert(emscripten_set_blur_callback("this_dom_element_does_not_exist", 0, 1, focus_cb) == EMSCRIPTEN_RESULT_UNKNOWN_TARGET); + assert(emscripten_set_focus_callback("this_dom_element_does_not_exist", 0, 1, focus_cb) == EMSCRIPTEN_RESULT_UNKNOWN_TARGET); + assert(emscripten_set_focusin_callback("this_dom_element_does_not_exist", 0, 1, focus_cb) == EMSCRIPTEN_RESULT_UNKNOWN_TARGET); + assert(emscripten_set_focusout_callback("this_dom_element_does_not_exist", 0, 1, focus_cb) == EMSCRIPTEN_RESULT_UNKNOWN_TARGET); + + assert(emscripten_set_fullscreenchange_callback("this_dom_element_does_not_exist", 0, 1, fullscreenchange_cb) == EMSCRIPTEN_RESULT_UNKNOWN_TARGET); + + assert(emscripten_set_pointerlockchange_callback("this_dom_element_does_not_exist", 0, 1, pointerlockchange_cb) == EMSCRIPTEN_RESULT_UNKNOWN_TARGET); + + assert(emscripten_set_pointerlockerror_callback("this_dom_element_does_not_exist", 0, 1, pointerlockerror_cb) == EMSCRIPTEN_RESULT_UNKNOWN_TARGET); + + assert(emscripten_set_touchstart_callback("this_dom_element_does_not_exist", 0, 1, touch_cb) == EMSCRIPTEN_RESULT_UNKNOWN_TARGET); + assert(emscripten_set_touchend_callback("this_dom_element_does_not_exist", 0, 1, touch_cb) == EMSCRIPTEN_RESULT_UNKNOWN_TARGET); + assert(emscripten_set_touchmove_callback("this_dom_element_does_not_exist", 0, 1, touch_cb) == EMSCRIPTEN_RESULT_UNKNOWN_TARGET); + assert(emscripten_set_touchcancel_callback("this_dom_element_does_not_exist", 0, 1, touch_cb) == EMSCRIPTEN_RESULT_UNKNOWN_TARGET); + return 0; +} From a36c3f6f0f6a849b81637d3368ca0243e9013508 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 11 May 2023 10:20:24 -0700 Subject: [PATCH 0227/1523] Move dlopen file operations into native code. NFC (#19310) This allows the file data to be read by just a single thread (the calling thread) and shared with all the others via shared memory. Fixes: #19245 --- emcc.py | 6 --- src/generated_struct_info32.json | 6 ++- src/generated_struct_info64.json | 6 ++- src/library_dylink.js | 37 ++++++---------- src/struct_info_internal.json | 2 + system/lib/libc/dynlink.c | 43 +++++++++++++++---- system/lib/libc/musl/src/internal/dynlink.h | 6 +++ .../metadce/test_metadce_hello_dylink.jssize | 2 +- test/test_other.py | 41 ++++++++++++------ 9 files changed, 94 insertions(+), 55 deletions(-) diff --git a/emcc.py b/emcc.py index d0d09f294acc3..ef558e531f25e 100755 --- a/emcc.py +++ b/emcc.py @@ -2307,12 +2307,6 @@ def phase_linker_setup(options, state, newargs): settings.SYSCALLS_REQUIRE_FILESYSTEM = 0 settings.JS_LIBRARIES.append((0, 'library_wasmfs.js')) settings.REQUIRED_EXPORTS += ['_wasmfs_read_file'] - if settings.MAIN_MODULE: - # Dynamic library support uses JS API internals, so include it all - # TODO: rewriting more of the dynamic linking support code into wasm could - # avoid this. also, after we remove the old FS, we could write a - # more specific API for wasmfs/dynamic linking integration perhaps - settings.FORCE_FILESYSTEM = 1 if settings.FORCE_FILESYSTEM: # Add exports for the JS API. Like the old JS FS, WasmFS by default # includes just what JS parts it actually needs, and FORCE_FILESYSTEM is diff --git a/src/generated_struct_info32.json b/src/generated_struct_info32.json index 1a160f0d19462..acb5641fd5618 100644 --- a/src/generated_struct_info32.json +++ b/src/generated_struct_info32.json @@ -1321,12 +1321,14 @@ "d_type": 18 }, "dso": { - "__size__": 28, + "__size__": 36, + "file_data": 28, + "file_data_size": 32, "flags": 4, "mem_addr": 12, "mem_allocated": 8, "mem_size": 16, - "name": 28, + "name": 36, "table_addr": 20, "table_size": 24 }, diff --git a/src/generated_struct_info64.json b/src/generated_struct_info64.json index 4a8b96dd5f6bc..973b4220d0200 100644 --- a/src/generated_struct_info64.json +++ b/src/generated_struct_info64.json @@ -1321,12 +1321,14 @@ "d_type": 18 }, "dso": { - "__size__": 48, + "__size__": 64, + "file_data": 48, + "file_data_size": 56, "flags": 8, "mem_addr": 16, "mem_allocated": 12, "mem_size": 24, - "name": 48, + "name": 64, "table_addr": 32, "table_size": 40 }, diff --git a/src/library_dylink.js b/src/library_dylink.js index b897f5720a325..fa06a62fbbb15 100644 --- a/src/library_dylink.js +++ b/src/library_dylink.js @@ -905,10 +905,6 @@ var LibraryDylink = { // - if flags.loadAsync=true, the loading is performed asynchronously and // loadDynamicLibrary returns corresponding promise. // - // - if flags.fs is provided, it is used as FS-like interface to load library data. - // By default, when flags.fs=undefined, native loading capabilities of the - // environment are used. - // // If a library was already loaded, it is not loaded a second time. However // flags.global and flags.nodelete are handled every time a load request is made. // Once a library becomes "global" or "nodelete", it cannot be removed or unloaded. @@ -960,12 +956,13 @@ var LibraryDylink = { // libName -> libData function loadLibData() { // for wasm, we can use fetch for async, but for fs mode we can only imitate it - if (flags.fs && flags.fs.findObject(libName)) { - var libData = flags.fs.readFile(libName, {encoding: 'binary'}); - if (!(libData instanceof Uint8Array)) { - libData = new Uint8Array(libData); + if (handle) { + var data = {{{ makeGetValue('handle', C_STRUCTS.dso.file_data, '*') }}}; + var dataSize = {{{ makeGetValue('handle', C_STRUCTS.dso.file_data_size, '*') }}}; + if (data && dataSize) { + var libData = HEAP8.slice(data, data + dataSize); + return flags.loadAsync ? Promise.resolve(libData) : libData; } - return flags.loadAsync ? Promise.resolve(libData) : libData; } var libFile = locateFile(libName); @@ -987,7 +984,7 @@ var LibraryDylink = { // lookup preloaded cache first if (preloadedWasm[libName]) { #if DYLINK_DEBUG - err('using preloaded module for: ' + libName); + dbg('using preloaded module for: ' + libName); #endif var libModule = preloadedWasm[libName]; return flags.loadAsync ? Promise.resolve(libModule) : libModule; @@ -1059,7 +1056,7 @@ var LibraryDylink = { }, // void* dlopen(const char* filename, int flags); - $dlopenInternal__deps: ['$FS', '$ENV', '$dlSetError', '$PATH'], + $dlopenInternal__deps: ['$ENV', '$dlSetError', '$PATH'], $dlopenInternal: function(handle, jsflags) { // void *dlopen(const char *file, int mode); // http://pubs.opengroup.org/onlinepubs/009695399/functions/dlopen.html @@ -1079,7 +1076,6 @@ var LibraryDylink = { global, nodelete: Boolean(flags & {{{ cDefs.RTLD_NODELETE }}}), loadAsync: jsflags.loadAsync, - fs: jsflags.fs, } if (jsflags.loadAsync) { @@ -1104,18 +1100,12 @@ var LibraryDylink = { _dlopen_js: function(handle) { #if ASYNCIFY return Asyncify.handleSleep((wakeUp) => { - var jsflags = { - loadAsync: true, - fs: FS, // load libraries from provided filesystem - } + var jsflags = { loadAsync: true } var promise = dlopenInternal(handle, jsflags); promise.then(wakeUp).catch(() => wakeUp(0)); }); #else - var jsflags = { - loadAsync: false, - fs: FS, // load libraries from provided filesystem - } + var jsflags = { loadAsync: false } return dlopenInternal(handle, jsflags); #endif }, @@ -1125,8 +1115,8 @@ var LibraryDylink = { _emscripten_dlopen_js: function(handle, onsuccess, onerror, user_data) { /** @param {Object=} e */ function errorCallback(e) { - var filename = UTF8ToString({{{ makeGetValue('handle', C_STRUCTS.dso.name, '*') }}}); - dlSetError('Could not load dynamic lib: ' + filename + '\n' + e); + var filename = UTF8ToString(handle + {{{ C_STRUCTS.dso.name }}}); + dlSetError('Could not load dynamic libX: ' + filename + '\n' + e); {{{ runtimeKeepalivePop() }}} callUserCallback(() => {{{ makeDynCall('vpp', 'onerror') }}}(handle, user_data)); } @@ -1136,7 +1126,8 @@ var LibraryDylink = { } {{{ runtimeKeepalivePush() }}} - var promise = dlopenInternal(handle, { loadAsync: true }); + var jsflags = { loadAsync: true } + var promise = dlopenInternal(handle, jsflags); if (promise) { promise.then(successCallback, errorCallback); } else { diff --git a/src/struct_info_internal.json b/src/struct_info_internal.json index e1d9999ea8958..fa59ad4aaa8c1 100644 --- a/src/struct_info_internal.json +++ b/src/struct_info_internal.json @@ -40,6 +40,8 @@ "mem_size", "table_addr", "table_size", + "file_data", + "file_data_size", "name" ] } diff --git a/system/lib/libc/dynlink.c b/system/lib/libc/dynlink.c index fea12b76fcd09..bfb8416a1204d 100644 --- a/system/lib/libc/dynlink.c +++ b/system/lib/libc/dynlink.c @@ -11,6 +11,7 @@ #define _GNU_SOURCE #include #include +#include #include #include #include @@ -19,6 +20,7 @@ #include #include #include +#include #include #include @@ -81,6 +83,8 @@ static thread_local struct dlevent* thread_local_tail = &main_event; static pthread_mutex_t write_lock = PTHREAD_MUTEX_INITIALIZER; static thread_local bool skip_dlsync = false; +static void dlsync(); + static void do_write_lock() { // Once we have the lock we want to avoid automatic code sync as that would // result in a deadlock. @@ -155,6 +159,14 @@ static void load_library_done(struct dso* p) { p->table_addr, p->table_size); new_dlevent(p, -1); +#ifdef _REENTRANT + // Block until all other threads have loaded this module. + dlsync(); +#endif + if (p->file_data) { + free(p->file_data); + p->file_data_size = 0; + } } static struct dso* load_library_start(const char* name, int flags) { @@ -169,6 +181,29 @@ static struct dso* load_library_start(const char* name, int flags) { p->flags = flags; strcpy(p->name, name); + // If the file exists in the filesystem, load it here into linear memory which + // makes the data available to JS, and to other threads. This data gets + // free'd later once all threads have loaded the DSO. + struct stat statbuf; + if (stat(name, &statbuf) == 0 && S_ISREG(statbuf.st_mode)) { + int fd = open(name, O_RDONLY); + if (fd >= 0) { + off_t size = lseek(fd, 0, SEEK_END); + if (size != (off_t)-1) { + lseek(fd, 0, SEEK_SET); + p->file_data = malloc(size); + if (p->file_data) { + if (read(fd, p->file_data, size) == size) { + p->file_data_size = size; + } else { + free(p->file_data); + } + } + } + close(fd); + } + } + return p; } @@ -424,10 +459,6 @@ static void dlopen_onsuccess(struct dso* dso, void* user_data) { dso->mem_addr, dso->mem_size); load_library_done(dso); -#ifdef _REENTRANT - // Block until all other threads have loaded this module. - dlsync(); -#endif do_write_unlock(); data->onsuccess(data->user_data, dso); free(data); @@ -526,10 +557,6 @@ static struct dso* _dlopen(const char* file, int flags) { } dbg("dlopen_js: success: %p", p); load_library_done(p); -#ifdef _REENTRANT - // Block until all other threads have loaded this module. - dlsync(); -#endif end: dbg("dlopen(%s): done: %p", file, p); do_write_unlock(); diff --git a/system/lib/libc/musl/src/internal/dynlink.h b/system/lib/libc/musl/src/internal/dynlink.h index de668f4a3845d..a90658bbb45d7 100644 --- a/system/lib/libc/musl/src/internal/dynlink.h +++ b/system/lib/libc/musl/src/internal/dynlink.h @@ -29,6 +29,12 @@ struct dso { void* table_addr; size_t table_size; + // For DSO load events, where the DSO comes from a file on disc, this + // is a pointer the file data read in by the laoding thread and shared with + // others. + uint8_t* file_data; + size_t file_data_size; + // Flexible array; must be final element of struct char name[]; }; diff --git a/test/other/metadce/test_metadce_hello_dylink.jssize b/test/other/metadce/test_metadce_hello_dylink.jssize index fb3b566636284..a86975277b10a 100644 --- a/test/other/metadce/test_metadce_hello_dylink.jssize +++ b/test/other/metadce/test_metadce_hello_dylink.jssize @@ -1 +1 @@ -28151 +28007 diff --git a/test/test_other.py b/test/test_other.py index 1ff46ad1097db..0977b4918b972 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -6371,7 +6371,13 @@ def test_RUNTIME_LINKED_LIBS(self): self.assertBinaryEqual('main.wasm', 'main2.wasm') - def test_ld_library_path(self): + @parameterized({ + '': ([],), + 'pthread': (['-g', '-pthread', '-Wno-experimental', '-sPROXY_TO_PTHREAD', '-sEXIT_RUNTIME'],), + }) + def test_ld_library_path(self, args): + if args: + self.setup_node_pthreads() create_file('hello1.c', r''' #include @@ -6456,17 +6462,17 @@ def test_ld_library_path(self): return 0; } ''') - self.run_process([EMCC, '-o', 'hello1.wasm', 'hello1.c', '-sSIDE_MODULE']) - self.run_process([EMCC, '-o', 'hello2.wasm', 'hello2.c', '-sSIDE_MODULE']) - self.run_process([EMCC, '-o', 'hello3.wasm', 'hello3.c', '-sSIDE_MODULE']) - self.run_process([EMCC, '-o', 'hello4.wasm', 'hello4.c', '-sSIDE_MODULE']) + self.run_process([EMCC, '-o', 'hello1.wasm', 'hello1.c', '-sSIDE_MODULE'] + args) + self.run_process([EMCC, '-o', 'hello2.wasm', 'hello2.c', '-sSIDE_MODULE'] + args) + self.run_process([EMCC, '-o', 'hello3.wasm', 'hello3.c', '-sSIDE_MODULE'] + args) + self.run_process([EMCC, '-o', 'hello4.wasm', 'hello4.c', '-sSIDE_MODULE'] + args) self.run_process([EMCC, '--profiling-funcs', '-o', 'main.js', 'main.c', '-sMAIN_MODULE=2', '-sINITIAL_MEMORY=32Mb', '--embed-file', 'hello1.wasm@/lib/libhello1.wasm', '--embed-file', 'hello2.wasm@/usr/lib/libhello2.wasm', '--embed-file', 'hello3.wasm@/libhello3.wasm', '--embed-file', 'hello4.wasm@/usr/local/lib/libhello4.wasm', 'hello1.wasm', 'hello2.wasm', 'hello3.wasm', 'hello4.wasm', '-sNO_AUTOLOAD_DYLIBS', - '--pre-js', 'pre.js']) + '--pre-js', 'pre.js'] + args) out = self.run_js('main.js') self.assertContained('Hello1', out) self.assertContained('Hello2', out) @@ -13404,7 +13410,13 @@ def test_windows_batch_file_dp0_expansion_bug(self): create_file('build_with_quotes.bat', f'@"emcc" {test_file("hello_world.c")}') self.run_process(['build_with_quotes.bat']) - def test_preload_module(self): + @parameterized({ + '': ([],), + 'pthread': (['-g', '-pthread', '-Wno-experimental', '-sPROXY_TO_PTHREAD', '-sEXIT_RUNTIME'],), + }) + def test_preload_module(self, args): + if args: + self.setup_node_pthreads() # TODO(sbc): This test is copyied from test_browser.py. Perhaps find a better way to # share code between them. create_file('library.c', r''' @@ -13413,17 +13425,20 @@ def test_preload_module(self): return 42; } ''') - self.run_process([EMCC, 'library.c', '-sSIDE_MODULE', '-o', 'library.so']) + self.run_process([EMCC, 'library.c', '-sSIDE_MODULE', '-o', 'library.so'] + args) create_file('main.c', r''' #include #include #include #include + #include int main() { - int found = EM_ASM_INT( - return preloadedWasm['/library.so'] !== undefined; - ); - assert(found); + if (emscripten_is_main_runtime_thread()) { + int found = EM_ASM_INT( + return preloadedWasm['/library.so'] !== undefined; + ); + assert(found); + } void *lib_handle = dlopen("/library.so", RTLD_NOW); assert(lib_handle); typedef int (*voidfunc)(); @@ -13434,4 +13449,4 @@ def test_preload_module(self): return 0; } ''') - self.do_runf('main.c', 'done\n', emcc_args=['-sMAIN_MODULE=2', '--preload-file', '.@/', '--use-preload-plugins']) + self.do_runf('main.c', 'done\n', emcc_args=['-sMAIN_MODULE=2', '--preload-file', '.@/', '--use-preload-plugins'] + args) From cbc190221d7e277cb7cf6f4b556952e31fa64dcd Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 11 May 2023 10:37:56 -0700 Subject: [PATCH 0228/1523] Bind `err` to `console.error` rather than `console.warn` (#19326) Now that we have `dbg()` for debug output (see #19126) we can redirect `err()` to `console.error()` so that folks who call `err()` will get a full stack trace in devtools. --- ChangeLog.md | 3 +++ src/runtime_debug.js | 4 ++-- src/shell.js | 6 +++--- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 48593447f5eeb..ccb562f546241 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -20,6 +20,9 @@ See docs/process.md for more on how version tagging works. 3.1.39 (in development) ----------------------- +- The JS `err()` function will now bind to `console.error` by default rather + than `console.warning`. For debugging/tracing/logging we recommend the + `dbg()` function instead. (#19326) 3.1.38 - 05/10/23 ----------------- diff --git a/src/runtime_debug.js b/src/runtime_debug.js index c062e1c70ada6..144588b1df489 100644 --- a/src/runtime_debug.js +++ b/src/runtime_debug.js @@ -167,7 +167,7 @@ function dbg(text) { } else #endif // TODO(sbc): Make this configurable somehow. Its not always convenient for - // logging to show up as errors. - console.error.apply(console, arguments); + // logging to show up as warnings. + console.warn.apply(console, arguments); } #endif diff --git a/src/shell.js b/src/shell.js index d7899a6062c84..b1ed99a73b115 100644 --- a/src/shell.js +++ b/src/shell.js @@ -439,12 +439,12 @@ if (ENVIRONMENT_IS_NODE) { // Set up the out() and err() hooks, which are how we can print to stdout or // stderr, respectively. -// Normally just binding console.log/console.warn here works fine, but +// Normally just binding console.log/console.error here works fine, but // under node (with workers) we see missing/out-of-order messages so route // directly to stdout and stderr. // See https://github.com/emscripten-core/emscripten/issues/14804 var defaultPrint = console.log.bind(console); -var defaultPrintErr = console.warn.bind(console); +var defaultPrintErr = console.error.bind(console); if (ENVIRONMENT_IS_NODE) { defaultPrint = (...args) => fs.writeSync(1, args.join(' ') + '\n'); defaultPrintErr = (...args) => fs.writeSync(2, args.join(' ') + '\n'); @@ -453,7 +453,7 @@ if (ENVIRONMENT_IS_NODE) { {{{ makeModuleReceiveWithVar('err', 'printErr', 'defaultPrintErr', true) }}} #else {{{ makeModuleReceiveWithVar('out', 'print', 'console.log.bind(console)', true) }}} -{{{ makeModuleReceiveWithVar('err', 'printErr', 'console.warn.bind(console)', true) }}} +{{{ makeModuleReceiveWithVar('err', 'printErr', 'console.error.bind(console)', true) }}} #endif // Merge back in the overrides From 8b102b28c6d2c418a7795f0661633207b8f31383 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 11 May 2023 12:11:38 -0700 Subject: [PATCH 0229/1523] [Docs] Update some notes on speed (#19323) Fixes #19297 --- site/source/docs/optimizing/Optimizing-Code.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/source/docs/optimizing/Optimizing-Code.rst b/site/source/docs/optimizing/Optimizing-Code.rst index 5ce8e63108331..05993b5e88990 100644 --- a/site/source/docs/optimizing/Optimizing-Code.rst +++ b/site/source/docs/optimizing/Optimizing-Code.rst @@ -245,7 +245,7 @@ To ensure that compiled code contains enough information for profiling, build yo Troubleshooting poor performance ================================ -Emscripten-compiled code can currently achieve approximately half the speed of a native build. If the performance is significantly poorer than expected, you can also run through the additional troubleshooting steps below: +Emscripten-compiled code can often be close to the speed of a native build. If the performance is significantly poorer than expected, you can also run through the additional troubleshooting steps below: - :ref:`Building-Projects` is a two-stage process: compiling source code files to LLVM **and** generating JavaScript from LLVM. Did you build using the same optimization values in **both** steps (``-O2`` or ``-O3``)? - Test on multiple browsers. If performance is acceptable on one browser and significantly poorer on another, then :ref:`file a bug report `, noting the problem browser and other relevant information. From 374b58436c4bc2bd98b89a3a3d18a51e9571072f Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 11 May 2023 13:35:34 -0700 Subject: [PATCH 0230/1523] More use of arrow functions in library_sdl.js. NFC (#19339) --- src/library_sdl.js | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/src/library_sdl.js b/src/library_sdl.js index 129cb567d7b50..0ac3546a16ab6 100644 --- a/src/library_sdl.js +++ b/src/library_sdl.js @@ -1125,13 +1125,13 @@ var LibrarySDL = { audio.paused = false; if (!webAudio.decodedBuffer) { if (webAudio.onDecodeComplete === undefined) abort("Cannot play back audio object that was not loaded"); - webAudio.onDecodeComplete.push(function() { if (!audio.paused) SDL.playWebAudio(audio); }); + webAudio.onDecodeComplete.push(() => { if (!audio.paused) SDL.playWebAudio(audio); }); return; } audio.webAudioNode = SDL.audioContext['createBufferSource'](); audio.webAudioNode['buffer'] = webAudio.decodedBuffer; audio.webAudioNode['loop'] = audio.loop; - audio.webAudioNode['onended'] = function() { audio['onended'](); } // For element compatibility, route the onended signal to the instance. + audio.webAudioNode['onended'] = audio['onended']; // For element compatibility, route the onended signal to the instance. audio.webAudioPannerNode = SDL.audioContext['createPanner'](); // avoid Chrome bug @@ -1457,9 +1457,11 @@ var LibrarySDL = { SDL_SetVideoMode__deps: ['$GL'], SDL_SetVideoMode__proxy: 'sync', SDL_SetVideoMode: function(width, height, depth, flags) { - ['touchstart', 'touchend', 'touchmove', 'mousedown', 'mouseup', 'mousemove', 'DOMMouseScroll', 'mousewheel', 'wheel', 'mouseout'].forEach(function(event) { - Module['canvas'].addEventListener(event, SDL.receiveEvent, true); - }); + ['touchstart', 'touchend', 'touchmove', + 'mousedown', 'mouseup', 'mousemove', + 'mousewheel', 'wheel', 'mouseout', + 'DOMMouseScroll', + ].forEach((e) => Module['canvas'].addEventListener(e, SDL.receiveEvent, true)); var canvas = Module['canvas']; @@ -1471,7 +1473,7 @@ var LibrarySDL = { if (!SDL.addedResizeListener) { SDL.addedResizeListener = true; - Browser.resizeListeners.push(function(w, h) { + Browser.resizeListeners.push((w, h) => { if (!SDL.settingVideoMode) { SDL.receiveEvent({ type: 'resize', @@ -2056,10 +2058,8 @@ var LibrarySDL = { }, SDL_PumpEvents__proxy: 'sync', - SDL_PumpEvents: function(){ - SDL.events.forEach(function(event) { - SDL.handleEvent(event); - }); + SDL_PumpEvents: function() { + SDL.events.forEach(SDL.handleEvent); }, // An Emscripten-specific extension to SDL: Some browser APIs require that they are called from within an event handler function. @@ -2205,7 +2205,7 @@ var LibrarySDL = { var x = _malloc({{{ getNativeTypeSize('i32') }}}); var y = _malloc({{{ getNativeTypeSize('i32') }}}); var comp = _malloc({{{ getNativeTypeSize('i32') }}}); - addCleanup(function() { + addCleanup(() => { _free(x); _free(y); _free(comp); @@ -2247,7 +2247,7 @@ var LibrarySDL = { if (raw === null) err('Trying to reuse preloaded image, but freePreloadedMediaOnUse is set!'); #if STB_IMAGE var name = stringToNewUTF8(filename); - addCleanup(function() { + addCleanup(() => { _free(name); }); raw = callStbImage('stbi_load', [name]); @@ -2448,9 +2448,7 @@ var LibrarySDL = { }; Asyncify.sleepCallbacks.push(sleepCallback); SDL.audio.callbackRemover = () => { - Asyncify.sleepCallbacks = Asyncify.sleepCallbacks.filter(function(callback) { - return callback !== sleepCallback; - }); + Asyncify.sleepCallbacks = Asyncify.sleepCallbacks.filter((callback) => callback !== sleepCallback); } #endif @@ -2771,7 +2769,7 @@ var LibrarySDL = { var onDecodeComplete = (data) => { webAudio.decodedBuffer = data; // Call all handlers that were waiting for this decode to finish, and clear the handler list. - webAudio.onDecodeComplete.forEach(function(e) { e(); }); + webAudio.onDecodeComplete.forEach((e) => e()); webAudio.onDecodeComplete = undefined; // Don't allow more callback handlers since audio has finished decoding. }; SDL.audioContext['decodeAudioData'](arrayBuffer, onDecodeComplete); @@ -2887,7 +2885,7 @@ var LibrarySDL = { audio.numChannels = info.audio.numChannels; audio.frequency = info.audio.frequency; } - audio['onended'] = function SDL_audio_onended() { // TODO: cache these + audio['onended'] = function() { // TODO: cache these if (channelInfo.audio == this) { channelInfo.audio.paused = true; channelInfo.audio = null; } if (SDL.channelFinished) {{{ makeDynCall('vi', 'SDL.channelFinished') }}}(channel); } From a6087b3c9276adfc546ba0f4d4fce0e388159a25 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 11 May 2023 13:42:02 -0700 Subject: [PATCH 0231/1523] Remove dead code from src/Fetch.js. NFC (#19336) --- src/Fetch.js | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/src/Fetch.js b/src/Fetch.js index ef52028a8ec9b..aa1d59eeb8beb 100644 --- a/src/Fetch.js +++ b/src/Fetch.js @@ -228,7 +228,7 @@ function fetchCacheData(/** @type {IDBDatabase} */ db, fetch, data, onsuccess, o #endif // ~FETCH_SUPPORT_INDEXEDDB function fetchXHR(fetch, onsuccess, onerror, onprogress, onreadystatechange) { - var url = HEAPU32[fetch + {{{ C_STRUCTS.emscripten_fetch_t.url }}} >> 2]; + var url = {{{ makeGetValue('fetch', C_STRUCTS.emscripten_fetch_t.url, '*') }}}; if (!url) { #if FETCH_DEBUG dbg('fetch: XHR failed, no URL specified!'); @@ -239,13 +239,9 @@ function fetchXHR(fetch, onsuccess, onerror, onprogress, onreadystatechange) { var url_ = UTF8ToString(url); var fetch_attr = fetch + {{{ C_STRUCTS.emscripten_fetch_t.__attributes }}}; - var requestMethod = UTF8ToString(fetch_attr); + var requestMethod = UTF8ToString({{{ makeGetValue('fetch_attr', C_STRUCTS.emscripten_fetch_attr_t.requestMethod, '*') }}}); if (!requestMethod) requestMethod = 'GET'; - var userData = {{{ makeGetValue('fetch_attr', C_STRUCTS.emscripten_fetch_t.userData, '*') }}}; - var fetchAttributes = {{{ makeGetValue('fetch_attr', C_STRUCTS.emscripten_fetch_attr_t.attributes, 'u32') }}}; var timeoutMsecs = {{{ makeGetValue('fetch_attr', C_STRUCTS.emscripten_fetch_attr_t.timeoutMSecs, 'u32') }}}; - var withCredentials = !!{{{ makeGetValue('fetch_attr', C_STRUCTS.emscripten_fetch_attr_t.withCredentials, 'u8') }}}; - var destinationPath = {{{ makeGetValue('fetch_attr', C_STRUCTS.emscripten_fetch_attr_t.destinationPath, '*') }}}; var userName = {{{ makeGetValue('fetch_attr', C_STRUCTS.emscripten_fetch_attr_t.userName, '*') }}}; var password = {{{ makeGetValue('fetch_attr', C_STRUCTS.emscripten_fetch_attr_t.password, '*') }}}; var requestHeaders = {{{ makeGetValue('fetch_attr', C_STRUCTS.emscripten_fetch_attr_t.requestHeaders, '*') }}}; @@ -253,21 +249,16 @@ function fetchXHR(fetch, onsuccess, onerror, onprogress, onreadystatechange) { var dataPtr = {{{ makeGetValue('fetch_attr', C_STRUCTS.emscripten_fetch_attr_t.requestData, '*') }}}; var dataLength = {{{ makeGetValue('fetch_attr', C_STRUCTS.emscripten_fetch_attr_t.requestDataSize, '*') }}}; + var fetchAttributes = {{{ makeGetValue('fetch_attr', C_STRUCTS.emscripten_fetch_attr_t.attributes, 'u32') }}}; var fetchAttrLoadToMemory = !!(fetchAttributes & {{{ cDefs.EMSCRIPTEN_FETCH_LOAD_TO_MEMORY }}}); var fetchAttrStreamData = !!(fetchAttributes & {{{ cDefs.EMSCRIPTEN_FETCH_STREAM_DATA }}}); -#if FETCH_SUPPORT_INDEXEDDB - var fetchAttrPersistFile = !!(fetchAttributes & {{{ cDefs.EMSCRIPTEN_FETCH_PERSIST_FILE }}}); -#endif - var fetchAttrAppend = !!(fetchAttributes & {{{ cDefs.EMSCRIPTEN_FETCH_APPEND }}}); - var fetchAttrReplace = !!(fetchAttributes & {{{ cDefs.EMSCRIPTEN_FETCH_REPLACE }}}); var fetchAttrSynchronous = !!(fetchAttributes & {{{ cDefs.EMSCRIPTEN_FETCH_SYNCHRONOUS }}}); - var fetchAttrWaitable = !!(fetchAttributes & {{{ cDefs.EMSCRIPTEN_FETCH_WAITABLE }}}); var userNameStr = userName ? UTF8ToString(userName) : undefined; var passwordStr = password ? UTF8ToString(password) : undefined; var xhr = new XMLHttpRequest(); - xhr.withCredentials = withCredentials; + xhr.withCredentials = !!{{{ makeGetValue('fetch_attr', C_STRUCTS.emscripten_fetch_attr_t.withCredentials, 'u8') }}};; #if FETCH_DEBUG dbg('fetch: xhr.timeout: ' + xhr.timeout + ', xhr.withCredentials: ' + xhr.withCredentials); dbg('fetch: xhr.open(requestMethod="' + requestMethod + '", url: "' + url_ +'", userName: ' + userNameStr + ', password: ' + passwordStr + ');'); @@ -449,13 +440,10 @@ function startFetch(fetch, successcb, errorcb, progresscb, readystatechangecb) { var onprogress = HEAPU32[fetch_attr + {{{ C_STRUCTS.emscripten_fetch_attr_t.onprogress }}} >> 2]; var onreadystatechange = HEAPU32[fetch_attr + {{{ C_STRUCTS.emscripten_fetch_attr_t.onreadystatechange }}} >> 2]; var fetchAttributes = HEAPU32[fetch_attr + {{{ C_STRUCTS.emscripten_fetch_attr_t.attributes }}} >> 2]; - var fetchAttrLoadToMemory = !!(fetchAttributes & {{{ cDefs.EMSCRIPTEN_FETCH_LOAD_TO_MEMORY }}}); - var fetchAttrStreamData = !!(fetchAttributes & {{{ cDefs.EMSCRIPTEN_FETCH_STREAM_DATA }}}); #if FETCH_SUPPORT_INDEXEDDB var fetchAttrPersistFile = !!(fetchAttributes & {{{ cDefs.EMSCRIPTEN_FETCH_PERSIST_FILE }}}); var fetchAttrNoDownload = !!(fetchAttributes & {{{ cDefs.EMSCRIPTEN_FETCH_NO_DOWNLOAD }}}); #endif - var fetchAttrAppend = !!(fetchAttributes & {{{ cDefs.EMSCRIPTEN_FETCH_APPEND }}}); var fetchAttrReplace = !!(fetchAttributes & {{{ cDefs.EMSCRIPTEN_FETCH_REPLACE }}}); var fetchAttrSynchronous = !!(fetchAttributes & {{{ cDefs.EMSCRIPTEN_FETCH_SYNCHRONOUS }}}); From 5fb5fe7bc0885b2feb1a647bff8c328150c4dbca Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 11 May 2023 14:08:16 -0700 Subject: [PATCH 0232/1523] Move last remaining code in runtime.js into parseTools.js. NFC (#19338) This file only had one remaining function and contained inaccurate information at the top. --- src/compiler.js | 1 - src/parseTools.js | 25 ++++++++++++++++++++++++- src/runtime.js | 35 ----------------------------------- 3 files changed, 24 insertions(+), 37 deletions(-) delete mode 100644 src/runtime.js diff --git a/src/compiler.js b/src/compiler.js index 976cd55527cc8..0701b0b04850d 100755 --- a/src/compiler.js +++ b/src/compiler.js @@ -94,7 +94,6 @@ if (VERBOSE) { load('modules.js'); load('parseTools.js'); load('jsifier.js'); -load('runtime.js'); if (!STRICT) { load('parseTools_legacy.js'); } diff --git a/src/parseTools.js b/src/parseTools.js index 91608eef8da34..ee2a1dcbae6d1 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -170,7 +170,8 @@ function needsQuoting(ident) { return true; } -const POINTER_SIZE = MEMORY64 ? 8 : 4; +global.POINTER_SIZE = MEMORY64 ? 8 : 4; +global.STACK_ALIGN = 16; const POINTER_BITS = POINTER_SIZE * 8; const POINTER_TYPE = 'u' + POINTER_BITS; const POINTER_JS_TYPE = MEMORY64 ? "'bigint'" : "'number'"; @@ -258,6 +259,28 @@ function indentify(text, indent) { // Correction tools +function getNativeTypeSize(type) { + switch (type) { + case 'i1': case 'i8': case 'u8': return 1; + case 'i16': case 'u16': return 2; + case 'i32': case 'u32': return 4; + case 'i64': case 'u64': return 8; + case 'float': return 4; + case 'double': return 8; + default: { + if (type[type.length - 1] === '*') { + return POINTER_SIZE; + } + if (type[0] === 'i') { + const bits = Number(type.substr(1)); + assert(bits % 8 === 0, 'getNativeTypeSize invalid bits ' + bits + ', type ' + type); + return bits / 8; + } + return 0; + } + } +} + function getHeapOffset(offset, type) { if (type == 'i64' && !WASM_BIGINT) { // We are foreced to use the 32-bit heap for 64-bit values when we don't diff --git a/src/runtime.js b/src/runtime.js deleted file mode 100644 index 52ecb963112ec..0000000000000 --- a/src/runtime.js +++ /dev/null @@ -1,35 +0,0 @@ -/** - * @license - * Copyright 2010 The Emscripten Authors - * SPDX-License-Identifier: MIT - */ - -// "use strict"; - -// code used both at compile time and runtime is defined here, then put on -// the Runtime object for compile time and support.js for the generated code - -global.POINTER_SIZE = MEMORY64 ? 8 : 4; -global.STACK_ALIGN = 16; - -function getNativeTypeSize(type) { - switch (type) { - case 'i1': case 'i8': case 'u8': return 1; - case 'i16': case 'u16': return 2; - case 'i32': case 'u32': return 4; - case 'i64': case 'u64': return 8; - case 'float': return 4; - case 'double': return 8; - default: { - if (type[type.length - 1] === '*') { - return POINTER_SIZE; - } - if (type[0] === 'i') { - const bits = Number(type.substr(1)); - assert(bits % 8 === 0, 'getNativeTypeSize invalid bits ' + bits + ', type ' + type); - return bits / 8; - } - return 0; - } - } -} From 347262aec9c4450e34b6af617d1420dbda2f6662 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 11 May 2023 15:52:41 -0700 Subject: [PATCH 0233/1523] Use HandleAllocator for fetch API. NFC (#19337) --- src/Fetch.js | 60 +++++++++++++++++------------ src/library.js | 3 ++ src/library_fetch.js | 7 +--- system/lib/fetch/emscripten_fetch.c | 57 +++++++-------------------- test/fetch/xhr_abort.cpp | 2 +- 5 files changed, 55 insertions(+), 74 deletions(-) diff --git a/src/Fetch.js b/src/Fetch.js index aa1d59eeb8beb..474ddb5362ee3 100644 --- a/src/Fetch.js +++ b/src/Fetch.js @@ -5,14 +5,16 @@ */ var Fetch = { - // Map of integer fetch id to XHR request object - xhrs: {}, + // HandleAllocator for XHR request object + // xhrs: undefined, - // The web worker that runs proxied file I/O requests. (this field is populated on demand, start as undefined to save code size) + // The web worker that runs proxied file I/O requests. (this field is + // populated on demand, start as undefined to save code size) // worker: undefined, // Specifies an instance to the IndexedDB database. The database is opened - // as a preload step before the Emscripten application starts. (this field is populated on demand, start as undefined to save code size) + // as a preload step before the Emscripten application starts. (this field is + // populated on demand, start as undefined to save code size) // dbInstance: undefined, #if FETCH_SUPPORT_INDEXEDDB @@ -40,8 +42,12 @@ var Fetch = { }, #endif - staticInit: function() { + init: function() { + Fetch.xhrs = new HandleAllocator(); #if FETCH_SUPPORT_INDEXEDDB +#if PTHREADS + if (ENVIRONMENT_IS_PTHREAD) return; +#endif var onsuccess = (db) => { #if FETCH_DEBUG dbg('fetch: IndexedDB successfully opened.'); @@ -293,8 +299,12 @@ function fetchXHR(fetch, onsuccess, onerror, onprogress, onreadystatechange) { xhr.setRequestHeader(keyStr, valueStr); } } - var id = {{{ makeGetValue('fetch', C_STRUCTS.emscripten_fetch_t.id, 'u32') }}}; - Fetch.xhrs[id] = xhr; + + var id = Fetch.xhrs.allocate(xhr); +#if FETCH_DEBUG + dbg('fetch: id=' + id); +#endif + {{{ makeSetValue('fetch', C_STRUCTS.emscripten_fetch_t.id, 'id', 'u32') }}}; var data = (dataPtr && dataLength) ? HEAPU8.slice(dataPtr, dataPtr + dataLength) : null; // TODO: Support specifying custom headers to the request. @@ -334,7 +344,7 @@ function fetchXHR(fetch, onsuccess, onerror, onprogress, onreadystatechange) { xhr.onload = (e) => { // check if xhr was aborted by user and don't try to call back - if (!(id in Fetch.xhrs)) { + if (!Fetch.xhrs.has(id)) { return; } saveResponseAndStatus(); @@ -352,7 +362,7 @@ function fetchXHR(fetch, onsuccess, onerror, onprogress, onreadystatechange) { }; xhr.onerror = (e) => { // check if xhr was aborted by user and don't try to call back - if (!(id in Fetch.xhrs)) { + if (!Fetch.xhrs.has(id)) { return; } #if FETCH_DEBUG @@ -363,7 +373,7 @@ function fetchXHR(fetch, onsuccess, onerror, onprogress, onreadystatechange) { }; xhr.ontimeout = (e) => { // check if xhr was aborted by user and don't try to call back - if (!(id in Fetch.xhrs)) { + if (!Fetch.xhrs.has(id)) { return; } #if FETCH_DEBUG @@ -373,7 +383,7 @@ function fetchXHR(fetch, onsuccess, onerror, onprogress, onreadystatechange) { }; xhr.onprogress = (e) => { // check if xhr was aborted by user and don't try to call back - if (!(id in Fetch.xhrs)) { + if (!Fetch.xhrs.has(id)) { return; } var ptrLen = (fetchAttrLoadToMemory && fetchAttrStreamData && xhr.response) ? xhr.response.byteLength : 0; @@ -405,7 +415,7 @@ function fetchXHR(fetch, onsuccess, onerror, onprogress, onreadystatechange) { }; xhr.onreadystatechange = (e) => { // check if xhr was aborted by user and don't try to call back - if (!(id in Fetch.xhrs)) { + if (!Fetch.xhrs.has(id)) { {{{ runtimeKeepalivePop() }}} return; } @@ -560,27 +570,27 @@ function startFetch(fetch, successcb, errorcb, progresscb, readystatechangecb) { } function fetchGetResponseHeadersLength(id) { - return lengthBytesUTF8(Fetch.xhrs[id].getAllResponseHeaders()) + 1; + return lengthBytesUTF8(Fetch.xhrs.get(id).getAllResponseHeaders()) + 1; } function fetchGetResponseHeaders(id, dst, dstSizeBytes) { - var responseHeaders = Fetch.xhrs[id].getAllResponseHeaders(); - var lengthBytes = lengthBytesUTF8(responseHeaders) + 1; - stringToUTF8(responseHeaders, dst, dstSizeBytes); - return Math.min(lengthBytes, dstSizeBytes); + var responseHeaders = Fetch.xhrs.get(id).getAllResponseHeaders(); + var lengthBytes = lengthBytesUTF8(responseHeaders) + 1; + stringToUTF8(responseHeaders, dst, dstSizeBytes); + return Math.min(lengthBytes, dstSizeBytes); } //Delete the xhr JS object, allowing it to be garbage collected. function fetchFree(id) { #if FETCH_DEBUG - dbg("fetch: Deleting id:" + id + " of " + Fetch.xhrs); + dbg("fetch: fetchFree id:" + id); #endif - var xhr = Fetch.xhrs[id]; - if (xhr) { - delete Fetch.xhrs[id]; - // check if fetch is still in progress and should be aborted - if (xhr.readyState > 0 && xhr.readyState < 4) { - xhr.abort(); - } + if (Fetch.xhrs.has(id)) { + var xhr = Fetch.xhrs.get(id); + Fetch.xhrs.free(id); + // check if fetch is still in progress and should be aborted + if (xhr.readyState > 0 && xhr.readyState < 4) { + xhr.abort(); } + } } diff --git a/src/library.js b/src/library.js index 5192b952fe183..75fc483ff08b3 100644 --- a/src/library.js +++ b/src/library.js @@ -3667,6 +3667,9 @@ mergeInto(LibraryManager.library, { #endif return this.allocated[id]; }; + this.has = function(id) { + return this.allocated[id] !== undefined; + }; this.allocate = function(handle) { var id = this.freelist.pop() || this.allocated.length; this.allocated[id] = handle; diff --git a/src/library_fetch.js b/src/library_fetch.js index 5b6ba93dddf8e..431f573f8b10f 100644 --- a/src/library_fetch.js +++ b/src/library_fetch.js @@ -7,11 +7,8 @@ #include Fetch.js var LibraryFetch = { -#if PTHREADS - $Fetch__postset: 'if (!ENVIRONMENT_IS_PTHREAD) Fetch.staticInit();', -#else - $Fetch__postset: 'Fetch.staticInit();', -#endif + $Fetch__postset: 'Fetch.init();', + $Fetch__deps: ['$HandleAllocator'], $Fetch: Fetch, _emscripten_fetch_get_response_headers_length__deps: ['$lengthBytesUTF8'], _emscripten_fetch_get_response_headers_length: fetchGetResponseHeadersLength, diff --git a/system/lib/fetch/emscripten_fetch.c b/system/lib/fetch/emscripten_fetch.c index 01edeb3a7cce2..bc3287441bfd0 100644 --- a/system/lib/fetch/emscripten_fetch.c +++ b/system/lib/fetch/emscripten_fetch.c @@ -67,12 +67,10 @@ void emscripten_fetch_attr_init(emscripten_fetch_attr_t* fetch_attr) { memset(fetch_attr, 0, sizeof(emscripten_fetch_attr_t)); } -static int globalFetchIdCounter = 1; emscripten_fetch_t* emscripten_fetch(emscripten_fetch_attr_t* fetch_attr, const char* url) { - if (!fetch_attr) - return 0; - if (!url) - return 0; + if (!fetch_attr || !url) { + return NULL; + } const bool synchronous = (fetch_attr->attributes & EMSCRIPTEN_FETCH_SYNCHRONOUS) != 0; const bool readFromIndexedDB = @@ -85,14 +83,13 @@ emscripten_fetch_t* emscripten_fetch(emscripten_fetch_attr_t* fetch_attr, const #ifdef FETCH_DEBUG emscripten_console_errorf("emscripten_fetch('%s') failed! Synchronous blocking XHRs and IndexedDB operations are not supported on the main browser thread. Try dropping the EMSCRIPTEN_FETCH_SYNCHRONOUS flag, or run with the linker flag --proxy-to-worker to decouple main C runtime thread from the main browser thread.", url); #endif - return 0; + return NULL; } - emscripten_fetch_t* fetch = (emscripten_fetch_t*)malloc(sizeof(emscripten_fetch_t)); - if (!fetch) - return 0; - memset(fetch, 0, sizeof(emscripten_fetch_t)); - fetch->id = globalFetchIdCounter++; // TODO: make this thread-safe! + emscripten_fetch_t* fetch = (emscripten_fetch_t*)calloc(1, sizeof(emscripten_fetch_t)); + if (!fetch) { + return NULL; + } fetch->userData = fetch_attr->userData; fetch->__attributes.timeoutMSecs = fetch_attr->timeoutMSecs; fetch->__attributes.attributes = fetch_attr->attributes; @@ -117,6 +114,8 @@ emscripten_fetch_t* emscripten_fetch(emscripten_fetch_attr_t* fetch_attr, const STRDUP_OR_ABORT(fetch->__attributes.userName, fetch_attr->userName); STRDUP_OR_ABORT(fetch->__attributes.password, fetch_attr->password); STRDUP_OR_ABORT(fetch->__attributes.overriddenMimeType, fetch_attr->overriddenMimeType); +#undef STRDUP_OR_ABORT + if (fetch_attr->requestHeaders) { size_t headersCount = 0; while (fetch_attr->requestHeaders[headersCount]) @@ -124,54 +123,26 @@ emscripten_fetch_t* emscripten_fetch(emscripten_fetch_attr_t* fetch_attr, const const char** headers = (const char**)malloc((headersCount + 1) * sizeof(const char*)); if (!headers) { fetch_free(fetch); - return 0; + return NULL; } memset((void*)headers, 0, (headersCount + 1) * sizeof(const char*)); for (size_t i = 0; i < headersCount; ++i) { headers[i] = strdup(fetch_attr->requestHeaders[i]); - if (!headers[i]) - - { + if (!headers[i]) { for (size_t j = 0; j < i; ++j) { free((void*)headers[j]); } free((void*)headers); fetch_free(fetch); - return 0; + return NULL; } } headers[headersCount] = 0; fetch->__attributes.requestHeaders = headers; } -#undef STRDUP_OR_ABORT - -// In asm.js we can use a fetch worker, which is created from the main asm.js -// code. That lets us do sync operations by blocking on the worker etc. -// In the wasm backend we don't have a fetch worker implemented yet, however, -// we can still do basic synchronous fetches in the same places: if we can -// block on another thread then we aren't the main thread, and if we aren't -// the main thread then synchronous xhrs are legitimate. -#if __EMSCRIPTEN_PTHREADS__ && !defined(__wasm__) - const bool waitable = (fetch_attr->attributes & EMSCRIPTEN_FETCH_WAITABLE) != 0; - // Depending on the type of fetch, we can either perform it in the same Worker/thread than the - // caller, or we might need to run it in a separate Worker. There is a dedicated fetch worker that - // is available for the fetch, but in some scenarios it might be desirable to run in the same - // Worker as the caller, so deduce here whether to run the fetch in this thread, or if we need to - // use the fetch-worker instead. - if (waitable // Waitable fetches can be synchronously waited on, so must always be proxied - || (synchronous && - (readFromIndexedDB || writeToIndexedDB))) // Synchronous IndexedDB access needs proxying - { - fetch->__proxyState = 1; // sent to proxy worker. - emscripten_proxy_fetch(fetch); - - if (synchronous) - emscripten_fetch_wait(fetch, INFINITY); - } else -#endif - emscripten_start_fetch(fetch); + emscripten_start_fetch(fetch); return fetch; } diff --git a/test/fetch/xhr_abort.cpp b/test/fetch/xhr_abort.cpp index 7de7cab8248c1..91ba06153d847 100644 --- a/test/fetch/xhr_abort.cpp +++ b/test/fetch/xhr_abort.cpp @@ -18,7 +18,7 @@ void handleError(emscripten_fetch_t *fetch) { bool isAbortedStatus = fetch->status == (unsigned short) -1; assert(isAbortedStatus); // should have aborted status EM_ASM({ - const xhr = Fetch.xhrs[$0]; + const xhr = Fetch.xhrs.get($0); const oldReadyStateChangeHandler = xhr.onreadystatechange; // Overriding xhr handlers to check if xhr.abort() was called xhr.onreadystatechange = (e) => { From 6ab4f3a33e13b53a50afd380fe9caa0a9e7db846 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 12 May 2023 15:37:04 -0700 Subject: [PATCH 0234/1523] Fix bug in wasm preload plugin (#19342) Because we were not passing `byteArray` to the onload handle, no data was actually getting written to the fileystem in FS_createPreloadedFile -> processData -> finish and these preloaded files were being written as empty files. This matches the behavior of the other two plugins we have for images and audio. Fixing this bug allows us to fix one of the issues with `test_preload_module`, which is that it was falling back to loading from the a URL if the file was not found. By preloading the file under a different name we prevent the URL fallback from working. The URL fallback had been silently masking the `FS_createPreloadedFile` issue. --- src/library_dylink.js | 2 +- test/test_other.py | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/library_dylink.js b/src/library_dylink.js index fa06a62fbbb15..1e5133defd3e8 100644 --- a/src/library_dylink.js +++ b/src/library_dylink.js @@ -27,7 +27,7 @@ var LibraryDylink = { () => loadWebAssemblyModule(byteArray, {loadAsync: true, nodelete: true})).then( (module) => { preloadedWasm[name] = module; - onload(); + onload(byteArray); }, (error) => { err('failed to instantiate wasm: ' + name + ': ' + error); diff --git a/test/test_other.py b/test/test_other.py index 0977b4918b972..13c2e14ba5c4c 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -13425,14 +13425,21 @@ def test_preload_module(self, args): return 42; } ''') - self.run_process([EMCC, 'library.c', '-sSIDE_MODULE', '-o', 'library.so'] + args) + self.run_process([EMCC, 'library.c', '-sSIDE_MODULE', '-o', 'tmp.so'] + args) create_file('main.c', r''' #include #include #include + #include #include #include + int main() { + // Check the file exists in the VFS + struct stat statbuf; + assert(stat("/library.so", &statbuf) == 0); + + // Check that it was preloaded if (emscripten_is_main_runtime_thread()) { int found = EM_ASM_INT( return preloadedWasm['/library.so'] !== undefined; @@ -13449,4 +13456,4 @@ def test_preload_module(self, args): return 0; } ''') - self.do_runf('main.c', 'done\n', emcc_args=['-sMAIN_MODULE=2', '--preload-file', '.@/', '--use-preload-plugins'] + args) + self.do_runf('main.c', 'done\n', emcc_args=['-sMAIN_MODULE=2', '--preload-file', 'tmp.so@library.so', '--use-preload-plugins'] + args) From 59eb365568d84b1bee406e4cd970a89033e5da8b Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 12 May 2023 15:49:18 -0700 Subject: [PATCH 0235/1523] Rebaseline codesize expectations. NFC --- test/code_size/random_printf_wasm.json | 8 ++++---- test/other/metadce/test_metadce_cxx_ctors1.jssize | 2 +- test/other/metadce/test_metadce_cxx_ctors2.jssize | 2 +- test/other/metadce/test_metadce_cxx_except.jssize | 2 +- test/other/metadce/test_metadce_cxx_except_wasm.jssize | 2 +- test/other/metadce/test_metadce_cxx_mangle.jssize | 2 +- test/other/metadce/test_metadce_cxx_noexcept.jssize | 2 +- test/other/metadce/test_metadce_hello_O0.jssize | 2 +- test/other/metadce/test_metadce_hello_O1.jssize | 2 +- test/other/metadce/test_metadce_hello_O2.jssize | 2 +- test/other/metadce/test_metadce_hello_O3.jssize | 2 +- test/other/metadce/test_metadce_hello_Os.jssize | 2 +- test/other/metadce/test_metadce_hello_Oz.jssize | 2 +- test/other/metadce/test_metadce_hello_dylink.jssize | 2 +- .../metadce/test_metadce_hello_export_nothing.jssize | 2 +- .../metadce/test_metadce_libcxxabi_message_O3.jssize | 2 +- .../test_metadce_libcxxabi_message_O3_standalone.jssize | 2 +- test/other/metadce/test_metadce_mem_O3.jssize | 2 +- test/other/metadce/test_metadce_mem_O3_grow.jssize | 2 +- .../metadce/test_metadce_mem_O3_grow_standalone.jssize | 2 +- test/other/metadce/test_metadce_mem_O3_standalone.jssize | 2 +- .../metadce/test_metadce_mem_O3_standalone_lib.jssize | 2 +- .../metadce/test_metadce_mem_O3_standalone_narg.jssize | 2 +- .../test_metadce_mem_O3_standalone_narg_flto.jssize | 2 +- test/other/metadce/test_metadce_minimal_64.jssize | 2 +- test/other/metadce/test_metadce_minimal_O0.jssize | 2 +- test/other/metadce/test_metadce_minimal_O1.jssize | 2 +- test/other/metadce/test_metadce_minimal_O2.jssize | 2 +- test/other/metadce/test_metadce_minimal_O3.jssize | 2 +- test/other/metadce/test_metadce_minimal_Os.jssize | 2 +- test/other/metadce/test_metadce_minimal_Oz-ctors.jssize | 2 +- test/other/metadce/test_metadce_minimal_Oz.jssize | 2 +- test/other/metadce/test_metadce_minimal_pthreads.jssize | 2 +- test/other/test_unoptimized_code_size.js.size | 2 +- test/other/test_unoptimized_code_size_no_asserts.js.size | 2 +- test/other/test_unoptimized_code_size_strict.js.size | 2 +- 36 files changed, 39 insertions(+), 39 deletions(-) diff --git a/test/code_size/random_printf_wasm.json b/test/code_size/random_printf_wasm.json index 61d36dd843d9f..a28ce0352afa0 100644 --- a/test/code_size/random_printf_wasm.json +++ b/test/code_size/random_printf_wasm.json @@ -1,6 +1,6 @@ { - "a.html": 12778, - "a.html.gz": 6975, - "total": 12778, - "total_gz": 6975 + "a.html": 12770, + "a.html.gz": 6971, + "total": 12770, + "total_gz": 6971 } diff --git a/test/other/metadce/test_metadce_cxx_ctors1.jssize b/test/other/metadce/test_metadce_cxx_ctors1.jssize index e64ca67cf3c41..e8285cbf9a2a9 100644 --- a/test/other/metadce/test_metadce_cxx_ctors1.jssize +++ b/test/other/metadce/test_metadce_cxx_ctors1.jssize @@ -1 +1 @@ -25922 +25923 diff --git a/test/other/metadce/test_metadce_cxx_ctors2.jssize b/test/other/metadce/test_metadce_cxx_ctors2.jssize index 20a238310a29c..5a5460255508f 100644 --- a/test/other/metadce/test_metadce_cxx_ctors2.jssize +++ b/test/other/metadce/test_metadce_cxx_ctors2.jssize @@ -1 +1 @@ -25886 +25887 diff --git a/test/other/metadce/test_metadce_cxx_except.jssize b/test/other/metadce/test_metadce_cxx_except.jssize index c9e2df1f45fcf..f57d3540e6b92 100644 --- a/test/other/metadce/test_metadce_cxx_except.jssize +++ b/test/other/metadce/test_metadce_cxx_except.jssize @@ -1 +1 @@ -30436 +30437 diff --git a/test/other/metadce/test_metadce_cxx_except_wasm.jssize b/test/other/metadce/test_metadce_cxx_except_wasm.jssize index 832a59a4fbb2b..79ce5434529ec 100644 --- a/test/other/metadce/test_metadce_cxx_except_wasm.jssize +++ b/test/other/metadce/test_metadce_cxx_except_wasm.jssize @@ -1 +1 @@ -25731 +25732 diff --git a/test/other/metadce/test_metadce_cxx_mangle.jssize b/test/other/metadce/test_metadce_cxx_mangle.jssize index 73d9a9794b958..c9e2df1f45fcf 100644 --- a/test/other/metadce/test_metadce_cxx_mangle.jssize +++ b/test/other/metadce/test_metadce_cxx_mangle.jssize @@ -1 +1 @@ -30435 +30436 diff --git a/test/other/metadce/test_metadce_cxx_noexcept.jssize b/test/other/metadce/test_metadce_cxx_noexcept.jssize index e64ca67cf3c41..e8285cbf9a2a9 100644 --- a/test/other/metadce/test_metadce_cxx_noexcept.jssize +++ b/test/other/metadce/test_metadce_cxx_noexcept.jssize @@ -1 +1 @@ -25922 +25923 diff --git a/test/other/metadce/test_metadce_hello_O0.jssize b/test/other/metadce/test_metadce_hello_O0.jssize index a17534e412b0e..6b5b7088d354d 100644 --- a/test/other/metadce/test_metadce_hello_O0.jssize +++ b/test/other/metadce/test_metadce_hello_O0.jssize @@ -1 +1 @@ -23842 +23843 diff --git a/test/other/metadce/test_metadce_hello_O1.jssize b/test/other/metadce/test_metadce_hello_O1.jssize index 477a586314ed3..1c35f29ce93d9 100644 --- a/test/other/metadce/test_metadce_hello_O1.jssize +++ b/test/other/metadce/test_metadce_hello_O1.jssize @@ -1 +1 @@ -8364 +8365 diff --git a/test/other/metadce/test_metadce_hello_O2.jssize b/test/other/metadce/test_metadce_hello_O2.jssize index 638de7309a0eb..ae46500945d0d 100644 --- a/test/other/metadce/test_metadce_hello_O2.jssize +++ b/test/other/metadce/test_metadce_hello_O2.jssize @@ -1 +1 @@ -5944 +5945 diff --git a/test/other/metadce/test_metadce_hello_O3.jssize b/test/other/metadce/test_metadce_hello_O3.jssize index f6cc210c14d5d..7974cb622864c 100644 --- a/test/other/metadce/test_metadce_hello_O3.jssize +++ b/test/other/metadce/test_metadce_hello_O3.jssize @@ -1 +1 @@ -5770 +5771 diff --git a/test/other/metadce/test_metadce_hello_Os.jssize b/test/other/metadce/test_metadce_hello_Os.jssize index f6cc210c14d5d..7974cb622864c 100644 --- a/test/other/metadce/test_metadce_hello_Os.jssize +++ b/test/other/metadce/test_metadce_hello_Os.jssize @@ -1 +1 @@ -5770 +5771 diff --git a/test/other/metadce/test_metadce_hello_Oz.jssize b/test/other/metadce/test_metadce_hello_Oz.jssize index 07176ad9c13dc..bb28ca38928b1 100644 --- a/test/other/metadce/test_metadce_hello_Oz.jssize +++ b/test/other/metadce/test_metadce_hello_Oz.jssize @@ -1 +1 @@ -5729 +5730 diff --git a/test/other/metadce/test_metadce_hello_dylink.jssize b/test/other/metadce/test_metadce_hello_dylink.jssize index a86975277b10a..f450807b16165 100644 --- a/test/other/metadce/test_metadce_hello_dylink.jssize +++ b/test/other/metadce/test_metadce_hello_dylink.jssize @@ -1 +1 @@ -28007 +28009 diff --git a/test/other/metadce/test_metadce_hello_export_nothing.jssize b/test/other/metadce/test_metadce_hello_export_nothing.jssize index bc14fa04a5289..8c83c7141d764 100644 --- a/test/other/metadce/test_metadce_hello_export_nothing.jssize +++ b/test/other/metadce/test_metadce_hello_export_nothing.jssize @@ -1 +1 @@ -4514 +4515 diff --git a/test/other/metadce/test_metadce_libcxxabi_message_O3.jssize b/test/other/metadce/test_metadce_libcxxabi_message_O3.jssize index 89810b1541216..2e3f3cf6bd9e6 100644 --- a/test/other/metadce/test_metadce_libcxxabi_message_O3.jssize +++ b/test/other/metadce/test_metadce_libcxxabi_message_O3.jssize @@ -1 +1 @@ -5040 +5041 diff --git a/test/other/metadce/test_metadce_libcxxabi_message_O3_standalone.jssize b/test/other/metadce/test_metadce_libcxxabi_message_O3_standalone.jssize index 800920fac0dbc..f00811b24122b 100644 --- a/test/other/metadce/test_metadce_libcxxabi_message_O3_standalone.jssize +++ b/test/other/metadce/test_metadce_libcxxabi_message_O3_standalone.jssize @@ -1 +1 @@ -5108 +5109 diff --git a/test/other/metadce/test_metadce_mem_O3.jssize b/test/other/metadce/test_metadce_mem_O3.jssize index a37e2a8309c39..6bb6c758c86e7 100644 --- a/test/other/metadce/test_metadce_mem_O3.jssize +++ b/test/other/metadce/test_metadce_mem_O3.jssize @@ -1 +1 @@ -5980 +5981 diff --git a/test/other/metadce/test_metadce_mem_O3_grow.jssize b/test/other/metadce/test_metadce_mem_O3_grow.jssize index 21faf3262f93b..9e39e40188fb3 100644 --- a/test/other/metadce/test_metadce_mem_O3_grow.jssize +++ b/test/other/metadce/test_metadce_mem_O3_grow.jssize @@ -1 +1 @@ -6316 +6317 diff --git a/test/other/metadce/test_metadce_mem_O3_grow_standalone.jssize b/test/other/metadce/test_metadce_mem_O3_grow_standalone.jssize index 1e587493b7d85..500e5046a5549 100644 --- a/test/other/metadce/test_metadce_mem_O3_grow_standalone.jssize +++ b/test/other/metadce/test_metadce_mem_O3_grow_standalone.jssize @@ -1 +1 @@ -5706 +5707 diff --git a/test/other/metadce/test_metadce_mem_O3_standalone.jssize b/test/other/metadce/test_metadce_mem_O3_standalone.jssize index 142e175a948df..92048a505a35e 100644 --- a/test/other/metadce/test_metadce_mem_O3_standalone.jssize +++ b/test/other/metadce/test_metadce_mem_O3_standalone.jssize @@ -1 +1 @@ -5628 +5629 diff --git a/test/other/metadce/test_metadce_mem_O3_standalone_lib.jssize b/test/other/metadce/test_metadce_mem_O3_standalone_lib.jssize index 8fc0c002218ce..87210c9efe676 100644 --- a/test/other/metadce/test_metadce_mem_O3_standalone_lib.jssize +++ b/test/other/metadce/test_metadce_mem_O3_standalone_lib.jssize @@ -1 +1 @@ -5126 +5127 diff --git a/test/other/metadce/test_metadce_mem_O3_standalone_narg.jssize b/test/other/metadce/test_metadce_mem_O3_standalone_narg.jssize index 800920fac0dbc..f00811b24122b 100644 --- a/test/other/metadce/test_metadce_mem_O3_standalone_narg.jssize +++ b/test/other/metadce/test_metadce_mem_O3_standalone_narg.jssize @@ -1 +1 @@ -5108 +5109 diff --git a/test/other/metadce/test_metadce_mem_O3_standalone_narg_flto.jssize b/test/other/metadce/test_metadce_mem_O3_standalone_narg_flto.jssize index 800920fac0dbc..f00811b24122b 100644 --- a/test/other/metadce/test_metadce_mem_O3_standalone_narg_flto.jssize +++ b/test/other/metadce/test_metadce_mem_O3_standalone_narg_flto.jssize @@ -1 +1 @@ -5108 +5109 diff --git a/test/other/metadce/test_metadce_minimal_64.jssize b/test/other/metadce/test_metadce_minimal_64.jssize index 12167a2b4e159..440fbf5902ebb 100644 --- a/test/other/metadce/test_metadce_minimal_64.jssize +++ b/test/other/metadce/test_metadce_minimal_64.jssize @@ -1 +1 @@ -3952 +3953 diff --git a/test/other/metadce/test_metadce_minimal_O0.jssize b/test/other/metadce/test_metadce_minimal_O0.jssize index ee2c9295201b2..841285e9cb5f4 100644 --- a/test/other/metadce/test_metadce_minimal_O0.jssize +++ b/test/other/metadce/test_metadce_minimal_O0.jssize @@ -1 +1 @@ -20091 +20092 diff --git a/test/other/metadce/test_metadce_minimal_O1.jssize b/test/other/metadce/test_metadce_minimal_O1.jssize index 3c4089ce00ff3..c52024da24d16 100644 --- a/test/other/metadce/test_metadce_minimal_O1.jssize +++ b/test/other/metadce/test_metadce_minimal_O1.jssize @@ -1 +1 @@ -4678 +4679 diff --git a/test/other/metadce/test_metadce_minimal_O2.jssize b/test/other/metadce/test_metadce_minimal_O2.jssize index ffb0927ae4ae7..5abe252937e88 100644 --- a/test/other/metadce/test_metadce_minimal_O2.jssize +++ b/test/other/metadce/test_metadce_minimal_O2.jssize @@ -1 +1 @@ -3612 +3613 diff --git a/test/other/metadce/test_metadce_minimal_O3.jssize b/test/other/metadce/test_metadce_minimal_O3.jssize index c9818c5c65dfe..8e66fe9e2cf2f 100644 --- a/test/other/metadce/test_metadce_minimal_O3.jssize +++ b/test/other/metadce/test_metadce_minimal_O3.jssize @@ -1 +1 @@ -3541 +3542 diff --git a/test/other/metadce/test_metadce_minimal_Os.jssize b/test/other/metadce/test_metadce_minimal_Os.jssize index c9818c5c65dfe..8e66fe9e2cf2f 100644 --- a/test/other/metadce/test_metadce_minimal_Os.jssize +++ b/test/other/metadce/test_metadce_minimal_Os.jssize @@ -1 +1 @@ -3541 +3542 diff --git a/test/other/metadce/test_metadce_minimal_Oz-ctors.jssize b/test/other/metadce/test_metadce_minimal_Oz-ctors.jssize index 51feb77641d07..c8804381437c3 100644 --- a/test/other/metadce/test_metadce_minimal_Oz-ctors.jssize +++ b/test/other/metadce/test_metadce_minimal_Oz-ctors.jssize @@ -1 +1 @@ -3522 +3523 diff --git a/test/other/metadce/test_metadce_minimal_Oz.jssize b/test/other/metadce/test_metadce_minimal_Oz.jssize index c9818c5c65dfe..8e66fe9e2cf2f 100644 --- a/test/other/metadce/test_metadce_minimal_Oz.jssize +++ b/test/other/metadce/test_metadce_minimal_Oz.jssize @@ -1 +1 @@ -3541 +3542 diff --git a/test/other/metadce/test_metadce_minimal_pthreads.jssize b/test/other/metadce/test_metadce_minimal_pthreads.jssize index 5c6c88b9001f7..5f9626305d9a4 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.jssize +++ b/test/other/metadce/test_metadce_minimal_pthreads.jssize @@ -1 +1 @@ -15425 +15426 diff --git a/test/other/test_unoptimized_code_size.js.size b/test/other/test_unoptimized_code_size.js.size index adf34be9a2082..1e2918b84d776 100644 --- a/test/other/test_unoptimized_code_size.js.size +++ b/test/other/test_unoptimized_code_size.js.size @@ -1 +1 @@ -59636 +59638 diff --git a/test/other/test_unoptimized_code_size_no_asserts.js.size b/test/other/test_unoptimized_code_size_no_asserts.js.size index 2a7a3ea68f817..5ff8d77a15fd1 100644 --- a/test/other/test_unoptimized_code_size_no_asserts.js.size +++ b/test/other/test_unoptimized_code_size_no_asserts.js.size @@ -1 +1 @@ -33255 +33256 diff --git a/test/other/test_unoptimized_code_size_strict.js.size b/test/other/test_unoptimized_code_size_strict.js.size index 76e26a7c5e517..42ec6578d58b4 100644 --- a/test/other/test_unoptimized_code_size_strict.js.size +++ b/test/other/test_unoptimized_code_size_strict.js.size @@ -1 +1 @@ -58578 +58580 From 90d76db21200d42f5536bc3a01a22303e398d8b4 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 12 May 2023 15:51:36 -0700 Subject: [PATCH 0236/1523] Remove non-determinsim tolerance from code size tests. NFC (#19348) --- test/test_other.py | 24 ++---------------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/test/test_other.py b/test/test_other.py index 13c2e14ba5c4c..af9cc35025561 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -7812,6 +7812,7 @@ def check_expected_size_in_file(self, desc, filename, size): print(' seen %s size: %d (expected: %d) (delta: %d), ratio to expected: %f' % (desc, size, expected_size, delta, ratio)) self.assertLess(ratio, size_slack) + @crossplatform def test_unoptimized_code_size(self): # We don't care too about unoptimized code size but we would like to keep it # under control to a certain extent. This test allows us to track major @@ -10014,6 +10015,7 @@ def test(args, closure, opt): 'math': ('math', False), 'hello_wasm_worker': ('hello_wasm_worker', False, True), }) + @crossplatform def test_minimal_runtime_code_size(self, test_name, js, compare_js_output=False): smallest_code_size_args = ['-sMINIMAL_RUNTIME=2', '-sENVIRONMENT=web', @@ -10144,28 +10146,6 @@ def get_file_gzipped_size(f): print('size of ' + f + ' == ' + str(size) + ', expected ' + str(expected_size) + ', delta=' + str(size - expected_size) + print_percent(size, expected_size)) print('size of ' + f_gz + ' == ' + str(size_gz) + ', expected ' + str(expected_size_gz) + ', delta=' + str(size_gz - expected_size_gz) + print_percent(size_gz, expected_size_gz)) - # Hack: Generated .mem initializer files have different sizes on different - # platforms (Windows gives x, CircleCI Linux gives x-17 bytes, my home - # Linux gives x+2 bytes..). Likewise asm.js files seem to be affected by - # the LLVM IR text names, which lead to asm.js names, which leads to - # difference code size, which leads to different relooper choices, - # as a result leading to slightly different total code sizes. - # Also as of July 16, 2020, wasm2js files have different sizes on - # different platforms (Windows and MacOS improved to give a slightly - # better thing than Linux does, which didn't change; this just - # started to happen on CI, not in response to a code update, so it - # may have been present all along but just noticed now; it only - # happens in wasm2js, so it may be platform-nondeterminism in closure - # compiler). - # TODO: identify what is causing this. meanwhile allow some amount of slop - if not common.EMTEST_REBASELINE: - if js: - slop = 30 - else: - slop = 20 - if size <= expected_size + slop and size >= expected_size - slop: - size = expected_size - # N.B. even though the test code above prints out gzip compressed sizes, regression testing is done against uncompressed sizes # this is because optimizing for compressed sizes can be unpredictable and sometimes counterproductive total_output_size += size From 69be6d3c14ba89a20dd3e0d1de37a409c067ff3a Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 15 May 2023 12:33:57 -0700 Subject: [PATCH 0237/1523] Remove commended out debugging code from 2012. NFC (#19364) It not clear how this code is/was useful. --- src/library_browser.js | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/library_browser.js b/src/library_browser.js index df6b6a9ee41cf..e7f8df09fa793 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -1308,17 +1308,3 @@ var LibraryBrowser = { autoAddDeps(LibraryBrowser, '$Browser'); mergeInto(LibraryManager.library, LibraryBrowser); - -/* Useful stuff for browser debugging - -function slowLog(label, text) { - if (!slowLog.labels) slowLog.labels = {}; - if (!slowLog.labels[label]) slowLog.labels[label] = 0; - var now = Date.now(); - if (now - slowLog.labels[label] > 1000) { - out(label + ': ' + text); - slowLog.labels[label] = now; - } -} - -*/ From efbe6e9a458b744d25165ca73f33db0cf72d72a3 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 15 May 2023 12:42:49 -0700 Subject: [PATCH 0238/1523] Use struct_info.py for EM_TIMING macros. NFC (#19365) --- src/generated_struct_info32.json | 3 +++ src/generated_struct_info64.json | 3 +++ src/library_browser.js | 18 +++++++++++------- src/struct_info.json | 5 ++++- test/matrix_multiply.cpp | 4 ---- 5 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/generated_struct_info32.json b/src/generated_struct_info32.json index acb5641fd5618..375664fbb7650 100644 --- a/src/generated_struct_info32.json +++ b/src/generated_struct_info32.json @@ -220,6 +220,9 @@ "EM_PROMISE_REJECT": 3, "EM_PROXIED_RESIZE_OFFSCREENCANVAS": 654311424, "EM_QUEUED_JS_CALL_MAX_ARGS": 20, + "EM_TIMING_RAF": 1, + "EM_TIMING_SETIMMEDIATE": 2, + "EM_TIMING_SETTIMEOUT": 0, "ENAMETOOLONG": 37, "ENETDOWN": 38, "ENETRESET": 39, diff --git a/src/generated_struct_info64.json b/src/generated_struct_info64.json index 973b4220d0200..dc16a1f78977e 100644 --- a/src/generated_struct_info64.json +++ b/src/generated_struct_info64.json @@ -220,6 +220,9 @@ "EM_PROMISE_REJECT": 3, "EM_PROXIED_RESIZE_OFFSCREENCANVAS": 654311424, "EM_QUEUED_JS_CALL_MAX_ARGS": 20, + "EM_TIMING_RAF": 1, + "EM_TIMING_SETIMMEDIATE": 2, + "EM_TIMING_SETTIMEOUT": 0, "ENAMETOOLONG": 37, "ENETDOWN": 38, "ENETRESET": 39, diff --git a/src/library_browser.js b/src/library_browser.js index e7f8df09fa793..1dda0c3efbdac 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -826,18 +826,18 @@ var LibraryBrowser = { {{{ runtimeKeepalivePush() }}} Browser.mainLoop.running = true; } - if (mode == 0 /*EM_TIMING_SETTIMEOUT*/) { + if (mode == {{{ cDefs.EM_TIMING_SETTIMEOUT }}}) { Browser.mainLoop.scheduler = function Browser_mainLoop_scheduler_setTimeout() { var timeUntilNextTick = Math.max(0, Browser.mainLoop.tickStartTime + value - _emscripten_get_now())|0; setTimeout(Browser.mainLoop.runner, timeUntilNextTick); // doing this each time means that on exception, we stop }; Browser.mainLoop.method = 'timeout'; - } else if (mode == 1 /*EM_TIMING_RAF*/) { + } else if (mode == {{{ cDefs.EM_TIMING_RAF }}}) { Browser.mainLoop.scheduler = function Browser_mainLoop_scheduler_rAF() { Browser.requestAnimationFrame(Browser.mainLoop.runner); }; Browser.mainLoop.method = 'rAF'; - } else if (mode == 2 /*EM_TIMING_SETIMMEDIATE*/) { + } else if (mode == {{{ cDefs.EM_TIMING_SETIMMEDIATE}}}) { if (typeof setImmediate == 'undefined') { // Emulate setImmediate. (note: not a complete polyfill, we don't emulate clearImmediate() to keep code size to minimum, since not needed) var setImmediates = []; @@ -962,11 +962,11 @@ var LibraryBrowser = { // Implement very basic swap interval control Browser.mainLoop.currentFrameNumber = Browser.mainLoop.currentFrameNumber + 1 | 0; - if (Browser.mainLoop.timingMode == 1/*EM_TIMING_RAF*/ && Browser.mainLoop.timingValue > 1 && Browser.mainLoop.currentFrameNumber % Browser.mainLoop.timingValue != 0) { + if (Browser.mainLoop.timingMode == {{{ cDefs.EM_TIMING_RAF }}} && Browser.mainLoop.timingValue > 1 && Browser.mainLoop.currentFrameNumber % Browser.mainLoop.timingValue != 0) { // Not the scheduled time to render this frame - skip. Browser.mainLoop.scheduler(); return; - } else if (Browser.mainLoop.timingMode == 0/*EM_TIMING_SETTIMEOUT*/) { + } else if (Browser.mainLoop.timingMode == {{{ cDefs.EM_TIMING_SETTIMEOUT }}}) { Browser.mainLoop.tickStartTime = _emscripten_get_now(); } @@ -1018,8 +1018,12 @@ var LibraryBrowser = { } if (!noSetTiming) { - if (fps && fps > 0) _emscripten_set_main_loop_timing(0/*EM_TIMING_SETTIMEOUT*/, 1000.0 / fps); - else _emscripten_set_main_loop_timing(1/*EM_TIMING_RAF*/, 1); // Do rAF by rendering each frame (no decimating) + if (fps && fps > 0) { + _emscripten_set_main_loop_timing({{{ cDefs.EM_TIMING_SETTIMEOUT }}}, 1000.0 / fps); + } else { + // Do rAF by rendering each frame (no decimating) + _emscripten_set_main_loop_timing({{{ cDefs.EM_TIMING_RAF }}}, 1); + } Browser.mainLoop.scheduler(); } diff --git a/src/struct_info.json b/src/struct_info.json index 534d4c4ca575d..a48592641fcfc 100644 --- a/src/struct_info.json +++ b/src/struct_info.json @@ -943,7 +943,10 @@ "EM_LOG_NO_PATHS", "EM_LOG_FUNC_PARAMS", "EM_LOG_DEBUG", - "EM_LOG_INFO" + "EM_LOG_INFO", + "EM_TIMING_SETTIMEOUT", + "EM_TIMING_RAF", + "EM_TIMING_SETIMMEDIATE" ] }, { diff --git a/test/matrix_multiply.cpp b/test/matrix_multiply.cpp index 96f0617584ab6..45a2be134a1dd 100644 --- a/test/matrix_multiply.cpp +++ b/test/matrix_multiply.cpp @@ -107,10 +107,6 @@ int main(int argc, char **argv) } printf("Performing %d multiplications of matrices of size %dx%d and %dx%d. Distributing multiplication across %d animation frames (matrix muls per frame=%d).\n", NumFrames*ItersPerFrame, A, B, B, C, NumFrames, ItersPerFrame); -// #define EM_TIMING_SETTIMEOUT 0 -// #define EM_TIMING_RAF 1 -// #define EM_TIMING_SETIMMEDIATE 2 - mA = new float[A*B]; mB = new float[B*C]; mDst = new float[A*C]; From e917744cbe3bdc327131a8bc212781ae8209e299 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 15 May 2023 14:02:35 -0700 Subject: [PATCH 0239/1523] Remove EM_JS version of `console_error` in test code. NFC (#19366) Followup to #19329 --- test/wasm_worker/terminate_all_wasm_workers.c | 10 +++------- test/wasm_worker/terminate_wasm_worker.c | 10 +++------- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/test/wasm_worker/terminate_all_wasm_workers.c b/test/wasm_worker/terminate_all_wasm_workers.c index 385a5e31a1b47..847dda59b9c79 100644 --- a/test/wasm_worker/terminate_all_wasm_workers.c +++ b/test/wasm_worker/terminate_all_wasm_workers.c @@ -5,16 +5,12 @@ // Tests that calling emscripten_terminate_all_wasm_workers() properly terminates // each child Wasm Worker of the calling thread. -EM_JS(void, console_error, (char* str), { - console.error(UTF8ToString(str)); -}); - static volatile int worker_started = 0; void this_function_should_not_be_called(void *userData) { worker_started = -1; - console_error("this_function_should_not_be_called"); + emscripten_console_error("this_function_should_not_be_called"); #ifdef REPORT_RESULT REPORT_RESULT(1/*fail*/); #endif @@ -24,7 +20,7 @@ void test_passed(void *userData) { if (worker_started == 2) { - console_error("test_passed"); + emscripten_console_error("test_passed"); #ifdef REPORT_RESULT REPORT_RESULT(0/*ok*/); #endif @@ -34,7 +30,7 @@ void test_passed(void *userData) void worker_main() { ++worker_started; - console_error("Hello from wasm worker!"); + emscripten_console_error("Hello from wasm worker!"); // Schedule a function to be called, that should never happen, since the Worker // dies before that. emscripten_set_timeout(this_function_should_not_be_called, 2000, 0); diff --git a/test/wasm_worker/terminate_wasm_worker.c b/test/wasm_worker/terminate_wasm_worker.c index ce3989bced614..fa3fb0fe04abb 100644 --- a/test/wasm_worker/terminate_wasm_worker.c +++ b/test/wasm_worker/terminate_wasm_worker.c @@ -5,16 +5,12 @@ // Tests that calling emscripten_terminate_wasm_worker() properly terminates // a Wasm Worker. -EM_JS(void, console_error, (char* str), { - console.error(UTF8ToString(str)); -}); - static volatile int worker_started = 0; void this_function_should_not_be_called(void *userData) { worker_started = -1; - console_error("this_function_should_not_be_called"); + emscripten_console_error("this_function_should_not_be_called"); #ifdef REPORT_RESULT REPORT_RESULT(1/*fail*/); #endif @@ -24,7 +20,7 @@ void test_passed(void *userData) { if (worker_started == 1) { - console_error("test_passed"); + emscripten_console_error("test_passed"); #ifdef REPORT_RESULT REPORT_RESULT(0/*ok*/); #endif @@ -34,7 +30,7 @@ void test_passed(void *userData) void worker_main() { worker_started = 1; - console_error("Hello from wasm worker!"); + emscripten_console_error("Hello from wasm worker!"); // Schedule a function to be called, that should never happen, since the Worker // dies before that. emscripten_set_timeout(this_function_should_not_be_called, 2000, 0); From d2c2c148ba582456b94827907fcde0ab7cffd658 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 15 May 2023 14:32:12 -0700 Subject: [PATCH 0240/1523] Fix reverse deps with `-sERROR_ON_UNDEFINED_SYMBOLS=0` (#19352) The change to `test_only_force_stdlibs` was needed because the failure case is now a build time rather than runtime error. Using `-sWARN_ON_UNDEFINED_SYMBOLS=0` (which implicitly sets `ERROR_ON_UNDEFINED_SYMBOLS=0` too) cannot prevent/delay errors when certain types of symbols are missing. For example the linker will always error on missing data symbols. After this change the linker will also always error on missing revert dependencies (of which malloc is one in this test case). Fixes: #19234 --- emcc.py | 2 +- test/test_other.py | 30 ++++++++++++++++++++++++------ tools/building.py | 5 +---- 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/emcc.py b/emcc.py index ef558e531f25e..956766473b9e6 100755 --- a/emcc.py +++ b/emcc.py @@ -540,7 +540,7 @@ def build_symbol_list(filename): """ library_syms = generate_js_sym_info() - write_file(filename, json.dumps(library_syms, separators=(',', ':'))) + write_file(filename, json.dumps(library_syms, separators=(',', ':'), indent=2)) # We need to use a separate lock here for symbol lists because, unlike with system libraries, # it's normally for these file to get pruned as part of normal operation. This means that it diff --git a/test/test_other.py b/test/test_other.py index af9cc35025561..8afbd1ff090d6 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -5198,15 +5198,17 @@ def test_bad_lookup(self): 'full_only': [{'EMCC_FORCE_STDLIBS': 'libc,libc++abi,libc++,libmalloc', 'EMCC_ONLY_FORCED_STDLIBS': '1'}, False], }) def test_only_force_stdlibs(self, env, fail): + cmd = [EMXX, test_file('hello_libcxx.cpp')] with env_modify(env): - err = self.run_process([EMXX, test_file('hello_libcxx.cpp'), '-sWARN_ON_UNDEFINED_SYMBOLS=0'], stderr=PIPE).stderr - if 'EMCC_ONLY_FORCED_STDLIBS' in env: - self.assertContained('EMCC_ONLY_FORCED_STDLIBS is deprecated', err) if fail: - output = self.run_js('a.out.js', assert_returncode=NON_ZERO) - self.assertContained('missing function', output) + err = self.expect_fail(cmd) + self.assertContained('undefined symbol: malloc', err) else: - self.assertContained('hello, world!', self.run_js('a.out.js')) + err = self.run_process(cmd, stderr=PIPE).stderr + if 'EMCC_ONLY_FORCED_STDLIBS' in env: + self.assertContained('EMCC_ONLY_FORCED_STDLIBS is deprecated', err) + else: + self.assertContained('hello, world!', self.run_js('a.out.js')) def test_only_force_stdlibs_2(self): create_file('src.cpp', r''' @@ -12029,6 +12031,22 @@ def test_main_module_no_undefined(self): # Test that ERROR_ON_UNDEFINED_SYMBOLS works with MAIN_MODULE. self.do_runf(test_file('hello_world.c'), emcc_args=['-sMAIN_MODULE', '-sERROR_ON_UNDEFINED_SYMBOLS']) + def test_reverse_deps_allow_undefined(self): + # Check that reverse deps are still included even when -sERROR_ON_UNDEFINED_SYMBOLS=0. + create_file('test.c', ''' + #include + #include + #include + + int main() { + // Reference in getaddrinfo which has reverse deps on malloc and htons + // We expect these to be exported even when -sERROR_ON_UNDEFINED_SYMBOLS=0. + printf("%p\\n", &getaddrinfo); + return 0; + } + ''') + self.do_runf('test.c', emcc_args=['-sERROR_ON_UNDEFINED_SYMBOLS=0']) + @parameterized({ 'relocatable': ('-sRELOCATABLE',), 'linkable': ('-sLINKABLE',), diff --git a/tools/building.py b/tools/building.py index 20a8ce465d744..6a8749459aa51 100644 --- a/tools/building.py +++ b/tools/building.py @@ -135,10 +135,7 @@ def create_stub_object(external_symbols): stubfile = shared.get_temp_files().get('libemscripten_js_symbols.so').name stubs = ['#STUB'] for name, deps in external_symbols.items(): - if settings.ERROR_ON_UNDEFINED_SYMBOLS: - stubs.append('%s: %s' % (name, ','.join(deps))) - else: - stubs.append(name) + stubs.append('%s: %s' % (name, ','.join(deps))) utils.write_file(stubfile, '\n'.join(stubs)) return stubfile From 8d978a500efe87172fc414358f6431fcfa83bfe2 Mon Sep 17 00:00:00 2001 From: juj Date: Tue, 16 May 2023 00:50:36 +0300 Subject: [PATCH 0241/1523] Update html-minifier-terser from 6.1.0 to 7.2.0 (#19368) This updates its dependency terser to 5.16.6 to avoid https://nvd.nist.gov/vuln/detail/CVE-2022-25858 that affected terser < 5.14.2. --- package-lock.json | 89 ++++++++++++++++++++++++----------------------- package.json | 2 +- 2 files changed, 47 insertions(+), 44 deletions(-) diff --git a/package-lock.json b/package-lock.json index 16026dd816996..99b7251aee988 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,5 @@ { - "name": "emscripten", + "name": "main", "lockfileVersion": 2, "requires": true, "packages": { @@ -7,7 +7,7 @@ "dependencies": { "acorn": "^8.7.1", "google-closure-compiler": "20220502.0.0", - "html-minifier-terser": "6.1.0", + "html-minifier-terser": "7.2.0", "wasm2c": "1.0.0" }, "devDependencies": { @@ -777,9 +777,9 @@ } }, "node_modules/clean-css": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.2.2.tgz", - "integrity": "sha512-/eR8ru5zyxKzpBLv9YZvMXgTSSQn7AdkMItMYynsFgGwTveCRVam9IUPFloE85B4vAIj05IuKmmEoV7/AQjT0w==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.2.tgz", + "integrity": "sha512-JVJbM+f3d3Q704rF4bqQ5UUyTtuJ0JRKNbTKVEeujCCBoMdkEi+V+e8oktO9qGQNSvHrFTM6JZRXrUvGR1czww==", "dependencies": { "source-map": "~0.6.0" }, @@ -1036,6 +1036,17 @@ "node": ">=10.13.0" } }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/env-variable": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/env-variable/-/env-variable-0.0.6.tgz", @@ -1697,40 +1708,32 @@ "node": ">=4" } }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "bin": { - "he": "bin/he" - } - }, "node_modules/html-minifier-terser": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", - "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-7.2.0.tgz", + "integrity": "sha512-tXgn3QfqPIpGl9o+K5tpcj3/MN4SfLtsx2GWwBC3SSd0tXQGyF3gsSqad8loJgKZGM3ZxbYDd5yhiBIdWpmvLA==", "dependencies": { "camel-case": "^4.1.2", - "clean-css": "^5.2.2", - "commander": "^8.3.0", - "he": "^1.2.0", + "clean-css": "~5.3.2", + "commander": "^10.0.0", + "entities": "^4.4.0", "param-case": "^3.0.4", "relateurl": "^0.2.7", - "terser": "^5.10.0" + "terser": "^5.15.1" }, "bin": { "html-minifier-terser": "cli.js" }, "engines": { - "node": ">=12" + "node": "^14.13.1 || >=16.0.0" } }, "node_modules/html-minifier-terser/node_modules/commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", "engines": { - "node": ">= 12" + "node": ">=14" } }, "node_modules/iconv-lite": { @@ -4161,9 +4164,9 @@ "dev": true }, "clean-css": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.2.2.tgz", - "integrity": "sha512-/eR8ru5zyxKzpBLv9YZvMXgTSSQn7AdkMItMYynsFgGwTveCRVam9IUPFloE85B4vAIj05IuKmmEoV7/AQjT0w==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.2.tgz", + "integrity": "sha512-JVJbM+f3d3Q704rF4bqQ5UUyTtuJ0JRKNbTKVEeujCCBoMdkEi+V+e8oktO9qGQNSvHrFTM6JZRXrUvGR1czww==", "requires": { "source-map": "~0.6.0" }, @@ -4384,6 +4387,11 @@ "tapable": "^2.2.0" } }, + "entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==" + }, "env-variable": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/env-variable/-/env-variable-0.0.6.tgz", @@ -4871,29 +4879,24 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" - }, "html-minifier-terser": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", - "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-7.2.0.tgz", + "integrity": "sha512-tXgn3QfqPIpGl9o+K5tpcj3/MN4SfLtsx2GWwBC3SSd0tXQGyF3gsSqad8loJgKZGM3ZxbYDd5yhiBIdWpmvLA==", "requires": { "camel-case": "^4.1.2", - "clean-css": "^5.2.2", - "commander": "^8.3.0", - "he": "^1.2.0", + "clean-css": "~5.3.2", + "commander": "^10.0.0", + "entities": "^4.4.0", "param-case": "^3.0.4", "relateurl": "^0.2.7", - "terser": "^5.10.0" + "terser": "^5.15.1" }, "dependencies": { "commander": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", - "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==" + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==" } } }, diff --git a/package.json b/package.json index 19f924d45ca5e..b1673d47885f2 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "dependencies": { "acorn": "^8.7.1", "google-closure-compiler": "20220502.0.0", - "html-minifier-terser": "6.1.0", + "html-minifier-terser": "7.2.0", "wasm2c": "1.0.0" }, "scripts": { From 9677b7df77e61db0b2eb91f5c7525429968cb084 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 15 May 2023 15:31:41 -0700 Subject: [PATCH 0242/1523] dylink: Make preload plugin dependency conditional on FILESYTEM (#19362) The preload plugin system is part of the core filesystem code in `library_fs_shared.py`. Fixes: #19361 --- src/library_browser.js | 4 ++++ src/library_dylink.js | 10 +++++++++- test/test_other.py | 5 ++++- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/library_browser.js b/src/library_browser.js index 1dda0c3efbdac..9913a93bc720d 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -12,9 +12,11 @@ var LibraryBrowser = { '$safeSetTimeout', '$warnOnce', 'emscripten_set_main_loop_timing', +#if FILESYSTEM || WASMFS '$preloadPlugins', #if MAIN_MODULE '$preloadedWasm', +#endif #endif ], $Browser__postset: ` @@ -105,6 +107,7 @@ var LibraryBrowser = { if (Browser.initted) return; Browser.initted = true; +#if FILESYSTEM || WASMFS // Support for plugins that can process preloaded files. You can add more of these to // your app by creating and appending to preloadPlugins. // @@ -209,6 +212,7 @@ var LibraryBrowser = { }, 10000); }; preloadPlugins.push(audioPlugin); +#endif // Canvas event setup diff --git a/src/library_dylink.js b/src/library_dylink.js index 1e5133defd3e8..1a74a5fc39a57 100644 --- a/src/library_dylink.js +++ b/src/library_dylink.js @@ -10,6 +10,7 @@ var dlopenMissingError = "'To use dlopen, you need enable dynamic linking, see h var LibraryDylink = { #if RELOCATABLE +#if FILESYSTEM || WASMFS $registerWasmPlugin__deps: ['$preloadPlugins'], $registerWasmPlugin: function() { // Use string keys here to avoid minification since the plugin consumer @@ -43,6 +44,7 @@ var LibraryDylink = { registerWasmPlugin(); `, $preloadedWasm: {}, +#endif // FILESYSTEM $isSymbolDefined: function(symName) { // Ignore 'stub' symbols that are auto-generated as part of the original @@ -910,7 +912,11 @@ var LibraryDylink = { // Once a library becomes "global" or "nodelete", it cannot be removed or unloaded. $loadDynamicLibrary__deps: ['$LDSO', '$loadWebAssemblyModule', '$isInternalSym', '$mergeLibSymbols', '$newDSO', - '$asyncLoad', '$preloadedWasm'], + '$asyncLoad', +#if FILESYSTEM || WASMFS + '$preloadedWasm', +#endif + ], $loadDynamicLibrary__docs: ` /** * @param {number=} handle @@ -981,6 +987,7 @@ var LibraryDylink = { // libName -> exports function getExports() { +#if FILESYSTEM || WASMFS // lookup preloaded cache first if (preloadedWasm[libName]) { #if DYLINK_DEBUG @@ -989,6 +996,7 @@ var LibraryDylink = { var libModule = preloadedWasm[libName]; return flags.loadAsync ? Promise.resolve(libModule) : libModule; } +#endif // module not preloaded - load lib data and create new module from it if (flags.loadAsync) { diff --git a/test/test_other.py b/test/test_other.py index 8afbd1ff090d6..4db28ef8df22d 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -4994,7 +4994,7 @@ def test_libc_files_without_syscalls(self): }''') self.run_process([EMXX, 'src.cpp']) - def test_syscall_without_filesystem(self): + def test_syscall_no_filesystem(self): # a program which includes a non-trivial syscall, but disables the filesystem. create_file('src.c', r''' #include @@ -5004,6 +5004,9 @@ def test_syscall_without_filesystem(self): }''') self.run_process([EMCC, 'src.c', '-sNO_FILESYSTEM']) + def test_dylink_no_filesystem(self): + self.run_process([EMCC, test_file('hello_world.c'), '-sMAIN_MODULE=2', '-sNO_FILESYSTEM']) + def test_dashS(self): self.run_process([EMCC, test_file('hello_world.c'), '-S']) self.assertExists('hello_world.s') From 0c5e7ee46fc7a5f360aa6a1cb57821e6ecfd89de Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 15 May 2023 16:11:27 -0700 Subject: [PATCH 0243/1523] Convert more JS code to use string template literals (#19351) Here are some of the vim commands I used to create this PR: ``` :%s/'\([^']\+\)' + \([^']\+\) + '\([^']\+\)'/`\1${\2}\3`/c :%s/'\([^']\+\)' + \([^']\+\)/`\1${\2}`/c :%s/'\([^']\+\)' + \([^')]\+\)/`\1${\2}`/c :%s/\([^']\+\)" + \([^')]\+\)/`\1${\2}`/c :%s/"\([^']\+\)" + \([^')]\+\)/`\1${\2}`/c :%s/`\([^`]\+\)` + \([^']\+\) + '\([^']\+\)'/`\1${\2}\3`/c :%s/`\([^`]\+\)` + \([^' ]\+\) + '\([^']\+\)'/`\1${\2}\3`/c :%s/`\([^`]\+\)` + \([^' ]\+\) + '\([^']\+\)'/`\1${\2}\3`/c :%s/`\([^`]\+\)` + \([^' ]\+\) + `\([^`]\+\)`/`\1${\2}\3`/c :%s/`\([^`]\+\)` + \([^' ]\+\) + `\([^`]\+\)`/`\1${\2}\3`/c :%s/`\([^`]\+\)` + \([^')]\+\)/`\1${\2}`/c ``` Followup to #19330 --- src/Fetch.js | 62 +++--- src/IDBStore.js | 2 +- src/arrayUtils.js | 2 +- src/embind/embind.js | 52 ++--- src/emrun_postjs.js | 2 +- src/headless.js | 28 +-- src/library.js | 41 ++-- src/library_async.js | 16 +- src/library_dylink.js | 72 +++---- src/library_fs.js | 14 +- src/library_fs_shared.js | 4 +- src/library_getvalue.js | 4 +- src/library_glemu.js | 64 +++--- src/library_nodefs.js | 2 +- src/library_noderawfs.js | 2 +- src/library_openal.js | 188 +++++++++--------- src/library_promise.js | 28 +-- src/proxyWorker.js | 10 +- src/shell.js | 4 +- src/utility.js | 4 +- .../metadce/test_metadce_cxx_ctors1.jssize | 2 +- .../metadce/test_metadce_cxx_ctors1.size | 2 +- .../metadce/test_metadce_cxx_ctors2.jssize | 2 +- .../metadce/test_metadce_cxx_ctors2.size | 2 +- .../metadce/test_metadce_cxx_except.jssize | 2 +- .../metadce/test_metadce_cxx_except.size | 2 +- .../test_metadce_cxx_except_wasm.jssize | 2 +- .../metadce/test_metadce_cxx_except_wasm.size | 2 +- .../metadce/test_metadce_cxx_mangle.jssize | 2 +- .../metadce/test_metadce_cxx_mangle.size | 2 +- .../metadce/test_metadce_cxx_noexcept.jssize | 2 +- .../metadce/test_metadce_cxx_noexcept.size | 2 +- .../metadce/test_metadce_hello_dylink.jssize | 2 +- .../test_metadce_minimal_pthreads.size | 2 +- test/other/test_unoptimized_code_size.js.size | 2 +- .../test_unoptimized_code_size_strict.js.size | 2 +- tools/file_packager.py | 18 +- 37 files changed, 325 insertions(+), 326 deletions(-) diff --git a/src/Fetch.js b/src/Fetch.js index 474ddb5362ee3..0fb95e324bb51 100644 --- a/src/Fetch.js +++ b/src/Fetch.js @@ -22,7 +22,7 @@ var Fetch = { openDatabase: function(dbname, dbversion, onsuccess, onerror) { try { #if FETCH_DEBUG - dbg('fetch: indexedDB.open(dbname="' + dbname + '", dbversion="' + dbversion + '");'); + dbg(`fetch: indexedDB.open(dbname="${dbname}", dbversion="${dbversion}");`); #endif var openRequest = indexedDB.open(dbname, dbversion); } catch (e) { return onerror(e); } @@ -92,7 +92,7 @@ function fetchDeleteCachedData(db, fetch, onsuccess, onerror) { request.onsuccess = (event) => { var value = event.target.result; #if FETCH_DEBUG - dbg('fetch: Deleted file ' + pathStr + ' from IndexedDB'); + dbg(`fetch: Deleted file ${pathStr} from IndexedDB`); #endif HEAPU32[fetch + {{{ C_STRUCTS.emscripten_fetch_t.data }}} >> 2] = 0; writeI53ToI64(fetch + {{{ C_STRUCTS.emscripten_fetch_t.numBytes }}}, 0); @@ -105,7 +105,7 @@ function fetchDeleteCachedData(db, fetch, onsuccess, onerror) { }; request.onerror = (error) => { #if FETCH_DEBUG - dbg('fetch: Failed to delete file ' + pathStr + ' from IndexedDB! error: ' + error); + dbg(`fetch: Failed to delete file ${pathStr} from IndexedDB! error: ${error}`); #endif HEAPU16[fetch + {{{ C_STRUCTS.emscripten_fetch_t.readyState }}} >> 1] = 4; // Mimic XHR readyState 4 === 'DONE: The operation is complete' HEAPU16[fetch + {{{ C_STRUCTS.emscripten_fetch_t.status }}} >> 1] = 404; // Mimic XHR HTTP status code 404 "Not Found" @@ -114,7 +114,7 @@ function fetchDeleteCachedData(db, fetch, onsuccess, onerror) { }; } catch(e) { #if FETCH_DEBUG - dbg('fetch: Failed to load file ' + pathStr + ' from IndexedDB! Got exception ' + e); + dbg(`fetch: Failed to load file ${pathStr} from IndexedDB! Got exception ${e}`); #endif onerror(fetch, 0, e); } @@ -143,7 +143,7 @@ function fetchLoadCachedData(db, fetch, onsuccess, onerror) { var value = event.target.result; var len = value.byteLength || value.length; #if FETCH_DEBUG - dbg('fetch: Loaded file ' + pathStr + ' from IndexedDB, length: ' + len); + dbg(`fetch: Loaded file ${pathStr} from IndexedDB, length: ${len}`); #endif // The data pointer malloc()ed here has the same lifetime as the emscripten_fetch_t structure itself has, and is // freed when emscripten_fetch_close() is called. @@ -160,7 +160,7 @@ function fetchLoadCachedData(db, fetch, onsuccess, onerror) { } else { // Succeeded to load, but the load came back with the value of undefined, treat that as an error since we never store undefined in db. #if FETCH_DEBUG - dbg('fetch: File ' + pathStr + ' not found in IndexedDB'); + dbg(`fetch: File ${pathStr} not found in IndexedDB`); #endif HEAPU16[fetch + {{{ C_STRUCTS.emscripten_fetch_t.readyState }}} >> 1] = 4; // Mimic XHR readyState 4 === 'DONE: The operation is complete' HEAPU16[fetch + {{{ C_STRUCTS.emscripten_fetch_t.status }}} >> 1] = 404; // Mimic XHR HTTP status code 404 "Not Found" @@ -170,7 +170,7 @@ function fetchLoadCachedData(db, fetch, onsuccess, onerror) { }; getRequest.onerror = (error) => { #if FETCH_DEBUG - dbg('fetch: Failed to load file ' + pathStr + ' from IndexedDB!'); + dbg(`fetch: Failed to load file ${pathStr} from IndexedDB!`); #endif HEAPU16[fetch + {{{ C_STRUCTS.emscripten_fetch_t.readyState }}} >> 1] = 4; // Mimic XHR readyState 4 === 'DONE: The operation is complete' HEAPU16[fetch + {{{ C_STRUCTS.emscripten_fetch_t.status }}} >> 1] = 404; // Mimic XHR HTTP status code 404 "Not Found" @@ -179,7 +179,7 @@ function fetchLoadCachedData(db, fetch, onsuccess, onerror) { }; } catch(e) { #if FETCH_DEBUG - dbg('fetch: Failed to load file ' + pathStr + ' from IndexedDB! Got exception ' + e); + dbg(`fetch: Failed to load file ${pathStr} from IndexedDB! Got exception ${e}`); #endif onerror(fetch, 0, e); } @@ -205,7 +205,7 @@ function fetchCacheData(/** @type {IDBDatabase} */ db, fetch, data, onsuccess, o var putRequest = packages.put(data, destinationPathStr); putRequest.onsuccess = (event) => { #if FETCH_DEBUG - dbg('fetch: Stored file "' + destinationPathStr + '" to IndexedDB cache.'); + dbg(`fetch: Stored file "${destinationPathStr}" to IndexedDB cache.`); #endif HEAPU16[fetch + {{{ C_STRUCTS.emscripten_fetch_t.readyState }}} >> 1] = 4; // Mimic XHR readyState 4 === 'DONE: The operation is complete' HEAPU16[fetch + {{{ C_STRUCTS.emscripten_fetch_t.status }}} >> 1] = 200; // Mimic XHR HTTP status code 200 "OK" @@ -214,7 +214,7 @@ function fetchCacheData(/** @type {IDBDatabase} */ db, fetch, data, onsuccess, o }; putRequest.onerror = (error) => { #if FETCH_DEBUG - dbg('fetch: Failed to store file "' + destinationPathStr + '" to IndexedDB cache!'); + dbg(`fetch: Failed to store file "${destinationPathStr}" to IndexedDB cache!`); #endif // Most likely we got an error if IndexedDB is unwilling to store any more data for this page. // TODO: Can we identify and break down different IndexedDB-provided errors and convert those @@ -226,7 +226,7 @@ function fetchCacheData(/** @type {IDBDatabase} */ db, fetch, data, onsuccess, o }; } catch(e) { #if FETCH_DEBUG - dbg('fetch: Failed to store file "' + destinationPathStr + '" to IndexedDB cache! Exception: ' + e); + dbg(`fetch: Failed to store file "${destinationPathStr}" to IndexedDB cache! Exception: ${e}`); #endif onerror(fetch, 0, e); } @@ -266,8 +266,8 @@ function fetchXHR(fetch, onsuccess, onerror, onprogress, onreadystatechange) { var xhr = new XMLHttpRequest(); xhr.withCredentials = !!{{{ makeGetValue('fetch_attr', C_STRUCTS.emscripten_fetch_attr_t.withCredentials, 'u8') }}};; #if FETCH_DEBUG - dbg('fetch: xhr.timeout: ' + xhr.timeout + ', xhr.withCredentials: ' + xhr.withCredentials); - dbg('fetch: xhr.open(requestMethod="' + requestMethod + '", url: "' + url_ +'", userName: ' + userNameStr + ', password: ' + passwordStr + ');'); + dbg(`fetch: xhr.timeout: ${xhr.timeout}, xhr.withCredentials: ${xhr.withCredentials}`); + dbg(`fetch: xhr.open(requestMethod="${requestMethod}", url: "${url}", userName: ${userNameStr}, password: ${passwordStr}`); #endif xhr.open(requestMethod, url_, !fetchAttrSynchronous, userNameStr, passwordStr); if (!fetchAttrSynchronous) xhr.timeout = timeoutMsecs; // XHR timeout field is only accessible in async XHRs, and must be set after .open() but before .send(). @@ -280,7 +280,7 @@ function fetchXHR(fetch, onsuccess, onerror, onprogress, onreadystatechange) { if (overriddenMimeType) { var overriddenMimeTypeStr = UTF8ToString(overriddenMimeType); #if FETCH_DEBUG - dbg('fetch: xhr.overrideMimeType("' + overriddenMimeTypeStr + '");'); + dbg(`fetch: xhr.overrideMimeType("${overriddenMimeTypeStr}");`); #endif xhr.overrideMimeType(overriddenMimeTypeStr); } @@ -294,7 +294,7 @@ function fetchXHR(fetch, onsuccess, onerror, onprogress, onreadystatechange) { var keyStr = UTF8ToString(key); var valueStr = UTF8ToString(value); #if FETCH_DEBUG - dbg('fetch: xhr.setRequestHeader("' + keyStr + '", "' + valueStr + '");'); + dbg(`fetch: xhr.setRequestHeader("${keyStr}", "${valueStr}");`); #endif xhr.setRequestHeader(keyStr, valueStr); } @@ -302,7 +302,7 @@ function fetchXHR(fetch, onsuccess, onerror, onprogress, onreadystatechange) { var id = Fetch.xhrs.allocate(xhr); #if FETCH_DEBUG - dbg('fetch: id=' + id); + dbg(`fetch: id=${id}`); #endif {{{ makeSetValue('fetch', C_STRUCTS.emscripten_fetch_t.id, 'id', 'u32') }}}; var data = (dataPtr && dataLength) ? HEAPU8.slice(dataPtr, dataPtr + dataLength) : null; @@ -320,7 +320,7 @@ function fetchXHR(fetch, onsuccess, onerror, onprogress, onreadystatechange) { } if (ptrLen > 0) { #if FETCH_DEBUG - dbg('fetch: allocating ' + ptrLen + ' bytes in Emscripten heap for xhr data'); + dbg(`fetch: allocating ${ptrLen} bytes in Emscripten heap for xhr data`); #endif // The data pointer malloc()ed here has the same lifetime as the emscripten_fetch_t structure itself has, and is // freed when emscripten_fetch_close() is called. @@ -350,12 +350,12 @@ function fetchXHR(fetch, onsuccess, onerror, onprogress, onreadystatechange) { saveResponseAndStatus(); if (xhr.status >= 200 && xhr.status < 300) { #if FETCH_DEBUG - dbg('fetch: xhr of URL "' + xhr.url_ + '" / responseURL "' + xhr.responseURL + '" succeeded with status ' + xhr.status); + dbg(`fetch: xhr of URL "${xhr.url_}" / responseURL "${xhr.responseURL}" succeeded with status ${xhr.status}`); #endif if (onsuccess) onsuccess(fetch, xhr, e); } else { #if FETCH_DEBUG - dbg('fetch: xhr of URL "' + xhr.url_ + '" / responseURL "' + xhr.responseURL + '" failed with status ' + xhr.status); + dbg(`fetch: xhr of URL "${xhr.url_}" / responseURL "${xhr.responseURL}" failed with status ${xhr.status}`); #endif if (onerror) onerror(fetch, xhr, e); } @@ -366,7 +366,7 @@ function fetchXHR(fetch, onsuccess, onerror, onprogress, onreadystatechange) { return; } #if FETCH_DEBUG - dbg('fetch: xhr of URL "' + xhr.url_ + '" / responseURL "' + xhr.responseURL + '" finished with error, readyState ' + xhr.readyState + ' and status ' + xhr.status); + dbg(`fetch: xhr of URL "${xhr.url_}" / responseURL "${xhr.responseURL}" finished with error, readyState ${xhr.readyState} and status ${xhr.status}`); #endif saveResponseAndStatus(); if (onerror) onerror(fetch, xhr, e); @@ -377,7 +377,7 @@ function fetchXHR(fetch, onsuccess, onerror, onprogress, onreadystatechange) { return; } #if FETCH_DEBUG - dbg('fetch: xhr of URL "' + xhr.url_ + '" / responseURL "' + xhr.responseURL + '" timed out, readyState ' + xhr.readyState + ' and status ' + xhr.status); + dbg(`fetch: xhr of URL "${xhr.url_}" / responseURL "${xhr.responseURL}" timed out, readyState ${xhr.readyState} and status ${xhr.status}`); #endif if (onerror) onerror(fetch, xhr, e); }; @@ -390,7 +390,7 @@ function fetchXHR(fetch, onsuccess, onerror, onprogress, onreadystatechange) { var ptr = 0; if (ptrLen > 0 && fetchAttrLoadToMemory && fetchAttrStreamData) { #if FETCH_DEBUG - dbg('fetch: allocating ' + ptrLen + ' bytes in Emscripten heap for xhr data'); + dbg(`fetch: allocating ${ptrLen} bytes in Emscripten heap for xhr data`); #endif #if ASSERTIONS assert(onprogress, 'When doing a streaming fetch, you should have an onprogress handler registered to receive the chunks!'); @@ -426,13 +426,13 @@ function fetchXHR(fetch, onsuccess, onerror, onprogress, onreadystatechange) { if (onreadystatechange) onreadystatechange(fetch, xhr, e); }; #if FETCH_DEBUG - dbg('fetch: xhr.send(data=' + data + ')'); + dbg(`fetch: xhr.send(data=${data})`); #endif try { xhr.send(data); } catch(e) { #if FETCH_DEBUG - dbg('fetch: xhr failed with exception: ' + e); + dbg(`fetch: xhr failed with exception: ${e}`); #endif if (onerror) onerror(fetch, xhr, e); } @@ -467,7 +467,7 @@ function startFetch(fetch, successcb, errorcb, progresscb, readystatechangecb) { var reportSuccess = (fetch, xhr, e) => { #if FETCH_DEBUG - dbg('fetch: operation success. e: ' + e); + dbg(`fetch: operation success. e: ${e}`); #endif {{{ runtimeKeepalivePop() }}} doCallback(() => { @@ -485,7 +485,7 @@ function startFetch(fetch, successcb, errorcb, progresscb, readystatechangecb) { var reportError = (fetch, xhr, e) => { #if FETCH_DEBUG - dbg('fetch: operation failed: ' + e); + dbg(`fetch: operation failed: ${e}`); #endif {{{ runtimeKeepalivePop() }}} doCallback(() => { @@ -496,7 +496,7 @@ function startFetch(fetch, successcb, errorcb, progresscb, readystatechangecb) { var reportReadyStateChange = (fetch, xhr, e) => { #if FETCH_DEBUG - dbg('fetch: ready state change. e: ' + e); + dbg(`fetch: ready state change. e: ${e}`); #endif doCallback(() => { if (onreadystatechange) {{{ makeDynCall('vp', 'onreadystatechange') }}}(fetch); @@ -506,7 +506,7 @@ function startFetch(fetch, successcb, errorcb, progresscb, readystatechangecb) { var performUncachedXhr = (fetch, xhr, e) => { #if FETCH_DEBUG - dbg('fetch: starting (uncached) XHR: ' + e); + dbg(`fetch: starting (uncached) XHR: ${e}`); #endif fetchXHR(fetch, reportSuccess, reportError, reportProgress, reportReadyStateChange); }; @@ -514,7 +514,7 @@ function startFetch(fetch, successcb, errorcb, progresscb, readystatechangecb) { #if FETCH_SUPPORT_INDEXEDDB var cacheResultAndReportSuccess = (fetch, xhr, e) => { #if FETCH_DEBUG - dbg('fetch: operation success. Caching result.. e: ' + e); + dbg(`fetch: operation success. Caching result.. e: ${e}`); #endif var storeSuccess = (fetch, xhr, e) => { #if FETCH_DEBUG @@ -541,7 +541,7 @@ function startFetch(fetch, successcb, errorcb, progresscb, readystatechangecb) { var performCachedXhr = (fetch, xhr, e) => { #if FETCH_DEBUG - dbg('fetch: starting (cached) XHR: ' + e); + dbg(`fetch: starting (cached) XHR: ${e}`); #endif fetchXHR(fetch, cacheResultAndReportSuccess, reportError, reportProgress, reportReadyStateChange); }; @@ -583,7 +583,7 @@ function fetchGetResponseHeaders(id, dst, dstSizeBytes) { //Delete the xhr JS object, allowing it to be garbage collected. function fetchFree(id) { #if FETCH_DEBUG - dbg("fetch: fetchFree id:" + id); + dbg(`fetch: fetchFree id:${id}`); #endif if (Fetch.xhrs.has(id)) { var xhr = Fetch.xhrs.get(id); diff --git a/src/IDBStore.js b/src/IDBStore.js index 60ac176ee3e79..a05ab0d79f999 100644 --- a/src/IDBStore.js +++ b/src/IDBStore.js @@ -69,7 +69,7 @@ req.onsuccess = (event) => { var result = event.target.result; if (!result) { - return callback('file ' + id + ' not found'); + return callback(`file ${id} not found`); } return callback(null, result); }; diff --git a/src/arrayUtils.js b/src/arrayUtils.js index 916469f96318f..a5f7449078f7d 100644 --- a/src/arrayUtils.js +++ b/src/arrayUtils.js @@ -19,7 +19,7 @@ function intArrayToString(array) { var chr = array[i]; if (chr > 0xFF) { #if ASSERTIONS - assert(false, 'Character code ' + chr + ' (' + String.fromCharCode(chr) + ') at offset ' + i + ' not in 0x00-0xFF.'); + assert(false, `Character code ${chr} (${String.fromCharCode(chr)}) at offset ${i} not in 0x00-0xFF.`); #endif chr &= 0xFF; } diff --git a/src/embind/embind.js b/src/embind/embind.js index 15c021ab7ce14..b390fc2a23fe2 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -80,7 +80,7 @@ var LibraryEmbind = { } types.forEach(visit); - throw new UnboundTypeError(message + ': ' + unboundTypes.map(getTypeName).join([', '])); + throw new UnboundTypeError(`${message}: ` + unboundTypes.map(getTypeName).join([', '])); }, // Creates a function overload resolution table to the given method 'methodName' in the given prototype, @@ -173,7 +173,7 @@ var LibraryEmbind = { if (this.message === undefined) { return this.name; } else { - return this.name + ': ' + this.message; + return `${this.name}: ${this.message}`; } }; @@ -225,7 +225,7 @@ var LibraryEmbind = { $registerInheritedInstance: function(class_, ptr, instance) { ptr = getBasestPointer(class_, ptr); if (registeredInstances.hasOwnProperty(ptr)) { - throwBindingError('Tried to register registered instance: ' + ptr); + throwBindingError(`Tried to register registered instance: ${ptr}`); } else { registeredInstances[ptr] = instance; } @@ -237,7 +237,7 @@ var LibraryEmbind = { if (registeredInstances.hasOwnProperty(ptr)) { delete registeredInstances[ptr]; } else { - throwBindingError('Tried to unregister unregistered instance: ' + ptr); + throwBindingError(`Tried to unregister unregistered instance: ${ptr}`); } }, @@ -384,7 +384,7 @@ var LibraryEmbind = { for (var i = 0; i < count; i++) { // TODO(https://github.com/emscripten-core/emscripten/issues/17310): // Find a way to hoist the `>> 2` or `>> 3` out of this loop. - array.push({{{ makeGetValue('firstElement', 'i * ' + POINTER_SIZE, '*') }}}); + array.push({{{ makeGetValue('firstElement', `i * ${POINTER_SIZE}`, '*') }}}); } return array; }, @@ -459,7 +459,7 @@ var LibraryEmbind = { case 4: return 2; case 8: return 3; default: - throw new TypeError('Unknown type size: ' + size); + throw new TypeError(`Unknown type size: ${size}`); } }, @@ -804,7 +804,7 @@ var LibraryEmbind = { }, 'toWireType': function(destructors, value) { if (!(typeof value == 'string')) { - throwBindingError('Cannot pass non-string to C++ string type ' + name); + throwBindingError(`Cannot pass non-string to C++ string type ${name}`); } // assumes 4-byte alignment @@ -993,7 +993,7 @@ var LibraryEmbind = { throwBindingError(`function ${humanName} called with ${arguments.length} arguments, expected ${expectedArgCount} args!`); } #if EMSCRIPTEN_TRACING - Module.emscripten_trace_enter_context('embind::' + humanName); + Module.emscripten_trace_enter_context(`embind::${humanName}`); #endif destructors.length = 0; var thisWired; @@ -1051,11 +1051,11 @@ var LibraryEmbind = { argsListWired += (i!==0?", ":"")+"arg"+i+"Wired"; } - var invokerFnBody = - "return function "+makeLegalFunctionName(humanName)+"("+argsList+") {\n" + - "if (arguments.length !== "+(argCount - 2)+") {\n" + - "throwBindingError('function "+humanName+" called with ' + arguments.length + ' arguments, expected "+(argCount - 2)+" args!');\n" + - "}\n"; + var invokerFnBody = ` + return function ${makeLegalFunctionName(humanName)}(${argsList}) { + if (arguments.length !== ${argCount - 2}) { + throwBindingError('function ${humanName} called with ${arguments.length} arguments, expected ${argCount - 2} args!'); + }`; #if EMSCRIPTEN_TRACING invokerFnBody += `Module.emscripten_trace_enter_context('embind::${humanName}');\n`; @@ -1417,7 +1417,7 @@ var LibraryEmbind = { var ptr; if (handle === null) { if (this.isReference) { - throwBindingError('null is not a valid ' + this.name); + throwBindingError(`null is not a valid ${this.name}`); } if (this.isSmartPointer) { @@ -1495,7 +1495,7 @@ var LibraryEmbind = { $constNoSmartPtrRawPointerToWireType: function(destructors, handle) { if (handle === null) { if (this.isReference) { - throwBindingError('null is not a valid ' + this.name); + throwBindingError(`null is not a valid ${this.name}`); } return 0; } @@ -1504,7 +1504,7 @@ var LibraryEmbind = { throwBindingError(`Cannot pass "${embindRepr(handle)}" as a ${this.name}`); } if (!handle.$$.ptr) { - throwBindingError('Cannot pass deleted object as a pointer of type ' + this.name); + throwBindingError(`Cannot pass deleted object as a pointer of type ${this.name}`); } var handleClass = handle.$$.ptrType.registeredClass; var ptr = upcastPointer(handle.$$.ptr, handleClass, this.registeredClass); @@ -1517,7 +1517,7 @@ var LibraryEmbind = { $nonConstNoSmartPtrRawPointerToWireType: function(destructors, handle) { if (handle === null) { if (this.isReference) { - throwBindingError('null is not a valid ' + this.name); + throwBindingError(`null is not a valid ${this.name}`); } return 0; } @@ -2106,7 +2106,7 @@ var LibraryEmbind = { whenDependentTypesAreResolved([], [rawClassType], function(classType) { classType = classType[0]; - var humanName = 'constructor ' + classType.name; + var humanName = `constructor ${classType.name}`; if (undefined === classType.registeredClass.constructor_body) { classType.registeredClass.constructor_body = []; @@ -2158,10 +2158,10 @@ var LibraryEmbind = { $validateThis__deps: ['$throwBindingError', '$upcastPointer'], $validateThis: function(this_, classType, humanName) { if (!(this_ instanceof Object)) { - throwBindingError(humanName + ' with invalid "this": ' + this_); + throwBindingError(`${humanName} with invalid "this": ${this_}`); } if (!(this_ instanceof classType.registeredClass.constructor)) { - throwBindingError(humanName + ' incompatible with "this" of type ' + this_.constructor.name); + throwBindingError(`${humanName} incompatible with "this" of type ${this_.constructor.name}`); } if (!this_.$$.ptr) { throwBindingError(`cannot call emscripten binding method ${humanName} on deleted object`); @@ -2192,7 +2192,7 @@ var LibraryEmbind = { whenDependentTypesAreResolved([], [rawClassType], function(classType) { classType = classType[0]; - var humanName = classType.name + '.' + methodName; + var humanName = `${classType.name}.${methodName}`; if (methodName.startsWith("@@")) { methodName = Symbol[methodName.substring(2)]; @@ -2259,7 +2259,7 @@ var LibraryEmbind = { whenDependentTypesAreResolved([], [classType], function(classType) { classType = classType[0]; - var humanName = classType.name + '.' + fieldName; + var humanName = `${classType.name}.${fieldName}`; var desc = { get: function() { throwUnboundTypeError(`Cannot access ${humanName} due to unbound types`, [getterReturnType, setterArgumentType]); @@ -2328,7 +2328,7 @@ var LibraryEmbind = { rawInvoker = embind__requireFunction(invokerSignature, rawInvoker); whenDependentTypesAreResolved([], [rawClassType], function(classType) { classType = classType[0]; - var humanName = classType.name + '.' + methodName; + var humanName = `${classType.name}.${methodName}`; function unboundTypesHandler() { throwUnboundTypeError(`Cannot call ${humanName} due to unbound types`, rawArgTypes); @@ -2395,7 +2395,7 @@ var LibraryEmbind = { whenDependentTypesAreResolved([], [rawClassType], function(classType) { classType = classType[0]; - var humanName = classType.name + '.' + fieldName; + var humanName = `${classType.name}.${fieldName}`; var desc = { get: function() { throwUnboundTypeError(`Cannot access ${humanName} due to unbound types`, [rawFieldType]); @@ -2519,7 +2519,7 @@ var LibraryEmbind = { name = name.replace(/[^a-zA-Z0-9_]/g, '$'); var f = name.charCodeAt(0); if (f >= char_0 && f <= char_9) { - return '_' + name; + return `_${name}`; } return name; }, @@ -2596,7 +2596,7 @@ var LibraryEmbind = { var Value = Object.create(enumType.constructor.prototype, { value: {value: enumValue}, - constructor: {value: createNamedFunction(enumType.name + '_' + name, function() {})}, + constructor: {value: createNamedFunction(`${enumType.name}_${name}`, function() {})}, }); Enum.values[enumValue] = Value; Enum[name] = Value; diff --git a/src/emrun_postjs.js b/src/emrun_postjs.js index f7edf0b324b8d..5aecc5e932a26 100644 --- a/src/emrun_postjs.js +++ b/src/emrun_postjs.js @@ -84,7 +84,7 @@ if (typeof window == "object" && (typeof ENVIRONMENT_IS_PTHREAD == 'undefined' | // EM_ASM({emrun_file_dump("file.dat", HEAPU8.subarray($0, $0 + $1));}, my_data_pointer, my_data_pointer_byte_length); var emrun_file_dump = (filename, data) => { var http = new XMLHttpRequest(); - out('Dumping out file "' + filename + '" with ' + data.length + ' bytes of data.'); + out(`Dumping out file "${filename}" with ${data.length} bytes of data.`); http.open("POST", "stdio.html?file=" + filename, true); http.send(data); // XXX this does not work in workers, for some odd reason (issue #2681) }; diff --git a/src/headless.js b/src/headless.js index 130e948c0ceb1..4e4ba100f906e 100644 --- a/src/headless.js +++ b/src/headless.js @@ -33,12 +33,12 @@ var window = { uid: 0, requestAnimationFrame: function(func) { func.uid = window.uid++; - headlessPrint('adding raf ' + func.uid); + headlessPrint(`adding raf ${func.uid}`); window.rafs.push(func); }, setTimeout: function(func, ms) { func.uid = window.uid++; - headlessPrint('adding timeout ' + func.uid); + headlessPrint(`adding timeout ${func.uid}`); window.timeouts.push({ func: func, when: window.fakeNow + (ms || 0) @@ -50,7 +50,7 @@ var window = { var iter = 0; while (!this.stopped) { var start = Date.realNow(); - headlessPrint('event loop: ' + (iter++)); + headlessPrint(`event loop: ${(iter++)}`); if (window.rafs.length == 0 && window.timeouts.length == 0) { if (window.onIdle) { window.onIdle(); @@ -63,7 +63,7 @@ var window = { window.rafs = []; for (var i = 0; i < currRafs.length; i++) { var raf = currRafs[i]; - headlessPrint('calling raf: ' + raf.uid);// + ': ' + raf.toString().substring(0, 50)); + headlessPrint(`calling raf: ${raf.uid}`);// + ': ' + raf.toString().substring(0, 50)); raf(); } // timeouts @@ -72,12 +72,12 @@ var window = { window.timeouts = []; while (timeouts.length && timeouts[timeouts.length-1].when <= now) { var timeout = timeouts.pop(); - headlessPrint('calling timeout: ' + timeout.func.uid);// + ': ' + timeout.func.toString().substring(0, 50)); + headlessPrint(`calling timeout: ${timeout.func.uid}`);// + ': ' + timeout.func.toString().substring(0, 50)); timeout.func(); } // increment 'time' window.fakeNow += 16.666; - headlessPrint('main event loop iteration took ' + (Date.realNow() - start) + ' ms'); + headlessPrint(`main event loop iteration took ${Date.realNow() - start} ms`); } }, eventListeners: {}, @@ -137,7 +137,7 @@ var document = { case 'script': { var ret = {}; window.setTimeout(() => { - headlessPrint('loading script: ' + ret.src); + headlessPrint(`loading script: ${ret.src}`); load(ret.src); headlessPrint(' script loaded.'); if (ret.onload) { @@ -156,7 +156,7 @@ var document = { }, }; } - default: throw 'createElement ' + what + new Error().stack; + default: throw `createElement ${what}${new Error().stack}`; } }, elements: {}, @@ -249,7 +249,7 @@ var Worker = (workerPath) => { var workerCode = read(workerPath); workerCode = workerCode.replace(/Module/g, 'zzModuleyy' + (Worker.id++)). // prevent collision with the global Module object. Note that this becomes global, so we need unique ids replace(/\nonmessage = /, '\nvar onmessage = '); // workers commonly do "onmessage = ", we need to varify that to sandbox - headlessPrint('loading worker ' + workerPath + ' : ' + workerCode.substring(0, 50)); + headlessPrint(`loading worker ${workerPath} : ${workerCode.substring(0, 50)}`); eval(workerCode); // will implement onmessage() function duplicateJSON(json) { @@ -264,18 +264,18 @@ var Worker = (workerPath) => { this.terminate = () => {}; this.postMessage = (msg) => { msg.messageId = Worker.messageId++; - headlessPrint('main thread sending message ' + msg.messageId + ' to worker ' + workerPath); + headlessPrint(`main thread sending message ${msg.messageId} to worker ${workerPath}`); window.setTimeout(() => { - headlessPrint('worker ' + workerPath + ' receiving message ' + msg.messageId); + headlessPrint(`worker ${workerPath} receiving message ${msg.messageId}`); onmessage({ data: duplicateJSON(msg) }); }); }; var thisWorker = this; var postMessage = (msg) => { msg.messageId = Worker.messageId++; - headlessPrint('worker ' + workerPath + ' sending message ' + msg.messageId); + headlessPrint(`worker ${workerPath} sending message ${msg.messageId}`); window.setTimeout(() => { - headlessPrint('main thread receiving message ' + msg.messageId + ' from ' + workerPath); + headlessPrint(`main thread receiving message ${msg.messageId} from ${workerPath}`); thisWorker.onmessage({ data: duplicateJSON(msg) }); }); }; @@ -288,7 +288,7 @@ var screen = { // XXX these values may need to be adjusted availWidth: 2100, availHeight: 1283, }; -if (typeof console == "undefined") { +if (typeof console == 'undefined') { console = { log: function(x) { print(x); diff --git a/src/library.js b/src/library.js index 75fc483ff08b3..75c97e6ebfac1 100644 --- a/src/library.js +++ b/src/library.js @@ -408,9 +408,9 @@ mergeInto(LibraryManager.library, { // AppleWebKit/605.1.15 Safari/604.1 Version/13.0.4 iPhone OS 13_3 on iPhone 6s with iOS 13.3 // AppleWebKit/605.1.15 Version/13.0.3 Intel Mac OS X 10_15_1 on Safari 13.0.3 (15608.3.10.1.4) on macOS Catalina 10.15.1 // Hence the support status of .copyWithin() for Safari version range [10.0.0, 10.1.0] is unknown. - emscripten_memcpy_big: '= Uint8Array.prototype.copyWithin\n' + - ' ? (dest, src, num) => HEAPU8.copyWithin(dest, src, src + num)\n' + - ' : (dest, src, num) => HEAPU8.set(HEAPU8.subarray(src, src+num), dest)\n', + emscripten_memcpy_big: `= Uint8Array.prototype.copyWithin + ? (dest, src, num) => HEAPU8.copyWithin(dest, src, src + num) + : (dest, src, num) => HEAPU8.set(HEAPU8.subarray(src, src+num), dest)`, #else emscripten_memcpy_big: function(dest, src, num) { HEAPU8.copyWithin(dest, src, src + num); @@ -2284,7 +2284,7 @@ mergeInto(LibraryManager.library, { #endif delete timers[which]; #if RUNTIME_DEBUG - dbg('itimer fired: ' + which); + dbg(`itimer fired: ${which}`); #endif callUserCallback(() => __emscripten_timeout(which, _emscripten_get_now())); }, timeout_ms); @@ -2451,7 +2451,7 @@ mergeInto(LibraryManager.library, { if (typeof a == 'number' || typeof a == 'string') { str += a; } else { - str += '(' + typeof a + ')'; + str += `(${typeof a}})`; } } str += ')'; @@ -2991,7 +2991,7 @@ mergeInto(LibraryManager.library, { $runEmAsmFunction: function(code, sigPtr, argbuf) { var args = readEmAsmArgs(sigPtr, argbuf); #if ASSERTIONS - if (!ASM_CONSTS.hasOwnProperty(code)) abort('No EM_ASM constant found at address ' + code); + if (!ASM_CONSTS.hasOwnProperty(code)) abort(`No EM_ASM constant found at address ${code}`); #endif return ASM_CONSTS[code].apply(null, args); }, @@ -3034,7 +3034,7 @@ mergeInto(LibraryManager.library, { } #endif #if ASSERTIONS - if (!ASM_CONSTS.hasOwnProperty(code)) abort('No EM_ASM constant found at address ' + code); + if (!ASM_CONSTS.hasOwnProperty(code)) abort(`No EM_ASM constant found at address ${code}`); #endif return ASM_CONSTS[code].apply(null, args); }, @@ -3249,7 +3249,7 @@ mergeInto(LibraryManager.library, { } #endif #if ASSERTIONS - assert(getWasmTableEntry(ptr), 'missing table entry in dynCall: ' + ptr); + assert(getWasmTableEntry(ptr), `missing table entry in dynCall: ${ptr}`); #endif #if MEMORY64 // With MEMORY64 we have an additional step to convert `p` arguments to @@ -3426,7 +3426,7 @@ mergeInto(LibraryManager.library, { // that wish to return to JS event loop. if (e instanceof ExitStatus || e == 'unwind') { #if RUNTIME_DEBUG - dbg('handleException: unwinding: EXITSTATUS=' + EXITSTATUS); + dbg(`handleException: unwinding: EXITSTATUS=${EXITSTATUS}`); #endif return EXITSTATUS; } @@ -3434,7 +3434,7 @@ mergeInto(LibraryManager.library, { checkStackCookie(); if (e instanceof WebAssembly.RuntimeError) { if (_emscripten_stack_get_current() <= 0) { - err('Stack overflow detected. You can try increasing -sSTACK_SIZE (currently set to ' + {{{ STACK_SIZE }}} + ')'); + err('Stack overflow detected. You can try increasing -sSTACK_SIZE (currently set to {{{ STACK_SIZE }}})'); } } #endif @@ -3450,7 +3450,7 @@ mergeInto(LibraryManager.library, { $runtimeKeepalivePush: function() { runtimeKeepaliveCounter += 1; #if RUNTIME_DEBUG - dbg('runtimeKeepalivePush -> counter=' + runtimeKeepaliveCounter); + dbg(`runtimeKeepalivePush -> counter=${runtimeKeepaliveCounter}`); #endif }, @@ -3461,7 +3461,7 @@ mergeInto(LibraryManager.library, { #endif runtimeKeepaliveCounter -= 1; #if RUNTIME_DEBUG - dbg('runtimeKeepalivePop -> counter=' + runtimeKeepaliveCounter); + dbg(`runtimeKeepalivePop -> counter=${runtimeKeepaliveCounter}`); #endif }, @@ -3512,11 +3512,11 @@ mergeInto(LibraryManager.library, { } #endif #if RUNTIME_DEBUG - dbg('maybeExit: user callback done: runtimeKeepaliveCounter=' + runtimeKeepaliveCounter); + dbg(`maybeExit: user callback done: runtimeKeepaliveCounter=${runtimeKeepaliveCounter}`); #endif if (!keepRuntimeAlive()) { #if RUNTIME_DEBUG - dbg('maybeExit: calling exit() implicitly after user callback completed: ' + EXITSTATUS); + dbg(`maybeExit: calling exit() implicitly after user callback completed: ${EXITSTATUS}`); #endif try { #if PTHREADS @@ -3557,7 +3557,7 @@ mergeInto(LibraryManager.library, { $asyncLoad__docs: '/** @param {boolean=} noRunDep */', $asyncLoad: function(url, onload, onerror, noRunDep) { - var dep = !noRunDep ? getUniqueRunDependency('al ' + url) : ''; + var dep = !noRunDep ? getUniqueRunDependency(`al ${url}`) : ''; readAsync(url, (arrayBuffer) => { assert(arrayBuffer, `Loading data file "${url}" failed (no arrayBuffer).`); onload(new Uint8Array(arrayBuffer)); @@ -3645,7 +3645,7 @@ mergeInto(LibraryManager.library, { ptr += {{{ POINTER_SIZE }}}; var name = UTF8ToString(name_addr) #if RUNTIME_DEBUG - dbg('preloading files: ' + name); + dbg(`preloading files: ${name}`); #endif FS.createPath('/', PATH.dirname(name), true, true); // canOwn this data in the filesystem, it is a slice of wasm memory that will never change @@ -3663,7 +3663,7 @@ mergeInto(LibraryManager.library, { this.freelist = []; this.get = function(id) { #if ASSERTIONS - assert(this.allocated[id] !== undefined, 'invalid handle: ' + id); + assert(this.allocated[id] !== undefined, `invalid handle: ${id}`); #endif return this.allocated[id]; }; @@ -3700,12 +3700,11 @@ mergeInto(LibraryManager.library, { function autoAddDeps(object, name) { for (var item in object) { - if (item.substr(-6) != '__deps') { + if (!item.endsWith('__deps')) { if (!object[item + '__deps']) { - object[item + '__deps'] = [name]; - } else { - object[item + '__deps'].push(name); // add to existing list + object[item + '__deps'] = []; } + object[item + '__deps'].push(name); } } } diff --git a/src/library_async.js b/src/library_async.js index 541cc04d06ed5..67cde1d4d69bb 100644 --- a/src/library_async.js +++ b/src/library_async.js @@ -51,7 +51,7 @@ mergeInto(LibraryManager.library, { // Wrap async imports with a suspending WebAssembly function. if (isAsyncifyImport) { #if ASSERTIONS - assert(sig, 'Missing __sig for ' + x); + assert(sig, `Missing __sig for ${x}`); #endif var type = sigToWasmTypes(sig); #if ASYNCIFY_DEBUG @@ -89,7 +89,7 @@ mergeInto(LibraryManager.library, { !isAsyncifyImport && !changedToDisabled && !ignoredInvoke) { - throw new Error('import ' + x + ' was not in ASYNCIFY_IMPORTS, but changed the state'); + throw new Error(`import ${x} was not in ASYNCIFY_IMPORTS, but changed the state`); } } }; @@ -126,7 +126,7 @@ mergeInto(LibraryManager.library, { #endif ret[x] = function() { #if ASYNCIFY_DEBUG >= 2 - dbg('ASYNCIFY: ' + ' '.repeat(Asyncify.exportCallStack.length) + ' try ' + x); + dbg(`ASYNCIFY: ${' '.repeat(Asyncify.exportCallStack.length} try ${x}`); #endif #if ASYNCIFY == 1 Asyncify.exportCallStack.push(x); @@ -139,7 +139,7 @@ mergeInto(LibraryManager.library, { var y = Asyncify.exportCallStack.pop(); assert(y === x); #if ASYNCIFY_DEBUG >= 2 - dbg('ASYNCIFY: ' + ' '.repeat(Asyncify.exportCallStack.length) + ' finally ' + x); + dbg(`ASYNCIFY: ${' '.repeat(Asyncify.exportCallStack.length)} finally ${x}`); #endif Asyncify.maybeStopUnwind(); } @@ -299,7 +299,7 @@ mergeInto(LibraryManager.library, { #endif if (ABORT) return; #if ASYNCIFY_DEBUG - dbg('ASYNCIFY: handleSleep ' + Asyncify.state); + dbg(`ASYNCIFY: handleSleep ${Asyncify.state}`); #endif if (Asyncify.state === Asyncify.State.Normal) { // Prepare to sleep. Call startAsync, and see what happens: @@ -328,7 +328,7 @@ mergeInto(LibraryManager.library, { assert(!Asyncify.exportCallStack.length, 'Waking up (starting to rewind) must be done from JS, without compiled code on the stack.'); #endif #if ASYNCIFY_DEBUG - dbg('ASYNCIFY: start rewind ' + Asyncify.currData); + dbg(`ASYNCIFY: start rewind ${Asyncify.currData}`); #endif Asyncify.state = Asyncify.State.Rewinding; runAndAbortIfError(() => _asyncify_start_rewind(Asyncify.currData)); @@ -378,7 +378,7 @@ mergeInto(LibraryManager.library, { // TODO: reuse, don't alloc/free every sleep Asyncify.currData = Asyncify.allocateData(); #if ASYNCIFY_DEBUG - dbg('ASYNCIFY: start unwind ' + Asyncify.currData); + dbg(`ASYNCIFY: start unwind ${Asyncify.currData}`); #endif if (typeof Browser != 'undefined' && Browser.mainLoop.func) { Browser.mainLoop.pause(); @@ -397,7 +397,7 @@ mergeInto(LibraryManager.library, { // Call all sleep callbacks now that the sleep-resume is all done. Asyncify.sleepCallbacks.forEach((func) => callUserCallback(func)); } else { - abort('invalid state: ' + Asyncify.state); + abort(`invalid state: ${Asyncify.state}`); } return Asyncify.handleSleepReturnValue; }, diff --git a/src/library_dylink.js b/src/library_dylink.js index 1a74a5fc39a57..97cb60d4ac92e 100644 --- a/src/library_dylink.js +++ b/src/library_dylink.js @@ -31,7 +31,7 @@ var LibraryDylink = { onload(byteArray); }, (error) => { - err('failed to instantiate wasm: ' + name + ': ' + error); + err(`failed to instantiate wasm: ${name}: ${error}`); onerror(); }); } @@ -172,25 +172,25 @@ var LibraryDylink = { } if (replace || GOT[symName].value == 0) { #if DYLINK_DEBUG - dbg("updateGOT: before: " + symName + ' : ' + GOT[symName].value); + dbg(`updateGOT: before: ${symName} : ${GOT[symName].value}`); #endif if (typeof value == 'function') { GOT[symName].value = {{{ to64('addFunction(value)') }}}; #if DYLINK_DEBUG - dbg("updateGOT: FUNC: " + symName + ' : ' + GOT[symName].value); + dbg(`updateGOT: FUNC: ${symName} : ${GOT[symName].value}`); #endif } else if (typeof value == {{{ POINTER_JS_TYPE }}}) { GOT[symName].value = value; } else { - err("unhandled export type for `" + symName + "`: " + (typeof value)); + err(`unhandled export type for '${symName}': ${typeof value}`); } #if DYLINK_DEBUG - dbg("updateGOT: after: " + symName + ' : ' + GOT[symName].value + ' (' + value + ')'); + dbg(`updateGOT: after: ${symName} : ${GOT[symName].value} (${value})`); #endif } #if DYLINK_DEBUG else if (GOT[symName].value != value) { - dbg("updateGOT: EXISTING SYMBOL: " + symName + ' : ' + GOT[symName].value + ' (' + value + ')'); + dbg(`udateGOT: EXISTING SYMBOL: ${symName} : ${GOT[symName].value} (${value})`); } #endif } @@ -241,21 +241,21 @@ var LibraryDylink = { if (!value && !GOT[symName].required) { // Ignore undefined symbols that are imported as weak. #if DYLINK_DEBUG - dbg('ignoring undefined weak symbol: ' + symName); + dbg(`ignoring undefined weak symbol: ${symName}`); #endif continue; } #if ASSERTIONS - assert(value, 'undefined symbol `' + symName + '`. 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'); + assert(value, `undefined symbol '${symName}'. 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 #if DYLINK_DEBUG - dbg('assigning dynamic symbol from main module: ' + symName + ' -> ' + prettyPrint(value)); + dbg(`assigning dynamic symbol from main module: ${symName} -> ${prettyPrint(value)}`); #endif if (typeof value == 'function') { /** @suppress {checkTypes} */ GOT[symName].value = {{{ to64('addFunction(value, value.sig)') }}}; #if DYLINK_DEBUG - dbg('assigning table entry for : ' + symName + ' -> ' + GOT[symName].value); + dbg(`assigning table entry for : ${symName} -> ${GOT[symName].value}`); #endif } else if (typeof value == 'number') { GOT[symName].value = {{{ to64('value') }}}; @@ -264,7 +264,7 @@ var LibraryDylink = { GOT[symName].value = value; #endif } else { - throw new Error('bad export type for `' + symName + '`: ' + (typeof value)); + throw new Error(`bad export type for '${symName}': ${typeof value}`); } } } @@ -329,7 +329,7 @@ var LibraryDylink = { $dlSetError__deps: ['__dl_seterr', '$stringToUTF8OnStack', '$withStackSave'], $dlSetError: function(msg) { #if DYLINK_DEBUG - dbg('dlSetError: ' + msg); + dbg(`dlSetError: ${msg}`); #endif withStackSave(() => { var cmsg = stringToUTF8OnStack(msg); @@ -517,7 +517,7 @@ var LibraryDylink = { } } else { #if ASSERTIONS - err('unknown dylink.0 subsection: ' + subsectionType) + err(`unknown dylink.0 subsection: ${subsectionType}`) #endif // unknown subsection offset += subsectionSize; @@ -527,12 +527,12 @@ var LibraryDylink = { #if ASSERTIONS var tableAlign = Math.pow(2, customSection.tableAlign); - assert(tableAlign === 1, 'invalid tableAlign ' + tableAlign); + assert(tableAlign === 1, `invalid tableAlign ${tableAlign}`); assert(offset == end); #endif #if DYLINK_DEBUG - dbg('dylink needed:' + customSection.neededDynlibs); + dbg(`dylink needed:${customSection.neededDynlibs}`); #endif return customSection; @@ -596,7 +596,7 @@ var LibraryDylink = { #if DYLINK_DEBUG $dumpTable: function() { for (var i = 0; i < wasmTable.length; i++) - dbg('table: ' + i + ' : ' + wasmTable.get(i)); + dbg(`table: ${i} : ${wasmTable.get(i)}`); }, #endif @@ -684,7 +684,7 @@ var LibraryDylink = { resolved = moduleExports[sym]; } #if ASSERTIONS - assert(resolved, 'undefined symbol `' + 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'); + assert(resolved, `undefined symbol '${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; } @@ -778,9 +778,9 @@ var LibraryDylink = { } } args = args.join(','); - var func = '(' + args +' ) => { ' + body + '};' + var func = `(${args}) => { ${body} };`; #if DYLINK_DEBUG - dbg('adding new EM_ASM constant at: ' + ptrToString(start)); + dbg(`adding new EM_ASM constant at: ${ptrToString(start)}`); #endif {{{ makeEval('ASM_CONSTS[start] = eval(func)') }}}; } @@ -869,7 +869,7 @@ var LibraryDylink = { $setDylinkStackLimits: function(stackTop, stackMax) { for (var name in LDSO.loadedLibsByName) { #if DYLINK_DEBUG - dbg('setDylinkStackLimits[' + name + ']'); + dbg(`setDylinkStackLimits[${name}]`); #endif var lib = LDSO.loadedLibsByName[name]; if (lib.exports['__set_stack_limits']) { @@ -924,8 +924,8 @@ var LibraryDylink = { */`, $loadDynamicLibrary: function(libName, flags = {global: true, nodelete: true}, localScope, handle) { #if DYLINK_DEBUG - dbg('loadDynamicLibrary: ' + libName + ' handle:' + handle); - dbg('existing: ' + Object.keys(LDSO.loadedLibsByName)); + dbg(`loadDynamicLibrary: ${libName} handle: ${handle}`); + dbg(`existing: ${Object.keys(LDSO.loadedLibsByName)}`); #endif // when loadDynamicLibrary did not have flags, libraries were loaded // globally & permanently @@ -980,7 +980,7 @@ var LibraryDylink = { // load the binary synchronously if (!readBinary) { - throw new Error(libFile + ': file not found, and synchronous loading of external files is not available'); + throw new Error(`${libFile}: file not found, and synchronous loading of external files is not available`); } return readBinary(libFile); } @@ -991,7 +991,7 @@ var LibraryDylink = { // lookup preloaded cache first if (preloadedWasm[libName]) { #if DYLINK_DEBUG - dbg('using preloaded module for: ' + libName); + dbg(`using preloaded module for: ${libName}`); #endif var libModule = preloadedWasm[libName]; return flags.loadAsync ? Promise.resolve(libModule) : libModule; @@ -1071,7 +1071,7 @@ var LibraryDylink = { var filename = UTF8ToString(handle + {{{ C_STRUCTS.dso.name }}}); var flags = {{{ makeGetValue('handle', C_STRUCTS.dso.flags, 'i32') }}}; #if DYLINK_DEBUG - dbg('dlopenInternal: ' + filename); + dbg(`dlopenInternal: ${filename}`); #endif filename = PATH.normalize(filename); var searchpaths = []; @@ -1094,9 +1094,9 @@ var LibraryDylink = { return loadDynamicLibrary(filename, combinedFlags, localScope, handle) } catch (e) { #if ASSERTIONS - err('Error in loading dynamic library ' + filename + ": " + e); + err(`Error in loading dynamic library ${filename}: ${e}`); #endif - dlSetError('Could not load dynamic lib: ' + filename + '\n' + e); + dlSetError(`Could not load dynamic lib: ${filename}\n${e}`); return 0; } }, @@ -1124,7 +1124,7 @@ var LibraryDylink = { /** @param {Object=} e */ function errorCallback(e) { var filename = UTF8ToString(handle + {{{ C_STRUCTS.dso.name }}}); - dlSetError('Could not load dynamic libX: ' + filename + '\n' + e); + dlSetError(`'Could not load dynamic lib: ${filename}\n${e}`); {{{ runtimeKeepalivePop() }}} callUserCallback(() => {{{ makeDynCall('vpp', 'onerror') }}}(handle, user_data)); } @@ -1153,7 +1153,7 @@ var LibraryDylink = { var sym = symDict[symName]; var result = addFunction(sym, sym.sig); #if DYLINK_DEBUG - dbg('_dlsym_catchup: result=' + result); + dbg(`_dlsym_catchup: result=${result}`); #endif return result; }, @@ -1165,17 +1165,17 @@ var LibraryDylink = { // http://pubs.opengroup.org/onlinepubs/009695399/functions/dlsym.html symbol = UTF8ToString(symbol); #if DYLINK_DEBUG - dbg('dlsym_js: ' + symbol); + dbg(`dlsym_js: ${symbol}`); #endif var result; var newSymIndex; var lib = LDSO.loadedLibsByHandle[handle]; #if ASSERTIONS - assert(lib, 'Tried to dlsym() from an unopened handle: ' + handle); + assert(lib, `Tried to dlsym() from an unopened handle: ${handle}`); #endif if (!lib.exports.hasOwnProperty(symbol) || lib.exports[symbol].stub) { - dlSetError('Tried to lookup unknown symbol "' + symbol + '" in dynamic lib: ' + lib.name) + dlSetError(`Tried to lookup unknown symbol "${symbol}" in dynamic lib: ${lib.name}`) return 0; } newSymIndex = Object.keys(lib.exports).indexOf(symbol); @@ -1191,7 +1191,7 @@ var LibraryDylink = { if (typeof result == 'function') { #if DYLINK_DEBUG - dbg('dlsym_js: ' + symbol + ' getting table slot for: ' + result); + dbg(`dlsym_js: ${symbol} getting table slot for: ${result}`); #endif #if ASYNCIFY @@ -1203,7 +1203,7 @@ var LibraryDylink = { var addr = getFunctionAddress(result); if (addr) { #if DYLINK_DEBUG - dbg('symbol already exists in table: ' + symbol); + dbg(`symbol already exists in table: ${symbol}`); #endif result = addr; } else { @@ -1213,13 +1213,13 @@ var LibraryDylink = { // `__sig` specified in library JS file. result = addFunction(result, result.sig); #if DYLINK_DEBUG - dbg('adding symbol to table: ' + symbol); + dbg(`adding symbol to table: ${symbol}`); #endif {{{ makeSetValue('symbolIndex', 0, 'newSymIndex', '*') }}}; } } #if DYLINK_DEBUG - dbg('dlsym_js: ' + symbol + ' -> ' + result); + dbg(`dlsym_js: ${symbol} -> ${result}`); #endif return result; }, diff --git a/src/library_fs.js b/src/library_fs.js index bd432c991f25c..4726e020994eb 100644 --- a/src/library_fs.js +++ b/src/library_fs.js @@ -186,9 +186,9 @@ FS.staticInit();` + if (FS.isRoot(node)) { var mount = node.mount.mountpoint; if (!path) return mount; - return mount[mount.length-1] !== '/' ? mount + '/' + path : mount + path; + return mount[mount.length-1] !== '/' ? `${mount}/${path}` : mount + path; } - path = path ? node.name + '/' + path : node.name; + path = path ? `${node.name}/${path}` : node.name; node = node.parent; } }, @@ -492,7 +492,7 @@ FS.staticInit();` + FS.syncFSRequests++; if (FS.syncFSRequests > 1) { - err('warning: ' + FS.syncFSRequests + ' FS.syncfs operations in flight at once, probably just doing extra work'); + err(`warning: ${FS.syncFSRequests} FS.syncfs operations in flight at once, probably just doing extra work`); } var mounts = FS.getMounts(FS.root.mount); @@ -1261,7 +1261,7 @@ FS.staticInit();` + opts.flags = opts.flags || {{{ cDefs.O_RDONLY }}}; opts.encoding = opts.encoding || 'binary'; if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') { - throw new Error('Invalid encoding type "' + opts.encoding + '"'); + throw new Error(`Invalid encoding type "${opts.encoding}"`); } var ret; var stream = FS.open(path, opts.flags); @@ -1404,9 +1404,9 @@ FS.staticInit();` + var stdout = FS.open('/dev/stdout', {{{ cDefs.O_WRONLY }}}); var stderr = FS.open('/dev/stderr', {{{ cDefs.O_WRONLY }}}); #if ASSERTIONS - assert(stdin.fd === 0, 'invalid handle for stdin (' + stdin.fd + ')'); - assert(stdout.fd === 1, 'invalid handle for stdout (' + stdout.fd + ')'); - assert(stderr.fd === 2, 'invalid handle for stderr (' + stderr.fd + ')'); + assert(stdin.fd === 0, `invalid handle for stdin (${stdin.fd})`); + assert(stdout.fd === 1, `invalid handle for stdout (${stdout.fd})`); + assert(stderr.fd === 2, `invalid handle for stderr (${stderr.fd})`); #endif }, ensureErrnoError: () => { diff --git a/src/library_fs_shared.js b/src/library_fs_shared.js index e595fb3fe2c7a..bb97c52ef7270 100644 --- a/src/library_fs_shared.js +++ b/src/library_fs_shared.js @@ -56,7 +56,7 @@ mergeInto(LibraryManager.library, { // of parent and name being that we just join them anyways var fullname = name ? PATH_FS.resolve(PATH.join2(parent, name)) : parent; #endif - var dep = getUniqueRunDependency('cp ' + fullname); // might have several active requests for the same fullname + var dep = getUniqueRunDependency(`cp ${fullname}`); // might have several active requests for the same fullname function processData(byteArray) { function finish(byteArray) { if (preFinish) preFinish(); @@ -95,7 +95,7 @@ mergeInto(LibraryManager.library, { }; var flags = flagModes[str]; if (typeof flags == 'undefined') { - throw new Error('Unknown file open mode: ' + str); + throw new Error(`Unknown file open mode: ${str}`); } return flags; }, diff --git a/src/library_getvalue.js b/src/library_getvalue.js index d09010d760306..da070d1f3bbb2 100644 --- a/src/library_getvalue.js +++ b/src/library_getvalue.js @@ -17,7 +17,7 @@ function setValueImpl(ptr, value, type = 'i8') { case 'float': {{{ makeSetValue('ptr', '0', 'value', 'float') }}}; break; case 'double': {{{ makeSetValue('ptr', '0', 'value', 'double') }}}; break; case '*': {{{ makeSetValue('ptr', '0', 'value', '*') }}}; break; - default: abort('invalid type for setValue: ' + type); + default: abort(`invalid type for setValue: ${type}`); } } @@ -32,7 +32,7 @@ function getValueImpl(ptr, type = 'i8') { case 'float': return {{{ makeGetValue('ptr', '0', 'float') }}}; case 'double': return {{{ makeGetValue('ptr', '0', 'double') }}}; case '*': return {{{ makeGetValue('ptr', '0', '*') }}}; - default: abort('invalid type for getValue: ' + type); + default: abort(`invalid type for getValue: ${type}`); } } diff --git a/src/library_glemu.js b/src/library_glemu.js index 4b10f3bc6252e..f2ac9b3b2b953 100644 --- a/src/library_glemu.js +++ b/src/library_glemu.js @@ -181,10 +181,10 @@ var LibraryGLEmulation = { #if RELOCATABLE {{{ (updateExport = (name) => { - var name = '_' + name; - var exported = 'Module["' + name + '"]'; + var name = `_${name}`; + var exported = `Module["${name}"]`; // make sure we write to an existing export, and are not repeating ourselves - return 'assert(' + exported + ' !== ' + name + '); ' + exported + ' = ' + name + ';'; + return `assert(${exported} !== ${name}); ${exported} = ${name};`; }, '') }}} #else @@ -489,20 +489,20 @@ var LibraryGLEmulation = { for (var i = 0; i < GLImmediate.MAX_TEXTURES; i++) { // XXX To handle both regular texture mapping and cube mapping, we use vec4 for tex coordinates. old = source; - var need_vtc = source.search('v_texCoord' + i) == -1; - source = source.replace(new RegExp('gl_TexCoord\\[' + i + '\\]', 'g'), 'v_texCoord' + i) - .replace(new RegExp('gl_MultiTexCoord' + i, 'g'), 'a_texCoord' + i); + var need_vtc = source.search(`v_texCoord${i}`) == -1; + source = source.replace(new RegExp(`gl_TexCoord\\[${i}\\]`, 'g'), `v_texCoord${i}`) + .replace(new RegExp(`gl_MultiTexCoord${i}`, 'g'), `a_texCoord${i}`); if (source != old) { - source = 'attribute vec4 a_texCoord' + i + '; \n' + source; + source = `attribute vec4 a_texCoord${i}; \n${source}`; if (need_vtc) { - source = 'varying vec4 v_texCoord' + i + '; \n' + source; + source = `varying vec4 v_texCoord${i}; \n${source}`; } } old = source; - source = source.replace(new RegExp('gl_TextureMatrix\\[' + i + '\\]', 'g'), 'u_textureMatrix' + i); + source = source.replace(new RegExp(`gl_TextureMatrix\\[${i}\\]`, 'g'), `u_textureMatrix${i}`); if (source != old) { - source = 'uniform mat4 u_textureMatrix' + i + '; \n' + source; + source = `uniform mat4 u_textureMatrix${i}; \n${source}`; } } if (source.includes('gl_FrontColor')) { @@ -525,7 +525,7 @@ var LibraryGLEmulation = { } else { // Fragment shader for (i = 0; i < GLImmediate.MAX_TEXTURES; i++) { old = source; - source = source.replace(new RegExp('gl_TexCoord\\[' + i + '\\]', 'g'), 'v_texCoord' + i); + source = source.replace(new RegExp(`gl_TexCoord\\[${i}\\]`, 'g'), `v_texCoord${i}`); if (source != old) { source = 'varying vec4 v_texCoord' + i + '; \n' + source; } @@ -568,10 +568,10 @@ var LibraryGLEmulation = { GLctx.compileShader(GL.shaders[shader]); #if GL_DEBUG if (!GLctx.getShaderParameter(GL.shaders[shader], GLctx.COMPILE_STATUS)) { - dbg('Failed to compile shader: ' + GLctx.getShaderInfoLog(GL.shaders[shader])); - dbg('Info: ' + JSON.stringify(GL.shaderInfos[shader])); - dbg('Original source: ' + GL.shaderOriginalSources[shader]); - dbg('Source: ' + GL.shaderSources[shader]); + dbg(`Failed to compile shader: ${GLctx.getShaderInfoLog(GL.shaders[shader])}`); + dbg(`Info: ${JSON.stringify(GL.shaderInfos[shader])}`); + dbg(`Original source: ${GL.shaderOriginalSources[shader]}`); + dbg(`Source: ${GL.shaderSources[shader]}`); throw 'Shader compilation halt'; } #endif @@ -591,7 +591,7 @@ var LibraryGLEmulation = { _glDetachShader = _emscripten_glDetachShader = (program, shader) => { var programShader = GL.programShaders[program]; if (!programShader) { - err('WARNING: _glDetachShader received invalid program: ' + program); + err(`WARNING: _glDetachShader received invalid program: ${program}`); return; } var index = programShader.indexOf(shader); @@ -607,8 +607,8 @@ var LibraryGLEmulation = { dbg('[using program with shaders]'); if (program) { GL.programShaders[program].forEach(function(shader) { - dbg(' shader ' + shader + ', original source: ' + GL.shaderOriginalSources[shader]); - dbg(' Source: ' + GL.shaderSources[shader]); + dbg(` shader ${shader}, original source: ${GL.shaderOriginalSources[shader]}`); + dbg(` Source: ${GL.shaderSources[shader]}`); }); } } @@ -760,7 +760,7 @@ var LibraryGLEmulation = { } else if (GL.shaders[id]) { _glDeleteShader(id); } else { - err('WARNING: deleteObject received invalid id: ' + id); + err(`WARNING: deleteObject received invalid id: ${id}`); } }, glDeleteObjectARB: 'glDeleteObject', @@ -789,7 +789,7 @@ var LibraryGLEmulation = { } _glGetShaderiv(id, type, result); } else { - err('WARNING: getObjectParameteriv received invalid id: ' + id); + err(`WARNING: getObjectParameteriv received invalid id: ${id}`); } }, glGetObjectParameterivARB: 'glGetObjectParameteriv', @@ -801,7 +801,7 @@ var LibraryGLEmulation = { } else if (GL.shaders[id]) { _glGetShaderInfoLog(id, maxLength, length, infoLog); } else { - err('WARNING: glGetInfoLog received invalid id: ' + id); + err(`WARNING: glGetInfoLog received invalid id: ${id}`); } }, glGetInfoLogARB: 'glGetInfoLog', @@ -2161,7 +2161,7 @@ var LibraryGLEmulation = { var renderer = keyView.get(); if (!renderer) { #if GL_DEBUG - dbg('generating renderer for ' + JSON.stringify(attributes)); + dbg(`generating renderer for ${JSON.stringify(attributes)}`); #endif renderer = GLImmediate.createRenderer(); GLImmediate.currentRenderer = renderer; @@ -2460,7 +2460,7 @@ var LibraryGLEmulation = { } if (useCurrProgram) { - this.texCoordLocations[i] = GLctx.getAttribLocation(this.program, 'a_texCoord' + i); + this.texCoordLocations[i] = GLctx.getAttribLocation(this.program, `a_texCoord${i}`); } else { this.texCoordLocations[i] = GLctx.getAttribLocation(this.program, aTexCoordPrefix + i); } @@ -2485,7 +2485,7 @@ var LibraryGLEmulation = { this.textureMatrixLocations = []; for (var i = 0; i < GLImmediate.MAX_TEXTURES; i++) { - this.textureMatrixLocations[i] = GLctx.getUniformLocation(this.program, 'u_textureMatrix' + i); + this.textureMatrixLocations[i] = GLctx.getUniformLocation(this.program, `u_textureMatrix${i}`); } this.normalLocation = GLctx.getAttribLocation(this.program, 'a_normal'); @@ -2513,7 +2513,7 @@ var LibraryGLEmulation = { this.hasClipPlane = false; this.clipPlaneEquationLocation = []; for (var clipPlaneId = 0; clipPlaneId < GLEmulation.MAX_CLIP_PLANES; clipPlaneId++) { - this.clipPlaneEquationLocation[clipPlaneId] = GLctx.getUniformLocation(this.program, 'u_clipPlaneEquation' + clipPlaneId); + this.clipPlaneEquationLocation[clipPlaneId] = GLctx.getUniformLocation(this.program, `u_clipPlaneEquation${clipPlaneId}`); this.hasClipPlane = (this.hasClipPlane || this.clipPlaneEquationLocation[clipPlaneId]); } @@ -2529,10 +2529,10 @@ var LibraryGLEmulation = { this.lightSpecularLocation = [] this.lightPositionLocation = [] for (var lightId = 0; lightId < GLEmulation.MAX_LIGHTS; lightId++) { - this.lightAmbientLocation[lightId] = GLctx.getUniformLocation(this.program, 'u_lightAmbient' + lightId); - this.lightDiffuseLocation[lightId] = GLctx.getUniformLocation(this.program, 'u_lightDiffuse' + lightId); - this.lightSpecularLocation[lightId] = GLctx.getUniformLocation(this.program, 'u_lightSpecular' + lightId); - this.lightPositionLocation[lightId] = GLctx.getUniformLocation(this.program, 'u_lightPosition' + lightId); + this.lightAmbientLocation[lightId] = GLctx.getUniformLocation(this.program, `u_lightAmbient${lightId}`); + this.lightDiffuseLocation[lightId] = GLctx.getUniformLocation(this.program, `u_lightDiffuse${lightId}`); + this.lightSpecularLocation[lightId] = GLctx.getUniformLocation(this.program, `u_lightSpecular${lightId}`); + this.lightPositionLocation[lightId] = GLctx.getUniformLocation(this.program, `u_lightPosition${lightId}`); } this.hasAlphaTest = GLEmulation.alphaTestEnabled; @@ -3401,7 +3401,7 @@ var LibraryGLEmulation = { break; default: // invalid value provided #if GL_ASSERTIONS - err('glAlphaFunc: Invalid alpha comparison function 0x' + ptrToString(func) + ' !'); + err(`glAlphaFunc: Invalid alpha comparison function ${ptrToString(func)}!`); #endif break; } @@ -3439,7 +3439,7 @@ var LibraryGLEmulation = { var attrib = GLEmulation.getAttributeFromCapability(cap); if (attrib === null) { #if ASSERTIONS - err('WARNING: unhandled clientstate: ' + cap); + err(`WARNING: unhandled clientstate: ${cap}`); #endif return; } @@ -3459,7 +3459,7 @@ var LibraryGLEmulation = { var attrib = GLEmulation.getAttributeFromCapability(cap); if (attrib === null) { #if ASSERTIONS - err('WARNING: unhandled clientstate: ' + cap); + err(`WARNING: unhandled clientstate: ${cap}`); #endif return; } diff --git a/src/library_nodefs.js b/src/library_nodefs.js index 1a67b6822fb2f..707589f6a7e28 100644 --- a/src/library_nodefs.js +++ b/src/library_nodefs.js @@ -37,7 +37,7 @@ mergeInto(LibraryManager.library, { convertNodeCode: (e) => { var code = e.code; #if ASSERTIONS - assert(code in ERRNO_CODES, 'unexpected node error code: ' + code + ' (' + e + ')'); + assert(code in ERRNO_CODES, `unexpected node error code: ${code} (${e})`); #endif return ERRNO_CODES[code]; }, diff --git a/src/library_noderawfs.js b/src/library_noderawfs.js index f3e9ecb848b5e..dc98b1f00a918 100644 --- a/src/library_noderawfs.js +++ b/src/library_noderawfs.js @@ -33,7 +33,7 @@ mergeInto(LibraryManager.library, { assert(parent) assert(parent.path) #endif - return FS.lookupPath(parent.path + '/' + name).node; + return FS.lookupPath(`${parent.path}/${name}`).node; }, lookupPath: function(path, opts = {}) { if (opts.parent) { diff --git a/src/library_openal.js b/src/library_openal.js index 1731e5bfa9790..44c1713c8bcab 100644 --- a/src/library_openal.js +++ b/src/library_openal.js @@ -199,7 +199,7 @@ var LibraryOpenAL = { warnOnce('Unable to start AudioBufferSourceNode playback! Not supported by the browser?'); } - dbg('scheduleSourceAudio() queuing buffer ' + buf.id + ' for source ' + src.id + ' at ' + startTime + ' (offset by ' + startOffset + ')'); + dbg(`scheduleSourceAudio() queuing buffer ${buf.id} for source ${src.id} at ${startTime} (offset by ${startOffset})`); #endif audioSrc._startTime = startTime; src.audioQueue.push(audioSrc); @@ -344,11 +344,11 @@ var LibraryOpenAL = { src.bufsProcessed = 0; src.bufOffset = 0.0; #if OPENAL_DEBUG - dbg('setSourceState() resetting and playing source ' + src.id); + dbg(`setSourceState() resetting and playing source ${src.id}`); #endif } else { #if OPENAL_DEBUG - dbg('setSourceState() playing source ' + src.id + ' at ' + src.bufOffset); + dbg(`setSourceState() playing source ${src.id} at ${src.bufOffset}`); #endif } @@ -365,7 +365,7 @@ var LibraryOpenAL = { src.state = 0x1013 /* AL_PAUSED */; #if OPENAL_DEBUG - dbg('setSourceState() pausing source ' + src.id + ' at ' + src.bufOffset); + dbg(`setSourceState() pausing source ${src.id} at ${src.bufOffset}`); #endif } } else if (state === 0x1014 /* AL_STOPPED */) { @@ -376,7 +376,7 @@ var LibraryOpenAL = { src.bufOffset = 0.0; AL.stopSourceAudio(src); #if OPENAL_DEBUG - dbg('setSourceState() stopping source ' + src.id); + dbg(`setSourceState() stopping source ${src.id}`); #endif } } else if (state === 0x1011 /* AL_INITIAL */) { @@ -387,7 +387,7 @@ var LibraryOpenAL = { src.bufOffset = 0.0; AL.stopSourceAudio(src); #if OPENAL_DEBUG - dbg('setSourceState() initializing source ' + src.id); + dbg(`setSourceState() initializing source ${src.id}`); #endif } } @@ -761,7 +761,7 @@ var LibraryOpenAL = { return AL.currentCtx.distanceModel; default: #if OPENAL_DEBUG - dbg(funcname + '() param ' + ptrToString(param) + ' is unknown or not implemented'); + dbg(`${funcname}() param ${ptrToString(param}`) + ' is unknown or not implemented'); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return null; @@ -780,7 +780,7 @@ var LibraryOpenAL = { case {{{ cDefs.AL_DOPPLER_FACTOR }}}: if (!Number.isFinite(value) || value < 0.0) { // Strictly negative values are disallowed #if OPENAL_DEBUG - dbg(funcname + '() value ' + value + ' is out of range'); + dbg(`${funcname}() value ${value} is out of range`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; @@ -792,7 +792,7 @@ var LibraryOpenAL = { case {{{ cDefs.AL_SPEED_OF_SOUND }}}: if (!Number.isFinite(value) || value <= 0.0) { // Negative or zero values are disallowed #if OPENAL_DEBUG - dbg(funcname + '() value ' + value + ' is out of range'); + dbg(`${funcname}() value ${value} is out of range`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; @@ -815,7 +815,7 @@ var LibraryOpenAL = { break; default: #if OPENAL_DEBUG - dbg(funcname + '() value ' + value + ' is out of range'); + dbg(`${funcname}() value ${value} is out of range`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; @@ -823,7 +823,7 @@ var LibraryOpenAL = { break; default: #if OPENAL_DEBUG - dbg(funcname + '() param ' + ptrToString(param) + ' is unknown or not implemented'); + dbg(`${funcname}() param ${ptrToString(param)} is unknown or not implemented`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; @@ -849,7 +849,7 @@ var LibraryOpenAL = { return AL.currentCtx.gain.gain.value; default: #if OPENAL_DEBUG - dbg(funcname + '() param ' + ptrToString(param) + ' is unknown or not implemented'); + dbg(`${funcname}() param ${ptrToString(param)} is unknown or not implemented`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return null; @@ -865,7 +865,7 @@ var LibraryOpenAL = { } if (value === null) { #if OPENAL_DEBUG - dbg(funcname + '(): param ' + ptrToString(param) + ' has wrong signature'); + dbg(`${funcname}(): param ${ptrToString(param)} has wrong signature`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; @@ -876,7 +876,7 @@ var LibraryOpenAL = { case {{{ cDefs.AL_POSITION }}}: if (!Number.isFinite(value[0]) || !Number.isFinite(value[1]) || !Number.isFinite(value[2])) { #if OPENAL_DEBUG - dbg(funcname + '() param AL_POSITION value ' + value + ' is out of range'); + dbg(`${funcname}() param AL_POSITION value ${value} is out of range`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; @@ -890,7 +890,7 @@ var LibraryOpenAL = { case {{{ cDefs.AL_VELOCITY }}}: if (!Number.isFinite(value[0]) || !Number.isFinite(value[1]) || !Number.isFinite(value[2])) { #if OPENAL_DEBUG - dbg(funcname + '() param AL_VELOCITY value ' + value + ' is out of range'); + dbg(`${funcname}() param AL_VELOCITY value ${value} is out of range`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; @@ -904,7 +904,7 @@ var LibraryOpenAL = { case {{{ cDefs.AL_GAIN }}}: if (!Number.isFinite(value) || value < 0.0) { #if OPENAL_DEBUG - dbg(funcname + '() param AL_GAIN value ' + value + ' is out of range'); + dbg(`${funcname}() param AL_GAIN value ${value} is out of range`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; @@ -917,7 +917,7 @@ var LibraryOpenAL = { || !Number.isFinite(value[3]) || !Number.isFinite(value[4]) || !Number.isFinite(value[5]) ) { #if OPENAL_DEBUG - dbg(funcname + '() param AL_ORIENTATION value ' + value + ' is out of range'); + dbg(`${funcname}() param AL_ORIENTATION value ${value} is out of range`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; @@ -933,7 +933,7 @@ var LibraryOpenAL = { break; default: #if OPENAL_DEBUG - dbg(funcname + '() param ' + ptrToString(param) + ' is unknown or not implemented'); + dbg(`${funcname}() param ${ptrToString(param)} is unknown or not implemented`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; @@ -975,7 +975,7 @@ var LibraryOpenAL = { ]; default: #if OPENAL_DEBUG - dbg(funcname + '() param ' + ptrToString(param) + ' is unknown or not implemented'); + dbg(`${funcname}() param ${ptrToString(param)} is unknown or not implemented`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return null; @@ -999,7 +999,7 @@ var LibraryOpenAL = { } if (value === null) { #if OPENAL_DEBUG - dbg(funcname + '(): param ' + ptrToString(param) + ' has wrong signature'); + dbg(`${funcname}(): param ${ptrToString(param)} has wrong signature`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; @@ -1009,7 +1009,7 @@ var LibraryOpenAL = { case 0x2004 /* AL_SIZE */: if (value !== 0) { #if OPENAL_DEBUG - dbg(funcname + '() param AL_SIZE value ' + value + ' is out of range'); + dbg(`${funcname}() param AL_SIZE value ${value} is out of range`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; @@ -1020,7 +1020,7 @@ var LibraryOpenAL = { case 0x2015 /* AL_LOOP_POINTS_SOFT */: if (value[0] < 0 || value[0] > buf.length || value[1] < 0 || value[1] > buf.Length || value[0] >= value[1]) { #if OPENAL_DEBUG - dbg(funcname + '() param AL_LOOP_POINTS_SOFT value ' + value + ' is out of range'); + dbg(`${funcname}() param AL_LOOP_POINTS_SOFT value ${value} is out of range`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; @@ -1040,7 +1040,7 @@ var LibraryOpenAL = { break; default: #if OPENAL_DEBUG - dbg(funcname + '() param ' + ptrToString(param) + ' is unknown or not implemented'); + dbg(`${funcname}() param ${ptrToString(param)}' is unknown or not implemented`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; @@ -1151,7 +1151,7 @@ var LibraryOpenAL = { return src.distanceModel; default: #if OPENAL_DEBUG - dbg(funcname + '() param ' + ptrToString(param) + ' is unknown or not implemented'); + dbg(`${funcname}() param ${ptrToString(param)}' is unknown or not implemented`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return null; @@ -1175,7 +1175,7 @@ var LibraryOpenAL = { } if (value === null) { #if OPENAL_DEBUG - dbg(funcname + '(): param ' + ptrToString(param) + ' has wrong signature'); + dbg(`${funcname}(): param ${ptrToString(param)}' has wrong signature`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; @@ -1191,7 +1191,7 @@ var LibraryOpenAL = { AL.updateSourceSpace(src); } else { #if OPENAL_DEBUG - dbg(funcname + '() param AL_SOURCE_RELATIVE value ' + value + ' is out of range'); + dbg(`${funcname}() param AL_SOURCE_RELATIVE value ${value} is out of range`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; @@ -1200,7 +1200,7 @@ var LibraryOpenAL = { case 0x1001 /* AL_CONE_INNER_ANGLE */: if (!Number.isFinite(value)) { #if OPENAL_DEBUG - dbg(funcname + '() param AL_CONE_INNER_ANGLE value ' + value + ' is out of range'); + dbg(`${funcname}() param AL_CONE_INNER_ANGLE value ${value} is out of range`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; @@ -1214,7 +1214,7 @@ var LibraryOpenAL = { case 0x1002 /* AL_CONE_OUTER_ANGLE */: if (!Number.isFinite(value)) { #if OPENAL_DEBUG - dbg(funcname + '() param AL_CONE_OUTER_ANGLE value ' + value + ' is out of range'); + dbg(`${funcname}() param AL_CONE_OUTER_ANGLE value ${value} is out of range`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; @@ -1228,7 +1228,7 @@ var LibraryOpenAL = { case 0x1003 /* AL_PITCH */: if (!Number.isFinite(value) || value <= 0.0) { #if OPENAL_DEBUG - dbg(funcname + '() param AL_PITCH value ' + value + ' is out of range'); + dbg(`${funcname}() param AL_PITCH value ${value} is out of range`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; @@ -1244,7 +1244,7 @@ var LibraryOpenAL = { case {{{ cDefs.AL_POSITION }}}: if (!Number.isFinite(value[0]) || !Number.isFinite(value[1]) || !Number.isFinite(value[2])) { #if OPENAL_DEBUG - dbg(funcname + '() param AL_POSITION value ' + value + ' is out of range'); + dbg(`${funcname}() param AL_POSITION value ${value} is out of range`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; @@ -1258,7 +1258,7 @@ var LibraryOpenAL = { case {{{ cDefs.AL_DIRECTION }}}: if (!Number.isFinite(value[0]) || !Number.isFinite(value[1]) || !Number.isFinite(value[2])) { #if OPENAL_DEBUG - dbg(funcname + '() param AL_DIRECTION value ' + value + ' is out of range'); + dbg(`${funcname}() param AL_DIRECTION value ${value} is out of range`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; @@ -1272,7 +1272,7 @@ var LibraryOpenAL = { case {{{ cDefs.AL_VELOCITY }}}: if (!Number.isFinite(value[0]) || !Number.isFinite(value[1]) || !Number.isFinite(value[2])) { #if OPENAL_DEBUG - dbg(funcname + '() param AL_VELOCITY value ' + value + ' is out of range'); + dbg(`${funcname}() param AL_VELOCITY value ${value} is out of range`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; @@ -1303,7 +1303,7 @@ var LibraryOpenAL = { } } else { #if OPENAL_DEBUG - dbg(funcname + '() param AL_LOOPING value ' + value + ' is out of range'); + dbg(`${funcname}() param AL_LOOPING value ${value} is out of range`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; @@ -1354,7 +1354,7 @@ var LibraryOpenAL = { case {{{ cDefs.AL_GAIN }}}: if (!Number.isFinite(value) || value < 0.0) { #if OPENAL_DEBUG - dbg(funcname + '() param AL_GAIN value ' + value + ' is out of range'); + dbg(`${funcname}() param AL_GAIN value ${value} is out of range`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; @@ -1364,7 +1364,7 @@ var LibraryOpenAL = { case 0x100D /* AL_MIN_GAIN */: if (!Number.isFinite(value) || value < 0.0 || value > Math.min(src.maxGain, 1.0)) { #if OPENAL_DEBUG - dbg(funcname + '() param AL_MIN_GAIN value ' + value + ' is out of range'); + dbg(`${funcname}() param AL_MIN_GAIN value ${value} is out of range`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; @@ -1377,7 +1377,7 @@ var LibraryOpenAL = { case 0x100E /* AL_MAX_GAIN */: if (!Number.isFinite(value) || value < Math.max(0.0, src.minGain) || value > 1.0) { #if OPENAL_DEBUG - dbg(funcname + '() param AL_MAX_GAIN value ' + value + ' is out of range'); + dbg(`${funcname}() param AL_MAX_GAIN value ${value} is out of range`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; @@ -1390,7 +1390,7 @@ var LibraryOpenAL = { case 0x1020 /* AL_REFERENCE_DISTANCE */: if (!Number.isFinite(value) || value < 0.0) { #if OPENAL_DEBUG - dbg(funcname + '() param AL_REFERENCE_DISTANCE value ' + value + ' is out of range'); + dbg(`${funcname}() param AL_REFERENCE_DISTANCE value ${value} is out of range`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; @@ -1403,7 +1403,7 @@ var LibraryOpenAL = { case 0x1021 /* AL_ROLLOFF_FACTOR */: if (!Number.isFinite(value) || value < 0.0) { #if OPENAL_DEBUG - dbg(funcname + '() param AL_ROLLOFF_FACTOR value ' + value + ' is out of range'); + dbg(`${funcname}() param AL_ROLLOFF_FACTOR value ${value} is out of range`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; @@ -1416,7 +1416,7 @@ var LibraryOpenAL = { case 0x1022 /* AL_CONE_OUTER_GAIN */: if (!Number.isFinite(value) || value < 0.0 || value > 1.0) { #if OPENAL_DEBUG - dbg(funcname + '() param AL_CORE_OUTER_GAIN value ' + value + ' is out of range'); + dbg(`${funcname}() param AL_CORE_OUTER_GAIN value ${value} is out of range`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; @@ -1429,7 +1429,7 @@ var LibraryOpenAL = { case 0x1023 /* AL_MAX_DISTANCE */: if (!Number.isFinite(value) || value < 0.0) { #if OPENAL_DEBUG - dbg(funcname + '() param AL_MAX_DISTANCE value ' + value + ' is out of range'); + dbg(`${funcname}() param AL_MAX_DISTANCE value ${value} is out of range`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; @@ -1442,7 +1442,7 @@ var LibraryOpenAL = { case 0x1024 /* AL_SEC_OFFSET */: if (value < 0.0 || value > AL.sourceDuration(src)) { #if OPENAL_DEBUG - dbg(funcname + '() param AL_SEC_OFFSET value ' + value + ' is out of range'); + dbg(`${funcname}() param AL_SEC_OFFSET value ${value} is out of range`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; @@ -1464,7 +1464,7 @@ var LibraryOpenAL = { } if (value < 0.0 || value > srcLen) { #if OPENAL_DEBUG - dbg(funcname + '() param AL_SAMPLE_OFFSET value ' + value + ' is out of range'); + dbg(`${funcname}() param AL_SAMPLE_OFFSET value ${value} is out of range`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; @@ -1487,7 +1487,7 @@ var LibraryOpenAL = { } if (value < 0.0 || value > srcLen) { #if OPENAL_DEBUG - dbg(funcname + '() param AL_BYTE_OFFSET value ' + value + ' is out of range'); + dbg(`${funcname}() param AL_BYTE_OFFSET value ${value} is out of range`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; @@ -1498,7 +1498,7 @@ var LibraryOpenAL = { case 0x1214 /* AL_SOURCE_SPATIALIZE_SOFT */: if (value !== {{{ cDefs.AL_FALSE }}} && value !== {{{ cDefs.AL_TRUE }}} && value !== 2 /* AL_AUTO_SOFT */) { #if OPENAL_DEBUG - dbg(funcname + '() param AL_SOURCE_SPATIALIZE_SOFT value ' + value + ' is out of range'); + dbg(`${funcname}() param AL_SOURCE_SPATIALIZE_SOFT value ${value} is out of range`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; @@ -1531,7 +1531,7 @@ var LibraryOpenAL = { break; default: #if OPENAL_DEBUG - dbg(funcname + '() param AL_DISTANCE_MODEL value ' + value + ' is out of range'); + dbg(`${funcname}() param AL_DISTANCE_MODEL value ${value} is out of range`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; @@ -1539,7 +1539,7 @@ var LibraryOpenAL = { break; default: #if OPENAL_DEBUG - dbg(funcname + '() param ' + ptrToString(param) + ' is unknown or not implemented'); + dbg(`${funcname}() param ${ptrToString(param)}' is unknown or not implemented`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; @@ -1565,7 +1565,7 @@ var LibraryOpenAL = { requireValidCaptureDevice: function(deviceId, funcname) { if (deviceId === 0) { #if OPENAL_DEBUG - dbg(funcname+'() on a NULL device is an error'); + dbg(`${funcname}() on a NULL device is an error`); #endif AL.alcErr = {{{ cDefs.ALC_INVALID_DEVICE }}}; return null; @@ -1573,7 +1573,7 @@ var LibraryOpenAL = { var c = AL.captures[deviceId]; if (!c) { #if OPENAL_DEBUG - dbg(funcname+'() on an invalid device'); + dbg(`${funcname}() on an invalid device`); #endif AL.alcErr = {{{ cDefs.ALC_INVALID_DEVICE }}}; return null; @@ -1583,13 +1583,13 @@ var LibraryOpenAL = { #if OPENAL_DEBUG switch (err.name) { case 'PermissionDeniedError': - dbg(funcname+'() but the user denied access to the device'); + dbg(`${funcname}() but the user denied access to the device`); break; case 'NotFoundError': - dbg(funcname+'() but no capture device was found'); + dbg(`${funcname}() but no capture device was found`); break; default: - dbg(funcname+'() but a MediaStreamError was encountered: ' + err); + dbg(`${funcname}() but a MediaStreamError was encountered: ${err}`); break; } #endif @@ -1667,7 +1667,7 @@ var LibraryOpenAL = { AL.sharedCaptureAudioCtx = new AudioContext(); } catch(e) { #if OPENAL_DEBUG - dbg('alcCaptureOpenDevice() could not create the shared capture AudioContext: ' + e); + dbg(`alcCaptureOpenDevice() could not create the shared capture AudioContext: ${e}`); #endif // See previously mentioned rationale for ALC_OUT_OF_MEMORY AL.alcErr = 0xA005 /* ALC_OUT_OF_MEMORY */; @@ -1692,7 +1692,7 @@ var LibraryOpenAL = { break; default: #if OPENAL_DEBUG - dbg('alcCaptureOpenDevice() with unsupported format ' + format); + dbg(`alcCaptureOpenDevice() with unsupported format ${format}`); #endif AL.alcErr = {{{ cDefs.ALC_INVALID_VALUE }}}; return 0; @@ -1730,7 +1730,7 @@ var LibraryOpenAL = { } } catch(e) { #if OPENAL_DEBUG - dbg('alcCaptureOpenDevice() failed to allocate internal buffers (is bufferSize low enough?): ' + e); + dbg(`alcCaptureOpenDevice() failed to allocate internal buffers (is bufferSize low enough?): ${e}`); #endif AL.alcErr = 0xA005 /* ALC_OUT_OF_MEMORY */; return 0; @@ -1768,7 +1768,7 @@ var LibraryOpenAL = { var onError = (mediaStreamError) => { newCapture.mediaStreamError = mediaStreamError; #if OPENAL_DEBUG - dbg('navigator.getUserMedia() errored with: ' + mediaStreamError); + dbg(`navigator.getUserMedia() errored with: ${mediaStreamError}`); #endif }; var onSuccess = (mediaStream) => { @@ -2138,7 +2138,7 @@ var LibraryOpenAL = { break; default: #if OPENAL_DEBUG - dbg('Unsupported ALC_HRTF_SOFT mode ' + val); + dbg(`Unsupported ALC_HRTF_SOFT mode ${val}`); #endif AL.alcErr = {{{ cDefs.ALC_INVALID_VALUE }}}; return 0; @@ -2147,7 +2147,7 @@ var LibraryOpenAL = { case 0x1996 /* ALC_HRTF_ID_SOFT */: if (val !== 0) { #if OPENAL_DEBUG - dbg('Invalid ALC_HRTF_ID_SOFT index ' + val); + dbg(`Invalid ALC_HRTF_ID_SOFT index ${val}`); #endif AL.alcErr = {{{ cDefs.ALC_INVALID_VALUE }}}; return 0; @@ -2155,7 +2155,7 @@ var LibraryOpenAL = { break; default: #if OPENAL_DEBUG - dbg('Unsupported context attribute ' + ptrToString(attr)); + dbg(`Unsupported context attribute ${ptrToString(attr)}`); #endif AL.alcErr = 0xA004; /* ALC_INVALID_VALUE */ return 0; @@ -2367,7 +2367,7 @@ var LibraryOpenAL = { default: #if OPENAL_DEBUG - dbg('No value for `' + pEnumName + '` is known by alcGetEnumValue()'); + dbg(`No value for `${pEnumName}` is known by alcGetEnumValue()`); #endif AL.alcErr = {{{ cDefs.ALC_INVALID_VALUE }}}; return {{{ cDefs.AL_NONE }}}; @@ -2566,7 +2566,7 @@ var LibraryOpenAL = { break; default: #if OPENAL_DEBUG - dbg('alcGetIntegerv() with param ' + ptrToString(param) + ' not implemented yet'); + dbg(`alcGetIntegerv() with param ${ptrToString(param)} not implemented yet`); #endif AL.alcErr = {{{ cDefs.ALC_INVALID_ENUM }}}; return; @@ -2651,7 +2651,7 @@ var LibraryOpenAL = { ret = 'Web Audio HRTF'; } else { #if OPENAL_DEBUG - dbg('alcGetStringiSOFT() with param ALC_HRTF_SPECIFIER_SOFT index ' + index + ' is out of range'); + dbg(`alcGetStringiSOFT() with param ALC_HRTF_SPECIFIER_SOFT index ${index} is out of range`); #endif AL.alcErr = {{{ cDefs.ALC_INVALID_VALUE }}}; return 0; @@ -2660,7 +2660,7 @@ var LibraryOpenAL = { default: if (index !== 0) { #if OPENAL_DEBUG - dbg('alcGetStringiSOFT() with param ' + ptrToString(param) + ' not implemented yet'); + dbg(`alcGetStringiSOFT() with param ${ptrToString(param)} not implemented yet`); #endif AL.alcErr = {{{ cDefs.ALC_INVALID_ENUM }}}; return 0; @@ -3009,7 +3009,7 @@ var LibraryOpenAL = { default: #if OPENAL_DEBUG - dbg('No value for `' + name + '` is known by alGetEnumValue()'); + dbg(`No value for `${name}` is known by alGetEnumValue()`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return 0; @@ -3091,7 +3091,7 @@ var LibraryOpenAL = { break; default: #if OPENAL_DEBUG - dbg('alEnable() with param ' + ptrToString(param) + ' not implemented yet'); + dbg(`alEnable() with param ${ptrToString(param)} not implemented yet`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; @@ -3113,7 +3113,7 @@ var LibraryOpenAL = { break; default: #if OPENAL_DEBUG - dbg('alDisable() with param ' + ptrToString(param) + ' not implemented yet'); + dbg(`alDisable() with param ${ptrToString(param)} not implemented yet`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; @@ -3133,7 +3133,7 @@ var LibraryOpenAL = { return AL.currentCtx.sourceDistanceModel ? {{{ cDefs.AL_FALSE }}} : {{{ cDefs.AL_TRUE }}}; default: #if OPENAL_DEBUG - dbg('alIsEnabled() with param ' + ptrToString(param) + ' not implemented yet'); + dbg(`alIsEnabled() with param ${ptrToString(param)} not implemented yet`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return 0; @@ -3154,7 +3154,7 @@ var LibraryOpenAL = { return val; default: #if OPENAL_DEBUG - dbg('alGetDouble(): param ' + ptrToString(param) + ' has wrong signature'); + dbg(`alGetDouble(): param ${ptrToString(param)} has wrong signature`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return 0.0; @@ -3177,7 +3177,7 @@ var LibraryOpenAL = { break; default: #if OPENAL_DEBUG - dbg('alGetDoublev(): param ' + ptrToString(param) + ' has wrong signature'); + dbg(`alGetDoublev(): param ${ptrToString(param)} has wrong signature`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; @@ -3198,7 +3198,7 @@ var LibraryOpenAL = { return val; default: #if OPENAL_DEBUG - dbg('alGetFloat(): param ' + ptrToString(param) + ' has wrong signature'); + dbg(`alGetFloat(): param ${ptrToString(param)} has wrong signature`); #endif return 0.0; } @@ -3220,7 +3220,7 @@ var LibraryOpenAL = { break; default: #if OPENAL_DEBUG - dbg('alGetFloatv(): param ' + ptrToString(param) + ' has wrong signature'); + dbg(`alGetFloatv(): param ${ptrToString(param)} has wrong signature`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; @@ -3241,7 +3241,7 @@ var LibraryOpenAL = { return val; default: #if OPENAL_DEBUG - dbg('alGetInteger(): param ' + ptrToString(param) + ' has wrong signature'); + dbg(`alGetInteger(): param ${ptrToString(param)} has wrong signature`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return 0; @@ -3264,7 +3264,7 @@ var LibraryOpenAL = { break; default: #if OPENAL_DEBUG - dbg('alGetIntegerv(): param ' + ptrToString(param) + ' has wrong signature'); + dbg(`alGetIntegerv(): param ${ptrToString(param)} has wrong signature`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; @@ -3285,7 +3285,7 @@ var LibraryOpenAL = { return val !== 0 ? {{{ cDefs.AL_TRUE }}} : {{{ cDefs.AL_FALSE }}}; default: #if OPENAL_DEBUG - dbg('alGetBoolean(): param ' + ptrToString(param) + ' has wrong signature'); + dbg(`alGetBoolean(): param ${ptrToString(param)} has wrong signature`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return {{{ cDefs.AL_FALSE }}}; @@ -3308,7 +3308,7 @@ var LibraryOpenAL = { break; default: #if OPENAL_DEBUG - dbg('alGetBooleanv(): param ' + ptrToString(param) + ' has wrong signature'); + dbg(`alGetBooleanv(): param ${ptrToString(param)} has wrong signature`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; @@ -3373,7 +3373,7 @@ var LibraryOpenAL = { break; default: #if OPENAL_DEBUG - dbg('alGetListenerf(): param ' + ptrToString(param) + ' has wrong signature'); + dbg(`alGetListenerf(): param ${ptrToString(param)} has wrong signature`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; @@ -3403,7 +3403,7 @@ var LibraryOpenAL = { break; default: #if OPENAL_DEBUG - dbg('alGetListener3f(): param ' + ptrToString(param) + ' has wrong signature'); + dbg(`alGetListener3f(): param ${ptrToString(param)} has wrong signature`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; @@ -3441,7 +3441,7 @@ var LibraryOpenAL = { break; default: #if OPENAL_DEBUG - dbg('alGetListenerfv(): param ' + ptrToString(param) + ' has wrong signature'); + dbg(`alGetListenerfv(): param ${ptrToString(param)} has wrong signature`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; @@ -3463,7 +3463,7 @@ var LibraryOpenAL = { } #if OPENAL_DEBUG - dbg('alGetListeneri(): param ' + ptrToString(param) + ' has wrong signature'); + dbg(`alGetListeneri(): param ${ptrToString(param)} has wrong signature`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; }, @@ -3491,7 +3491,7 @@ var LibraryOpenAL = { break; default: #if OPENAL_DEBUG - dbg('alGetListener3i(): param ' + ptrToString(param) + ' has wrong signature'); + dbg(`alGetListener3i(): param ${ptrToString(param)} has wrong signature`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; @@ -3529,7 +3529,7 @@ var LibraryOpenAL = { break; default: #if OPENAL_DEBUG - dbg('alGetListeneriv(): param ' + ptrToString(param) + ' has wrong signature'); + dbg(`alGetListeneriv(): param ${ptrToString(param)} has wrong signature`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; @@ -3793,7 +3793,7 @@ var LibraryOpenAL = { break; default: #if OPENAL_DEBUG - dbg('alBufferData() called with invalid format ' + format); + dbg(`alBufferData() called with invalid format ${format}`; #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; @@ -3802,7 +3802,7 @@ var LibraryOpenAL = { buf.audioBuf = audioBuf; } catch (e) { #if OPENAL_DEBUG - dbg('alBufferData() upload failed with an exception ' + e); + dbg(`alBufferData() upload failed with an exception ${e}`; #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_VALUE }}}; return; @@ -3824,7 +3824,7 @@ var LibraryOpenAL = { } #if OPENAL_DEBUG - dbg('alGetBufferf(): param ' + ptrToString(param) + ' has wrong signature'); + dbg(`alGetBufferf(): param ${ptrToString(param)} has wrong signature`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; }, @@ -3844,7 +3844,7 @@ var LibraryOpenAL = { } #if OPENAL_DEBUG - dbg('alGetBuffer3f(): param ' + ptrToString(param) + ' has wrong signature'); + dbg(`alGetBuffer3f(): param ${ptrToString(param)} has wrong signature`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; }, @@ -3864,7 +3864,7 @@ var LibraryOpenAL = { } #if OPENAL_DEBUG - dbg('alGetBufferfv(): param ' + ptrToString(param) + ' has wrong signature'); + dbg(`alGetBufferfv(): param ${ptrToString(param)} has wrong signature`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; }, @@ -3892,7 +3892,7 @@ var LibraryOpenAL = { break; default: #if OPENAL_DEBUG - dbg('alGetBufferi(): param ' + ptrToString(param) + ' has wrong signature'); + dbg(`alGetBufferi(): param ${ptrToString(param)} has wrong signature`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; @@ -3914,7 +3914,7 @@ var LibraryOpenAL = { } #if OPENAL_DEBUG - dbg('alGetBuffer3i(): param ' + ptrToString(param) + ' has wrong signature'); + dbg(`alGetBuffer3i(): param ${ptrToString(param)} has wrong signature`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; }, @@ -3946,7 +3946,7 @@ var LibraryOpenAL = { break; default: #if OPENAL_DEBUG - dbg('alGetBufferiv(): param ' + ptrToString(param) + ' has wrong signature'); + dbg(`alGetBufferiv(): param ${ptrToString(param)} has wrong signature`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; @@ -4397,7 +4397,7 @@ var LibraryOpenAL = { break; default: #if OPENAL_DEBUG - dbg('alGetSourcef(): param ' + ptrToString(param) + ' has wrong signature'); + dbg(`alGetSourcef(): param ${ptrToString(param)} has wrong signature`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; @@ -4428,7 +4428,7 @@ var LibraryOpenAL = { break; default: #if OPENAL_DEBUG - dbg('alGetSource3f(): param ' + ptrToString(param) + ' has wrong signature'); + dbg(`alGetSource3f(): param ${ptrToString(param)} has wrong signature`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; @@ -4475,7 +4475,7 @@ var LibraryOpenAL = { break; default: #if OPENAL_DEBUG - dbg('alGetSourcefv(): param ' + ptrToString(param) + ' has wrong signature'); + dbg(`alGetSourcefv(): param ${ptrToString(param)} has wrong signature`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; @@ -4520,7 +4520,7 @@ var LibraryOpenAL = { break; default: #if OPENAL_DEBUG - dbg('alGetSourcei(): param ' + ptrToString(param) + ' has wrong signature'); + dbg(`alGetSourcei(): param ${ptrToString(param)} has wrong signature`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; @@ -4551,7 +4551,7 @@ var LibraryOpenAL = { break; default: #if OPENAL_DEBUG - dbg('alGetSource3i(): param ' + ptrToString(param) + ' has wrong signature'); + dbg(`alGetSource3i(): param ${ptrToString(param)} has wrong signature`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; @@ -4603,7 +4603,7 @@ var LibraryOpenAL = { break; default: #if OPENAL_DEBUG - dbg('alGetSourceiv(): param ' + ptrToString(param) + ' has wrong signature'); + dbg(`alGetSourceiv(): param ${ptrToString(param)} has wrong signature`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; diff --git a/src/library_promise.js b/src/library_promise.js index 8d9b5eb0efe1d..ae66ec34f2669 100644 --- a/src/library_promise.js +++ b/src/library_promise.js @@ -22,7 +22,7 @@ mergeInto(LibraryManager.library, { }); promiseInfo.id = promiseMap.allocate(promiseInfo); #if RUNTIME_DEBUG - dbg('makePromise: ' + promiseInfo.id); + dbg(`makePromise: ${promiseInfo.id}`); #endif return promiseInfo; }, @@ -45,7 +45,7 @@ mergeInto(LibraryManager.library, { emscripten_promise_destroy__deps: ['$promiseMap'], emscripten_promise_destroy: function(id) { #if RUNTIME_DEBUG - dbg('emscripten_promise_destroy: ' + id); + dbg(`emscripten_promise_destroy: ${id}`); #endif promiseMap.free(id); }, @@ -55,7 +55,7 @@ mergeInto(LibraryManager.library, { 'emscripten_promise_destroy'], emscripten_promise_resolve: function(id, result, value) { #if RUNTIME_DEBUG - dbg('emscripten_promise_resolve: ' + id); + dbg(`emscripten_promise_resolve: ${id}`); #endif var info = promiseMap.get(id); switch (result) { @@ -84,7 +84,7 @@ mergeInto(LibraryManager.library, { $makePromiseCallback: function(callback, userData) { return (value) => { #if RUNTIME_DEBUG - dbg('emscripten promise callback: ' + value); + dbg(`emscripten promise callback: ${value}`); #endif {{{ runtimeKeepalivePop() }}}; var stack = stackSave(); @@ -142,7 +142,7 @@ mergeInto(LibraryManager.library, { onRejected, userData) { #if RUNTIME_DEBUG - dbg('emscripten_promise_then: ' + id); + dbg(`emscripten_promise_then: ${id}`); #endif {{{ runtimeKeepalivePush() }}}; var promise = getPromise(id); @@ -151,7 +151,7 @@ mergeInto(LibraryManager.library, { makePromiseCallback(onRejected, userData)) }); #if RUNTIME_DEBUG - dbg('emscripten_promise_then: -> ' + newId); + dbg(`emscripten_promise_then: -> ${newId}`); #endif return newId; }, @@ -160,7 +160,7 @@ mergeInto(LibraryManager.library, { emscripten_promise_all: function(idBuf, resultBuf, size) { var promises = idsToPromises(idBuf, size); #if RUNTIME_DEBUG - dbg('emscripten_promise_all: ' + promises); + dbg(`emscripten_promise_all: ${promises}`); #endif var id = promiseMap.allocate({ promise: Promise.all(promises).then((results) => { @@ -174,7 +174,7 @@ mergeInto(LibraryManager.library, { }) }); #if RUNTIME_DEBUG - dbg('create: ' + id); + dbg(`create: ${id}`); #endif return id; }, @@ -183,7 +183,7 @@ mergeInto(LibraryManager.library, { emscripten_promise_all_settled: function(idBuf, resultBuf, size) { var promises = idsToPromises(idBuf, size); #if RUNTIME_DEBUG - dbg('emscripten_promise_all_settled: ' + promises); + dbg(`emscripten_promise_all_settled: ${promises}`); #endif var id = promiseMap.allocate({ promise: Promise.allSettled(promises).then((results) => { @@ -211,7 +211,7 @@ mergeInto(LibraryManager.library, { }) }); #if RUNTIME_DEBUG - dbg('create: ' + id); + dbg(`create: ${id}`); #endif return id; }, @@ -226,7 +226,7 @@ mergeInto(LibraryManager.library, { emscripten_promise_any: function(idBuf, errorBuf, size) { var promises = idsToPromises(idBuf, size); #if RUNTIME_DEBUG - dbg('emscripten_promise_any: ' + promises); + dbg(`emscripten_promise_any: ${promises}`); #endif #if ASSERTIONS assert(typeof Promise.any !== 'undefined', "Promise.any does not exist"); @@ -242,7 +242,7 @@ mergeInto(LibraryManager.library, { }) }); #if RUNTIME_DEBUG - dbg('create: ' + id); + dbg(`create: ${id}`); #endif return id; }, @@ -251,13 +251,13 @@ mergeInto(LibraryManager.library, { emscripten_promise_race: function(idBuf, size) { var promises = idsToPromises(idBuf, size); #if RUNTIME_DEBUG - dbg('emscripten_promise_race: ' + promises); + dbg(`emscripten_promise_race: ${promises}`); #endif var id = promiseMap.allocate({ promise: Promise.race(promises) }); #if RUNTIME_DEBUG - dbg('create: ' + id); + dbg(`create: ${id}`); #endif return id; } diff --git a/src/proxyWorker.js b/src/proxyWorker.js index 9a6b50d7da331..aa3548938dd2c 100644 --- a/src/proxyWorker.js +++ b/src/proxyWorker.js @@ -8,19 +8,19 @@ if (typeof console == 'undefined') { // we can't call Module.printErr because that might be circular var console = { log: function(x) { - if (typeof dump == 'function') dump('log: ' + x + '\n'); + if (typeof dump == 'function') dump(`log: ${x}\n`); }, debug: function(x) { - if (typeof dump == 'function') dump('debug: ' + x + '\n'); + if (typeof dump == 'function') dump(`debug: ${x}\n`); }, info: function(x) { - if (typeof dump == 'function') dump('info: ' + x + '\n'); + if (typeof dump == 'function') dump(`info: ${x}\n`); }, warn: function(x) { - if (typeof dump == 'function') dump('warn: ' + x + '\n'); + if (typeof dump == 'function') dump(`warn: ${x}\n`); }, error: function(x) { - if (typeof dump == 'function') dump('error: ' + x + '\n'); + if (typeof dump == 'function') dump(`error: ${x}\n`); }, }; } diff --git a/src/shell.js b/src/shell.js index b1ed99a73b115..2768ef0f0bced 100644 --- a/src/shell.js +++ b/src/shell.js @@ -236,7 +236,7 @@ if (ENVIRONMENT_IS_NODE) { process.on('uncaughtException', (ex) => { // suppress ExitStatus exceptions from showing an error #if RUNTIME_DEBUG - dbg('node: uncaughtException: ' + ex) + dbg(`node: uncaughtException: ${ex}`) #endif if (ex !== 'unwind' && !(ex instanceof ExitStatus) && !(ex.context instanceof ExitStatus)) { throw ex; @@ -349,7 +349,7 @@ if (ENVIRONMENT_IS_SHELL) { if (toThrow && typeof toThrow == 'object' && toThrow.stack) { toLog = [toThrow, toThrow.stack]; } - err('exiting due to exception: ' + toLog); + err(`exiting due to exception: ${toLog}`); } quit(status); }); diff --git a/src/utility.js b/src/utility.js index fea766f28b78f..c97667e0f3c0b 100644 --- a/src/utility.js +++ b/src/utility.js @@ -27,9 +27,9 @@ function dump(item) { if (Object.prototype.hasOwnProperty.call(item, i)) { const j = item[i]; if (typeof j == 'string' || typeof j == 'number') { - ret.push(i + ': ' + j); + ret.push(`${i}: ${j}`); } else { - ret.push(i + ': [?]'); + ret.push(`${i}: [?]`); } } } diff --git a/test/other/metadce/test_metadce_cxx_ctors1.jssize b/test/other/metadce/test_metadce_cxx_ctors1.jssize index e8285cbf9a2a9..6ed4ae37700b9 100644 --- a/test/other/metadce/test_metadce_cxx_ctors1.jssize +++ b/test/other/metadce/test_metadce_cxx_ctors1.jssize @@ -1 +1 @@ -25923 +25933 diff --git a/test/other/metadce/test_metadce_cxx_ctors1.size b/test/other/metadce/test_metadce_cxx_ctors1.size index c3e6c8e8b8cec..7cb7cf00d785b 100644 --- a/test/other/metadce/test_metadce_cxx_ctors1.size +++ b/test/other/metadce/test_metadce_cxx_ctors1.size @@ -1 +1 @@ -123502 +123479 diff --git a/test/other/metadce/test_metadce_cxx_ctors2.jssize b/test/other/metadce/test_metadce_cxx_ctors2.jssize index 5a5460255508f..6f07b8bd2eae0 100644 --- a/test/other/metadce/test_metadce_cxx_ctors2.jssize +++ b/test/other/metadce/test_metadce_cxx_ctors2.jssize @@ -1 +1 @@ -25887 +25897 diff --git a/test/other/metadce/test_metadce_cxx_ctors2.size b/test/other/metadce/test_metadce_cxx_ctors2.size index e9659e9d95013..7a2e462123ec6 100644 --- a/test/other/metadce/test_metadce_cxx_ctors2.size +++ b/test/other/metadce/test_metadce_cxx_ctors2.size @@ -1 +1 @@ -123407 +123373 diff --git a/test/other/metadce/test_metadce_cxx_except.jssize b/test/other/metadce/test_metadce_cxx_except.jssize index f57d3540e6b92..14cacbe2b6cbc 100644 --- a/test/other/metadce/test_metadce_cxx_except.jssize +++ b/test/other/metadce/test_metadce_cxx_except.jssize @@ -1 +1 @@ -30437 +30447 diff --git a/test/other/metadce/test_metadce_cxx_except.size b/test/other/metadce/test_metadce_cxx_except.size index 75ce5068ec801..27e59ea3c5748 100644 --- a/test/other/metadce/test_metadce_cxx_except.size +++ b/test/other/metadce/test_metadce_cxx_except.size @@ -1 +1 @@ -166271 +166244 diff --git a/test/other/metadce/test_metadce_cxx_except_wasm.jssize b/test/other/metadce/test_metadce_cxx_except_wasm.jssize index 79ce5434529ec..d3f89d763150e 100644 --- a/test/other/metadce/test_metadce_cxx_except_wasm.jssize +++ b/test/other/metadce/test_metadce_cxx_except_wasm.jssize @@ -1 +1 @@ -25732 +25742 diff --git a/test/other/metadce/test_metadce_cxx_except_wasm.size b/test/other/metadce/test_metadce_cxx_except_wasm.size index d1ea9f9b1f5fc..c2edb388c6c10 100644 --- a/test/other/metadce/test_metadce_cxx_except_wasm.size +++ b/test/other/metadce/test_metadce_cxx_except_wasm.size @@ -1 +1 @@ -137069 +137042 diff --git a/test/other/metadce/test_metadce_cxx_mangle.jssize b/test/other/metadce/test_metadce_cxx_mangle.jssize index c9e2df1f45fcf..6692325dc5cb5 100644 --- a/test/other/metadce/test_metadce_cxx_mangle.jssize +++ b/test/other/metadce/test_metadce_cxx_mangle.jssize @@ -1 +1 @@ -30436 +30446 diff --git a/test/other/metadce/test_metadce_cxx_mangle.size b/test/other/metadce/test_metadce_cxx_mangle.size index d3ad8dde956d8..d310455c80818 100644 --- a/test/other/metadce/test_metadce_cxx_mangle.size +++ b/test/other/metadce/test_metadce_cxx_mangle.size @@ -1 +1 @@ -221359 +219418 diff --git a/test/other/metadce/test_metadce_cxx_noexcept.jssize b/test/other/metadce/test_metadce_cxx_noexcept.jssize index e8285cbf9a2a9..6ed4ae37700b9 100644 --- a/test/other/metadce/test_metadce_cxx_noexcept.jssize +++ b/test/other/metadce/test_metadce_cxx_noexcept.jssize @@ -1 +1 @@ -25923 +25933 diff --git a/test/other/metadce/test_metadce_cxx_noexcept.size b/test/other/metadce/test_metadce_cxx_noexcept.size index 04a2ee6190e4b..b8f5d0b10a39e 100644 --- a/test/other/metadce/test_metadce_cxx_noexcept.size +++ b/test/other/metadce/test_metadce_cxx_noexcept.size @@ -1 +1 @@ -126299 +126272 diff --git a/test/other/metadce/test_metadce_hello_dylink.jssize b/test/other/metadce/test_metadce_hello_dylink.jssize index f450807b16165..28a6cab7467e1 100644 --- a/test/other/metadce/test_metadce_hello_dylink.jssize +++ b/test/other/metadce/test_metadce_hello_dylink.jssize @@ -1 +1 @@ -28009 +28024 diff --git a/test/other/metadce/test_metadce_minimal_pthreads.size b/test/other/metadce/test_metadce_minimal_pthreads.size index a8093fa03841c..94f4b0c88daef 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.size +++ b/test/other/metadce/test_metadce_minimal_pthreads.size @@ -1 +1 @@ -19045 +19067 diff --git a/test/other/test_unoptimized_code_size.js.size b/test/other/test_unoptimized_code_size.js.size index 1e2918b84d776..cc84a949cd741 100644 --- a/test/other/test_unoptimized_code_size.js.size +++ b/test/other/test_unoptimized_code_size.js.size @@ -1 +1 @@ -59638 +59630 diff --git a/test/other/test_unoptimized_code_size_strict.js.size b/test/other/test_unoptimized_code_size_strict.js.size index 42ec6578d58b4..7b6c1d7f7e426 100644 --- a/test/other/test_unoptimized_code_size_strict.js.size +++ b/test/other/test_unoptimized_code_size_strict.js.size @@ -1 +1 @@ -58580 +58572 diff --git a/tools/file_packager.py b/tools/file_packager.py index 748a6c7060552..9061c18ab8333 100755 --- a/tools/file_packager.py +++ b/tools/file_packager.py @@ -627,13 +627,13 @@ def generate_js(data_target, data_files, metadata): create_preloaded = ''' Module['FS_createPreloadedFile'](this.name, null, byteArray, true, true, function() { - Module['removeRunDependency']('fp ' + that.name); + Module['removeRunDependency'](`fp ${that.name}`); }, function() { - err('Preloading file ' + that.name + ' failed'); + err(`Preloading file ${that.name} failed`); }, false, true); // canOwn this data in the filesystem, it is a slide into the heap that will never change\n''' create_data = '''// canOwn this data in the filesystem, it is a slide into the heap that will never change Module['FS_createDataFile'](this.name, null, byteArray, true, true, true); - Module['removeRunDependency']('fp ' + that.name);''' + Module['removeRunDependency'](`fp ${that.name}`);''' if not options.lz4: # Data requests - for getting a block of data out of the big archive - have @@ -650,7 +650,7 @@ def generate_js(data_target, data_files, metadata): open: function(mode, name) { this.name = name; this.requests[name] = this; - Module['addRunDependency']('fp ' + this.name); + Module['addRunDependency'](`fp ${this.name}`); }, send: function() {}, onload: function() { @@ -821,7 +821,7 @@ def generate_js(data_target, data_files, metadata): nextChunkSliceStart += CHUNK_SIZE; var putPackageRequest = packages.put( packageData.slice(chunkSliceStart, nextChunkSliceStart), - 'package/' + packageName + '/' + chunkId + `package/${packageName}/${chunkId}` ); chunkSliceStart = nextChunkSliceStart; putPackageRequest.onsuccess = function(event) { @@ -837,7 +837,7 @@ def generate_js(data_target, data_files, metadata): 'uuid': packageMeta.uuid, 'chunkCount': chunkCount }, - 'metadata/' + packageName + `metadata/${packageName}` ); putMetadataRequest.onsuccess = function(event) { callback(packageData); @@ -857,7 +857,7 @@ def generate_js(data_target, data_files, metadata): function checkCachedPackage(db, packageName, callback, errback) { var transaction = db.transaction([METADATA_STORE_NAME], IDB_RO); var metadata = transaction.objectStore(METADATA_STORE_NAME); - var getRequest = metadata.get('metadata/' + packageName); + var getRequest = metadata.get(`metadata/${packageName}`); getRequest.onsuccess = function(event) { var result = event.target.result; if (!result) { @@ -881,7 +881,7 @@ def generate_js(data_target, data_files, metadata): var chunks = new Array(chunkCount); for (var chunkId = 0; chunkId < chunkCount; chunkId++) { - var getRequest = packages.get('package/' + packageName + '/' + chunkId); + var getRequest = packages.get(`package/${packageName}/${chunkId}`); getRequest.onsuccess = function(event) { // If there's only 1 chunk, there's nothing to concatenate it with so we can just return it now if (chunkCount == 1) { @@ -960,7 +960,7 @@ def generate_js(data_target, data_files, metadata): num++; } total = Math.ceil(total * Module.expectedDataFileDownloads/num); - if (Module['setStatus']) Module['setStatus']('Downloading data... (' + loaded + '/' + total + ')'); + if (Module['setStatus']) Module['setStatus'](`Downloading data... (${loaded}/${total})`); } else if (!Module.dataFileDownloads) { if (Module['setStatus']) Module['setStatus']('Downloading data...'); } From 5306d339098614261a9a00505239d3669f4a4dba Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 15 May 2023 16:36:17 -0700 Subject: [PATCH 0244/1523] Rebaseline codesize expectations. NFC --- test/other/metadce/test_metadce_cxx_ctors1.size | 2 +- test/other/metadce/test_metadce_cxx_ctors2.size | 2 +- test/other/metadce/test_metadce_cxx_except.size | 2 +- test/other/metadce/test_metadce_cxx_except_wasm.size | 2 +- test/other/metadce/test_metadce_cxx_mangle.size | 2 +- test/other/metadce/test_metadce_cxx_noexcept.size | 2 +- test/other/metadce/test_metadce_minimal_pthreads.size | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/test/other/metadce/test_metadce_cxx_ctors1.size b/test/other/metadce/test_metadce_cxx_ctors1.size index 7cb7cf00d785b..c3e6c8e8b8cec 100644 --- a/test/other/metadce/test_metadce_cxx_ctors1.size +++ b/test/other/metadce/test_metadce_cxx_ctors1.size @@ -1 +1 @@ -123479 +123502 diff --git a/test/other/metadce/test_metadce_cxx_ctors2.size b/test/other/metadce/test_metadce_cxx_ctors2.size index 7a2e462123ec6..e9659e9d95013 100644 --- a/test/other/metadce/test_metadce_cxx_ctors2.size +++ b/test/other/metadce/test_metadce_cxx_ctors2.size @@ -1 +1 @@ -123373 +123407 diff --git a/test/other/metadce/test_metadce_cxx_except.size b/test/other/metadce/test_metadce_cxx_except.size index 27e59ea3c5748..75ce5068ec801 100644 --- a/test/other/metadce/test_metadce_cxx_except.size +++ b/test/other/metadce/test_metadce_cxx_except.size @@ -1 +1 @@ -166244 +166271 diff --git a/test/other/metadce/test_metadce_cxx_except_wasm.size b/test/other/metadce/test_metadce_cxx_except_wasm.size index c2edb388c6c10..d1ea9f9b1f5fc 100644 --- a/test/other/metadce/test_metadce_cxx_except_wasm.size +++ b/test/other/metadce/test_metadce_cxx_except_wasm.size @@ -1 +1 @@ -137042 +137069 diff --git a/test/other/metadce/test_metadce_cxx_mangle.size b/test/other/metadce/test_metadce_cxx_mangle.size index d310455c80818..d3ad8dde956d8 100644 --- a/test/other/metadce/test_metadce_cxx_mangle.size +++ b/test/other/metadce/test_metadce_cxx_mangle.size @@ -1 +1 @@ -219418 +221359 diff --git a/test/other/metadce/test_metadce_cxx_noexcept.size b/test/other/metadce/test_metadce_cxx_noexcept.size index b8f5d0b10a39e..04a2ee6190e4b 100644 --- a/test/other/metadce/test_metadce_cxx_noexcept.size +++ b/test/other/metadce/test_metadce_cxx_noexcept.size @@ -1 +1 @@ -126272 +126299 diff --git a/test/other/metadce/test_metadce_minimal_pthreads.size b/test/other/metadce/test_metadce_minimal_pthreads.size index 94f4b0c88daef..a8093fa03841c 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.size +++ b/test/other/metadce/test_metadce_minimal_pthreads.size @@ -1 +1 @@ -19067 +19045 From f711f8c408a084460069b81902290de92e2314bb Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 15 May 2023 16:54:41 -0700 Subject: [PATCH 0245/1523] Add TLS size to allocation in emscripten_malloc_wasm_worker (#19340) This fixes `lsan.test_wasm_worker_hello`. The reason this was failing is that lsan adds about 26k of TLS data which meant that 1024 bytes of total allocation was not nearly enough. Ideally we would fix this for `emscripten_create_wasm_worker` too. We could either do this by saying that the TLS region is always separetly allocated or we could provide some way to for the user to discover the TLS size (i.e. a wrapper around __builtin_wasm_tls_size) so that can add it to their own allocation. --- .../docs/api_reference/wasm_workers.rst | 9 +++-- system/include/emscripten/wasm_worker.h | 10 ++++-- system/lib/wasm_worker/library_wasm_worker.c | 34 +++++++++++-------- .../wasm_worker/library_wasm_worker_stub.c | 4 +-- test/wasm_worker/hello_wasm_worker.c | 2 ++ test/wasm_worker/malloc_wasm_worker.c | 1 + 6 files changed, 38 insertions(+), 22 deletions(-) diff --git a/site/source/docs/api_reference/wasm_workers.rst b/site/source/docs/api_reference/wasm_workers.rst index dd3e27a560428..c8e8fdcc09fb7 100644 --- a/site/source/docs/api_reference/wasm_workers.rst +++ b/site/source/docs/api_reference/wasm_workers.rst @@ -23,7 +23,7 @@ Quick Example int main() { - emscripten_wasm_worker_t worker = emscripten_malloc_wasm_worker(/*stack size: */1024); + emscripten_wasm_worker_t worker = emscripten_malloc_wasm_worker(/*stackSize: */1024); emscripten_wasm_worker_post_function_v(worker, run_in_worker); } @@ -33,8 +33,11 @@ which shares the same WebAssembly.Module and WebAssembly.Memory object. Then a ``postMessage()`` is passed to the Worker to ask it to execute the function ``run_in_worker()`` to print a string. -To explicitly control the memory allocation placement when creating a worker, use the -function ``emscripten_create_wasm_worker()``. +To explicitly control the memory allocation placement when creating a worker, +use the ``emscripten_create_wasm_worker()`` function. This function takes a +region of memory that must be large enough to hold both the stack and the TLS +data for the worker. You can use ``__builtin_wasm_tls_size()`` to find out at +runtime how much space is required for the program's TLS data. Introduction ============ diff --git a/system/include/emscripten/wasm_worker.h b/system/include/emscripten/wasm_worker.h index d9981a8cc126f..f75c48b63df37 100644 --- a/system/include/emscripten/wasm_worker.h +++ b/system/include/emscripten/wasm_worker.h @@ -17,16 +17,20 @@ extern "C" { behaves, the dynamically allocated memory can never be freed, so use this function only in scenarios where the page does not need to deinitialize/tear itself down. - emscripten_create_wasm_worker: Creates a Wasm Worker on given placed stack address. + emscripten_create_wasm_worker: Creates a Wasm Worker given a preallocated region for stack and TLS data. Use this function to manually manage the memory that a Worker should use. This function does not use any dynamic memory allocation. + Unlike with the above function, this variant requires that size of the + region provided is large enough to hold both stack and TLS area. + The size of the TLS area can be determined at runtime by calling + __builtin_wasm_tls_size(). Returns an ID that represents the given Worker. If not building with Wasm workers enabled (-sWASM_WORKERS=0), these functions will return 0 to denote failure. Note that the Worker will be loaded up asynchronously, and initially will not be executing any code. Use emscripten_wasm_worker_post_function_*() set of functions to start executing code on the Worker. */ -emscripten_wasm_worker_t emscripten_malloc_wasm_worker(uint32_t stackSize); -emscripten_wasm_worker_t emscripten_create_wasm_worker(void *stackLowestAddress __attribute__((nonnull)), uint32_t stackSize); +emscripten_wasm_worker_t emscripten_malloc_wasm_worker(size_t stackSize); +emscripten_wasm_worker_t emscripten_create_wasm_worker(void *stackPlusTLSAddress __attribute__((nonnull)), size_t stackPlusTLSSize); // Terminates the given Wasm Worker some time after it has finished executing its current, or possibly some subsequent // posted functions. Note that this function is not C++ RAII safe, but you must manually coordinate to release any diff --git a/system/lib/wasm_worker/library_wasm_worker.c b/system/lib/wasm_worker/library_wasm_worker.c index b0007c6417e8b..2b4bcadcb9ee3 100644 --- a/system/lib/wasm_worker/library_wasm_worker.c +++ b/system/lib/wasm_worker/library_wasm_worker.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include "emscripten_internal.h" @@ -11,6 +12,8 @@ #error __EMSCRIPTEN_WASM_WORKERS__ should be defined when building this file! #endif +#define ROUND_UP(x, ALIGNMENT) (((x)+ALIGNMENT-1)&-ALIGNMENT) + // Options: // #define STACK_OVERFLOW_CHECK 0/1/2 : set to the current stack overflow check mode @@ -22,35 +25,38 @@ static void emscripten_wasm_worker_main_thread_initialize() { assert((*sbrk_ptr & 15) == 0); assert(__builtin_wasm_tls_align() <= 16); __wasm_init_tls((void*)*sbrk_ptr); - *sbrk_ptr += (__builtin_wasm_tls_size() + 15) & -16; + *sbrk_ptr += ROUND_UP(__builtin_wasm_tls_size(), 16); } -emscripten_wasm_worker_t emscripten_create_wasm_worker(void *stackLowestAddress, uint32_t stackSize) +emscripten_wasm_worker_t emscripten_create_wasm_worker(void *stackPlusTLSAddress, size_t stackPlusTLSSize) { - assert(stackLowestAddress != 0); - assert((uintptr_t)stackLowestAddress % 16 == 0); - assert(stackSize > 0); - assert(stackSize % 16 == 0); + assert(stackPlusTLSAddress != 0); + assert((uintptr_t)stackPlusTLSAddress % 16 == 0); + assert(stackPlusTLSSize > 0); + assert(stackPlusTLSSize % 16 == 0); // Guard against a programming oopsie: The target Worker's stack cannot be part of the calling // thread's stack. - assert(emscripten_stack_get_base() <= (uintptr_t)stackLowestAddress || emscripten_stack_get_end() >= (uintptr_t)stackLowestAddress + stackSize + assert(emscripten_stack_get_base() <= (uintptr_t)stackPlusTLSAddress || emscripten_stack_get_end() >= (uintptr_t)stackPlusTLSAddress + stackPlusTLSSize && "When creating a Wasm Worker, its stack should be located either in global data or on the heap, not on the calling thread's own stack!"); - // The Worker's TLS area will be spliced off from the stack region. - // We expect TLS area to need to be at most 16 bytes aligned + // We expect TLS area to need to be at most 16 bytes aligned assert(__builtin_wasm_tls_align() == 0 || 16 % __builtin_wasm_tls_align() == 0); #ifndef NDEBUG - uint32_t tlsSize = (__builtin_wasm_tls_size() + 15) & -16; - assert(stackSize > tlsSize); + // The Worker's TLS area will be spliced off from the stack region, so the + // stack needs to be at least as large as the TLS region. + uint32_t tlsSize = ROUND_UP(__builtin_wasm_tls_size(), 16); + assert(stackPlusTLSSize > tlsSize); #endif - - return _emscripten_create_wasm_worker(stackLowestAddress, stackSize); + return _emscripten_create_wasm_worker(stackPlusTLSAddress, stackPlusTLSSize); } -emscripten_wasm_worker_t emscripten_malloc_wasm_worker(uint32_t stackSize) +emscripten_wasm_worker_t emscripten_malloc_wasm_worker(size_t stackSize) { + // Add the TLS size to the provided stackSize so that the allocation + // will always be large enough to hold the worker TLS data. + stackSize += ROUND_UP(__builtin_wasm_tls_size(), 16); return emscripten_create_wasm_worker(memalign(16, stackSize), stackSize); } diff --git a/system/lib/wasm_worker/library_wasm_worker_stub.c b/system/lib/wasm_worker/library_wasm_worker_stub.c index 8607603d49421..27693fec493eb 100644 --- a/system/lib/wasm_worker/library_wasm_worker_stub.c +++ b/system/lib/wasm_worker/library_wasm_worker_stub.c @@ -8,11 +8,11 @@ #error __EMSCRIPTEN_WASM_WORKERS__ should not be defined when building this file! #endif -emscripten_wasm_worker_t emscripten_create_wasm_worker(void *stackLowestAddress, uint32_t stackSize) { +emscripten_wasm_worker_t emscripten_create_wasm_worker(void *stackPlusTLSAddress, size_t stackPlusTLSSize) { return 0; } -emscripten_wasm_worker_t emscripten_malloc_wasm_worker(uint32_t stackSize) { +emscripten_wasm_worker_t emscripten_malloc_wasm_worker(size_t stackSize) { return 0; } diff --git a/test/wasm_worker/hello_wasm_worker.c b/test/wasm_worker/hello_wasm_worker.c index eeeaba390a950..a0047c0d0af1c 100644 --- a/test/wasm_worker/hello_wasm_worker.c +++ b/test/wasm_worker/hello_wasm_worker.c @@ -1,3 +1,4 @@ +#include #include #include @@ -14,5 +15,6 @@ void run_in_worker() int main() { emscripten_wasm_worker_t worker = emscripten_malloc_wasm_worker(/*stack size: */1024); + assert(worker); emscripten_wasm_worker_post_function_v(worker, run_in_worker); } diff --git a/test/wasm_worker/malloc_wasm_worker.c b/test/wasm_worker/malloc_wasm_worker.c index 0249e6c41dc30..ab7cb0450a8f5 100644 --- a/test/wasm_worker/malloc_wasm_worker.c +++ b/test/wasm_worker/malloc_wasm_worker.c @@ -17,5 +17,6 @@ int main() { assert(!emscripten_current_thread_is_wasm_worker()); emscripten_wasm_worker_t worker = emscripten_malloc_wasm_worker(/*stack size: */1024); + assert(worker); emscripten_wasm_worker_post_function_v(worker, worker_main); } From af60acb87cf3eb184ae220f3f3c640656b9dc7ef Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 16 May 2023 08:39:17 -0700 Subject: [PATCH 0246/1523] Define FILESYSTEM even when WASMFS is defined (#19369) WasmFS already implement a some parts of the wasm JS API so I think it makes since to consider WASMFS and flavor/subset of FILESYSTEM. --- emcc.py | 2 +- src/library_browser.js | 4 +-- src/library_dylink.js | 6 ++--- src/modules.js | 55 +++++++++++++++++++++--------------------- 4 files changed, 34 insertions(+), 33 deletions(-) diff --git a/emcc.py b/emcc.py index 956766473b9e6..da7eda09fbe9c 100755 --- a/emcc.py +++ b/emcc.py @@ -2303,7 +2303,7 @@ def phase_linker_setup(options, state, newargs): if settings.WASMFS: state.forced_stdlibs.append('libwasmfs') - settings.FILESYSTEM = 0 + settings.FILESYSTEM = 1 settings.SYSCALLS_REQUIRE_FILESYSTEM = 0 settings.JS_LIBRARIES.append((0, 'library_wasmfs.js')) settings.REQUIRED_EXPORTS += ['_wasmfs_read_file'] diff --git a/src/library_browser.js b/src/library_browser.js index 9913a93bc720d..e6dafaa36ce24 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -12,7 +12,7 @@ var LibraryBrowser = { '$safeSetTimeout', '$warnOnce', 'emscripten_set_main_loop_timing', -#if FILESYSTEM || WASMFS +#if FILESYSTEM '$preloadPlugins', #if MAIN_MODULE '$preloadedWasm', @@ -107,7 +107,7 @@ var LibraryBrowser = { if (Browser.initted) return; Browser.initted = true; -#if FILESYSTEM || WASMFS +#if FILESYSTEM // Support for plugins that can process preloaded files. You can add more of these to // your app by creating and appending to preloadPlugins. // diff --git a/src/library_dylink.js b/src/library_dylink.js index 97cb60d4ac92e..d96e6b4253af5 100644 --- a/src/library_dylink.js +++ b/src/library_dylink.js @@ -10,7 +10,7 @@ var dlopenMissingError = "'To use dlopen, you need enable dynamic linking, see h var LibraryDylink = { #if RELOCATABLE -#if FILESYSTEM || WASMFS +#if FILESYSTEM $registerWasmPlugin__deps: ['$preloadPlugins'], $registerWasmPlugin: function() { // Use string keys here to avoid minification since the plugin consumer @@ -913,7 +913,7 @@ var LibraryDylink = { $loadDynamicLibrary__deps: ['$LDSO', '$loadWebAssemblyModule', '$isInternalSym', '$mergeLibSymbols', '$newDSO', '$asyncLoad', -#if FILESYSTEM || WASMFS +#if FILESYSTEM '$preloadedWasm', #endif ], @@ -987,7 +987,7 @@ var LibraryDylink = { // libName -> exports function getExports() { -#if FILESYSTEM || WASMFS +#if FILESYSTEM // lookup preloaded cache first if (preloadedWasm[libName]) { #if DYLINK_DEBUG diff --git a/src/modules.js b/src/modules.js index 16f46ecb6b875..02fab14098467 100644 --- a/src/modules.js +++ b/src/modules.js @@ -78,35 +78,36 @@ global.LibraryManager = { } if (FILESYSTEM) { - // Core filesystem libraries (always linked against, unless -sFILESYSTEM=0 is specified) - libraries = libraries.concat([ - 'library_fs_shared.js', - 'library_fs.js', - 'library_memfs.js', - 'library_tty.js', - 'library_pipefs.js', // ok to include it by default since it's only used if the syscall is used - 'library_sockfs.js', // ok to include it by default since it's only used if the syscall is used - ]); - - if (NODERAWFS) { - // NODERAWFS requires NODEFS - if (!JS_LIBRARIES.includes('library_nodefs.js')) { - libraries.push('library_nodefs.js'); + libraries.push('library_fs_shared.js'); + if (WASMFS) { + libraries = libraries.concat([ + 'library_wasmfs.js', + 'library_wasmfs_js_file.js', + 'library_wasmfs_jsimpl.js', + 'library_wasmfs_fetch.js', + 'library_wasmfs_node.js', + 'library_wasmfs_opfs.js', + ]); + } else { + // Core filesystem libraries (always linked against, unless -sFILESYSTEM=0 is specified) + libraries = libraries.concat([ + 'library_fs.js', + 'library_memfs.js', + 'library_tty.js', + 'library_pipefs.js', // ok to include it by default since it's only used if the syscall is used + 'library_sockfs.js', // ok to include it by default since it's only used if the syscall is used + ]); + + if (NODERAWFS) { + // NODERAWFS requires NODEFS + if (!JS_LIBRARIES.includes('library_nodefs.js')) { + libraries.push('library_nodefs.js'); + } + libraries.push('library_noderawfs.js'); + // NODERAWFS overwrites library_path.js + libraries.push('library_nodepath.js'); } - libraries.push('library_noderawfs.js'); - // NODERAWFS overwrites library_path.js - libraries.push('library_nodepath.js'); } - } else if (WASMFS) { - libraries = libraries.concat([ - 'library_fs_shared.js', - 'library_wasmfs.js', - 'library_wasmfs_js_file.js', - 'library_wasmfs_jsimpl.js', - 'library_wasmfs_fetch.js', - 'library_wasmfs_node.js', - 'library_wasmfs_opfs.js', - ]); } // Additional JS libraries (without AUTO_JS_LIBRARIES, link to these explicitly via -lxxx.js) From 5634cfba584d53f5cb3e17f4c32599b5c888897e Mon Sep 17 00:00:00 2001 From: Hood Chatham Date: Tue, 16 May 2023 16:06:18 -0700 Subject: [PATCH 0247/1523] Fix addFunction for js function when WebAssembly.Function is available (#19306) --- src/jsifier.js | 5 ++- src/library_addfunction.js | 17 ++++----- test/test_browser.py | 2 ++ test/test_core.py | 29 --------------- test/test_other.py | 74 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 87 insertions(+), 40 deletions(-) diff --git a/src/jsifier.js b/src/jsifier.js index bd6c5607d3755..06a4e597b8e17 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -453,7 +453,7 @@ function ${name}(${args}) { } contentText = `var ${mangled} = ${snippet};`; } - const sig = LibraryManager.library[symbol + '__sig']; + let sig = LibraryManager.library[symbol + '__sig']; // asm module exports are done in emscripten.py, after the asm module is ready. Here // we also export library methods as necessary. if ((EXPORT_ALL || EXPORTED_FUNCTIONS.has(mangled)) && !isStub) { @@ -465,6 +465,9 @@ function ${name}(${args}) { // TODO: For asyncify we could only add the signatures we actually need, // of async imports/exports. if (sig && (RELOCATABLE || ASYNCIFY == 2)) { + if (!WASM_BIGINT) { + sig = sig[0].replace('j', 'i') + sig.slice(1).replace(/j/g, 'ii'); + } contentText += `\n${mangled}.sig = '${sig}';`; } if (ASYNCIFY && isAsyncFunction) { diff --git a/src/library_addfunction.js b/src/library_addfunction.js index 24ebe48afcca6..c02ecda6050fc 100644 --- a/src/library_addfunction.js +++ b/src/library_addfunction.js @@ -21,14 +21,12 @@ mergeInto(LibraryManager.library, { // Converts a signature like 'vii' into a description of the wasm types, like // { parameters: ['i32', 'i32'], results: [] }. $sigToWasmTypes: function(sig) { +#if ASSERTIONS && !WASM_BIGINT + assert(!sig.includes('j'), 'i64 not permitted in function signatures when WASM_BIGINT is disabled'); +#endif var typeNames = { 'i': 'i32', -#if MEMORY64 'j': 'i64', -#else - // i64 values will be split into two i32s. - 'j': 'i32', -#endif 'f': 'f32', 'd': 'f64', #if MEMORY64 @@ -46,11 +44,6 @@ mergeInto(LibraryManager.library, { assert(sig[i] in typeNames, 'invalid signature char: ' + sig[i]); #endif type.parameters.push(typeNames[sig[i]]); -#if !MEMORY64 - if (sig[i] === 'j') { - type.parameters.push('i32'); - } -#endif } return type; }, @@ -95,6 +88,10 @@ mergeInto(LibraryManager.library, { // return func; #else // WASM2JS +#if ASSERTIONS && !WASM_BIGINT + assert(!sig.includes('j'), 'i64 not permitted in function signatures when WASM_BIGINT is disabled'); +#endif + // If the type reflection proposal is available, use the new // "WebAssembly.Function" constructor. // Otherwise, construct a minimal wasm module importing the JS function and diff --git a/test/test_browser.py b/test/test_browser.py index 71c8914e50301..13e34f5ed7669 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -3353,6 +3353,7 @@ def test_cocos2d_hello(self): @parameterized({ 'asyncify': (['-sASYNCIFY=1'],), 'jspi': (['-sASYNCIFY=2', '-Wno-experimental'],), + 'jspi_wasm_bigint': (['-sASYNCIFY=2', '-sWASM_BIGINT', '-Wno-experimental'],), }) def test_async(self, args): if is_jspi(args) and not is_chrome(): @@ -5443,6 +5444,7 @@ def test_wasmfs_fetch_backend(self, args): @parameterized({ '': (['-pthread', '-sPROXY_TO_PTHREAD'],), 'jspi': (['-Wno-experimental', '-sASYNCIFY=2'],), + 'jspi_wasm_bigint': (['-Wno-experimental', '-sASYNCIFY=2', '-sWASM_BIGINT'],), }) @requires_threads def test_wasmfs_opfs(self, args): diff --git a/test/test_core.py b/test/test_core.py index 7d0d2226e6d7d..e43c5bc475ea0 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -7402,35 +7402,6 @@ def test_large_exported_response(self): self.do_run(src, 'waka 4999!') self.assertContained('_exported_func_from_response_file_1', read_file('src.js')) - def test_add_function(self): - self.set_setting('INVOKE_RUN', 0) - self.set_setting('WASM_ASYNC_COMPILATION', 0) - self.set_setting('ALLOW_TABLE_GROWTH') - self.set_setting('EXPORTED_RUNTIME_METHODS', ['callMain']) - self.emcc_args += ['--post-js', test_file('interop/test_add_function_post.js')] - - print('basics') - self.do_run_in_out_file_test('interop/test_add_function.cpp') - - print('with ALLOW_TABLE_GROWTH=0') - self.set_setting('ALLOW_TABLE_GROWTH', 0) - expected = 'Unable to grow wasm table' - if self.is_wasm2js(): - # in wasm2js the error message doesn't come from the VM, but from our - # emulation code. when ASSERTIONS are enabled we show a clear message, but - # in optimized builds we don't waste code size on that, and the JS engine - # shows a generic error. - expected = 'wasmTable.grow is not a function' - - self.do_runf(test_file('interop/test_add_function.cpp'), expected, assert_returncode=NON_ZERO) - - print('- with table growth') - self.set_setting('ALLOW_TABLE_GROWTH') - self.emcc_args += ['-DGROWTH'] - # enable costly assertions to verify correct table behavior - self.set_setting('ASSERTIONS', 2) - self.do_run_in_out_file_test('interop/test_add_function.cpp', interleaved_output=False) - def test_emulate_function_pointer_casts(self): # Forcibly disable EXIT_RUNTIME due to: # https://github.com/emscripten-core/emscripten/issues/15081 diff --git a/test/test_other.py b/test/test_other.py index 4db28ef8df22d..dabbe1588360c 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -13411,6 +13411,80 @@ def test_windows_batch_file_dp0_expansion_bug(self): create_file('build_with_quotes.bat', f'@"emcc" {test_file("hello_world.c")}') self.run_process(['build_with_quotes.bat']) + @parameterized({ + 'wasm2js': (True,), + '': (False,) + }) + def test_add_js_function(self, wasm2js): + self.set_setting('INVOKE_RUN', 0) + self.set_setting('WASM_ASYNC_COMPILATION', 0) + self.set_setting('ALLOW_TABLE_GROWTH') + self.set_setting('EXPORTED_RUNTIME_METHODS', ['callMain']) + if wasm2js: + self.set_setting('WASM', 0) + self.emcc_args += ['--post-js', test_file('interop/test_add_function_post.js')] + + print('basics') + self.do_run_in_out_file_test('interop/test_add_function.cpp') + + print('with ALLOW_TABLE_GROWTH=0') + self.set_setting('ALLOW_TABLE_GROWTH', 0) + expected = 'Unable to grow wasm table' + if wasm2js: + # in wasm2js the error message doesn't come from the VM, but from our + # emulation code. when ASSERTIONS are enabled we show a clear message, but + # in optimized builds we don't waste code size on that, and the JS engine + # shows a generic error. + expected = 'wasmTable.grow is not a function' + + self.do_runf(test_file('interop/test_add_function.cpp'), expected, assert_returncode=NON_ZERO) + + print('- with table growth') + self.set_setting('ALLOW_TABLE_GROWTH') + self.emcc_args += ['-DGROWTH'] + # enable costly assertions to verify correct table behavior + self.set_setting('ASSERTIONS', 2) + self.do_run_in_out_file_test('interop/test_add_function.cpp', interleaved_output=False) + + @parameterized({ + 'memory64_wasm_function': (True, True), + 'wasm_function': (False, True), + 'memory64': (True, False), + '': (False, False) + }) + @requires_v8 + def test_add_js_function_bigint(self, memory64, wasm_function): + self.set_setting('WASM_BIGINT') + + if memory64: + self.require_wasm64() + + if not wasm_function: + create_file('pre.js', 'delete WebAssembly.Function;') + self.emcc_args.append('--pre-js=pre.js') + + self.set_setting('ALLOW_TABLE_GROWTH') + create_file('main.c', r''' + #include + #include + + EM_JS_DEPS(deps, "$addFunction"); + + typedef long long (functype)(long long); + + int main() { + functype* f = (functype *)EM_ASM_INT({ + return addFunction((num) => { + return num + 4294967296n; + }, 'jj'); + }); + assert(f(26) == 26 + 4294967296); + assert(f(493921253191) == 493921253191 + 4294967296); + } + ''') + + self.do_runf('main.c', '') + @parameterized({ '': ([],), 'pthread': (['-g', '-pthread', '-Wno-experimental', '-sPROXY_TO_PTHREAD', '-sEXIT_RUNTIME'],), From dd4fbbee451e435c7ffbfd48f3f1c3fb6e2ab47c Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 16 May 2023 16:43:45 -0700 Subject: [PATCH 0248/1523] Enable `optimize_syscalls` when `MAIN_MODULE=2`. NFC (#19370) With `MAIN_MODULE=1` we cannot disable `SYSCALLS_REQUIRE_FILESYSTEM` since the side modules might depend on these syscalls. However we `MAIN_MODULE=2` we have a complete view of the side module imports so we can. --- emscripten.py | 15 +++++++++------ .../metadce/test_metadce_hello_dylink.jssize | 2 +- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/emscripten.py b/emscripten.py index 16b5c28481354..c134ce818c5c8 100644 --- a/emscripten.py +++ b/emscripten.py @@ -60,17 +60,18 @@ def write_output_file(outfile, module): outfile.write(module[i]) -def optimize_syscalls(declares): +def maybe_disable_filesystem(imports): """Disables filesystem if only a limited subset of syscalls is used. Our syscalls are static, and so if we see a very limited set of them - in particular, no open() syscall and just simple writing - then we don't need full filesystem support. If FORCE_FILESYSTEM is set, we can't do this. We also don't do it if INCLUDE_FULL_LIBRARY, since not including the filesystem would mean not including the full JS libraries, and the same for - MAIN_MODULE since a side module might need the filesystem. + MAIN_MODULE=1 since a side module might need the filesystem. """ - relevant_settings = ['FORCE_FILESYSTEM', 'INCLUDE_FULL_LIBRARY', 'MAIN_MODULE'] - if any(settings[s] for s in relevant_settings): + if any(settings[s] for s in ['FORCE_FILESYSTEM', 'INCLUDE_FULL_LIBRARY']): + return + if settings.MAIN_MODULE == 1: return if settings.FILESYSTEM == 0: @@ -79,7 +80,9 @@ def optimize_syscalls(declares): else: # TODO(sbc): Find a better way to identify wasi syscalls syscall_prefixes = ('__syscall_', 'fd_') - syscalls = {d for d in declares if d.startswith(syscall_prefixes) or d in ['path_open']} + side_module_imports = [shared.demangle_c_symbol_name(s) for s in settings.SIDE_MODULE_IMPORTS] + all_imports = set(imports).union(side_module_imports) + syscalls = {d for d in all_imports if d.startswith(syscall_prefixes) or d in ['path_open']} # check if the only filesystem syscalls are in: close, ioctl, llseek, write # (without open, etc.. nothing substantial can be done, so we can disable # extra filesystem support in that case) @@ -116,7 +119,7 @@ def get_weak_imports(main_wasm): def update_settings_glue(wasm_file, metadata): - optimize_syscalls(metadata.imports) + maybe_disable_filesystem(metadata.imports) # Integrate info from backend if settings.SIDE_MODULE: diff --git a/test/other/metadce/test_metadce_hello_dylink.jssize b/test/other/metadce/test_metadce_hello_dylink.jssize index 28a6cab7467e1..1a27139cbd9fd 100644 --- a/test/other/metadce/test_metadce_hello_dylink.jssize +++ b/test/other/metadce/test_metadce_hello_dylink.jssize @@ -1 +1 @@ -28024 +15091 From 0dd96b01260c053a6b33cfb7f04ff854eb9b779d Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 16 May 2023 17:02:08 -0700 Subject: [PATCH 0249/1523] Keep DSO file data around after dlsync. NFC (#19378) Its not generally safe to free this data because some threads might have been alseep when the dlsync occurred. In these cases they need to be able to catchup/sync when they wake at some point in the future. This also happens to fix the issue where new threads that get created after the dlopen didn't have access to the file data. The downside is that, for now, we leak the file data for DSOs that get loaded. Fixes: #19371 --- system/lib/libc/dynlink.c | 8 ++++---- test/core/pthread/test_pthread_dlopen.c | 14 +++++++++++++- test/test_core.py | 1 + 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/system/lib/libc/dynlink.c b/system/lib/libc/dynlink.c index bfb8416a1204d..c3e421b417a22 100644 --- a/system/lib/libc/dynlink.c +++ b/system/lib/libc/dynlink.c @@ -163,10 +163,10 @@ static void load_library_done(struct dso* p) { // Block until all other threads have loaded this module. dlsync(); #endif - if (p->file_data) { - free(p->file_data); - p->file_data_size = 0; - } + // TODO: figure out some way to tell when its safe to free p->file_data. Its + // not safe to do here because some threads could have been alseep then when + // the "dlsync" occurred and those threads will synchronize when they wake, + // which could be an arbitrarily long time in the future. } static struct dso* load_library_start(const char* name, int flags) { diff --git a/test/core/pthread/test_pthread_dlopen.c b/test/core/pthread/test_pthread_dlopen.c index 9613d02f39378..78ca23454c8c4 100644 --- a/test/core/pthread/test_pthread_dlopen.c +++ b/test/core/pthread/test_pthread_dlopen.c @@ -52,7 +52,7 @@ int main() { while (!started) {} printf("loading dylib\n"); - void* handle = dlopen("liblib.so", RTLD_NOW|RTLD_GLOBAL); + void* handle = dlopen("libside.so", RTLD_NOW|RTLD_GLOBAL); if (!handle) { printf("dlerror: %s\n", dlerror()); } @@ -78,6 +78,18 @@ int main() { assert(rc == 0); printf("done join\n"); + printf("starting second & third thread\n"); + pthread_t t2, t3; + rc = pthread_create(&t2, NULL, thread_main, NULL); + assert(rc == 0); + rc = pthread_create(&t3, NULL, thread_main, NULL); + assert(rc == 0); + rc = pthread_join(t2, NULL); + assert(rc == 0); + rc = pthread_join(t3, NULL); + assert(rc == 0); + printf("starting second & third thread\n"); + dlclose(handle); return 0; } diff --git a/test/test_core.py b/test/test_core.py index e43c5bc475ea0..64afa541b9144 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -9429,6 +9429,7 @@ def test_pthread_dlopen(self): self.emcc_args += ['-Wno-experimental', '-pthread'] self.build_dlfcn_lib(test_file('core/pthread/test_pthread_dlopen_side.c')) + self.emcc_args += ['--embed-file', 'liblib.so@libside.so'] self.prep_dlfcn_main() self.set_setting('EXIT_RUNTIME') self.set_setting('PROXY_TO_PTHREAD') From 89c293298de428100ab902d00130f3d491fe1bb8 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 16 May 2023 20:22:12 -0700 Subject: [PATCH 0250/1523] Add automatic dependency on setTempRet0 for i64-returning functions. NFC (#19377) --- emcc.py | 11 ++--------- src/jsifier.js | 10 ++++++++-- src/library_autodebug.js | 4 ++++ src/library_makeDynCall.js | 2 +- test/core/js_library_i64_params.js | 2 +- test/other/metadce/test_metadce_cxx_except.exports | 1 - test/other/metadce/test_metadce_cxx_except.size | 2 +- test/other/metadce/test_metadce_cxx_mangle.exports | 1 - test/other/metadce/test_metadce_cxx_mangle.size | 2 +- test/test_core.py | 1 - tools/building.py | 5 ++++- tools/gen_sig_info.py | 2 ++ 12 files changed, 24 insertions(+), 19 deletions(-) diff --git a/emcc.py b/emcc.py index da7eda09fbe9c..e686c9e722521 100755 --- a/emcc.py +++ b/emcc.py @@ -2589,15 +2589,8 @@ def check_memory_setting(setting): elif options.memory_init_file: diagnostics.warning('unsupported', '--memory-init-file is only supported with -sWASM=0') - if ( - settings.MAYBE_WASM2JS or - settings.AUTODEBUG or - settings.LINKABLE or - settings.INCLUDE_FULL_LIBRARY or - not settings.DISABLE_EXCEPTION_CATCHING or - (settings.MAIN_MODULE == 1 and (settings.DYNCALLS or not settings.WASM_BIGINT)) - ): - settings.REQUIRED_EXPORTS += ["getTempRet0", "setTempRet0"] + if settings.AUTODEBUG: + settings.REQUIRED_EXPORTS += ['setTempRet0'] if settings.LEGALIZE_JS_FFI: settings.REQUIRED_EXPORTS += ['__get_temp_ret', '__set_temp_ret'] diff --git a/src/jsifier.js b/src/jsifier.js index 06a4e597b8e17..af7fe2ec9fdf2 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -265,6 +265,13 @@ function ${name}(${args}) { } const deps = LibraryManager.library[symbol + '__deps'] || []; + let sig = LibraryManager.library[symbol + '__sig']; + if (!WASM_BIGINT && sig && sig[0] == 'j') { + // Without WASM_BIGINT functions that return i64 depend on setTempRet0 + // to return the upper 32-bits of the result. + // See makeReturn64 in parseTools.py. + deps.push('setTempRet0'); + } let isAsyncFunction = false; if (ASYNCIFY) { @@ -279,7 +286,7 @@ function ${name}(${args}) { } if (symbolsOnly) { - if (!isJsOnlySymbol(symbol) && LibraryManager.library.hasOwnProperty(symbol)) { + if (LibraryManager.library.hasOwnProperty(symbol)) { var value = LibraryManager.library[symbol]; var resolvedSymbol = symbol; // Resolve aliases before looking up deps @@ -453,7 +460,6 @@ function ${name}(${args}) { } contentText = `var ${mangled} = ${snippet};`; } - let sig = LibraryManager.library[symbol + '__sig']; // asm module exports are done in emscripten.py, after the asm module is ready. Here // we also export library methods as necessary. if ((EXPORT_ALL || EXPORTED_FUNCTIONS.has(mangled)) && !isStub) { diff --git a/src/library_autodebug.js b/src/library_autodebug.js index 042c11a21fcdf..fa53d92d3e99a 100644 --- a/src/library_autodebug.js +++ b/src/library_autodebug.js @@ -17,6 +17,7 @@ mergeInto(LibraryManager.library, { out('get_i32 ' + [loc, index, value]); return value; }, + $get_i64__deps: ['setTempRet0'], $get_i64: function(loc, index, low, high) { out('get_i64 ' + [loc, index, low, high]); setTempRet0(high); @@ -42,6 +43,7 @@ mergeInto(LibraryManager.library, { out('set_i32 ' + [loc, index, value]); return value; }, + $set_i64__deps: ['setTempRet0'], $set_i64: function(loc, index, low, high) { out('set_i64 ' + [loc, index, low, high]); setTempRet0(high); @@ -71,6 +73,7 @@ mergeInto(LibraryManager.library, { out('load_val_i32 ' + [loc, value]); return value; }, + $load_val_i64__deps: ['setTempRet0'], $load_val_i64: function(loc, low, high) { out('load_val_i64 ' + [loc, low, high]); setTempRet0(high); @@ -92,6 +95,7 @@ mergeInto(LibraryManager.library, { out('store_val_i32 ' + [loc, value]); return value; }, + $store_val_i64__deps: ['setTempRet0'], $store_val_i64: function(loc, low, high) { out('store_val_i64 ' + [loc, low, high]); setTempRet0(high); diff --git a/src/library_makeDynCall.js b/src/library_makeDynCall.js index 9e193013d0884..090993bc15925 100644 --- a/src/library_makeDynCall.js +++ b/src/library_makeDynCall.js @@ -5,7 +5,7 @@ */ mergeInto(LibraryManager.library, { - $createDyncallWrapper__deps: ['$generateFuncType', '$uleb128Encode'], + $createDyncallWrapper__deps: ['$generateFuncType', '$uleb128Encode', 'setTempRet0'], $createDyncallWrapper: function(sig) { var sections = []; var prelude = [ diff --git a/test/core/js_library_i64_params.js b/test/core/js_library_i64_params.js index 9d2150264334d..28a00cf1174df 100644 --- a/test/core/js_library_i64_params.js +++ b/test/core/js_library_i64_params.js @@ -1,6 +1,6 @@ TestLibrary = { jscall__deps: i53ConversionDeps, - jscall__sig: 'ij', + jscall__sig: 'jj', jscall: function({{{ defineI64Param('foo') }}}) { {{{ receiveI64ParamAsI53('foo', `(err('overflow'), ${makeReturn64('42')})`) }}} err('js:got: ' + foo); diff --git a/test/other/metadce/test_metadce_cxx_except.exports b/test/other/metadce/test_metadce_cxx_except.exports index 0697b34554a59..111e5eecfa084 100644 --- a/test/other/metadce/test_metadce_cxx_except.exports +++ b/test/other/metadce/test_metadce_cxx_except.exports @@ -12,7 +12,6 @@ dynCall_iiiiijj dynCall_jiiii dynCall_jiji dynCall_viijii -getTempRet0 main memory setTempRet0 diff --git a/test/other/metadce/test_metadce_cxx_except.size b/test/other/metadce/test_metadce_cxx_except.size index 75ce5068ec801..eec7f48731c08 100644 --- a/test/other/metadce/test_metadce_cxx_except.size +++ b/test/other/metadce/test_metadce_cxx_except.size @@ -1 +1 @@ -166271 +166245 diff --git a/test/other/metadce/test_metadce_cxx_mangle.exports b/test/other/metadce/test_metadce_cxx_mangle.exports index 33a07671bf2f2..bc4f56310af76 100644 --- a/test/other/metadce/test_metadce_cxx_mangle.exports +++ b/test/other/metadce/test_metadce_cxx_mangle.exports @@ -14,7 +14,6 @@ dynCall_jiiii dynCall_jiji dynCall_viijii free -getTempRet0 main memory setTempRet0 diff --git a/test/other/metadce/test_metadce_cxx_mangle.size b/test/other/metadce/test_metadce_cxx_mangle.size index d3ad8dde956d8..2c79ee8cab573 100644 --- a/test/other/metadce/test_metadce_cxx_mangle.size +++ b/test/other/metadce/test_metadce_cxx_mangle.size @@ -1 +1 @@ -221359 +221332 diff --git a/test/test_core.py b/test/test_core.py index 64afa541b9144..256d899c73c37 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -9704,7 +9704,6 @@ def test_syscall_intercept(self): def test_js_library_i64_params(self): # Tests the defineI64Param and receiveI64ParamAsI53 helpers that are # used to recieve i64 argument in syscalls. - self.set_setting('EXPORTED_RUNTIME_METHODS', ['setTempRet0']) self.emcc_args += ['--js-library=' + test_file('core/js_library_i64_params.js')] self.do_core_test('js_library_i64_params.c') diff --git a/tools/building.py b/tools/building.py index 6a8749459aa51..7b37bb181973d 100644 --- a/tools/building.py +++ b/tools/building.py @@ -135,7 +135,8 @@ def create_stub_object(external_symbols): stubfile = shared.get_temp_files().get('libemscripten_js_symbols.so').name stubs = ['#STUB'] for name, deps in external_symbols.items(): - stubs.append('%s: %s' % (name, ','.join(deps))) + if not name.startswith('$'): + stubs.append('%s: %s' % (name, ','.join(deps))) utils.write_file(stubfile, '\n'.join(stubs)) return stubfile @@ -144,6 +145,8 @@ def lld_flags_for_executable(external_symbols): cmd = [] if external_symbols: if settings.INCLUDE_FULL_LIBRARY: + # When INCLUDE_FULL_LIBRARY is set try to export every possible + # native dependency of a JS function. all_deps = set() for deps in external_symbols.values(): for dep in deps: diff --git a/tools/gen_sig_info.py b/tools/gen_sig_info.py index a85bfcf72f942..f281212252ded 100755 --- a/tools/gen_sig_info.py +++ b/tools/gen_sig_info.py @@ -152,6 +152,8 @@ def ignore_symbol(s, cxx): + if s.startswith('$'): + return True if s in {'SDL_GetKeyState'}: return True if s.startswith('emscripten_gl') or s.startswith('emscripten_alc'): From 400a1f67f921a721ffa9e279a30b48b6ac2b7ce0 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 17 May 2023 09:05:05 -0700 Subject: [PATCH 0251/1523] Remove WASM2C option (#19380) This was very useful for me personally in exploring the options in the wasm2c space, and in benchmarking in particular, for: https://kripken.github.io/blog/wasm/2020/07/27/wasmboxc.html At this time, however, all known users of wasm2c are using upstream wasm2c from wabt directly. And the benefits of emscripten's integration are diminishing as features like wasm-EH remove the need for emscripten-EH (which wasm2c supported here). So we might as well remove this option to get rid of the complexity, since this is already quite behind upstream wasm2c, and the work to update it is not trival, and not worth it given the lack of users. --- ChangeLog.md | 2 + emcc.py | 13 -- package-lock.json | 13 +- package.json | 3 +- src/settings.js | 19 --- test/common.py | 9 - test/test_benchmark.py | 42 ----- test/test_core.py | 42 +---- test/test_other.py | 44 ----- tools/wasm2c.py | 238 -------------------------- tools/wasm2c/autodebug.c | 87 ---------- tools/wasm2c/base.c | 154 ----------------- tools/wasm2c/main.c | 42 ----- tools/wasm2c/os.c | 321 ------------------------------------ tools/wasm2c/os_sandboxed.c | 22 --- tools/wasm2c/reactor.c | 14 -- 16 files changed, 9 insertions(+), 1056 deletions(-) delete mode 100644 tools/wasm2c.py delete mode 100644 tools/wasm2c/autodebug.c delete mode 100644 tools/wasm2c/base.c delete mode 100644 tools/wasm2c/main.c delete mode 100644 tools/wasm2c/os.c delete mode 100644 tools/wasm2c/os_sandboxed.c delete mode 100644 tools/wasm2c/reactor.c diff --git a/ChangeLog.md b/ChangeLog.md index ccb562f546241..0f75f60afbd22 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -23,6 +23,8 @@ See docs/process.md for more on how version tagging works. - The JS `err()` function will now bind to `console.error` by default rather than `console.warning`. For debugging/tracing/logging we recommend the `dbg()` function instead. (#19326) +- The `WASM2C` options has been removed. All known users are using upstream wabt + these days anyhow. 3.1.38 - 05/10/23 ----------------- diff --git a/emcc.py b/emcc.py index e686c9e722521..d02b5276873d2 100755 --- a/emcc.py +++ b/emcc.py @@ -51,7 +51,6 @@ import tools.line_endings from tools import feature_matrix from tools import js_manipulation -from tools import wasm2c from tools import webassembly from tools import config from tools import cache @@ -1898,15 +1897,6 @@ def phase_linker_setup(options, state, newargs): settings.STANDALONE_WASM = 1 settings.WASM_BIGINT = 1 - if settings.WASM2C: - # wasm2c only makes sense with standalone wasm - there will be no JS, - # just wasm and then C - settings.STANDALONE_WASM = 1 - # wasm2c doesn't need any special handling of i64, we have proper i64 - # handling on the FFI boundary, which is exactly like the case of JS with - # BigInt support - settings.WASM_BIGINT = 1 - if options.no_entry: settings.EXPECT_MAIN = 0 elif settings.STANDALONE_WASM: @@ -3803,9 +3793,6 @@ def preprocess_wasm2js_script(): if settings.DEBUG_LEVEL >= 3 and settings.SEPARATE_DWARF and os.path.exists(wasm_target): building.emit_debug_on_side(wasm_target) - if settings.WASM2C: - wasm2c.do_wasm2c(wasm_target) - # we have finished emitting the wasm, and so intermediate debug info will # definitely no longer be used tracking it. if debug_info: diff --git a/package-lock.json b/package-lock.json index 99b7251aee988..d6cc3984e50e8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,8 +7,7 @@ "dependencies": { "acorn": "^8.7.1", "google-closure-compiler": "20220502.0.0", - "html-minifier-terser": "7.2.0", - "wasm2c": "1.0.0" + "html-minifier-terser": "7.2.0" }, "devDependencies": { "es-check": "^6.2.1", @@ -3174,11 +3173,6 @@ "node": ">=0.10.0" } }, - "node_modules/wasm2c": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wasm2c/-/wasm2c-1.0.0.tgz", - "integrity": "sha512-4SIESF2JNxrry6XFa/UQcsQibn+bxPkQ/oqixiXz2o8fsMl8J4vtvhH/evgbi8vZajAlaukuihEcQTWb9tVLUA==" - }, "node_modules/watchpack": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", @@ -5984,11 +5978,6 @@ } } }, - "wasm2c": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wasm2c/-/wasm2c-1.0.0.tgz", - "integrity": "sha512-4SIESF2JNxrry6XFa/UQcsQibn+bxPkQ/oqixiXz2o8fsMl8J4vtvhH/evgbi8vZajAlaukuihEcQTWb9tVLUA==" - }, "watchpack": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", diff --git a/package.json b/package.json index b1673d47885f2..ab701d4615772 100644 --- a/package.json +++ b/package.json @@ -13,8 +13,7 @@ "dependencies": { "acorn": "^8.7.1", "google-closure-compiler": "20220502.0.0", - "html-minifier-terser": "7.2.0", - "wasm2c": "1.0.0" + "html-minifier-terser": "7.2.0" }, "scripts": { "lint": "eslint .", diff --git a/src/settings.js b/src/settings.js index f93140d04c4e3..cd78d210233b5 100644 --- a/src/settings.js +++ b/src/settings.js @@ -1933,25 +1933,6 @@ var DEFAULT_TO_CXX = true; // [link] var PRINTF_LONG_DOUBLE = false; -// Run wabt's wasm2c tool on the final wasm, and combine that with a C runtime, -// resulting in a .c file that you can compile with a C compiler to get a -// native executable that works the same as the normal js+wasm. This will also -// emit the wasm2c .h file. The output filenames will be X.wasm.c, X.wasm.h -// if your output is X.js or X.wasm (note the added .wasm. we make sure to emit, -// which avoids trampling a C file). -// [link] -// [experimental] -var WASM2C = false; - -// Experimental sandboxing mode, see -// https://kripken.github.io/blog/wasm/2020/07/27/wasmboxc.html -// -// * full: Normal full wasm2c sandboxing. This uses a signal handler if it can. -// * mask: Masks loads and stores. -// * none: No sandboxing at all. -// [experimental] -var WASM2C_SANDBOXING = 'full'; - // Setting this affects the path emitted in the wasm that refers to the DWARF // file, in -gseparate-dwarf mode. This allows the debugging file to be hosted // in a custom location. diff --git a/test/common.py b/test/common.py index 67313a03499be..b23c88c4e7edc 100644 --- a/test/common.py +++ b/test/common.py @@ -1383,15 +1383,6 @@ def _build_and_run(self, filename, expected_output, args=None, output_nicerizer= if not self.wasm_engines: logger.warning('no wasm engine was found to run the standalone part of this test') engines += self.wasm_engines - if self.get_setting('WASM2C') and not EMTEST_LACKS_NATIVE_CLANG: - # compile the c file to a native executable. - c = shared.replace_suffix(js_file, '.wasm.c') - executable = shared.replace_suffix(js_file, '.exe') - cmd = [shared.CLANG_CC, c, '-o', executable] + clang_native.get_clang_native_args() - self.run_process(cmd, env=clang_native.get_clang_native_env()) - # we can now run the executable directly, without an engine, which - # we indicate with None as the engine - engines += [[None]] if len(engines) == 0: self.skipTest('No JS engine present to run this test with. Check %s and the paths therein.' % config.EM_CONFIG) for engine in engines: diff --git a/test/test_benchmark.py b/test/test_benchmark.py index 6d8618725af9c..44f7080dd73eb 100644 --- a/test/test_benchmark.py +++ b/test/test_benchmark.py @@ -244,47 +244,6 @@ def get_output_files(self): return ret -class EmscriptenWasm2CBenchmarker(EmscriptenBenchmarker): - def __init__(self, name): - super().__init__(name, 'no engine needed') - - def build(self, parent, filename, args, shared_args, emcc_args, native_args, native_exec, lib_builder, has_output_parser): - # wasm2c doesn't want minimal runtime which the normal emscripten - # benchmarker defaults to, as we don't have any JS anyhow - emcc_args = emcc_args + [ - '-sSTANDALONE_WASM', - '-sMINIMAL_RUNTIME=0', - '-sWASM2C' - ] - - global LLVM_FEATURE_FLAGS - old_flags = LLVM_FEATURE_FLAGS - try: - # wasm2c does not support anything beyond MVP - LLVM_FEATURE_FLAGS = [] - super().build(parent, filename, args, shared_args, emcc_args, native_args, native_exec, lib_builder, has_output_parser) - finally: - LLVM_FEATURE_FLAGS = old_flags - - # move the JS away so there is no chance we run it by mistake - shutil.move(self.filename, self.filename + '.old.js') - - c = shared.replace_suffix(self.filenmame, '.wasm.c') - native = shared.replace_suffix(self.filenmame, '.exe') - - run_process(['clang', c, '-o', native, OPTIMIZATIONS, '-lm', - '-DWASM_RT_MAX_CALL_STACK_DEPTH=8000']) # for havlak - - self.filename = native - - def run(self, args): - return run_process([self.filename] + args, stdout=PIPE, stderr=PIPE, check=False).stdout - - def get_output_files(self): - # return the native code. c size may also be interesting. - return [self.filename] - - CHEERP_BIN = '/opt/cheerp/bin/' @@ -375,7 +334,6 @@ def get_output_files(self): EmscriptenBenchmarker(default_v8_name, aot_v8), EmscriptenBenchmarker(default_v8_name + '-lto', aot_v8, ['-flto']), EmscriptenBenchmarker(default_v8_name + '-ctors', aot_v8, ['-sEVAL_CTORS']), - # EmscriptenWasm2CBenchmarker('wasm2c') ] if os.path.exists(CHEERP_BIN): benchmarkers += [ diff --git a/test/test_core.py b/test/test_core.py index 256d899c73c37..5481e965b48c8 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -154,11 +154,6 @@ def metafunc(self, rawfs): return metafunc -def can_do_wasm2c(self): - # the npm version of wasm2c does not support MEMORY64 - return not self.get_setting('MEMORY64') - - def can_do_standalone(self, impure=False): # Pure standalone engines don't support MEMORY64 yet. Even with MEMORY64=2 (lowered) # the WASI APIs that take pointer values don't have 64-bit variants yet. @@ -202,7 +197,7 @@ def decorated(self): # Impure means a test that cannot run in a wasm VM yet, as it is not 100% # standalone. We can still run them with the JS code though. -def also_with_standalone_wasm(wasm2c=False, impure=False): +def also_with_standalone_wasm(impure=False): def decorated(func): def metafunc(self, standalone): if not standalone: @@ -221,11 +216,6 @@ def metafunc(self, standalone): self.wasm_engines = [] self.node_args += shared.node_bigint_flags() func(self) - if wasm2c and can_do_wasm2c(self): - print('wasm2c') - self.set_setting('WASM2C') - self.wasm_engines = [] - func(self) metafunc._parameterize = {'': (False,), 'standalone': (True,)} @@ -610,7 +600,7 @@ def test_cube2md5(self): shutil.copyfile(test_file('cube2md5.txt'), 'cube2md5.txt') self.do_run_from_file(test_file('cube2md5.cpp'), test_file('cube2md5.ok'), assert_returncode=NON_ZERO) - @also_with_standalone_wasm(wasm2c=True) + @also_with_standalone_wasm() @needs_make('make') def test_cube2hash(self): # A good test of i64 math @@ -1089,7 +1079,7 @@ def test_regex(self): self.do_core_test('test_regex.c') @crossplatform - @also_with_standalone_wasm(wasm2c=True, impure=True) + @also_with_standalone_wasm(impure=True) def test_longjmp_standalone(self): self.do_core_test('test_longjmp.c') @@ -6304,7 +6294,7 @@ def test_unistd_misc(self, fs): self.emcc_args += ['-lnodefs.js'] self.do_run_in_out_file_test('unistd/misc.c', interleaved_output=False) - @also_with_standalone_wasm(wasm2c=True) + @also_with_standalone_wasm() def test_posixtime(self): self.do_core_test('test_posixtime.c') @@ -7122,7 +7112,7 @@ def do_test(): else: do_test_openjpeg() - @also_with_standalone_wasm(wasm2c=True, impure=True) + @also_with_standalone_wasm(impure=True) @no_asan('autodebug logging interferes with asan') @with_env_modify({'EMCC_AUTODEBUG': '1'}) def test_autodebug_wasm(self): @@ -7134,28 +7124,6 @@ def test_autodebug_wasm(self): for msg in ['log_execution', 'get_i32', 'set_i32', 'load_ptr', 'load_val', 'store_ptr', 'store_val']: self.assertIn(msg, output) - @parameterized({ - 'full': ('full',), - 'mask': ('mask',), - 'none': ('none',), - }) - def test_wasm2c_sandboxing(self, mode): - if self.get_setting('WASMFS'): - # wasm2c disables JS legalization since we are building in standalone - # mode. this happens to work without wasmfs, but with wasmfs we get the - # time when we create/update a file, which uses clock_time_get that has an - # i64 param. For such an import to work we need wasm-bigint support. - self.node_args += shared.node_bigint_flags() - if not can_do_standalone(self): - return self.skipTest('standalone mode not supported') - if not can_do_wasm2c(self): - return self.skipTest('wasm2c not supported') - self.set_setting('STANDALONE_WASM') - self.set_setting('WASM2C') - self.set_setting('WASM2C_SANDBOXING', mode) - self.wasm_engines = [] - self.do_core_test('test_hello_world.c') - ### Integration tests @crossplatform diff --git a/test/test_other.py b/test/test_other.py index dabbe1588360c..df50bb866104f 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -11189,50 +11189,6 @@ def test_standalone_syscalls(self): for engine in config.WASM_ENGINES: self.assertContained(expected, self.run_js('test.wasm', engine)) - @requires_native_clang - def test_wasm2c_reactor(self): - # test compiling an unsafe library using wasm2c, then using it from a - # main program. this shows it is easy to use wasm2c as a sandboxing - # mechanism. - - # first compile the library with emcc, getting a .c and .h - self.run_process([EMCC, - test_file('other/wasm2c/unsafe-library.c'), - '-O3', '-o', 'lib.wasm', '-sWASM2C', '--no-entry']) - # compile the main program natively normally, together with the unsafe - # library - self.run_process([CLANG_CC, - test_file('other/wasm2c/my-code.c'), - 'lib.wasm.c', '-O3', '-o', 'program.exe'] + - clang_native.get_clang_native_args(), - env=clang_native.get_clang_native_env()) - output = self.run_process([os.path.abspath('program.exe')], stdout=PIPE).stdout - self.assertEqual(output, read_file(test_file('other/wasm2c/output.txt'))) - - @requires_native_clang - def test_wasm2c_multi_lib(self): - # compile two libraries to object files - for lib in ['a', 'b']: - self.run_process([EMCC, - test_file('other/wasm2c', f'unsafe-library-{lib}.c'), - '-O3', '-o', f'lib{lib}.wasm', '-sWASM2C', '--no-entry']) - # build with a different WASM_RT_MODULE_PREFIX for each library, so that - # they do not have colliding symbols - self.run_process([CLANG_CC, f'lib{lib}.wasm.c', '-O3', '-c', - f'-DWASM_RT_MODULE_PREFIX={lib}_'] + - clang_native.get_clang_native_args(), - env=clang_native.get_clang_native_env()) - - # compile the main program with the wasmboxed libraries - self.run_process([CLANG_CC, - test_file('other/wasm2c/my-code-multi.c'), - 'liba.wasm.o', 'libb.wasm.o', - '-O3', '-o', 'program.exe'] + - clang_native.get_clang_native_args(), - env=clang_native.get_clang_native_env()) - output = self.run_process([os.path.abspath('program.exe')], stdout=PIPE).stdout - self.assertEqual(output, read_file(test_file('other/wasm2c/output-multi.txt'))) - @parameterized({ 'wasm2js': (['-sWASM=0'], ''), 'modularize': (['-sMODULARIZE'], 'Module()'), diff --git a/tools/wasm2c.py b/tools/wasm2c.py deleted file mode 100644 index 0250b568c3a18..0000000000000 --- a/tools/wasm2c.py +++ /dev/null @@ -1,238 +0,0 @@ -# Copyright 2020 The Emscripten Authors. All rights reserved. -# Emscripten is available under two separate licenses, the MIT license and the -# University of Illinois/NCSA Open Source License. Both these licenses can be -# found in the LICENSE file. - -import os -import re - -from tools.shared import unsuffixed, check_call -from tools.settings import settings -from tools.utils import path_from_root, exit_with_error -from tools import config - - -# map an emscripten-style signature letter to a wasm2c C type -def s_to_c(s): - if s == 'v': - return 'void' - elif s == 'i': - return 'u32' - elif s == 'j': - return 'u64' - elif s == 'p': - if settings.MEMORY64: - return 'u64' - else: - return 'u32' - elif s == 'f': - return 'f32' - elif s == 'd': - return 'f64' - else: - exit_with_error('invalid sig element:' + str(s)) - - -# map a wasm2c C type to an emscripten-style signature letter -def c_to_s(c): - if c == 'WASM_RT_I32': - return 'i' - elif c == 'WASM_RT_I64': - return 'j' - elif c == 'WASM_RT_F32': - return 'f' - elif c == 'WASM_RT_F64': - return 'd' - else: - exit_with_error('invalid wasm2c type element:' + str(c)) - - -def get_func_types(code): - ''' - We look for this pattern: - - static void init_func_types(void) { - func_types[0] = wasm_rt_register_func_type(3, 1, WASM_RT_I32, WASM_RT_I32, WASM_RT_I32, WASM_RT_I32); - func_types[1] = wasm_rt_register_func_type(1, 1, WASM_RT_I32, WASM_RT_I32); - func_types[2] = wasm_rt_register_func_type(0, 0); - } - - We return a map of signatures names to their index. - ''' - init_func_types = re.search(r'static void init_func_types\(void\) {([^}]*)}', code) - if not init_func_types: - return {} - ret = {} - for entry in re.findall(r'func_types\[(\d+)\] = wasm_rt_register_func_type\((\d+), (\d+),? ?([^)]+)?\);', init_func_types[0]): - index, params, results, types = entry - index = int(index) - params = int(params) - results = int(results) - types = types.split(', ') - sig = '' - for i in range(params): - sig += c_to_s(types[i]) - if results == 0: - sig = 'v' + sig - else: - assert results == 1, 'no multivalue support' - sig = c_to_s(types[-1]) + sig - ret[sig] = index - return ret - - -def do_wasm2c(infile): - assert settings.STANDALONE_WASM - WASM2C = config.NODE_JS + [path_from_root('node_modules/wasm2c/wasm2c.js')] - WASM2C_DIR = path_from_root('node_modules/wasm2c') - c_file = unsuffixed(infile) + '.wasm.c' - h_file = unsuffixed(infile) + '.wasm.h' - cmd = WASM2C + [infile, '-o', c_file] - check_call(cmd) - total = '''\ -/* - * This file was generated by emcc+wasm2c. To compile it, use something like - * - * $CC FILE.c -O2 -lm -DWASM_RT_MAX_CALL_STACK_DEPTH=8000 - */ -''' - SEP = '\n/* ==================================== */\n' - - def bundle_file(filename): - nonlocal total - with open(filename) as f: - total += '// ' + filename + '\n' + f.read() + SEP - - # hermeticize the C file, by bundling in the wasm2c/ includes - headers = [ - (WASM2C_DIR, 'wasm-rt.h'), - (WASM2C_DIR, 'wasm-rt-impl.h'), - ('', h_file) - ] - for header in headers: - bundle_file(os.path.join(header[0], header[1])) - # add the wasm2c output - bundle_file(c_file) - # add the wasm2c runtime - bundle_file(os.path.join(WASM2C_DIR, 'wasm-rt-impl.c')) - # add the support code - support_files = ['base.c'] - if settings.AUTODEBUG: - support_files.append('autodebug.c') - if settings.EXPECT_MAIN: - # TODO: add an option for direct OS access. For now, do that when building - # an executable with main, as opposed to a library - support_files.append('os.c') - support_files.append('main.c') - else: - support_files.append('os_sandboxed.c') - support_files.append('reactor.c') - # for a reactor, also append wasmbox_* API definitions - with open(h_file, 'a') as f: - f.write(''' -// wasmbox_* API -// TODO: optional prefixing -extern void wasmbox_init(void); -''') - for support_file in support_files: - bundle_file(path_from_root(f'tools/wasm2c/{support_file}')) - # remove #includes of the headers we bundled - for header in headers: - total = total.replace('#include "%s"\n' % header[1], '/* include of %s */\n' % header[1]) - # generate the necessary invokes - invokes = [] - for sig in re.findall(r"\/\* import\: 'env' 'invoke_(\w+)' \*\/", total): - all_func_types = get_func_types(total) - - def name(i): - return 'a' + str(i) - - wabt_sig = sig[0] + 'i' + sig[1:] - typed_args = [s_to_c(sig[i]) + ' ' + name(i) for i in range(1, len(sig))] - full_typed_args = ['u32 fptr'] + typed_args - types = [s_to_c(sig[i]) for i in range(1, len(sig))] - args = [name(i) for i in range(1, len(sig))] - c_func_type = s_to_c(sig[0]) + ' (*)(' + (', '.join(types) if types else 'void') + ')' - if sig not in all_func_types: - exit_with_error('could not find signature ' + sig + ' in function types ' + str(all_func_types)) - type_index = all_func_types[sig] - - invokes.append(r''' -IMPORT_IMPL(%(return_type)s, Z_envZ_invoke_%(sig)sZ_%(wabt_sig)s, (%(full_typed_args)s), { - VERBOSE_LOG("invoke\n"); // waka - u32 sp = WASM_RT_ADD_PREFIX(Z_stackSaveZ_iv)(); - if (next_setjmp >= MAX_SETJMP_STACK) { - abort_with_message("too many nested setjmps"); - } - u32 id = next_setjmp++; - int result = setjmp(setjmp_stack[id]); - %(declare_return)s - if (result == 0) { - %(receive)sCALL_INDIRECT(w2c___indirect_function_table, %(c_func_type)s, %(type_index)s, fptr %(args)s); - /* if we got here, no longjmp or exception happened, we returned normally */ - } else { - /* A longjmp or an exception took us here. */ - WASM_RT_ADD_PREFIX(Z_stackRestoreZ_vi)(sp); - WASM_RT_ADD_PREFIX(Z_setThrewZ_vii)(1, 0); - } - next_setjmp--; - %(return)s -}); -''' % { - 'return_type': s_to_c(sig[0]) if sig[0] != 'v' else 'void', - 'sig': sig, - 'wabt_sig': wabt_sig, - 'full_typed_args': ', '.join(full_typed_args), - 'type_index': type_index, - 'c_func_type': c_func_type, - 'args': (', ' + ', '.join(args)) if args else '', - 'declare_return': (s_to_c(sig[0]) + ' returned_value = 0;') if sig[0] != 'v' else '', - 'receive': 'returned_value = ' if sig[0] != 'v' else '', - 'return': 'return returned_value;' if sig[0] != 'v' else '' - }) - - total += '\n'.join(invokes) - - # adjust sandboxing - TRAP_OOB = 'TRAP(OOB)' - assert total.count(TRAP_OOB) == 2 - if settings.WASM2C_SANDBOXING == 'full': - pass # keep it - elif settings.WASM2C_SANDBOXING == 'none': - total = total.replace(TRAP_OOB, '{}') - elif settings.WASM2C_SANDBOXING == 'mask': - assert not settings.ALLOW_MEMORY_GROWTH - assert (settings.INITIAL_MEMORY & (settings.INITIAL_MEMORY - 1)) == 0, 'poewr of 2' - total = total.replace(TRAP_OOB, '{}') - MEM_ACCESS = '[addr]' - assert total.count(MEM_ACCESS) == 3, '2 from wasm2c, 1 from runtime' - total = total.replace(MEM_ACCESS, '[addr & %d]' % (settings.INITIAL_MEMORY - 1)) - else: - exit_with_error('bad sandboxing') - - # adjust prefixing: emit simple output that works with multiple libraries, - # each compiled into its own single .c file, by adding 'static' in some places - # TODO: decide on the proper pattern for this in an upstream discussion in - # wasm2c; another option would be to prefix all these things. - for rep in [ - 'uint32_t wasm_rt_register_func_type(', - 'void wasm_rt_trap(', - 'void wasm_rt_allocate_memory(', - 'uint32_t wasm_rt_grow_memory(', - 'void wasm_rt_allocate_table(', - 'jmp_buf g_jmp_buf', - 'uint32_t g_func_type_count', - 'FuncType* g_func_types', - 'uint32_t wasm_rt_call_stack_depth', - 'uint32_t g_saved_call_stack_depth', - ]: - # remove 'extern' from declaration - total = total.replace('extern ' + rep, rep) - # add 'static' to implementation - old = total - total = total.replace(rep, 'static ' + rep) - assert old != total, f'did not find "{rep}"' - - # write out the final file - with open(c_file, 'w') as out: - out.write(total) diff --git a/tools/wasm2c/autodebug.c b/tools/wasm2c/autodebug.c deleted file mode 100644 index 3726055c2ebbf..0000000000000 --- a/tools/wasm2c/autodebug.c +++ /dev/null @@ -1,87 +0,0 @@ -IMPORT_IMPL(void, Z_envZ_log_executionZ_vi, (u32 loc), { - printf("log_execution %d\n", loc); -}); -IMPORT_IMPL(u32, Z_envZ_get_i32Z_iiii, (u32 loc, u32 index, u32 value), { - printf("get_i32 %d,%d,%d\n", loc, index, value); - return value; -}); -IMPORT_IMPL(u32, Z_envZ_get_i64Z_iiiii, (u32 loc, u32 index, u32 low, u32 high), { - printf("get_i64 %d,%d,%d,%d\n", loc, index, low, high); - w2c_setTempRet0(high); - return low; -}); -IMPORT_IMPL(f32, Z_envZ_get_f32Z_fiif, (u32 loc, u32 index, f32 value), { - printf("get_f32 %d,%d,%f\n", loc, index, value); - return value; -}); -IMPORT_IMPL(f64, Z_envZ_get_f64Z_diid, (u32 loc, u32 index, f64 value), { - printf("get_f64 %d,%d,%f\n", loc, index, value); - return value; -}); -IMPORT_IMPL(u32, Z_envZ_set_i32Z_iiii, (u32 loc, u32 index, u32 value), { - printf("set_i32 %d,%d,%d\n", loc, index, value); - return value; -}); -IMPORT_IMPL(u32, Z_envZ_set_i64Z_iiiii, (u32 loc, u32 index, u32 low, u32 high), { - printf("set_i64 %d,%d,%d,%d\n", loc, index, low, high); - w2c_setTempRet0(high); - return low; -}); -IMPORT_IMPL(f32, Z_envZ_set_f32Z_fiif, (u32 loc, u32 index, f32 value), { - printf("set_f32 %d,%d,%f\n", loc, index, value); - return value; -}); -IMPORT_IMPL(f64, Z_envZ_set_f64Z_diid, (u32 loc, u32 index, f64 value), { - printf("set_f64 %d,%d,%f\n", loc, index, value); - return value; -}); -IMPORT_IMPL(u32, Z_envZ_load_ptrZ_iiiii, (u32 loc, u32 bytes, u32 offset, u32 ptr), { - printf("load_ptr %d,%d,%d,%d\n", loc, bytes, offset, ptr); - return ptr; -}); -IMPORT_IMPL(u32, Z_envZ_load_val_i32Z_iii, (u32 loc, u32 value), { - printf("load_val_i32 %d,%d\n", loc, value); - return value; -}); -IMPORT_IMPL(u32, Z_envZ_load_val_i64Z_iiii, (u32 loc, u32 low, u32 high), { - printf("load_val_i64 %d,%d,%d\n", loc, low, high); - w2c_setTempRet0(high); - return low; -}); -IMPORT_IMPL(u64, Z_envZ_load_val_i64Z_jij, (u32 loc, u64 value), { - printf("load_val_i64 %d,%d,%d\n", loc, (u32)value, (u32)(value >> 32)); - return value; -}); -IMPORT_IMPL(f32, Z_envZ_load_val_f32Z_fif, (u32 loc, f32 value), { - printf("load_val_f32 %d,%f\n", loc, value); - return value; -}); -IMPORT_IMPL(f64, Z_envZ_load_val_f64Z_did, (u32 loc, f64 value), { - printf("load_val_f64 %d,%f\n", loc, value); - return value; -}); -IMPORT_IMPL(u32, Z_envZ_store_ptrZ_iiiii, (u32 loc, u32 bytes, u32 offset, u32 ptr), { - printf("store_ptr %d,%d,%d,%d\n", loc, bytes, offset, ptr); - return ptr; -}); -IMPORT_IMPL(u32, Z_envZ_store_val_i32Z_iii, (u32 loc, u32 value), { - printf("store_val_i32 %d,%d\n", loc, value); - return value; -}); -IMPORT_IMPL(u32, Z_envZ_store_val_i64Z_iiii, (u32 loc, u32 low, u32 high), { - printf("store_val_i64 %d,%d,%d\n", loc, low, high); - w2c_setTempRet0(high); - return low; -}); -IMPORT_IMPL(u64, Z_envZ_store_val_i64Z_jij, (u32 loc, u64 value), { - printf("store_val_i64 %d,%d,%d\n", loc, (u32)value, (u32)(value >> 32)); - return value; -}); -IMPORT_IMPL(f32, Z_envZ_store_val_f32Z_fif, (u32 loc, f32 value), { - printf("store_val_f32 %d,%f\n", loc, value); - return value; -}); -IMPORT_IMPL(f64, Z_envZ_store_val_f64Z_did, (u32 loc, f64 value), { - printf("store_val_f64 %d,%f\n", loc, value); - return value; -}); diff --git a/tools/wasm2c/base.c b/tools/wasm2c/base.c deleted file mode 100644 index 37d5c0dcf8855..0000000000000 --- a/tools/wasm2c/base.c +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Base of all support for wasm2c code. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// ssize_t detection: usually stdint provides it, but not on windows apparently -#ifdef _WIN32 -#ifdef _MSC_VER -#include -typedef SSIZE_T ssize_t; -#else // _MSC_VER -#ifdef _WIN64 -typedef signed long long ssize_t; -#else // _WIN64 -typedef signed long ssize_t; -#endif // _WIN64 -#endif // _MSC_VER -#endif // _WIN32 - -#include "wasm-rt.h" -#include "wasm-rt-impl.h" - -#define UNLIKELY(x) __builtin_expect(!!(x), 0) -#define LIKELY(x) __builtin_expect(!!(x), 1) - -#define TRAP(x) (wasm_rt_trap(WASM_RT_TRAP_##x), 0) - -#define MEMACCESS(addr) ((void*)&WASM_RT_ADD_PREFIX(Z_memory)->data[addr]) - -#undef MEMCHECK -#define MEMCHECK(a, t) \ - if (UNLIKELY((a) + sizeof(t) > WASM_RT_ADD_PREFIX(Z_memory)->size)) TRAP(OOB) - -#undef DEFINE_LOAD -#define DEFINE_LOAD(name, t1, t2, t3) \ - static inline t3 name(u64 addr) { \ - MEMCHECK(addr, t1); \ - t1 result; \ - memcpy(&result, MEMACCESS(addr), sizeof(t1)); \ - return (t3)(t2)result; \ - } - -#undef DEFINE_STORE -#define DEFINE_STORE(name, t1, t2) \ - static inline void name(u64 addr, t2 value) { \ - MEMCHECK(addr, t1); \ - t1 wrapped = (t1)value; \ - memcpy(MEMACCESS(addr), &wrapped, sizeof(t1)); \ - } - -DEFINE_LOAD(wasm_i32_load, u32, u32, u32); -DEFINE_LOAD(wasm_i64_load, u64, u64, u64); -DEFINE_LOAD(wasm_f32_load, f32, f32, f32); -DEFINE_LOAD(wasm_f64_load, f64, f64, f64); -DEFINE_LOAD(wasm_i32_load8_s, s8, s32, u32); -DEFINE_LOAD(wasm_i64_load8_s, s8, s64, u64); -DEFINE_LOAD(wasm_i32_load8_u, u8, u32, u32); -DEFINE_LOAD(wasm_i64_load8_u, u8, u64, u64); -DEFINE_LOAD(wasm_i32_load16_s, s16, s32, u32); -DEFINE_LOAD(wasm_i64_load16_s, s16, s64, u64); -DEFINE_LOAD(wasm_i32_load16_u, u16, u32, u32); -DEFINE_LOAD(wasm_i64_load16_u, u16, u64, u64); -DEFINE_LOAD(wasm_i64_load32_s, s32, s64, u64); -DEFINE_LOAD(wasm_i64_load32_u, u32, u64, u64); -DEFINE_STORE(wasm_i32_store, u32, u32); -DEFINE_STORE(wasm_i64_store, u64, u64); -DEFINE_STORE(wasm_f32_store, f32, f32); -DEFINE_STORE(wasm_f64_store, f64, f64); -DEFINE_STORE(wasm_i32_store8, u8, u32); -DEFINE_STORE(wasm_i32_store16, u16, u32); -DEFINE_STORE(wasm_i64_store8, u8, u64); -DEFINE_STORE(wasm_i64_store16, u16, u64); -DEFINE_STORE(wasm_i64_store32, u32, u64); - -// Imports - -#ifdef VERBOSE_LOGGING -#define VERBOSE_LOG(...) { printf(__VA_ARGS__); } -#else -#define VERBOSE_LOG(...) -#endif - -#define IMPORT_IMPL(ret, name, params, body) \ -static ret _##name params { \ - VERBOSE_LOG("[import: " #name "]\n"); \ - body \ -} \ -ret (*WASM_RT_ADD_PREFIX(name)) params = _##name; - -#define STUB_IMPORT_IMPL(ret, name, params, returncode) IMPORT_IMPL(ret, name, params, { return returncode; }); - -// Generic abort method for a runtime error in the runtime. - -static void abort_with_message(const char* message) { - fprintf(stderr, "%s\n", message); - TRAP(UNREACHABLE); -} - -// Maintain a stack of setjmps, each jump taking us back to the last invoke. - -#define MAX_SETJMP_STACK 1024 - -static jmp_buf setjmp_stack[MAX_SETJMP_STACK]; - -static u32 next_setjmp = 0; - -IMPORT_IMPL(void, Z_envZ__emscripten_throw_longjmpZ_vv, (), { - if (next_setjmp == 0) { - abort_with_message("longjmp without setjmp"); - } - longjmp(setjmp_stack[next_setjmp - 1], 1); -}); - -IMPORT_IMPL(void, Z_envZ_emscripten_notify_memory_growthZ_vi, (u32 size), {}); - -// Shared OS support in both sandboxed and unsandboxed mode - -#define WASI_DEFAULT_ERROR 63 /* __WASI_ERRNO_PERM */ -#define WASI_EINVAL 28 - -// Syscalls return a negative error code -#define EM_EACCES -2 - -STUB_IMPORT_IMPL(u32, Z_wasi_snapshot_preview1Z_fd_fdstat_getZ_iii, (u32 a, u32 b), WASI_DEFAULT_ERROR); -STUB_IMPORT_IMPL(u32, Z_wasi_snapshot_preview1Z_fd_syncZ_ii, (u32 a), WASI_DEFAULT_ERROR); -STUB_IMPORT_IMPL(u32, Z_envZ_dlopenZ_iii, (u32 a, u32 b), 1); -STUB_IMPORT_IMPL(u32, Z_envZ_dlcloseZ_ii, (u32 a), 1); -STUB_IMPORT_IMPL(u32, Z_envZ_dlsymZ_iii, (u32 a, u32 b), 0); -STUB_IMPORT_IMPL(u32, Z_envZ_dlerrorZ_iv, (), 0); -STUB_IMPORT_IMPL(u32, Z_envZ_signalZ_iii, (u32 a, u32 b), -1); -STUB_IMPORT_IMPL(u32, Z_envZ_systemZ_ii, (u32 a), -1); -STUB_IMPORT_IMPL(u32, Z_envZ_utimesZ_iii, (u32 a, u32 b), -1); -STUB_IMPORT_IMPL(u32, Z_envZ___sys_rmdirZ_ii, (u32 a), EM_EACCES); -STUB_IMPORT_IMPL(u32, Z_envZ___sys_renameZ_iii, (u32 a, u32 b), EM_EACCES); -STUB_IMPORT_IMPL(u32, Z_envZ___sys_lstat64Z_iii, (u32 a, u32 b), EM_EACCES); -STUB_IMPORT_IMPL(u32, Z_envZ___sys_dup3Z_iiii, (u32 a, u32 b, u32 c), EM_EACCES); -STUB_IMPORT_IMPL(u32, Z_envZ___sys_dup2Z_iii, (u32 a, u32 b), EM_EACCES); -STUB_IMPORT_IMPL(u32, Z_envZ___sys_getcwdZ_iii, (u32 a, u32 b), EM_EACCES); -STUB_IMPORT_IMPL(u32, Z_envZ___sys_ftruncate64Z_iiiii, (u32 a, u32 b, u32 c, u32 d), EM_EACCES); -STUB_IMPORT_IMPL(u32, Z_envZ_pthread_mutexattr_initZ_ii, (u32 a), 0); -STUB_IMPORT_IMPL(u32, Z_envZ_pthread_mutexattr_settypeZ_iii, (u32 a, u32 b), 0); -STUB_IMPORT_IMPL(u32, Z_envZ_pthread_mutexattr_destroyZ_ii, (u32 a), 0); -STUB_IMPORT_IMPL(u32, Z_envZ_pthread_createZ_iiiii, (u32 a, u32 b, u32 c, u32 d), -1); -STUB_IMPORT_IMPL(u32, Z_envZ_pthread_joinZ_iii, (u32 a, u32 b), -1); -STUB_IMPORT_IMPL(u32, Z_envZ___cxa_thread_atexitZ_iiii, (u32 a, u32 b, u32 c), -1); diff --git a/tools/wasm2c/main.c b/tools/wasm2c/main.c deleted file mode 100644 index ea7a535d437d2..0000000000000 --- a/tools/wasm2c/main.c +++ /dev/null @@ -1,42 +0,0 @@ -static int main_argc; -static char** main_argv; - -IMPORT_IMPL(u32, Z_wasi_snapshot_preview1Z_args_sizes_getZ_iii, (u32 pargc, u32 pargv_buf_size), { - wasm_i32_store(pargc, main_argc); - u32 buf_size = 0; - for (u32 i = 0; i < main_argc; i++) { - buf_size += strlen(main_argv[i]) + 1; - } - wasm_i32_store(pargv_buf_size, buf_size); - return 0; -}); - -IMPORT_IMPL(u32, Z_wasi_snapshot_preview1Z_args_getZ_iii, (u32 argv, u32 argv_buf), { - u32 buf_size = 0; - for (u32 i = 0; i < main_argc; i++) { - u32 ptr = argv_buf + buf_size; - wasm_i32_store(argv + i * 4, ptr); - char* arg = main_argv[i]; - strcpy(MEMACCESS(ptr), arg); - buf_size += strlen(arg) + 1; - } - return 0; -}); - -int main(int argc, char** argv) { - main_argc = argc; - main_argv = argv; - - init_fds(); - - init(); - - int trap_code; - if ((trap_code = setjmp(g_jmp_buf))) { - printf("[wasm trap %d, halting]\n", trap_code); - return 1; - } else { - WASM_RT_ADD_PREFIX(Z__startZ_vv)(); - } - return 0; -} diff --git a/tools/wasm2c/os.c b/tools/wasm2c/os.c deleted file mode 100644 index f5e0f0bde66ec..0000000000000 --- a/tools/wasm2c/os.c +++ /dev/null @@ -1,321 +0,0 @@ -#include -#include -#include - -#ifndef _WIN32 -#include -#else -#include -#endif - -IMPORT_IMPL(void, Z_wasi_snapshot_preview1Z_proc_exitZ_vi, (u32 x), { - exit(x); -}); - -#define MAX_FDS 1024 - -static int wasm_fd_to_native[MAX_FDS]; - -static u32 next_wasm_fd; - -#define WASM_STDIN 0 -#define WASM_STDOUT 1 -#define WASM_STDERR 2 - -static void init_fds() { -#ifndef _WIN32 - wasm_fd_to_native[WASM_STDIN] = STDIN_FILENO; - wasm_fd_to_native[WASM_STDOUT] = STDOUT_FILENO; - wasm_fd_to_native[WASM_STDERR] = STDERR_FILENO; -#else - wasm_fd_to_native[WASM_STDIN] = _fileno(stdin); - wasm_fd_to_native[WASM_STDOUT] = _fileno(stdout); - wasm_fd_to_native[WASM_STDERR] = _fileno(stderr); -#endif - next_wasm_fd = 3; -} - -static u32 get_or_allocate_wasm_fd(int nfd) { - // If the native fd is already mapped, return the same wasm fd for it. - for (int i = 0; i < next_wasm_fd; i++) { - if (wasm_fd_to_native[i] == nfd) { - return i; - } - } - if (next_wasm_fd >= MAX_FDS) { - abort_with_message("ran out of fds"); - } - u32 fd = next_wasm_fd; - wasm_fd_to_native[fd] = nfd; - next_wasm_fd++; - return fd; -} - -static int get_native_fd(u32 fd) { - if (fd >= MAX_FDS || fd >= next_wasm_fd) { - return -1; - } - return wasm_fd_to_native[fd]; -} - -IMPORT_IMPL(u32, Z_envZ___sys_openZ_iiii, (u32 path, u32 flags, u32 varargs), { - VERBOSE_LOG(" open: %s %d %d\n", MEMACCESS(path), flags, wasm_i32_load(varargs)); - int nfd = open(MEMACCESS(path), flags, wasm_i32_load(varargs)); - VERBOSE_LOG(" => native %d\n", nfd); - if (nfd >= 0) { - u32 fd = get_or_allocate_wasm_fd(nfd); - VERBOSE_LOG(" => wasm %d\n", fd); - return fd; - } - return -1; -}); - -IMPORT_IMPL(u32, Z_wasi_snapshot_preview1Z_fd_writeZ_iiiii, (u32 fd, u32 iov, u32 iovcnt, u32 pnum), { - int nfd = get_native_fd(fd); - VERBOSE_LOG(" fd_write wasm %d => native %d\n", fd, nfd); - if (nfd < 0) { - return WASI_DEFAULT_ERROR; - } - u32 num = 0; - for (u32 i = 0; i < iovcnt; i++) { - u32 ptr = wasm_i32_load(iov + i * 8); - u32 len = wasm_i32_load(iov + i * 8 + 4); - VERBOSE_LOG(" chunk %d %d\n", ptr, len); - ssize_t result; - // Use stdio for stdout/stderr to avoid mixing a low-level write() with - // other logging code, which can change the order from the expected. - if (fd == WASM_STDOUT) { - result = fwrite(MEMACCESS(ptr), 1, len, stdout); - } else if (fd == WASM_STDERR) { - result = fwrite(MEMACCESS(ptr), 1, len, stderr); - } else { - result = write(nfd, MEMACCESS(ptr), len); - } - if (result < 0) { - VERBOSE_LOG(" error, %d %s\n", errno, strerror(errno)); - return WASI_DEFAULT_ERROR; - } - if (result != len) { - VERBOSE_LOG(" amount error, %ld %d\n", result, len); - return WASI_DEFAULT_ERROR; - } - num += len; - } - VERBOSE_LOG(" success: %d\n", num); - wasm_i32_store(pnum, num); - return 0; -}); - -IMPORT_IMPL(u32, Z_wasi_snapshot_preview1Z_fd_readZ_iiiii, (u32 fd, u32 iov, u32 iovcnt, u32 pnum), { - int nfd = get_native_fd(fd); - VERBOSE_LOG(" fd_read wasm %d => native %d\n", fd, nfd); - if (nfd < 0) { - return WASI_DEFAULT_ERROR; - } - u32 num = 0; - for (u32 i = 0; i < iovcnt; i++) { - u32 ptr = wasm_i32_load(iov + i * 8); - u32 len = wasm_i32_load(iov + i * 8 + 4); - VERBOSE_LOG(" chunk %d %d\n", ptr, len); - ssize_t result = read(nfd, MEMACCESS(ptr), len); - if (result < 0) { - VERBOSE_LOG(" error, %d %s\n", errno, strerror(errno)); - return WASI_DEFAULT_ERROR; - } - num += result; - if (result != len) { - break; // nothing more to read - } - } - VERBOSE_LOG(" success: %d\n", num); - wasm_i32_store(pnum, num); - return 0; -}); - -IMPORT_IMPL(u32, Z_wasi_snapshot_preview1Z_fd_closeZ_ii, (u32 fd), { - // TODO full file support - int nfd = get_native_fd(fd); - VERBOSE_LOG(" close wasm %d => native %d\n", fd, nfd); - if (nfd < 0) { - return WASI_DEFAULT_ERROR; - } - close(nfd); - return 0; -}); - -IMPORT_IMPL(u32, Z_wasi_snapshot_preview1Z_environ_sizes_getZ_iii, (u32 pcount, u32 pbuf_size), { - // TODO: connect to actual env? - wasm_i32_store(pcount, 0); - wasm_i32_store(pbuf_size, 0); - return 0; -}); - -IMPORT_IMPL(u32, Z_wasi_snapshot_preview1Z_environ_getZ_iii, (u32 __environ, u32 environ_buf), { - // TODO: connect to actual env? - return 0; -}); - -static int whence_to_native(u32 whence) { - if (whence == 0) return SEEK_SET; - if (whence == 1) return SEEK_CUR; - if (whence == 2) return SEEK_END; - return -1; -} - -IMPORT_IMPL(u32, Z_wasi_snapshot_preview1Z_fd_seekZ_iijii, (u32 fd, u64 offset, u32 whence, u32 new_offset), { - int nfd = get_native_fd(fd); - int nwhence = whence_to_native(whence); - VERBOSE_LOG(" seek %d (=> native %d) %ld %d (=> %d) %d\n", fd, nfd, offset, whence, nwhence, new_offset); - if (nfd < 0) { - return WASI_DEFAULT_ERROR; - } - off_t off = lseek(nfd, offset, nwhence); - VERBOSE_LOG(" off: %ld\n", off); - if (off == (off_t)-1) { - VERBOSE_LOG(" error, %d %s\n", errno, strerror(errno)); - return WASI_DEFAULT_ERROR; - } - wasm_i64_store(new_offset, off); - return 0; -}); -IMPORT_IMPL(u32, Z_wasi_snapshot_preview1Z_fd_seekZ_iiiiii, (u32 a, u32 b, u32 c, u32 d, u32 e), { - return Z_wasi_snapshot_preview1Z_fd_seekZ_iijii(a, b + (((u64)c) << 32), d, e); -}); - -// TODO: set errno in wasm for things that need it - -IMPORT_IMPL(u32, Z_envZ___sys_unlinkZ_ii, (u32 path), { - VERBOSE_LOG(" unlink %s\n", MEMACCESS(path)); - if (unlink(MEMACCESS(path))) { - VERBOSE_LOG(" error, %d %s\n", errno, strerror(errno)); - return EM_EACCES; - } - return 0; -}); - -static u32 do_stat(int nfd, u32 buf) { - struct stat nbuf; - if (fstat(nfd, &nbuf)) { - VERBOSE_LOG(" error, %d %s\n", errno, strerror(errno)); - return EM_EACCES; - } - VERBOSE_LOG(" success, size=%ld\n", nbuf.st_size); - wasm_i32_store(buf + 0, nbuf.st_dev); - wasm_i32_store(buf + 4, 0); - wasm_i32_store(buf + 8, nbuf.st_ino); - wasm_i32_store(buf + 12, nbuf.st_mode); - wasm_i32_store(buf + 16, nbuf.st_nlink); - wasm_i32_store(buf + 20, nbuf.st_uid); - wasm_i32_store(buf + 24, nbuf.st_gid); - wasm_i32_store(buf + 28, nbuf.st_rdev); - wasm_i32_store(buf + 32, 0); - wasm_i64_store(buf + 40, nbuf.st_size); -#ifdef _WIN32 - wasm_i32_store(buf + 48, 512); // fixed blocksize on windows - wasm_i32_store(buf + 52, 0); // but no reported blocks... -#else - wasm_i32_store(buf + 48, nbuf.st_blksize); - wasm_i32_store(buf + 52, nbuf.st_blocks); -#endif -#if defined(__APPLE__) || defined(__NetBSD__) - wasm_i32_store(buf + 56, nbuf.st_atimespec.tv_sec); - wasm_i32_store(buf + 60, nbuf.st_atimespec.tv_nsec); - wasm_i32_store(buf + 64, nbuf.st_mtimespec.tv_sec); - wasm_i32_store(buf + 68, nbuf.st_mtimespec.tv_nsec); - wasm_i32_store(buf + 72, nbuf.st_ctimespec.tv_sec); - wasm_i32_store(buf + 76, nbuf.st_ctimespec.tv_nsec); -#elif defined(_WIN32) - wasm_i32_store(buf + 56, gmtime(&nbuf.st_atime)->tm_sec); - wasm_i32_store(buf + 60, 0); - wasm_i32_store(buf + 64, gmtime(&nbuf.st_mtime)->tm_sec); - wasm_i32_store(buf + 68, 0); - wasm_i32_store(buf + 72, gmtime(&nbuf.st_ctime)->tm_sec); - wasm_i32_store(buf + 76, 0); -#else - wasm_i32_store(buf + 56, nbuf.st_atim.tv_sec); - wasm_i32_store(buf + 60, nbuf.st_atim.tv_nsec); - wasm_i32_store(buf + 64, nbuf.st_mtim.tv_sec); - wasm_i32_store(buf + 68, nbuf.st_mtim.tv_nsec); - wasm_i32_store(buf + 72, nbuf.st_ctim.tv_sec); - wasm_i32_store(buf + 76, nbuf.st_ctim.tv_nsec); -#endif - wasm_i64_store(buf + 80, nbuf.st_ino); - return 0; -} - -IMPORT_IMPL(u32, Z_envZ___sys_fstat64Z_iii, (u32 fd, u32 buf), { - int nfd = get_native_fd(fd); - VERBOSE_LOG(" fstat64 %d (=> %d) %d\n", fd, nfd, buf); - if (nfd < 0) { - return EM_EACCES; - } - return do_stat(nfd, buf); -}); - -IMPORT_IMPL(u32, Z_envZ___sys_stat64Z_iii, (u32 path, u32 buf), { - VERBOSE_LOG(" stat64: %s\n", MEMACCESS(path)); - int nfd = open(MEMACCESS(path), O_RDONLY); // could be O_PATH on linux... - if (nfd < 0) { - VERBOSE_LOG(" error, %d %s\n", errno, strerror(errno)); - return EM_EACCES; - } - return do_stat(nfd, buf); -}); - -IMPORT_IMPL(u32, Z_envZ___sys_readZ_iiii, (u32 fd, u32 buf, u32 count), { - int nfd = get_native_fd(fd); - VERBOSE_LOG(" read %d (=> %d) %d %d\n", fd, nfd, buf, count); - if (nfd < 0) { - VERBOSE_LOG(" bad fd\n"); - return EM_EACCES; - } - ssize_t ret = read(nfd, MEMACCESS(buf), count); - VERBOSE_LOG(" native read: %ld\n", ret); - if (ret < 0) { - VERBOSE_LOG(" read error %d %s\n", errno, strerror(errno)); - return EM_EACCES; - } - return ret; -}); - -IMPORT_IMPL(u32, Z_envZ___sys_accessZ_iii, (u32 pathname, u32 mode), { - VERBOSE_LOG(" access: %s 0x%x\n", MEMACCESS(pathname), mode); - // TODO: sandboxing, convert mode - int result = access(MEMACCESS(pathname), mode); - if (result < 0) { - VERBOSE_LOG(" access error: %d %s\n", errno, strerror(errno)); - return EM_EACCES; - } - return 0; -}); - -#define WASM_CLOCK_REALTIME 0 -#define WASM_CLOCK_MONOTONIC 1 -#define WASM_CLOCK_PROCESS_CPUTIME 2 -#define WASM_CLOCK_THREAD_CPUTIME_ID 3 - -static int check_clock(u32 clock_id) { - return clock_id == WASM_CLOCK_REALTIME || clock_id == WASM_CLOCK_MONOTONIC || - clock_id == WASM_CLOCK_PROCESS_CPUTIME || clock_id == WASM_CLOCK_THREAD_CPUTIME_ID; -} - -IMPORT_IMPL(u32, Z_wasi_snapshot_preview1Z_clock_time_getZ_iiji, (u32 clock_id, u64 max_lag, u32 out), { - if (!check_clock(clock_id)) { - return WASI_EINVAL; - } - // TODO: handle realtime vs monotonic etc. - // wasi expects a result in nanoseconds, and we know how to convert clock() - // to seconds, so compute from there - const double NSEC_PER_SEC = 1000.0 * 1000.0 * 1000.0; - wasm_i64_store(out, (u64)(clock() / (CLOCKS_PER_SEC / NSEC_PER_SEC))); - return 0; -}); - -IMPORT_IMPL(u32, Z_wasi_snapshot_preview1Z_clock_res_getZ_iii, (u32 clock_id, u32 out), { - if (!check_clock(clock_id)) { - return WASI_EINVAL; - } - // TODO: handle realtime vs monotonic etc. For now just report "milliseconds". - wasm_i64_store(out, 1000 * 1000); - return 0; -}); diff --git a/tools/wasm2c/os_sandboxed.c b/tools/wasm2c/os_sandboxed.c deleted file mode 100644 index 728d7130cb006..0000000000000 --- a/tools/wasm2c/os_sandboxed.c +++ /dev/null @@ -1,22 +0,0 @@ -// Stubs for OS functions, for a sandboxed environment. Nothing is allowed -// exit the sandbox, calls to printf will fail, etc. - -IMPORT_IMPL(void, Z_wasi_snapshot_preview1Z_proc_exitZ_vi, (u32 x), { - abort_with_message("exit() called"); -}); - -STUB_IMPORT_IMPL(u32, Z_envZ___sys_openZ_iiii, (u32 path, u32 flags, u32 varargs), -1); -STUB_IMPORT_IMPL(u32, Z_wasi_snapshot_preview1Z_fd_writeZ_iiiii, (u32 fd, u32 iov, u32 iovcnt, u32 pnum), WASI_DEFAULT_ERROR); -STUB_IMPORT_IMPL(u32, Z_wasi_snapshot_preview1Z_fd_readZ_iiiii, (u32 fd, u32 iov, u32 iovcnt, u32 pnum), WASI_DEFAULT_ERROR); -STUB_IMPORT_IMPL(u32, Z_wasi_snapshot_preview1Z_fd_closeZ_ii, (u32 fd), WASI_DEFAULT_ERROR); -STUB_IMPORT_IMPL(u32, Z_wasi_snapshot_preview1Z_environ_sizes_getZ_iii, (u32 pcount, u32 pbuf_size), WASI_DEFAULT_ERROR); -STUB_IMPORT_IMPL(u32, Z_wasi_snapshot_preview1Z_environ_getZ_iii, (u32 __environ, u32 environ_buf), WASI_DEFAULT_ERROR); -STUB_IMPORT_IMPL(u32, Z_wasi_snapshot_preview1Z_fd_seekZ_iijii, (u32 fd, u64 offset, u32 whence, u32 new_offset), WASI_DEFAULT_ERROR); -STUB_IMPORT_IMPL(u32, Z_wasi_snapshot_preview1Z_fd_seekZ_iiiiii, (u32 a, u32 b, u32 c, u32 d, u32 e), WASI_DEFAULT_ERROR); -STUB_IMPORT_IMPL(u32, Z_envZ___sys_unlinkZ_ii, (u32 path), WASI_DEFAULT_ERROR); -STUB_IMPORT_IMPL(u32, Z_envZ___sys_fstat64Z_iii, (u32 fd, u32 buf), EM_EACCES); -STUB_IMPORT_IMPL(u32, Z_envZ___sys_stat64Z_iii, (u32 path, u32 buf), EM_EACCES); -STUB_IMPORT_IMPL(u32, Z_envZ___sys_readZ_iiii, (u32 fd, u32 buf, u32 count), EM_EACCES); -STUB_IMPORT_IMPL(u32, Z_envZ___sys_accessZ_iii, (u32 pathname, u32 mode), EM_EACCES); -STUB_IMPORT_IMPL(u32, Z_wasi_snapshot_preview1Z_clock_time_getZ_iiji, (u32 clock_id, u64 max_lag, u32 out), WASI_EINVAL); -STUB_IMPORT_IMPL(u32, Z_wasi_snapshot_preview1Z_clock_res_getZ_iii, (u32 clock_id, u32 out), WASI_EINVAL); diff --git a/tools/wasm2c/reactor.c b/tools/wasm2c/reactor.c deleted file mode 100644 index 647608beadc68..0000000000000 --- a/tools/wasm2c/reactor.c +++ /dev/null @@ -1,14 +0,0 @@ -// TODO: optional prefixing -void WASM_RT_ADD_PREFIX(wasmbox_init)(void) { - // Initialize wasm2c runtime. - WASM_RT_ADD_PREFIX(init)(); - - // Set up handling for a trap - int trap_code; - if ((trap_code = setjmp(g_jmp_buf))) { - printf("[wasm trap %d, halting]\n", trap_code); - abort(); - } else { - WASM_RT_ADD_PREFIX(Z__initializeZ_vv)(); - } -} From 7abc55577303259ef9790c796aee6d61cb596dd1 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 17 May 2023 09:08:43 -0700 Subject: [PATCH 0252/1523] Move unused code into parseTools_legacy.js. NFC (#19379) --- src/jsifier.js | 2 +- src/parseTools.js | 9 --------- src/parseTools_legacy.js | 7 +++++++ 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/jsifier.js b/src/jsifier.js index af7fe2ec9fdf2..a3ec43ecb934d 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -592,7 +592,7 @@ function ${name}(${args}) { warnings: warnings, asyncFuncs, ATINITS: ATINITS.join('\n'), - ATMAINS: ATMAINS.join('\n'), + ATMAINS: STRICT ? '' : ATMAINS.join('\n'), ATEXITS: ATEXITS.join('\n'), })); } diff --git a/src/parseTools.js b/src/parseTools.js index ee2a1dcbae6d1..167767e0f2915 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -654,15 +654,6 @@ function addAtInit(code) { ATINITS.push(code); } -// TODO(sbc): There are no more uses to ATMAINS or addAtMain in emscripten. -// We should look into removing these. -global.ATMAINS = []; - -function addAtMain(code) { - assert(HAS_MAIN, 'addAtMain called but program has no main function'); - ATMAINS.push(code); -} - global.ATEXITS = []; function addAtExit(code) { diff --git a/src/parseTools_legacy.js b/src/parseTools_legacy.js index 1a808b0c4a610..e335c6e026f90 100644 --- a/src/parseTools_legacy.js +++ b/src/parseTools_legacy.js @@ -99,3 +99,10 @@ global.Runtime = { POINTER_SIZE: POINTER_SIZE, QUANTUM_SIZE: POINTER_SIZE, }; + +global.ATMAINS = []; + +function addAtMain(code) { + assert(HAS_MAIN, 'addAtMain called but program has no main function'); + ATMAINS.push(code); +} From daecbfcac67d5299b4583e287f14e27fb59dc85e Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 17 May 2023 10:26:22 -0700 Subject: [PATCH 0253/1523] Bump binaryen to v113 (#19384) --- tools/building.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/building.py b/tools/building.py index 7b37bb181973d..fcd4df3697a62 100644 --- a/tools/building.py +++ b/tools/building.py @@ -38,7 +38,7 @@ # Building binaryen_checked = False -EXPECTED_BINARYEN_VERSION = 112 +EXPECTED_BINARYEN_VERSION = 113 _is_ar_cache: Dict[str, bool] = {} # the exports the user requested From fba7c2e4c27f493c55c8f783983701dc8b40022c Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 17 May 2023 16:20:57 -0700 Subject: [PATCH 0254/1523] Make use of musl's `weak` macro. NFC (#19385) --- system/lib/libc/emscripten_syscall_stubs.c | 4 ---- system/lib/standalone/standalone.c | 28 ++++++++++------------ tools/system_libs.py | 1 + 3 files changed, 14 insertions(+), 19 deletions(-) diff --git a/system/lib/libc/emscripten_syscall_stubs.c b/system/lib/libc/emscripten_syscall_stubs.c index 248efbdcb2331..78d16e8792877 100644 --- a/system/lib/libc/emscripten_syscall_stubs.c +++ b/system/lib/libc/emscripten_syscall_stubs.c @@ -46,10 +46,6 @@ static mode_t g_umask = S_IRWXU | S_IRWXG | S_IRWXO; #define STRINGIFY(s) #s #define STR(s) STRINGIFY(s) -#ifndef weak -#define weak __attribute__((__weak__)) -#endif - weak int __syscall_uname(intptr_t buf) { if (!buf) { return -EFAULT; diff --git a/system/lib/standalone/standalone.c b/system/lib/standalone/standalone.c index dcb0149bc63cd..1e89880a5a6cc 100644 --- a/system/lib/standalone/standalone.c +++ b/system/lib/standalone/standalone.c @@ -70,17 +70,17 @@ int clock_getres(clockid_t clk_id, struct timespec *tp) { // Mark these as weak so that wasmfs does not collide with it. That is, if // wasmfs is in use, we want to use that and not this. -__attribute__((__weak__)) int _mmap_js(size_t length, - int prot, - int flags, - int fd, - size_t offset, - int* allocated, - void** addr) { +weak int _mmap_js(size_t length, + int prot, + int flags, + int fd, + size_t offset, + int* allocated, + void** addr) { return -ENOSYS; } -__attribute__((__weak__)) int _munmap_js( +weak int _munmap_js( intptr_t addr, size_t length, int prot, int flags, int fd, size_t offset) { return -ENOSYS; } @@ -89,8 +89,7 @@ __attribute__((__weak__)) int _munmap_js( // corner case error checking; everything else is not permitted. // TODO: full file support for WASI, or an option for it // open() -__attribute__((__weak__)) -int __syscall_openat(int dirfd, intptr_t path, int flags, ...) { +weak int __syscall_openat(int dirfd, intptr_t path, int flags, ...) { if (!strcmp((const char*)path, "/dev/stdin")) { return STDIN_FILENO; } @@ -103,22 +102,21 @@ int __syscall_openat(int dirfd, intptr_t path, int flags, ...) { return -EPERM; } -__attribute__((__weak__)) int __syscall_ioctl(int fd, int op, ...) { +weak int __syscall_ioctl(int fd, int op, ...) { return -ENOSYS; } -__attribute__((__weak__)) int __syscall_fcntl64(int fd, int cmd, ...) { +weak int __syscall_fcntl64(int fd, int cmd, ...) { return -ENOSYS; } -__attribute__((__weak__)) int __syscall_fstat64(int fd, intptr_t buf) { +weak int __syscall_fstat64(int fd, intptr_t buf) { return -ENOSYS; } // There is no good source of entropy without an import. Make this weak so that // it can be replaced with a pRNG or a proper import. -__attribute__((__weak__)) -int getentropy(void* buffer, size_t length) { +weak int getentropy(void* buffer, size_t length) { abort(); } diff --git a/tools/system_libs.py b/tools/system_libs.py index 1485077d06f89..3c767f2b0d0cf 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -2047,6 +2047,7 @@ def can_use(self): class libstubs(DebugLibrary): name = 'libstubs' src_dir = 'system/lib/libc' + includes = ['system/lib/libc/musl/src/include'] src_files = ['emscripten_syscall_stubs.c', 'emscripten_libc_stubs.c'] From 4e01e0201518a51e2e9a1c858d3f11c18a38cdf3 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 17 May 2023 16:26:50 -0700 Subject: [PATCH 0255/1523] Fix multiple definitions of emscripten_memcpy_big in standalone mode (#19386) --- system/lib/standalone/standalone.c | 2 +- test/test_other.py | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/system/lib/standalone/standalone.c b/system/lib/standalone/standalone.c index 1e89880a5a6cc..d9de42f4c9c30 100644 --- a/system/lib/standalone/standalone.c +++ b/system/lib/standalone/standalone.c @@ -123,7 +123,7 @@ weak int getentropy(void* buffer, size_t length) { // Emscripten additions // Should never be called in standalone mode -void emscripten_memcpy_big(void *restrict dest, const void *restrict src, size_t n) { +weak void emscripten_memcpy_big(void *restrict dest, const void *restrict src, size_t n) { __builtin_unreachable(); } diff --git a/test/test_other.py b/test/test_other.py index df50bb866104f..0d41f9713d3b9 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -13488,3 +13488,8 @@ def test_preload_module(self, args): } ''') self.do_runf('main.c', 'done\n', emcc_args=['-sMAIN_MODULE=2', '--preload-file', 'tmp.so@library.so', '--use-preload-plugins'] + args) + + @node_pthreads + def test_standalone_whole_archive(self): + self.emcc_args += ['-sSTANDALONE_WASM', '-pthread', '-Wl,--whole-archive', '-lbulkmemory', '-lstandalonewasm', '-Wl,--no-whole-archive'] + self.do_runf(test_file('hello_world.c')) From 36f871819b566281d160470a1ec4515f379e9f77 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 17 May 2023 18:24:59 -0700 Subject: [PATCH 0256/1523] Rebaseline codesize expectations. NFC --- test/other/metadce/test_metadce_hello_dylink.jssize | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/other/metadce/test_metadce_hello_dylink.jssize b/test/other/metadce/test_metadce_hello_dylink.jssize index 1a27139cbd9fd..f14659634d305 100644 --- a/test/other/metadce/test_metadce_hello_dylink.jssize +++ b/test/other/metadce/test_metadce_hello_dylink.jssize @@ -1 +1 @@ -15091 +15054 From 02b938354be598a8070222c6066bc3944159bfe3 Mon Sep 17 00:00:00 2001 From: Derek Schuff Date: Thu, 18 May 2023 19:44:37 -0700 Subject: [PATCH 0257/1523] Mark 3.1.39 as released (#19393) --- ChangeLog.md | 5 ++++- emscripten-version.txt | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 0f75f60afbd22..658a00d4cdc8d 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -18,8 +18,11 @@ to browse the changes between the tags. See docs/process.md for more on how version tagging works. -3.1.39 (in development) +3.1.40 (in development) ----------------------- + +3.1.39 - 05/18/23 +----------------- - The JS `err()` function will now bind to `console.error` by default rather than `console.warning`. For debugging/tracing/logging we recommend the `dbg()` function instead. (#19326) diff --git a/emscripten-version.txt b/emscripten-version.txt index a3355af430b15..487ec7db5c6d2 100644 --- a/emscripten-version.txt +++ b/emscripten-version.txt @@ -1 +1 @@ -3.1.39-git +3.1.40-git From bfbef100f38bcad21284dcbd9ed463e404a264c9 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 19 May 2023 10:32:58 -0700 Subject: [PATCH 0258/1523] Rebaseline code size tests after LLVM changes (#19398) --- test/code_size/hello_webgl2_wasm.json | 8 ++++---- test/code_size/hello_webgl2_wasm2js.json | 8 ++++---- test/code_size/hello_webgl_wasm.json | 8 ++++---- test/code_size/hello_webgl_wasm2js.json | 8 ++++---- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/test/code_size/hello_webgl2_wasm.json b/test/code_size/hello_webgl2_wasm.json index d15f161407b87..405f3b72043b7 100644 --- a/test/code_size/hello_webgl2_wasm.json +++ b/test/code_size/hello_webgl2_wasm.json @@ -3,8 +3,8 @@ "a.html.gz": 379, "a.js": 4971, "a.js.gz": 2430, - "a.wasm": 10482, - "a.wasm.gz": 6707, - "total": 16022, - "total_gz": 9516 + "a.wasm": 10505, + "a.wasm.gz": 6720, + "total": 16045, + "total_gz": 9529 } diff --git a/test/code_size/hello_webgl2_wasm2js.json b/test/code_size/hello_webgl2_wasm2js.json index c7c3da01de188..ccf1b754ee15a 100644 --- a/test/code_size/hello_webgl2_wasm2js.json +++ b/test/code_size/hello_webgl2_wasm2js.json @@ -1,10 +1,10 @@ { "a.html": 567, "a.html.gz": 379, - "a.js": 18252, - "a.js.gz": 8055, + "a.js": 18284, + "a.js.gz": 8070, "a.mem": 3171, "a.mem.gz": 2713, - "total": 21990, - "total_gz": 11147 + "total": 22022, + "total_gz": 11162 } diff --git a/test/code_size/hello_webgl_wasm.json b/test/code_size/hello_webgl_wasm.json index 86d566419f1a9..1f8742c004762 100644 --- a/test/code_size/hello_webgl_wasm.json +++ b/test/code_size/hello_webgl_wasm.json @@ -3,8 +3,8 @@ "a.html.gz": 379, "a.js": 4450, "a.js.gz": 2250, - "a.wasm": 10482, - "a.wasm.gz": 6707, - "total": 15501, - "total_gz": 9336 + "a.wasm": 10505, + "a.wasm.gz": 6720, + "total": 15524, + "total_gz": 9349 } diff --git a/test/code_size/hello_webgl_wasm2js.json b/test/code_size/hello_webgl_wasm2js.json index 0ce1b1997c10a..b487536835b53 100644 --- a/test/code_size/hello_webgl_wasm2js.json +++ b/test/code_size/hello_webgl_wasm2js.json @@ -1,10 +1,10 @@ { "a.html": 567, "a.html.gz": 379, - "a.js": 17724, - "a.js.gz": 7870, + "a.js": 17756, + "a.js.gz": 7893, "a.mem": 3171, "a.mem.gz": 2713, - "total": 21462, - "total_gz": 10962 + "total": 21494, + "total_gz": 10985 } From 7cff8f120b1ce23f986e104d24181fb14b162327 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 19 May 2023 10:48:55 -0700 Subject: [PATCH 0259/1523] WasmFS: Allow the root to exist already (#19396) It's ok for the root to exist in some cases, e.g. if the preload hook created it or if we use NODERAWFS which makes the root the normal underlying filesystem. --- system/lib/wasmfs/wasmfs.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/system/lib/wasmfs/wasmfs.cpp b/system/lib/wasmfs/wasmfs.cpp index d4e8578f512a1..10b0419ed2ea9 100644 --- a/system/lib/wasmfs/wasmfs.cpp +++ b/system/lib/wasmfs/wasmfs.cpp @@ -85,9 +85,10 @@ std::shared_ptr WasmFS::initRootDirectory() { // The root directory is its own parent. lockedRoot.setParent(rootDirectory); + // If the /dev/ directory does not already exist, create it. (It may already + // exist in NODERAWFS mode, or if those files have been preloaded.) auto devDir = lockedRoot.insertDirectory("dev", S_IRUGO | S_IXUGO); - assert(devDir); - { + if (devDir) { auto lockedDev = devDir->locked(); lockedDev.mountChild("null", SpecialFiles::getNull()); lockedDev.mountChild("stdin", SpecialFiles::getStdin()); @@ -97,8 +98,9 @@ std::shared_ptr WasmFS::initRootDirectory() { lockedDev.mountChild("urandom", SpecialFiles::getURandom()); } - [[maybe_unused]] auto tmpDir = lockedRoot.insertDirectory("tmp", S_IRWXUGO); - assert(tmpDir); + // As with the /dev/ directory, it is not an error for /tmp/ to already + // exist. + lockedRoot.insertDirectory("tmp", S_IRWXUGO); return rootDirectory; } From 7e8b11cfaa78bdffe13bf4963347f4709e97ee76 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 19 May 2023 11:21:52 -0700 Subject: [PATCH 0260/1523] WasmFS: Open and close files in the JS API _wasmfs_write_file (#19397) The memory backend appears to allow lockedFile.write without .open first, but other backends like Node do not. In general, it seems correct to open the file before writing and close it after, and the read JS API call does so, so this fixes the write one. --- system/lib/wasmfs/js_api.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/system/lib/wasmfs/js_api.cpp b/system/lib/wasmfs/js_api.cpp index fe33dd4ff6dd7..f9de0e65ad37f 100644 --- a/system/lib/wasmfs/js_api.cpp +++ b/system/lib/wasmfs/js_api.cpp @@ -88,11 +88,24 @@ int _wasmfs_write_file(char* pathname, char* data, size_t data_size) { } auto lockedFile = dataFile->locked(); + int err = lockedFile.open(O_WRONLY); + if (err < 0) { + emscripten_console_error("Fatal error in FS.writeFile"); + abort(); + } + auto offset = lockedFile.getSize(); auto result = lockedFile.write((uint8_t*)data, data_size, offset); if (result != __WASI_ERRNO_SUCCESS) { return 0; } + + err = lockedFile.close(); + if (err < 0) { + emscripten_console_error("Fatal error in FS.writeFile"); + abort(); + } + return data_size; } From 98b618f09bc106d401c0045fa7252f1cd15bd3c0 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 19 May 2023 14:28:51 -0700 Subject: [PATCH 0261/1523] Test runner: Allow randomMODEn for any test mode (#19401) Previously other and browser were hardcoded. This allows all modes to work. For example, with this PR you can do tests/runner.py randomwasmfs10 and it will run 10 random wasmfs.* tests. --- test/runner.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/test/runner.py b/test/runner.py index 3baf775eb970c..53c75f16afbfc 100755 --- a/test/runner.py +++ b/test/runner.py @@ -207,14 +207,12 @@ def get_random_test_parameters(arg): relevant_modes = passing_core_test_modes if len(arg): num_str = arg - if arg.startswith('other'): - base_module = 'other' - relevant_modes = ['other'] - num_str = arg.replace('other', '') - elif arg.startswith('browser'): - base_module = 'browser' - relevant_modes = ['browser'] - num_str = arg.replace('browser', '') + for mode in passing_core_test_modes + misc_test_modes: + if arg.startswith(mode): + base_module = mode + relevant_modes = [mode] + num_str = arg.replace(mode, '') + break num_tests = int(num_str) return num_tests, base_module, relevant_modes From db960c80f8b37bd79c34772405674bf55e664910 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 22 May 2023 07:50:10 -0700 Subject: [PATCH 0262/1523] Simplify FS.fdnext and FS.createStream. NFC (#19391) In all cases where we want to force a particular fd, we specific a single one, and not a range. This means that range based search using FD.fdnext() is not necessary. This lays the ground work for moving to HandleAllocator. --- site/source/docs/api_reference/advanced-apis.rst | 4 ++-- src/library_fs.js | 10 ++++++---- src/library_noderawfs.js | 15 ++++++--------- src/library_syscall.js | 12 ++++++------ test/other/metadce/test_metadce_cxx_ctors1.jssize | 2 +- test/other/metadce/test_metadce_cxx_ctors2.jssize | 2 +- test/other/metadce/test_metadce_cxx_except.jssize | 2 +- .../metadce/test_metadce_cxx_except_wasm.jssize | 2 +- test/other/metadce/test_metadce_cxx_mangle.jssize | 2 +- .../metadce/test_metadce_cxx_noexcept.jssize | 2 +- 10 files changed, 26 insertions(+), 27 deletions(-) diff --git a/site/source/docs/api_reference/advanced-apis.rst b/site/source/docs/api_reference/advanced-apis.rst index 36656726b6267..23a917defc608 100644 --- a/site/source/docs/api_reference/advanced-apis.rst +++ b/site/source/docs/api_reference/advanced-apis.rst @@ -78,9 +78,9 @@ example, writing a new local file system) or legacy file system compatibility. .. js:function:: FS.isRoot(node) .. js:function:: FS.isMountpoint(node) .. js:function:: FS.isFIFO(node) -.. js:function:: FS.nextfd(fd_start, fd_end) +.. js:function:: FS.nextfd() .. js:function:: FS.getStream(fd) -.. js:function:: FS.createStream(stream, fd_start, fd_end) +.. js:function:: FS.createStream(stream, fd) .. js:function:: FS.closeStream(fd) .. js:function:: FS.getStreamFromPtr(ptr) .. js:function:: FS.getPtrForStream(stream) diff --git a/src/library_fs.js b/src/library_fs.js index 4726e020994eb..79970eb6a955f 100644 --- a/src/library_fs.js +++ b/src/library_fs.js @@ -373,8 +373,8 @@ FS.staticInit();` + // streams // MAX_OPEN_FDS: 4096, - nextfd: (fd_start = 0, fd_end = FS.MAX_OPEN_FDS) => { - for (var fd = fd_start; fd <= fd_end; fd++) { + nextfd: () => { + for (var fd = 0; fd <= FS.MAX_OPEN_FDS; fd++) { if (!FS.streams[fd]) { return fd; } @@ -385,7 +385,7 @@ FS.staticInit();` + // TODO parameterize this function such that a stream // object isn't directly passed in. not possible until // SOCKFS is completed. - createStream: (stream, fd_start, fd_end) => { + createStream: (stream, fd = -1) => { if (!FS.FSStream) { FS.FSStream = /** @constructor */ function() { this.shared = { }; @@ -426,7 +426,9 @@ FS.staticInit();` + } // clone it, so we can return an instance of FSStream stream = Object.assign(new FS.FSStream(), stream); - var fd = FS.nextfd(fd_start, fd_end); + if (fd == -1) { + fd = FS.nextfd(); + } stream.fd = fd; FS.streams[fd] = stream; return stream; diff --git a/src/library_noderawfs.js b/src/library_noderawfs.js index dc98b1f00a918..4de762e4130f1 100644 --- a/src/library_noderawfs.js +++ b/src/library_noderawfs.js @@ -44,9 +44,9 @@ mergeInto(LibraryManager.library, { return { path: path, node: { id: st.ino, mode: mode, node_ops: NODERAWFS, path: path }}; }, createStandardStreams: function() { - FS.streams[0] = FS.createStream({ nfd: 0, position: 0, path: '', flags: 0, tty: true, seekable: false }, 0, 0); + FS.createStream({ nfd: 0, position: 0, path: '', flags: 0, tty: true, seekable: false }, 0); for (var i = 1; i < 3; i++) { - FS.streams[i] = FS.createStream({ nfd: i, position: 0, path: '', flags: 577, tty: true, seekable: false }, i, i); + FS.createStream({ nfd: i, position: 0, path: '', flags: 577, tty: true, seekable: false }, i); } }, // generic function for all node creation @@ -81,7 +81,7 @@ mergeInto(LibraryManager.library, { fs.ftruncateSync.apply(void 0, arguments); }, utime: function(path, atime, mtime) { fs.utimesSync(path, atime/1000, mtime/1000); }, - open: function(path, flags, mode, suggestFD) { + open: function(path, flags, mode) { if (typeof flags == "string") { flags = FS_modeStringToFlags(flags) } @@ -93,15 +93,12 @@ mergeInto(LibraryManager.library, { throw new FS.ErrnoError(ERRNO_CODES.ENOTDIR); } var newMode = NODEFS.getMode(pathTruncated); - var fd = suggestFD != null ? suggestFD : FS.nextfd(nfd); var node = { id: st.ino, mode: newMode, node_ops: NODERAWFS, path: path } - var stream = FS.createStream({ nfd: nfd, position: 0, path: path, flags: flags, node: node, seekable: true }, fd, fd); - FS.streams[fd] = stream; - return stream; + return FS.createStream({ nfd: nfd, position: 0, path: path, flags: flags, node: node, seekable: true }, nfd); }, - createStream: function(stream, fd_start, fd_end){ + createStream: function(stream, fd) { // Call the original FS.createStream - var rtn = VFS.createStream(stream, fd_start, fd_end); + var rtn = VFS.createStream(stream, fd); if (typeof rtn.shared.refcnt == 'undefined') { rtn.shared.refcnt = 1; } else { diff --git a/src/library_syscall.js b/src/library_syscall.js index 9192995f60200..129151e09abb3 100644 --- a/src/library_syscall.js +++ b/src/library_syscall.js @@ -185,7 +185,7 @@ var SyscallsLibrary = { }, __syscall_dup: function(fd) { var old = SYSCALLS.getStreamFromFD(fd); - return FS.createStream(old, 0).fd; + return FS.createStream(old).fd; }, __syscall_pipe__deps: ['$PIPEFS'], __syscall_pipe: function(fdPtr) { @@ -956,15 +956,15 @@ var SyscallsLibrary = { FS.allocate(stream, offset, len); return 0; }, - __syscall_dup3: function(fd, suggestFD, flags) { + __syscall_dup3: function(fd, newfd, flags) { var old = SYSCALLS.getStreamFromFD(fd); #if ASSERTIONS assert(!flags); #endif - if (old.fd === suggestFD) return -{{{ cDefs.EINVAL }}}; - var suggest = FS.getStream(suggestFD); - if (suggest) FS.close(suggest); - return FS.createStream(old, suggestFD, suggestFD + 1).fd; + if (old.fd === newfd) return -{{{ cDefs.EINVAL }}}; + var existing = FS.getStream(newfd); + if (existing) FS.close(existing); + return FS.createStream(old, newfd).fd; }, }; diff --git a/test/other/metadce/test_metadce_cxx_ctors1.jssize b/test/other/metadce/test_metadce_cxx_ctors1.jssize index 6ed4ae37700b9..b7e08511e13c3 100644 --- a/test/other/metadce/test_metadce_cxx_ctors1.jssize +++ b/test/other/metadce/test_metadce_cxx_ctors1.jssize @@ -1 +1 @@ -25933 +25948 diff --git a/test/other/metadce/test_metadce_cxx_ctors2.jssize b/test/other/metadce/test_metadce_cxx_ctors2.jssize index 6f07b8bd2eae0..5c59d01da814e 100644 --- a/test/other/metadce/test_metadce_cxx_ctors2.jssize +++ b/test/other/metadce/test_metadce_cxx_ctors2.jssize @@ -1 +1 @@ -25897 +25912 diff --git a/test/other/metadce/test_metadce_cxx_except.jssize b/test/other/metadce/test_metadce_cxx_except.jssize index 14cacbe2b6cbc..3bd99284499e0 100644 --- a/test/other/metadce/test_metadce_cxx_except.jssize +++ b/test/other/metadce/test_metadce_cxx_except.jssize @@ -1 +1 @@ -30447 +30462 diff --git a/test/other/metadce/test_metadce_cxx_except_wasm.jssize b/test/other/metadce/test_metadce_cxx_except_wasm.jssize index d3f89d763150e..dabbf8a07d891 100644 --- a/test/other/metadce/test_metadce_cxx_except_wasm.jssize +++ b/test/other/metadce/test_metadce_cxx_except_wasm.jssize @@ -1 +1 @@ -25742 +25757 diff --git a/test/other/metadce/test_metadce_cxx_mangle.jssize b/test/other/metadce/test_metadce_cxx_mangle.jssize index 6692325dc5cb5..74bf7aad77fdc 100644 --- a/test/other/metadce/test_metadce_cxx_mangle.jssize +++ b/test/other/metadce/test_metadce_cxx_mangle.jssize @@ -1 +1 @@ -30446 +30461 diff --git a/test/other/metadce/test_metadce_cxx_noexcept.jssize b/test/other/metadce/test_metadce_cxx_noexcept.jssize index 6ed4ae37700b9..b7e08511e13c3 100644 --- a/test/other/metadce/test_metadce_cxx_noexcept.jssize +++ b/test/other/metadce/test_metadce_cxx_noexcept.jssize @@ -1 +1 @@ -25933 +25948 From d690e3d21688502f2a73222f05e1843fdeeaa469 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 22 May 2023 11:12:40 -0700 Subject: [PATCH 0263/1523] WasmFS: Use the shorter mkdirSync option form, like the old FS, to avoid a closure error (#19412) --- src/library_wasmfs_node.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/library_wasmfs_node.js b/src/library_wasmfs_node.js index d805104d3e0e7..39ddb60b6c07a 100644 --- a/src/library_wasmfs_node.js +++ b/src/library_wasmfs_node.js @@ -124,7 +124,7 @@ mergeInto(LibraryManager.library, { _wasmfs_node_insert_directory__deps: ['$wasmfsNodeConvertNodeCode'], _wasmfs_node_insert_directory: function(path_p, mode) { try { - fs.mkdirSync(UTF8ToString(path_p), { mode: mode }); + fs.mkdirSync(UTF8ToString(path_p), mode); } catch (e) { if (!e.code) throw e; return wasmfsNodeConvertNodeCode(e); From 1d5b0705c9f6a1e1a1da3aae6925b0f914d9e8d3 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 22 May 2023 11:14:32 -0700 Subject: [PATCH 0264/1523] WasmFS: Add basic NODERAWFS support (#19400) This PR makes the NODERAWFS flag make the root directory be created using the Node backend. That may not be 100% of what we need for NODERAWFS but it gets a significant amount of tests passing. To do that, add a hook that backends can use to override creation of the root directory. Then NODERAWFS support basically is just to link in a tiny library that overrides that hook. This adds a new test, test_noderawfs_wasmfs which verifies we write files out to the normal filesystem. Also, enable test_freetype, which now passes; previously it failed during a configure step (specifically, configure tried to write the size of an integer to a file... before this PR, the file was empty and it defined integer size as the empty string). So test_freetype both verifies NODERAWFS writes, and also it uses files internally (to read font files etc.) which seems useful to enable. Also, this is tested in test_fs_writeFile_rawfs. That test does FS.writeFile with NODERAWFS enabled. It passed before, because enabling NODERAWFS did nothing... for WasmFS the test really just worked on the MemoryFile backend, since it doesn't create a Node backend. With this PR, the test properly uses Node files, and passes (thanks to #19397 and #19396). Note: other.test_unistd_fstatfs_wasmfs was removed from CI because it was unnecessary - all other tests run anyhow. We only need to add select wasmfs tests because that mode does not run in full already. --- .circleci/config.yml | 4 ++-- emcc.py | 2 ++ src/library_wasmfs_node.js | 11 +++++++++++ system/include/emscripten/wasmfs.h | 5 +++++ system/lib/wasmfs/backends/noderawfs_root.cpp | 14 ++++++++++++++ system/lib/wasmfs/wasmfs.cpp | 14 +++++++++----- test/test_other.py | 3 ++- tools/system_libs.py | 16 ++++++++++++++++ 8 files changed, 61 insertions(+), 8 deletions(-) create mode 100644 system/lib/wasmfs/backends/noderawfs_root.cpp diff --git a/.circleci/config.yml b/.circleci/config.yml index 3e1da78df32f5..675c796add0ab 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -500,7 +500,6 @@ jobs: core2ss.test_pthread_thread_local_storage core2s.test_dylink_syslibs_missing_assertions wasm2js3.test_memorygrowth_2 - other.test_unistd_fstatfs_wasmfs wasmfs.test_hello_world wasmfs.test_hello_world_standalone wasmfs.test_unistd_links* @@ -524,7 +523,8 @@ jobs: wasmfs.test_stat wasmfs.test_fstatat wasmfs.test_unistd_links_memfs - wasmfs.test_fcntl_open" + wasmfs.test_fcntl_open + wasmfs.test_freetype" test-wasm2js1: executor: bionic steps: diff --git a/emcc.py b/emcc.py index d02b5276873d2..1bf995473c0dd 100755 --- a/emcc.py +++ b/emcc.py @@ -2293,6 +2293,8 @@ def phase_linker_setup(options, state, newargs): if settings.WASMFS: state.forced_stdlibs.append('libwasmfs') + if settings.NODERAWFS: + state.forced_stdlibs.append('libwasmfs_noderawfs') settings.FILESYSTEM = 1 settings.SYSCALLS_REQUIRE_FILESYSTEM = 0 settings.JS_LIBRARIES.append((0, 'library_wasmfs.js')) diff --git a/src/library_wasmfs_node.js b/src/library_wasmfs_node.js index 39ddb60b6c07a..ce6d7e5ad68bf 100644 --- a/src/library_wasmfs_node.js +++ b/src/library_wasmfs_node.js @@ -50,6 +50,7 @@ mergeInto(LibraryManager.library, { return wasmfsNodeFixStat(stat); }, + _wasmfs_node_readdir__sig: 'ipp', _wasmfs_node_readdir__deps: ['$wasmfsNodeConvertNodeCode'], _wasmfs_node_readdir: function(path_p, vec) { let path = UTF8ToString(path_p); @@ -80,6 +81,7 @@ mergeInto(LibraryManager.library, { // implicitly return 0 }, + _wasmfs_node_get_mode__sig: 'ipp', _wasmfs_node_get_mode__deps: ['$wasmfsNodeLstat'], _wasmfs_node_get_mode: function(path_p, mode_p) { let stat = wasmfsNodeLstat(UTF8ToString(path_p)); @@ -90,6 +92,7 @@ mergeInto(LibraryManager.library, { // implicitly return 0 }, + _wasmfs_node_stat_size__sig: 'ipp', _wasmfs_node_stat_size__deps: ['$wasmfsNodeLstat'], _wasmfs_node_stat_size: function(path_p, size_p) { let stat = wasmfsNodeLstat(UTF8ToString(path_p)); @@ -100,6 +103,7 @@ mergeInto(LibraryManager.library, { // implicitly return 0 }, + _wasmfs_node_fstat_size__sig: 'iip', _wasmfs_node_fstat_size__deps: ['$wasmfsNodeFstat'], _wasmfs_node_fstat_size: function(fd, size_p) { let stat = wasmfsNodeFstat(fd); @@ -110,6 +114,7 @@ mergeInto(LibraryManager.library, { // implicitly return 0 }, + _wasmfs_node_insert_file__sig: 'ipi', _wasmfs_node_insert_file__deps: ['$wasmfsNodeConvertNodeCode'], _wasmfs_node_insert_file: function(path_p, mode) { try { @@ -121,6 +126,7 @@ mergeInto(LibraryManager.library, { // implicitly return 0 }, + _wasmfs_node_insert_directory__sig: 'ipi', _wasmfs_node_insert_directory__deps: ['$wasmfsNodeConvertNodeCode'], _wasmfs_node_insert_directory: function(path_p, mode) { try { @@ -132,6 +138,7 @@ mergeInto(LibraryManager.library, { // implicitly return 0 }, + _wasmfs_node_unlink__sig: 'ip', _wasmfs_node_unlink__deps: ['$wasmfsNodeConvertNodeCode'], _wasmfs_node_unlink: function(path_p) { try { @@ -143,6 +150,7 @@ mergeInto(LibraryManager.library, { // implicitly return 0 }, + _wasmfs_node_rmdir__sig: 'ip', _wasmfs_node_rmdir__deps: ['$wasmfsNodeConvertNodeCode'], _wasmfs_node_rmdir: function(path_p) { try { @@ -154,6 +162,7 @@ mergeInto(LibraryManager.library, { // implicitly return 0 }, + _wasmfs_node_open__sig: 'ipp', _wasmfs_node_open__deps: ['$wasmfsNodeConvertNodeCode'], _wasmfs_node_open: function(path_p, mode_p) { try { @@ -174,6 +183,7 @@ mergeInto(LibraryManager.library, { } }, + _wasmfs_node_read__sig: 'iipiip', _wasmfs_node_read__deps: ['$wasmfsNodeConvertNodeCode'], _wasmfs_node_read: function(fd, buf_p, len, pos, nread_p) { try { @@ -188,6 +198,7 @@ mergeInto(LibraryManager.library, { // implicitly return 0 }, + _wasmfs_node_write__sig: 'iipiip', _wasmfs_node_write__deps : ['$wasmfsNodeConvertNodeCode'], _wasmfs_node_write : function(fd, buf_p, len, pos, nwritten_p) { try { diff --git a/system/include/emscripten/wasmfs.h b/system/include/emscripten/wasmfs.h index 98cda2cb543e4..1b19e0622042c 100644 --- a/system/include/emscripten/wasmfs.h +++ b/system/include/emscripten/wasmfs.h @@ -71,6 +71,11 @@ backend_t wasmfs_create_icase_backend(backend_constructor_t create_backend, // Hooks +// A hook users can do to create the root directory. Overriding this allows the +// user to set a particular backend as the root. If this is not set then the +// default backend is used. +backend_t wasmfs_create_root_dir(void); + // A hook users can do to run code during WasmFS startup. This hook happens // before file preloading, so user code could create backends and mount them, // which would then affect in which backend the preloaded files are loaded (the diff --git a/system/lib/wasmfs/backends/noderawfs_root.cpp b/system/lib/wasmfs/backends/noderawfs_root.cpp new file mode 100644 index 0000000000000..edbb667582954 --- /dev/null +++ b/system/lib/wasmfs/backends/noderawfs_root.cpp @@ -0,0 +1,14 @@ +// Copyright 2023 The Emscripten Authors. All rights reserved. +// Emscripten is available under two separate licenses, the MIT license and the +// University of Illinois/NCSA Open Source License. Both these licenses can be +// found in the LICENSE file. + +#include "emscripten/wasmfs.h" + +namespace wasmfs { + +backend_t wasmfs_create_root_dir(void) { + return wasmfs_create_node_backend("."); +} + +} // namespace wasmfs diff --git a/system/lib/wasmfs/wasmfs.cpp b/system/lib/wasmfs/wasmfs.cpp index 10b0419ed2ea9..848ce4c4cb46b 100644 --- a/system/lib/wasmfs/wasmfs.cpp +++ b/system/lib/wasmfs/wasmfs.cpp @@ -70,14 +70,18 @@ WasmFS::~WasmFS() { rootDirectory->locked().setParent(nullptr); } -std::shared_ptr WasmFS::initRootDirectory() { - +// Special backends that want to install themselves as the root use this hook. +// Otherwise, we use the default backends. +__attribute__((weak)) extern backend_t wasmfs_create_root_dir(void) { #ifdef WASMFS_CASE_INSENSITIVE - auto rootBackend = - createIgnoreCaseBackend([]() { return createMemoryBackend(); }); + return createIgnoreCaseBackend([]() { return createMemoryBackend(); }); #else - auto rootBackend = createMemoryBackend(); + return createMemoryBackend(); #endif +} + +std::shared_ptr WasmFS::initRootDirectory() { + auto rootBackend = wasmfs_create_root_dir(); auto rootDirectory = rootBackend->createDirectory(S_IRUGO | S_IXUGO | S_IWUGO); auto lockedRoot = rootDirectory->locked(); diff --git a/test/test_other.py b/test/test_other.py index 0d41f9713d3b9..8b32cb70a784f 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -8881,8 +8881,9 @@ def test_toolchain_profiler_stderr(self): self.assertContained('start block "main"', stderr) self.assertContained('block "main" took', stderr) + @also_with_wasmfs def test_noderawfs(self): - self.run_process([EMXX, test_file('fs/test_fopen_write.cpp'), '-sNODERAWFS']) + self.run_process([EMXX, test_file('fs/test_fopen_write.cpp'), '-sNODERAWFS'] + self.get_emcc_args()) self.assertContained("read 11 bytes. Result: Hello data!", self.run_js('a.out.js')) # NODERAWFS should directly write on OS file system diff --git a/tools/system_libs.py b/tools/system_libs.py index 3c767f2b0d0cf..18d57e99178ec 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -1867,6 +1867,22 @@ def can_use(self): return settings.WASMFS +class libwasmfs_noderawfs(Library): + name = 'libwasmfs_noderawfs' + + cflags = ['-fno-exceptions', '-std=c++17'] + + includes = ['system/lib/wasmfs'] + + def get_files(self): + return files_in_path( + path='system/lib/wasmfs/backends', + filenames=['noderawfs_root.cpp']) + + def can_use(self): + return settings.WASMFS and settings.NODERAWFS + + class libhtml5(Library): name = 'libhtml5' From 6b179e3a5fe272b444f332fcbeb589c71cfa15b8 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 22 May 2023 11:20:47 -0700 Subject: [PATCH 0265/1523] WasmFS: Fix test_fcntl_misc (#19403) WasmFS now behaves the same as the old FS, which was correct, despite some confusion in the old comment that is removed here. --- .circleci/config.yml | 1 + test/fcntl/test_fcntl_misc.c | 5 ----- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 675c796add0ab..216c58c5491d3 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -506,6 +506,7 @@ jobs: wasmfs.test_atexit_standalone wasmfs.test_emscripten_get_now wasmfs.test_dyncall_specific_minimal_runtime + wasmfs.test_fcntl_misc wasmfs.test_utime wasmfs.test_unistd_unlink wasmfs.test_unistd_access diff --git a/test/fcntl/test_fcntl_misc.c b/test/fcntl/test_fcntl_misc.c index 1e3b4061ae7d9..57979998be449 100644 --- a/test/fcntl/test_fcntl_misc.c +++ b/test/fcntl/test_fcntl_misc.c @@ -25,12 +25,7 @@ int main() { printf("posix_fallocate: %d\n", posix_fallocate(f, 3, 2)); printf("errno: %d\n", errno); stat("/test", &s); -#if WASMFS - assert(s.st_size == 5); -#else - // The old FS, incorrectly, reports 6 here (unlike linux and wasmfs) assert(s.st_size == 6); -#endif memset(&s, 0, sizeof s); printf("\n"); errno = 0; From e711b019e7b1c74d45c39ae68271b62dfaaef4ac Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 22 May 2023 13:45:56 -0700 Subject: [PATCH 0266/1523] Auto-generate signatures for wasmfs functions. NFC (#19413) --- src/library_html5_webgl.js | 2 +- src/library_sigs.js | 54 +++++++++ src/library_wasmfs.js | 5 - src/library_wasmfs_jsimpl.js | 4 - src/library_wasmfs_node.js | 11 -- src/library_wasmfs_opfs.js | 38 ++---- system/lib/wasmfs/backends/fetch_backend.cpp | 7 +- system/lib/wasmfs/backends/fetch_backend.h | 13 +++ .../lib/wasmfs/backends/js_file_backend.cpp | 7 +- system/lib/wasmfs/backends/js_file_backend.h | 14 +++ system/lib/wasmfs/backends/node_backend.cpp | 39 +------ system/lib/wasmfs/backends/node_backend.h | 46 ++++++++ system/lib/wasmfs/backends/opfs_backend.cpp | 102 +---------------- system/lib/wasmfs/backends/opfs_backend.h | 108 ++++++++++++++++++ system/lib/wasmfs/file.cpp | 7 +- system/lib/wasmfs/wasmfs.cpp | 11 +- system/lib/wasmfs/wasmfs_internal.h | 19 +++ tools/gen_sig_info.py | 13 +++ 18 files changed, 282 insertions(+), 218 deletions(-) create mode 100644 system/lib/wasmfs/backends/fetch_backend.h create mode 100644 system/lib/wasmfs/backends/js_file_backend.h create mode 100644 system/lib/wasmfs/backends/node_backend.h create mode 100644 system/lib/wasmfs/backends/opfs_backend.h create mode 100644 system/lib/wasmfs/wasmfs_internal.h diff --git a/src/library_html5_webgl.js b/src/library_html5_webgl.js index 559068f3f5432..5295453c5bc97 100644 --- a/src/library_html5_webgl.js +++ b/src/library_html5_webgl.js @@ -609,7 +609,7 @@ function handleWebGLProxying(funcs) { } handleWebGLProxying(LibraryHtml5WebGL); -#endif // USE_PTHREADS +#endif // PTHREADS #if LibraryManager.has('library_webgl.js') autoAddDeps(LibraryHtml5WebGL, '$GL'); diff --git a/src/library_sigs.js b/src/library_sigs.js index 18ad740b9689a..4f4785f8da05b 100644 --- a/src/library_sigs.js +++ b/src/library_sigs.js @@ -363,6 +363,60 @@ sigs = { _setitimer_js__sig: 'iid', _timegm_js__sig: 'ip', _tzset_js__sig: 'vppp', + _wasmfs_copy_preloaded_file_data__sig: 'vip', + _wasmfs_create_fetch_backend_js__sig: 'vp', + _wasmfs_create_js_file_backend_js__sig: 'vp', + _wasmfs_get_num_preloaded_dirs__sig: 'i', + _wasmfs_get_num_preloaded_files__sig: 'i', + _wasmfs_get_preloaded_child_path__sig: 'vip', + _wasmfs_get_preloaded_file_mode__sig: 'ii', + _wasmfs_get_preloaded_file_size__sig: 'pi', + _wasmfs_get_preloaded_parent_path__sig: 'vip', + _wasmfs_get_preloaded_path_name__sig: 'vip', + _wasmfs_jsimpl_alloc_file__sig: 'vpp', + _wasmfs_jsimpl_async_alloc_file__sig: 'vppp', + _wasmfs_jsimpl_async_free_file__sig: 'vppp', + _wasmfs_jsimpl_async_get_size__sig: 'vpppp', + _wasmfs_jsimpl_async_read__sig: 'vpppppjp', + _wasmfs_jsimpl_async_write__sig: 'vpppppjp', + _wasmfs_jsimpl_free_file__sig: 'vpp', + _wasmfs_jsimpl_get_size__sig: 'ipp', + _wasmfs_jsimpl_read__sig: 'ippppj', + _wasmfs_jsimpl_write__sig: 'ippppj', + _wasmfs_node_close__sig: 'ii', + _wasmfs_node_fstat_size__sig: 'iip', + _wasmfs_node_get_mode__sig: 'ipp', + _wasmfs_node_insert_directory__sig: 'ipi', + _wasmfs_node_insert_file__sig: 'ipi', + _wasmfs_node_open__sig: 'ipp', + _wasmfs_node_read__sig: 'iipiip', + _wasmfs_node_readdir__sig: 'ipp', + _wasmfs_node_rmdir__sig: 'ip', + _wasmfs_node_stat_size__sig: 'ipp', + _wasmfs_node_unlink__sig: 'ip', + _wasmfs_node_write__sig: 'iipiip', + _wasmfs_opfs_close_access__sig: 'vpip', + _wasmfs_opfs_close_blob__sig: 'vi', + _wasmfs_opfs_flush_access__sig: 'vpip', + _wasmfs_opfs_free_directory__sig: 'vi', + _wasmfs_opfs_free_file__sig: 'vi', + _wasmfs_opfs_get_child__sig: 'vpippp', + _wasmfs_opfs_get_entries__sig: 'vpipp', + _wasmfs_opfs_get_size_access__sig: 'vpip', + _wasmfs_opfs_get_size_blob__sig: 'ii', + _wasmfs_opfs_get_size_file__sig: 'vpip', + _wasmfs_opfs_init_root_directory__sig: 'vp', + _wasmfs_opfs_insert_directory__sig: 'vpipp', + _wasmfs_opfs_insert_file__sig: 'vpipp', + _wasmfs_opfs_move_file__sig: 'vpiipp', + _wasmfs_opfs_open_access__sig: 'vpip', + _wasmfs_opfs_open_blob__sig: 'vpip', + _wasmfs_opfs_read_access__sig: 'iipii', + _wasmfs_opfs_read_blob__sig: 'ipipiip', + _wasmfs_opfs_remove_child__sig: 'vpipp', + _wasmfs_opfs_set_size_access__sig: 'vpijp', + _wasmfs_opfs_set_size_file__sig: 'vpijp', + _wasmfs_opfs_write_access__sig: 'iipii', abort__sig: 'v', alBuffer3f__sig: 'viifff', alBuffer3i__sig: 'viiiii', diff --git a/src/library_wasmfs.js b/src/library_wasmfs.js index fc05172dd8d5b..5d3d2f750decc 100644 --- a/src/library_wasmfs.js +++ b/src/library_wasmfs.js @@ -214,30 +214,25 @@ FS.createPreloadedFile = FS_createPreloadedFile; _wasmfs_get_preloaded_file_mode: function(index) { return wasmFSPreloadedFiles[index].mode; }, - _wasmfs_get_preloaded_parent_path__sig: 'vip', _wasmfs_get_preloaded_parent_path: function(index, parentPathBuffer) { var s = wasmFSPreloadedDirs[index].parentPath; var len = lengthBytesUTF8(s) + 1; stringToUTF8(s, parentPathBuffer, len); }, - _wasmfs_get_preloaded_child_path__sig: 'vip', _wasmfs_get_preloaded_child_path: function(index, childNameBuffer) { var s = wasmFSPreloadedDirs[index].childName; var len = lengthBytesUTF8(s) + 1; stringToUTF8(s, childNameBuffer, len); }, - _wasmfs_get_preloaded_path_name__sig: 'vip', _wasmfs_get_preloaded_path_name__deps: ['$lengthBytesUTF8', '$stringToUTF8'], _wasmfs_get_preloaded_path_name: function(index, fileNameBuffer) { var s = wasmFSPreloadedFiles[index].pathName; var len = lengthBytesUTF8(s) + 1; stringToUTF8(s, fileNameBuffer, len); }, - _wasmfs_get_preloaded_file_size__sig: 'pi', _wasmfs_get_preloaded_file_size: function(index) { return wasmFSPreloadedFiles[index].fileData.length; }, - _wasmfs_copy_preloaded_file_data__sig: 'vip', _wasmfs_copy_preloaded_file_data: function(index, buffer) { HEAPU8.set(wasmFSPreloadedFiles[index].fileData, buffer); } diff --git a/src/library_wasmfs_jsimpl.js b/src/library_wasmfs_jsimpl.js index 837b428998055..600e0afce1547 100644 --- a/src/library_wasmfs_jsimpl.js +++ b/src/library_wasmfs_jsimpl.js @@ -52,7 +52,6 @@ mergeInto(LibraryManager.library, { // implementors of backends: the hooks we call should return Promises, which // we then connect to the calling C++. - _wasmfs_jsimpl_async_alloc_file__sig: 'vppp', _wasmfs_jsimpl_async_alloc_file: async function(ctx, backend, file) { #if ASSERTIONS assert(wasmFS$backends[backend]); @@ -69,7 +68,6 @@ mergeInto(LibraryManager.library, { _emscripten_proxy_finish(ctx); }, - _wasmfs_jsimpl_async_write__sig: 'vpppppjp', _wasmfs_jsimpl_async_write: async function(ctx, backend, file, buffer, length, {{{ defineI64Param('offset') }}}, result_p) { {{{ receiveI64ParamAsDouble('offset') }}} #if ASSERTIONS @@ -80,7 +78,6 @@ mergeInto(LibraryManager.library, { _emscripten_proxy_finish(ctx); }, - _wasmfs_jsimpl_async_read__sig: 'vpppppjp', _wasmfs_jsimpl_async_read: async function(ctx, backend, file, buffer, length, {{{ defineI64Param('offset') }}}, result_p) { {{{ receiveI64ParamAsDouble('offset') }}} #if ASSERTIONS @@ -91,7 +88,6 @@ mergeInto(LibraryManager.library, { _emscripten_proxy_finish(ctx); }, - _wasmfs_jsimpl_async_get_size__sig: 'vpppp', _wasmfs_jsimpl_async_get_size: async function(ctx, backend, file, size_p) { #if ASSERTIONS assert(wasmFS$backends[backend]); diff --git a/src/library_wasmfs_node.js b/src/library_wasmfs_node.js index ce6d7e5ad68bf..39ddb60b6c07a 100644 --- a/src/library_wasmfs_node.js +++ b/src/library_wasmfs_node.js @@ -50,7 +50,6 @@ mergeInto(LibraryManager.library, { return wasmfsNodeFixStat(stat); }, - _wasmfs_node_readdir__sig: 'ipp', _wasmfs_node_readdir__deps: ['$wasmfsNodeConvertNodeCode'], _wasmfs_node_readdir: function(path_p, vec) { let path = UTF8ToString(path_p); @@ -81,7 +80,6 @@ mergeInto(LibraryManager.library, { // implicitly return 0 }, - _wasmfs_node_get_mode__sig: 'ipp', _wasmfs_node_get_mode__deps: ['$wasmfsNodeLstat'], _wasmfs_node_get_mode: function(path_p, mode_p) { let stat = wasmfsNodeLstat(UTF8ToString(path_p)); @@ -92,7 +90,6 @@ mergeInto(LibraryManager.library, { // implicitly return 0 }, - _wasmfs_node_stat_size__sig: 'ipp', _wasmfs_node_stat_size__deps: ['$wasmfsNodeLstat'], _wasmfs_node_stat_size: function(path_p, size_p) { let stat = wasmfsNodeLstat(UTF8ToString(path_p)); @@ -103,7 +100,6 @@ mergeInto(LibraryManager.library, { // implicitly return 0 }, - _wasmfs_node_fstat_size__sig: 'iip', _wasmfs_node_fstat_size__deps: ['$wasmfsNodeFstat'], _wasmfs_node_fstat_size: function(fd, size_p) { let stat = wasmfsNodeFstat(fd); @@ -114,7 +110,6 @@ mergeInto(LibraryManager.library, { // implicitly return 0 }, - _wasmfs_node_insert_file__sig: 'ipi', _wasmfs_node_insert_file__deps: ['$wasmfsNodeConvertNodeCode'], _wasmfs_node_insert_file: function(path_p, mode) { try { @@ -126,7 +121,6 @@ mergeInto(LibraryManager.library, { // implicitly return 0 }, - _wasmfs_node_insert_directory__sig: 'ipi', _wasmfs_node_insert_directory__deps: ['$wasmfsNodeConvertNodeCode'], _wasmfs_node_insert_directory: function(path_p, mode) { try { @@ -138,7 +132,6 @@ mergeInto(LibraryManager.library, { // implicitly return 0 }, - _wasmfs_node_unlink__sig: 'ip', _wasmfs_node_unlink__deps: ['$wasmfsNodeConvertNodeCode'], _wasmfs_node_unlink: function(path_p) { try { @@ -150,7 +143,6 @@ mergeInto(LibraryManager.library, { // implicitly return 0 }, - _wasmfs_node_rmdir__sig: 'ip', _wasmfs_node_rmdir__deps: ['$wasmfsNodeConvertNodeCode'], _wasmfs_node_rmdir: function(path_p) { try { @@ -162,7 +154,6 @@ mergeInto(LibraryManager.library, { // implicitly return 0 }, - _wasmfs_node_open__sig: 'ipp', _wasmfs_node_open__deps: ['$wasmfsNodeConvertNodeCode'], _wasmfs_node_open: function(path_p, mode_p) { try { @@ -183,7 +174,6 @@ mergeInto(LibraryManager.library, { } }, - _wasmfs_node_read__sig: 'iipiip', _wasmfs_node_read__deps: ['$wasmfsNodeConvertNodeCode'], _wasmfs_node_read: function(fd, buf_p, len, pos, nread_p) { try { @@ -198,7 +188,6 @@ mergeInto(LibraryManager.library, { // implicitly return 0 }, - _wasmfs_node_write__sig: 'iipiip', _wasmfs_node_write__deps : ['$wasmfsNodeConvertNodeCode'], _wasmfs_node_write : function(fd, buf_p, len, pos, nwritten_p) { try { diff --git a/src/library_wasmfs_opfs.js b/src/library_wasmfs_opfs.js index 630fdd5004b1c..72a6d11533e75 100644 --- a/src/library_wasmfs_opfs.js +++ b/src/library_wasmfs_opfs.js @@ -14,7 +14,7 @@ mergeInto(LibraryManager.library, { $wasmfsOPFSBlobs__deps: ["$HandleAllocator"], $wasmfsOPFSBlobs: "new HandleAllocator()", -#if !USE_PTHREADS +#if !PTHREADS // OPFS will only be used on modern browsers that supports JS classes. $FileSystemAsyncAccessHandle: class FileSystemAsyncAccessHandle { // This class implements the same interface as the sync version, but has @@ -62,12 +62,11 @@ mergeInto(LibraryManager.library, { // When using pthreads the proxy needs to know when the work is finished. // When used with JSPI the work will be executed in an async block so there // is no need to notify when done. -#if USE_PTHREADS +#if PTHREADS _emscripten_proxy_finish(ctx); #endif }, - _wasmfs_opfs_init_root_directory__sig: 'vp', _wasmfs_opfs_init_root_directory__deps: ['$wasmfsOPFSDirectoryHandles', '$wasmfsOPFSProxyFinish'], _wasmfs_opfs_init_root_directory: async function(ctx) { // allocated.length starts off as 1 since 0 is a reserved handle @@ -128,7 +127,6 @@ mergeInto(LibraryManager.library, { return wasmfsOPFSDirectoryHandles.allocate(childHandle); }, - _wasmfs_opfs_get_child__sig: 'vpippp', _wasmfs_opfs_get_child__deps: ['$wasmfsOPFSGetOrCreateFile', '$wasmfsOPFSGetOrCreateDir', '$wasmfsOPFSProxyFinish'], _wasmfs_opfs_get_child: @@ -145,7 +143,6 @@ mergeInto(LibraryManager.library, { wasmfsOPFSProxyFinish(ctx); }, - _wasmfs_opfs_get_entries__sig: 'vpipp', _wasmfs_opfs_get_entries__deps: ['$wasmfsOPFSProxyFinish'], _wasmfs_opfs_get_entries: async function(ctx, dirID, entriesPtr, errPtr) { let dirHandle = wasmfsOPFSDirectoryHandles.get(dirID); @@ -170,7 +167,6 @@ mergeInto(LibraryManager.library, { wasmfsOPFSProxyFinish(ctx); }, - _wasmfs_opfs_insert_file__sig: 'vpipp', _wasmfs_opfs_insert_file__deps: ['$wasmfsOPFSGetOrCreateFile', '$wasmfsOPFSProxyFinish'], _wasmfs_opfs_insert_file: async function(ctx, parent, namePtr, childIDPtr) { let name = UTF8ToString(namePtr); @@ -179,7 +175,6 @@ mergeInto(LibraryManager.library, { wasmfsOPFSProxyFinish(ctx); }, - _wasmfs_opfs_insert_directory__sig: 'vpipp', _wasmfs_opfs_insert_directory__deps: ['$wasmfsOPFSGetOrCreateDir', '$wasmfsOPFSProxyFinish'], _wasmfs_opfs_insert_directory: async function(ctx, parent, namePtr, childIDPtr) { @@ -189,7 +184,6 @@ mergeInto(LibraryManager.library, { wasmfsOPFSProxyFinish(ctx); }, - _wasmfs_opfs_move_file__sig: 'vpiipp', _wasmfs_opfs_move_file__deps: ['$wasmfsOPFSFileHandles', '$wasmfsOPFSDirectoryHandles', '$wasmfsOPFSProxyFinish'], @@ -206,7 +200,6 @@ mergeInto(LibraryManager.library, { wasmfsOPFSProxyFinish(ctx); }, - _wasmfs_opfs_remove_child__sig: 'vpipp', _wasmfs_opfs_remove_child__deps: ['$wasmfsOPFSDirectoryHandles', '$wasmfsOPFSProxyFinish'], _wasmfs_opfs_remove_child: async function(ctx, dirID, namePtr, errPtr) { let name = UTF8ToString(namePtr); @@ -220,22 +213,19 @@ mergeInto(LibraryManager.library, { wasmfsOPFSProxyFinish(ctx); }, - _wasmfs_opfs_free_file__sig: 'vi', _wasmfs_opfs_free_file__deps: ['$wasmfsOPFSFileHandles'], _wasmfs_opfs_free_file: function(fileID) { wasmfsOPFSFileHandles.free(fileID); }, - _wasmfs_opfs_free_directory__sig: 'vi', _wasmfs_opfs_free_directory__deps: ['$wasmfsOPFSDirectoryHandles'], _wasmfs_opfs_free_directory: function(dirID) { wasmfsOPFSDirectoryHandles.free(dirID); }, - _wasmfs_opfs_open_access__sig: 'vpip', _wasmfs_opfs_open_access__deps: ['$wasmfsOPFSFileHandles', '$wasmfsOPFSAccessHandles', '$wasmfsOPFSProxyFinish', -#if !USE_PTHREADS +#if !PTHREADS '$wasmfsOPFSCreateAsyncAccessHandle' #endif ], @@ -244,7 +234,7 @@ mergeInto(LibraryManager.library, { let accessID; try { let accessHandle; -#if USE_PTHREADS +#if PTHREADS // TODO: Remove this once the Access Handles API has settled. if (FileSystemFileHandle.prototype.createSyncAccessHandle.length == 0) { accessHandle = await fileHandle.createSyncAccessHandle(); @@ -272,7 +262,6 @@ mergeInto(LibraryManager.library, { wasmfsOPFSProxyFinish(ctx); }, - _wasmfs_opfs_open_blob__sig: 'vpip', _wasmfs_opfs_open_blob__deps: ['$wasmfsOPFSFileHandles', '$wasmfsOPFSBlobs', '$wasmfsOPFSProxyFinish'], _wasmfs_opfs_open_blob: async function(ctx, fileID, blobIDPtr) { @@ -295,7 +284,6 @@ mergeInto(LibraryManager.library, { wasmfsOPFSProxyFinish(ctx); }, - _wasmfs_opfs_close_access__sig: 'vpip', _wasmfs_opfs_close_access__deps: ['$wasmfsOPFSAccessHandles', '$wasmfsOPFSProxyFinish'], _wasmfs_opfs_close_access: async function(ctx, accessID, errPtr) { let accessHandle = wasmfsOPFSAccessHandles.get(accessID); @@ -309,19 +297,17 @@ mergeInto(LibraryManager.library, { wasmfsOPFSProxyFinish(ctx); }, - _wasmfs_opfs_close_blob__sig: 'vi', _wasmfs_opfs_close_blob__deps: ['$wasmfsOPFSBlobs'], _wasmfs_opfs_close_blob: function(blobID) { wasmfsOPFSBlobs.free(blobID); }, - _wasmfs_opfs_read_access__sig: 'iipii', _wasmfs_opfs_read_access__deps: ['$wasmfsOPFSAccessHandles'], - _wasmfs_opfs_read_access: {{{ asyncIf(!USE_PTHREADS) }}} function(accessID, bufPtr, len, pos) { + _wasmfs_opfs_read_access: {{{ asyncIf(!PTHREADS) }}} function(accessID, bufPtr, len, pos) { let accessHandle = wasmfsOPFSAccessHandles.get(accessID); let data = HEAPU8.subarray(bufPtr, bufPtr + len); try { - return {{{ awaitIf(!USE_PTHREADS) }}} accessHandle.read(data, {at: pos}); + return {{{ awaitIf(!PTHREADS) }}} accessHandle.read(data, {at: pos}); } catch (e) { if (e.name == "TypeError") { return -{{{ cDefs.EINVAL }}}; @@ -333,7 +319,6 @@ mergeInto(LibraryManager.library, { } }, - _wasmfs_opfs_read_blob__sig: 'ipipiip', _wasmfs_opfs_read_blob__deps: ['$wasmfsOPFSBlobs', '$wasmfsOPFSProxyFinish'], _wasmfs_opfs_read_blob: async function(ctx, blobID, bufPtr, len, pos, nreadPtr) { let blob = wasmfsOPFSBlobs.get(blobID); @@ -363,13 +348,12 @@ mergeInto(LibraryManager.library, { wasmfsOPFSProxyFinish(ctx); }, - _wasmfs_opfs_write_access__sig: 'iipii', _wasmfs_opfs_write_access__deps: ['$wasmfsOPFSAccessHandles'], - _wasmfs_opfs_write_access: {{{ asyncIf(!USE_PTHREADS) }}} function(accessID, bufPtr, len, pos) { + _wasmfs_opfs_write_access: {{{ asyncIf(!PTHREADS) }}} function(accessID, bufPtr, len, pos) { let accessHandle = wasmfsOPFSAccessHandles.get(accessID); let data = HEAPU8.subarray(bufPtr, bufPtr + len); try { - return {{{ awaitIf(!USE_PTHREADS) }}} accessHandle.write(data, {at: pos}); + return {{{ awaitIf(!PTHREADS) }}} accessHandle.write(data, {at: pos}); } catch (e) { if (e.name == "TypeError") { return -{{{ cDefs.EINVAL }}}; @@ -381,7 +365,6 @@ mergeInto(LibraryManager.library, { } }, - _wasmfs_opfs_get_size_access__sig: 'vpip', _wasmfs_opfs_get_size_access__deps: ['$wasmfsOPFSAccessHandles', '$wasmfsOPFSProxyFinish'], _wasmfs_opfs_get_size_access: async function(ctx, accessID, sizePtr) { let accessHandle = wasmfsOPFSAccessHandles.get(accessID); @@ -395,14 +378,12 @@ mergeInto(LibraryManager.library, { wasmfsOPFSProxyFinish(ctx); }, - _wasmfs_opfs_get_size_blob__sig: 'ii', _wasmfs_opfs_get_size_blob__deps: ['$wasmfsOPFSBlobs'], _wasmfs_opfs_get_size_blob: function(blobID) { // This cannot fail. return wasmfsOPFSBlobs.get(blobID).size; }, - _wasmfs_opfs_get_size_file__sig: 'vpip', _wasmfs_opfs_get_size_file__deps: ['$wasmfsOPFSFileHandles', '$wasmfsOPFSProxyFinish'], _wasmfs_opfs_get_size_file: async function(ctx, fileID, sizePtr) { let fileHandle = wasmfsOPFSFileHandles.get(fileID); @@ -416,7 +397,6 @@ mergeInto(LibraryManager.library, { wasmfsOPFSProxyFinish(ctx); }, - _wasmfs_opfs_set_size_access__sig: 'vpijp', _wasmfs_opfs_set_size_access__deps: ['$wasmfsOPFSAccessHandles', '$wasmfsOPFSProxyFinish'], _wasmfs_opfs_set_size_access: async function(ctx, accessID, {{{ defineI64Param('size') }}}, @@ -432,7 +412,6 @@ mergeInto(LibraryManager.library, { wasmfsOPFSProxyFinish(ctx); }, - _wasmfs_opfs_set_size_file__sig: 'vpijp', _wasmfs_opfs_set_size_file__deps: ['$wasmfsOPFSFileHandles', '$wasmfsOPFSProxyFinish'], _wasmfs_opfs_set_size_file: async function(ctx, fileID, {{{ defineI64Param('size') }}}, @@ -450,7 +429,6 @@ mergeInto(LibraryManager.library, { wasmfsOPFSProxyFinish(ctx); }, - _wasmfs_opfs_flush_access__sig: 'vpip', _wasmfs_opfs_flush_access__deps: ['$wasmfsOPFSAccessHandles', '$wasmfsOPFSProxyFinish'], _wasmfs_opfs_flush_access: async function(ctx, accessID, errPtr) { let accessHandle = wasmfsOPFSAccessHandles.get(accessID); diff --git a/system/lib/wasmfs/backends/fetch_backend.cpp b/system/lib/wasmfs/backends/fetch_backend.cpp index 2adf7f1eec478..ca7142d4d569d 100644 --- a/system/lib/wasmfs/backends/fetch_backend.cpp +++ b/system/lib/wasmfs/backends/fetch_backend.cpp @@ -6,16 +6,11 @@ // This file defines the JS file backend and JS file of the new file system. // See https://github.com/emscripten-core/emscripten/issues/15041. +#include "fetch_backend.h" #include "backend.h" #include "proxied_async_js_impl_backend.h" #include "wasmfs.h" -// See library_wasmfs_fetch.js - -extern "C" { -void _wasmfs_create_fetch_backend_js(wasmfs::backend_t); -} - namespace wasmfs { class FetchFile : public ProxiedAsyncJSImplFile { diff --git a/system/lib/wasmfs/backends/fetch_backend.h b/system/lib/wasmfs/backends/fetch_backend.h new file mode 100644 index 0000000000000..00c729942e89c --- /dev/null +++ b/system/lib/wasmfs/backends/fetch_backend.h @@ -0,0 +1,13 @@ +// Copyright 2021 The Emscripten Authors. All rights reserved. +// Emscripten is available under two separate licenses, the MIT license and the +// University of Illinois/NCSA Open Source License. Both these licenses can be +// found in the LICENSE file. + +#include "wasmfs.h" + +extern "C" { + +// See library_wasmfs_fetch.js +void _wasmfs_create_fetch_backend_js(wasmfs::backend_t); + +} diff --git a/system/lib/wasmfs/backends/js_file_backend.cpp b/system/lib/wasmfs/backends/js_file_backend.cpp index 41b484f51e5cb..8ea08d7068add 100644 --- a/system/lib/wasmfs/backends/js_file_backend.cpp +++ b/system/lib/wasmfs/backends/js_file_backend.cpp @@ -6,16 +6,11 @@ // This file defines the JS file backend and JS file of the new file system. // See https://github.com/emscripten-core/emscripten/issues/15041. +#include "js_file_backend.h" #include "backend.h" #include "js_impl_backend.h" #include "wasmfs.h" -// See library_wasmfs_js_file.js - -extern "C" { -void _wasmfs_create_js_file_backend_js(wasmfs::backend_t); -} - namespace wasmfs { extern "C" backend_t wasmfs_create_js_file_backend() { diff --git a/system/lib/wasmfs/backends/js_file_backend.h b/system/lib/wasmfs/backends/js_file_backend.h new file mode 100644 index 0000000000000..320195a40551c --- /dev/null +++ b/system/lib/wasmfs/backends/js_file_backend.h @@ -0,0 +1,14 @@ +// Copyright 2021 The Emscripten Authors. All rights reserved. +// Emscripten is available under two separate licenses, the MIT license and the +// University of Illinois/NCSA Open Source License. Both these licenses can be +// found in the LICENSE file. + +#include "wasmfs.h" + +extern "C" { + +// These helper functions are defined in library_wasmfs_js_file.js + +void _wasmfs_create_js_file_backend_js(wasmfs::backend_t); + +} diff --git a/system/lib/wasmfs/backends/node_backend.cpp b/system/lib/wasmfs/backends/node_backend.cpp index 7de34367a4a10..7d014112c0969 100644 --- a/system/lib/wasmfs/backends/node_backend.cpp +++ b/system/lib/wasmfs/backends/node_backend.cpp @@ -5,6 +5,7 @@ #include +#include "node_backend.h" #include "backend.h" #include "file.h" #include "support.h" @@ -14,44 +15,6 @@ namespace wasmfs { class NodeBackend; -extern "C" { - -// Fill `entries` and return 0 or an error code. -int _wasmfs_node_readdir(const char* path, - std::vector* entries); -// Write `mode` and return 0 or an error code. -int _wasmfs_node_get_mode(const char* path, mode_t* mode); - -// Write `size` and return 0 or an error code. -int _wasmfs_node_stat_size(const char* path, uint32_t* size); -int _wasmfs_node_fstat_size(int fd, uint32_t* size); - -// Create a new file system entry and return 0 or an error code. -int _wasmfs_node_insert_file(const char* path, mode_t mode); -int _wasmfs_node_insert_directory(const char* path, mode_t mode); - -// Unlink the given file and return 0 or an error code. -int _wasmfs_node_unlink(const char* path); -int _wasmfs_node_rmdir(const char* path); - -// Open the file and return the underlying file descriptor. -[[nodiscard]] int _wasmfs_node_open(const char* path, const char* mode); - -// Close the underlying file descriptor. -[[nodiscard]] int _wasmfs_node_close(int fd); - -// Read up to `size` bytes into `buf` from position `pos` in the file, writing -// the number of bytes read to `nread`. Return 0 on success or an error code. -int _wasmfs_node_read( - int fd, void* buf, uint32_t len, uint32_t pos, uint32_t* nread); - -// Write up to `size` bytes from `buf` at position `pos` in the file, writing -// the number of bytes written to `nread`. Return 0 on success or an error code. -int _wasmfs_node_write( - int fd, const void* buf, uint32_t len, uint32_t pos, uint32_t* nwritten); - -} // extern "C" - // The state of a file on the underlying Node file system. class NodeState { // Map all separate WasmFS opens of a file to a single underlying fd. diff --git a/system/lib/wasmfs/backends/node_backend.h b/system/lib/wasmfs/backends/node_backend.h new file mode 100644 index 0000000000000..c4af2a174ba1b --- /dev/null +++ b/system/lib/wasmfs/backends/node_backend.h @@ -0,0 +1,46 @@ +// Copyright 2022 The Emscripten Authors. All rights reserved. +// Emscripten is available under two separate licenses, the MIT license and the +// University of Illinois/NCSA Open Source License. Both these licenses can be +// found in the LICENSE file. + +#include // for mode_t + +extern "C" { + +// These helper functions are defined in library_wasmfs_node.js. + +// Fill `entries` and return 0 or an error code. +int _wasmfs_node_readdir(const char* path, void* entries + /* std::vector*/); +// Write `mode` and return 0 or an error code. +int _wasmfs_node_get_mode(const char* path, mode_t* mode); + +// Write `size` and return 0 or an error code. +int _wasmfs_node_stat_size(const char* path, uint32_t* size); +int _wasmfs_node_fstat_size(int fd, uint32_t* size); + +// Create a new file system entry and return 0 or an error code. +int _wasmfs_node_insert_file(const char* path, mode_t mode); +int _wasmfs_node_insert_directory(const char* path, mode_t mode); + +// Unlink the given file and return 0 or an error code. +int _wasmfs_node_unlink(const char* path); +int _wasmfs_node_rmdir(const char* path); + +// Open the file and return the underlying file descriptor. +[[nodiscard]] int _wasmfs_node_open(const char* path, const char* mode); + +// Close the underlying file descriptor. +[[nodiscard]] int _wasmfs_node_close(int fd); + +// Read up to `size` bytes into `buf` from position `pos` in the file, writing +// the number of bytes read to `nread`. Return 0 on success or an error code. +int _wasmfs_node_read( + int fd, void* buf, uint32_t len, uint32_t pos, uint32_t* nread); + +// Write up to `size` bytes from `buf` at position `pos` in the file, writing +// the number of bytes written to `nread`. Return 0 on success or an error code. +int _wasmfs_node_write( + int fd, const void* buf, uint32_t len, uint32_t pos, uint32_t* nwritten); + +} diff --git a/system/lib/wasmfs/backends/opfs_backend.cpp b/system/lib/wasmfs/backends/opfs_backend.cpp index 9245a393f9cea..626bddd6750de 100644 --- a/system/lib/wasmfs/backends/opfs_backend.cpp +++ b/system/lib/wasmfs/backends/opfs_backend.cpp @@ -6,6 +6,7 @@ #include #include +#include "opfs_backend.h" #include "backend.h" #include "file.h" #include "support.h" @@ -14,107 +15,6 @@ using namespace wasmfs; -extern "C" { - -// Ensure that the root OPFS directory is initialized with ID 0. -void _wasmfs_opfs_init_root_directory(em_proxying_ctx* ctx); - -// Look up the child under `parent` with `name`. Write 1 to `child_type` if it's -// a regular file or 2 if it's a directory. Write the child's file or directory -// ID to `child_id`, or -1 if the child does not exist, or -2 if the child -// exists but cannot be opened. -void _wasmfs_opfs_get_child(em_proxying_ctx* ctx, - int parent, - const char* name, - int* child_type, - int* child_id); - -// Create a file under `parent` with `name` and store its ID in `child_id`. -void _wasmfs_opfs_insert_file(em_proxying_ctx* ctx, - int parent, - const char* name, - int* child_id); - -// Create a directory under `parent` with `name` and store its ID in `child_id`. -void _wasmfs_opfs_insert_directory(em_proxying_ctx* ctx, - int parent, - const char* name, - int* child_id); - -void _wasmfs_opfs_move_file(em_proxying_ctx* ctx, - int file_id, - int new_parent_id, - const char* name, - int* err); - -void _wasmfs_opfs_remove_child(em_proxying_ctx* ctx, - int dir_id, - const char* name, - int* err); - -void _wasmfs_opfs_get_entries(em_proxying_ctx* ctx, - int dirID, - std::vector* entries, - int* err); - -void _wasmfs_opfs_open_access(em_proxying_ctx* ctx, - int file_id, - int* access_id); - -void _wasmfs_opfs_open_blob(em_proxying_ctx* ctx, int file_id, int* blob_id); - -void _wasmfs_opfs_close_access(em_proxying_ctx* ctx, int access_id, int* err); - -void _wasmfs_opfs_close_blob(int blob_id); - -void _wasmfs_opfs_free_file(int file_id); - -void _wasmfs_opfs_free_directory(int dir_id); - -// Synchronous read. Return the number of bytes read. -int _wasmfs_opfs_read_access(int access_id, - uint8_t* buf, - uint32_t len, - uint32_t pos); - -int _wasmfs_opfs_read_blob(em_proxying_ctx* ctx, - int blob_id, - uint8_t* buf, - uint32_t len, - uint32_t pos, - int32_t* nread); - -// Synchronous write. Return the number of bytes written. -int _wasmfs_opfs_write_access(int access_id, - const uint8_t* buf, - uint32_t len, - uint32_t pos); - -// Get the size via an AccessHandle. -void _wasmfs_opfs_get_size_access(em_proxying_ctx* ctx, - int access_id, - off_t* size); - -// TODO: return 64-byte off_t. -uint32_t _wasmfs_opfs_get_size_blob(int blob_id); - -// Get the size of a file handle via a File Blob. -void _wasmfs_opfs_get_size_file(em_proxying_ctx* ctx, int file_id, off_t* size); - -void _wasmfs_opfs_set_size_access(em_proxying_ctx* ctx, - int access_id, - off_t size, - int* err); - -void _wasmfs_opfs_set_size_file(em_proxying_ctx* ctx, - int file_id, - off_t size, - int* err); - -void _wasmfs_opfs_flush_access(em_proxying_ctx* ctx, int access_id, int* err); - -} // extern "C" - namespace { using ProxyWorker = emscripten::ProxyWorker; diff --git a/system/lib/wasmfs/backends/opfs_backend.h b/system/lib/wasmfs/backends/opfs_backend.h new file mode 100644 index 0000000000000..ffd3d25b5b7ae --- /dev/null +++ b/system/lib/wasmfs/backends/opfs_backend.h @@ -0,0 +1,108 @@ +#include + +#include + +#include "backend.h" + +using namespace wasmfs; + +extern "C" { + +// Ensure that the root OPFS directory is initialized with ID 0. +void _wasmfs_opfs_init_root_directory(em_proxying_ctx* ctx); + +// Look up the child under `parent` with `name`. Write 1 to `child_type` if it's +// a regular file or 2 if it's a directory. Write the child's file or directory +// ID to `child_id`, or -1 if the child does not exist, or -2 if the child +// exists but cannot be opened. +void _wasmfs_opfs_get_child(em_proxying_ctx* ctx, + int parent, + const char* name, + int* child_type, + int* child_id); + +// Create a file under `parent` with `name` and store its ID in `child_id`. +void _wasmfs_opfs_insert_file(em_proxying_ctx* ctx, + int parent, + const char* name, + int* child_id); + +// Create a directory under `parent` with `name` and store its ID in `child_id`. +void _wasmfs_opfs_insert_directory(em_proxying_ctx* ctx, + int parent, + const char* name, + int* child_id); + +void _wasmfs_opfs_move_file(em_proxying_ctx* ctx, + int file_id, + int new_parent_id, + const char* name, + int* err); + +void _wasmfs_opfs_remove_child(em_proxying_ctx* ctx, + int dir_id, + const char* name, + int* err); + +void _wasmfs_opfs_get_entries(em_proxying_ctx* ctx, + int dirID, + std::vector* entries, + int* err); + +void _wasmfs_opfs_open_access(em_proxying_ctx* ctx, + int file_id, + int* access_id); + +void _wasmfs_opfs_open_blob(em_proxying_ctx* ctx, int file_id, int* blob_id); + +void _wasmfs_opfs_close_access(em_proxying_ctx* ctx, int access_id, int* err); + +void _wasmfs_opfs_close_blob(int blob_id); + +void _wasmfs_opfs_free_file(int file_id); + +void _wasmfs_opfs_free_directory(int dir_id); + +// Synchronous read. Return the number of bytes read. +int _wasmfs_opfs_read_access(int access_id, + uint8_t* buf, + uint32_t len, + uint32_t pos); + +int _wasmfs_opfs_read_blob(em_proxying_ctx* ctx, + int blob_id, + uint8_t* buf, + uint32_t len, + uint32_t pos, + int32_t* nread); + +// Synchronous write. Return the number of bytes written. +int _wasmfs_opfs_write_access(int access_id, + const uint8_t* buf, + uint32_t len, + uint32_t pos); + +// Get the size via an AccessHandle. +void _wasmfs_opfs_get_size_access(em_proxying_ctx* ctx, + int access_id, + off_t* size); + +// TODO: return 64-byte off_t. +uint32_t _wasmfs_opfs_get_size_blob(int blob_id); + +// Get the size of a file handle via a File Blob. +void _wasmfs_opfs_get_size_file(em_proxying_ctx* ctx, int file_id, off_t* size); + +void _wasmfs_opfs_set_size_access(em_proxying_ctx* ctx, + int access_id, + off_t size, + int* err); + +void _wasmfs_opfs_set_size_file(em_proxying_ctx* ctx, + int file_id, + off_t size, + int* err); + +void _wasmfs_opfs_flush_access(em_proxying_ctx* ctx, int access_id, int* err); + +} // extern "C" diff --git a/system/lib/wasmfs/file.cpp b/system/lib/wasmfs/file.cpp index be6de1ae5e8d7..67f1590fed8d6 100644 --- a/system/lib/wasmfs/file.cpp +++ b/system/lib/wasmfs/file.cpp @@ -8,14 +8,9 @@ #include "file.h" #include "wasmfs.h" +#include "wasmfs_internal.h" #include -extern "C" { -size_t _wasmfs_get_preloaded_file_size(uint32_t index); - -void _wasmfs_copy_preloaded_file_data(uint32_t index, uint8_t* data); -} - namespace wasmfs { // diff --git a/system/lib/wasmfs/wasmfs.cpp b/system/lib/wasmfs/wasmfs.cpp index 848ce4c4cb46b..2c3f396f48cb9 100644 --- a/system/lib/wasmfs/wasmfs.cpp +++ b/system/lib/wasmfs/wasmfs.cpp @@ -12,6 +12,7 @@ #include "paths.h" #include "special_files.h" #include "wasmfs.h" +#include "wasmfs_internal.h" namespace wasmfs { @@ -33,16 +34,6 @@ backend_t createIgnoreCaseBackend(std::function createBacken); __attribute__((init_priority(100))) WasmFS wasmFS; # 31 "wasmfs.cpp" -// These helper functions will be linked in from library_wasmfs.js. -extern "C" { -int _wasmfs_get_num_preloaded_files(); -int _wasmfs_get_num_preloaded_dirs(); -int _wasmfs_get_preloaded_file_mode(int index); -void _wasmfs_get_preloaded_parent_path(int index, char* parentPath); -void _wasmfs_get_preloaded_path_name(int index, char* fileName); -void _wasmfs_get_preloaded_child_path(int index, char* childName); -} - // If the user does not implement this hook, do nothing. __attribute__((weak)) extern "C" void wasmfs_before_preload(void) {} diff --git a/system/lib/wasmfs/wasmfs_internal.h b/system/lib/wasmfs/wasmfs_internal.h new file mode 100644 index 0000000000000..3f34f50cf99b8 --- /dev/null +++ b/system/lib/wasmfs/wasmfs_internal.h @@ -0,0 +1,19 @@ +// Copyright 2021 The Emscripten Authors. All rights reserved. +// Emscripten is available under two separate licenses, the MIT license and the +// University of Illinois/NCSA Open Source License. Both these licenses can be +// found in the LICENSE file. + +extern "C" { + +// These helper functions are defined in library_wasmfs.js. + +int _wasmfs_get_num_preloaded_files(); +int _wasmfs_get_num_preloaded_dirs(); +int _wasmfs_get_preloaded_file_mode(int index); +void _wasmfs_get_preloaded_parent_path(int index, char* parentPath); +void _wasmfs_get_preloaded_path_name(int index, char* fileName); +void _wasmfs_get_preloaded_child_path(int index, char* childName); +size_t _wasmfs_get_preloaded_file_size(uint32_t index); +void _wasmfs_copy_preloaded_file_data(uint32_t index, uint8_t* data); + +} diff --git a/tools/gen_sig_info.py b/tools/gen_sig_info.py index f281212252ded..620665c347708 100755 --- a/tools/gen_sig_info.py +++ b/tools/gen_sig_info.py @@ -109,6 +109,13 @@ // Internal emscripten headers #include "emscripten_internal.h" +#include "wasmfs_internal.h" +#include "backends/opfs_backend.h" +#include "backends/fetch_backend.h" +#include "backends/node_backend.h" +#include "backends/js_file_backend.h" +#include "proxied_async_js_impl_backend.h" +#include "js_impl_backend.h" // Public musl/libc headers #include @@ -319,6 +326,7 @@ def extract_sig_info(sig_info, extra_settings=None, extra_cflags=None, cxx=False '--tracing', '-Wno-deprecated-declarations', '-I' + utils.path_from_root('system/lib/libc'), + '-I' + utils.path_from_root('system/lib/wasmfs'), '-o', obj_file] if not cxx: cmd += ['-I' + utils.path_from_root('system/lib/pthread'), @@ -357,6 +365,11 @@ def main(args): print('generating signatures ...') sig_info = {} + extract_sig_info(sig_info, {'WASMFS': 1, + 'JS_LIBRARIES': [], + 'USE_SDL': 0, + 'MAX_WEBGL_VERSION': 0, + 'AUTO_JS_LIBRARIES': 0}, cxx=True) extract_sig_info(sig_info, {'WASM_WORKERS': 1, 'JS_LIBRARIES': ['src/library_wasm_worker.js']}) extract_sig_info(sig_info, {'USE_GLFW': 3}, ['-DGLFW3']) extract_sig_info(sig_info, {'JS_LIBRARIES': ['src/embind/embind.js', 'src/embind/emval.js'], From fea7644e4d9e479b9f0be42df6ce6417a970635f Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 22 May 2023 13:58:02 -0700 Subject: [PATCH 0267/1523] Rebaseline codesize expectations. NFC --- test/other/metadce/test_metadce_cxx_ctors1.size | 2 +- test/other/metadce/test_metadce_cxx_ctors2.size | 2 +- test/other/metadce/test_metadce_cxx_except.size | 2 +- test/other/metadce/test_metadce_cxx_except_wasm.size | 2 +- test/other/metadce/test_metadce_cxx_mangle.size | 2 +- test/other/metadce/test_metadce_cxx_noexcept.size | 2 +- test/other/metadce/test_metadce_hello_O0.size | 2 +- test/other/metadce/test_metadce_hello_O1.size | 2 +- test/other/metadce/test_metadce_hello_O2.size | 2 +- test/other/metadce/test_metadce_hello_O3.size | 2 +- test/other/metadce/test_metadce_hello_Os.size | 2 +- test/other/metadce/test_metadce_hello_dylink.size | 2 +- test/other/test_unoptimized_code_size.wasm.size | 2 +- test/other/test_unoptimized_code_size_no_asserts.wasm.size | 2 +- test/other/test_unoptimized_code_size_strict.wasm.size | 2 +- 15 files changed, 15 insertions(+), 15 deletions(-) diff --git a/test/other/metadce/test_metadce_cxx_ctors1.size b/test/other/metadce/test_metadce_cxx_ctors1.size index c3e6c8e8b8cec..b05d1e60b163f 100644 --- a/test/other/metadce/test_metadce_cxx_ctors1.size +++ b/test/other/metadce/test_metadce_cxx_ctors1.size @@ -1 +1 @@ -123502 +123501 diff --git a/test/other/metadce/test_metadce_cxx_ctors2.size b/test/other/metadce/test_metadce_cxx_ctors2.size index e9659e9d95013..54432ac3ea7c6 100644 --- a/test/other/metadce/test_metadce_cxx_ctors2.size +++ b/test/other/metadce/test_metadce_cxx_ctors2.size @@ -1 +1 @@ -123407 +123406 diff --git a/test/other/metadce/test_metadce_cxx_except.size b/test/other/metadce/test_metadce_cxx_except.size index eec7f48731c08..27e59ea3c5748 100644 --- a/test/other/metadce/test_metadce_cxx_except.size +++ b/test/other/metadce/test_metadce_cxx_except.size @@ -1 +1 @@ -166245 +166244 diff --git a/test/other/metadce/test_metadce_cxx_except_wasm.size b/test/other/metadce/test_metadce_cxx_except_wasm.size index d1ea9f9b1f5fc..c12915789fd0c 100644 --- a/test/other/metadce/test_metadce_cxx_except_wasm.size +++ b/test/other/metadce/test_metadce_cxx_except_wasm.size @@ -1 +1 @@ -137069 +137052 diff --git a/test/other/metadce/test_metadce_cxx_mangle.size b/test/other/metadce/test_metadce_cxx_mangle.size index 2c79ee8cab573..0b5a6778421cd 100644 --- a/test/other/metadce/test_metadce_cxx_mangle.size +++ b/test/other/metadce/test_metadce_cxx_mangle.size @@ -1 +1 @@ -221332 +221331 diff --git a/test/other/metadce/test_metadce_cxx_noexcept.size b/test/other/metadce/test_metadce_cxx_noexcept.size index 04a2ee6190e4b..f1f3cc0e66cda 100644 --- a/test/other/metadce/test_metadce_cxx_noexcept.size +++ b/test/other/metadce/test_metadce_cxx_noexcept.size @@ -1 +1 @@ -126299 +126298 diff --git a/test/other/metadce/test_metadce_hello_O0.size b/test/other/metadce/test_metadce_hello_O0.size index e8b15f251ccec..9124a7bee78bd 100644 --- a/test/other/metadce/test_metadce_hello_O0.size +++ b/test/other/metadce/test_metadce_hello_O0.size @@ -1 +1 @@ -12123 +12125 diff --git a/test/other/metadce/test_metadce_hello_O1.size b/test/other/metadce/test_metadce_hello_O1.size index 49ce078f63b5e..3d212cf499fea 100644 --- a/test/other/metadce/test_metadce_hello_O1.size +++ b/test/other/metadce/test_metadce_hello_O1.size @@ -1 +1 @@ -2413 +2415 diff --git a/test/other/metadce/test_metadce_hello_O2.size b/test/other/metadce/test_metadce_hello_O2.size index fc7bdcf6f40e7..8cb1ed86567e4 100644 --- a/test/other/metadce/test_metadce_hello_O2.size +++ b/test/other/metadce/test_metadce_hello_O2.size @@ -1 +1 @@ -2055 +2056 diff --git a/test/other/metadce/test_metadce_hello_O3.size b/test/other/metadce/test_metadce_hello_O3.size index 2358ac3b44c5e..c102fe8faa1e0 100644 --- a/test/other/metadce/test_metadce_hello_O3.size +++ b/test/other/metadce/test_metadce_hello_O3.size @@ -1 +1 @@ -1755 +1756 diff --git a/test/other/metadce/test_metadce_hello_Os.size b/test/other/metadce/test_metadce_hello_Os.size index c439d95d8e000..461033f7a6258 100644 --- a/test/other/metadce/test_metadce_hello_Os.size +++ b/test/other/metadce/test_metadce_hello_Os.size @@ -1 +1 @@ -1747 +1748 diff --git a/test/other/metadce/test_metadce_hello_dylink.size b/test/other/metadce/test_metadce_hello_dylink.size index 6b4f6ad29f670..dcb81b5dcf759 100644 --- a/test/other/metadce/test_metadce_hello_dylink.size +++ b/test/other/metadce/test_metadce_hello_dylink.size @@ -1 +1 @@ -9514 +9515 diff --git a/test/other/test_unoptimized_code_size.wasm.size b/test/other/test_unoptimized_code_size.wasm.size index 39fb891cb1844..8b328036fbc18 100644 --- a/test/other/test_unoptimized_code_size.wasm.size +++ b/test/other/test_unoptimized_code_size.wasm.size @@ -1 +1 @@ -12156 +12158 diff --git a/test/other/test_unoptimized_code_size_no_asserts.wasm.size b/test/other/test_unoptimized_code_size_no_asserts.wasm.size index 9a1c49f077bd0..d32c904557015 100644 --- a/test/other/test_unoptimized_code_size_no_asserts.wasm.size +++ b/test/other/test_unoptimized_code_size_no_asserts.wasm.size @@ -1 +1 @@ -11603 +11605 diff --git a/test/other/test_unoptimized_code_size_strict.wasm.size b/test/other/test_unoptimized_code_size_strict.wasm.size index 39fb891cb1844..8b328036fbc18 100644 --- a/test/other/test_unoptimized_code_size_strict.wasm.size +++ b/test/other/test_unoptimized_code_size_strict.wasm.size @@ -1 +1 @@ -12156 +12158 From b76fdf445f0a8dfdebfd0f67749bfbc20665d397 Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Mon, 22 May 2023 23:12:19 +0200 Subject: [PATCH 0268/1523] Ensure system libraries are built on demand (#19405) Previously, when explicitly linking against a system library (e.g. `-lc`) that had not been built earlier, wasm-ld would raise an error indicating that the library could not be found. Use the `get_link_flag()` function to ensure that it triggers a build if the system library is not present in the cache. --- emcc.py | 4 ++-- test/test_other.py | 2 -- tools/system_libs.py | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/emcc.py b/emcc.py index 1bf995473c0dd..77e5d0d0cc0ed 100755 --- a/emcc.py +++ b/emcc.py @@ -4184,8 +4184,8 @@ def process_libraries(state, linker_inputs): # let wasm-ld handle that. However, we do want to map to the correct variant. # For example we map `-lc` to `-lc-mt` if we are building with threading support. if 'lib' + lib in system_libs_map: - lib = system_libs_map['lib' + lib] - new_flags.append((i, '-l' + strip_prefix(lib.get_base_name(), 'lib'))) + lib = system_libs_map['lib' + lib].get_link_flag() + new_flags.append((i, lib)) continue if building.map_and_apply_to_settings(lib): diff --git a/test/test_other.py b/test/test_other.py index 8b32cb70a784f..2781163ff71f6 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -12110,8 +12110,6 @@ def test_offset_convertor_plus_wasm2js(self): def test_standard_library_mapping(self): # Test the `-l` flags on the command line get mapped the correct libraries variant - self.run_process([EMBUILDER, 'build', 'libc-mt-debug', 'libcompiler_rt-mt', 'libdlmalloc-mt']) - libs = ['-lc', '-lbulkmemory', '-lcompiler_rt', '-lmalloc'] err = self.run_process([EMCC, test_file('hello_world.c'), '-pthread', '-nodefaultlibs', '-v'] + libs, stderr=PIPE).stderr diff --git a/tools/system_libs.py b/tools/system_libs.py index 18d57e99178ec..2367a0bfc09a6 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -426,7 +426,7 @@ def get_link_flag(self): This will trigger a build if this library is not in the cache. """ fullpath = self.build() - # For non-libaries (e.g. crt1.o) we pass the entire path to the linker + # For non-libraries (e.g. crt1.o) we pass the entire path to the linker if self.get_ext() != '.a': return fullpath # For libraries (.a) files, we pass the abbreviated `-l` form. From 5a4814e804d26583a329c8a2fd952046ec72e65f Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Tue, 23 May 2023 00:56:05 +0200 Subject: [PATCH 0269/1523] dylink: Ensure WASI module import is quoted (#19406) Avoids that Closure compiler would rename/mangle the property, causing instantiation failures. --- src/library_dylink.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/library_dylink.js b/src/library_dylink.js index d96e6b4253af5..3c5861181fdb7 100644 --- a/src/library_dylink.js +++ b/src/library_dylink.js @@ -738,7 +738,7 @@ var LibraryDylink = { 'GOT.mem': new Proxy({}, GOTHandler), 'GOT.func': new Proxy({}, GOTHandler), 'env': proxy, - {{{ WASI_MODULE_NAME }}}: proxy, + '{{{ WASI_MODULE_NAME }}}': proxy, }; function postInstantiation(instance) { From 85daeb91219cf4d2ecc15fa9321f8f77aef047a4 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 22 May 2023 16:58:54 -0700 Subject: [PATCH 0270/1523] Move some internal maintenance tools to tools/maint/ (#19419) Also, remove two ancient unused/untested tools: find_bigfuncs.py and find_bigvars.py. --- .circleci/config.yml | 2 +- em-config | 2 +- em-config.bat | 2 +- emar | 2 +- emar.bat | 2 +- embuilder | 2 +- embuilder.bat | 2 +- emcmake | 2 +- emcmake.bat | 2 +- emconfigure | 2 +- emconfigure.bat | 2 +- emdump | 2 +- emdump.bat | 2 +- emdwp | 2 +- emdwp.bat | 2 +- emmake | 2 +- emmake.bat | 2 +- emnm | 2 +- emnm.bat | 2 +- emprofile | 2 +- emprofile.bat | 2 +- emranlib | 2 +- emranlib.bat | 2 +- emrun | 2 +- emrun.bat | 2 +- emscons | 2 +- emscons.bat | 2 +- emsize | 2 +- emsize.bat | 2 +- emstrip | 2 +- emstrip.bat | 2 +- emsymbolizer | 2 +- emsymbolizer.bat | 2 +- system/bin/sdl-config | 2 +- system/bin/sdl-config.bat | 2 +- system/bin/sdl2-config | 2 +- system/bin/sdl2-config.bat | 2 +- {tools => test}/check_clean.py | 0 test/runner | 2 +- test/runner.bat | 2 +- tools/file_packager | 2 +- tools/file_packager.bat | 2 +- tools/find_bigfuncs.py | 119 ----------------------- tools/find_bigvars.py | 27 ----- tools/{ => maint}/add_license.py | 2 +- tools/{ => maint}/create_entry_points.py | 2 +- tools/{ => maint}/simde_update.py | 4 +- tools/run_python.bat | 2 +- tools/run_python.sh | 2 +- tools/webidl_binder | 2 +- tools/webidl_binder.bat | 2 +- 51 files changed, 49 insertions(+), 195 deletions(-) rename {tools => test}/check_clean.py (100%) delete mode 100644 tools/find_bigfuncs.py delete mode 100644 tools/find_bigvars.py rename tools/{ => maint}/add_license.py (98%) rename tools/{ => maint}/create_entry_points.py (96%) rename tools/{ => maint}/simde_update.py (95%) diff --git a/.circleci/config.yml b/.circleci/config.yml index 216c58c5491d3..af753c2e14c36 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -230,7 +230,7 @@ commands: name: run tests (<< parameters.title >>) command: | ./test/runner << parameters.test_targets >> - $EMSDK_PYTHON ./tools/check_clean.py + $EMSDK_PYTHON ./test/check_clean.py freeze-cache: description: "Freeze emscripten cache" steps: diff --git a/em-config b/em-config index 1a3a1c9691685..eef0f00c6730f 100755 --- a/em-config +++ b/em-config @@ -9,7 +9,7 @@ # Automatically generated by `create_entry_points.py`; DO NOT EDIT. # # To make modifications to this file, edit `tools/run_python.sh` and then run -# `tools/create_entry_points.py` +# `tools/maint/create_entry_points.py` # $PYTHON -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal # of cpython used in cross compilation via setup.py. diff --git a/em-config.bat b/em-config.bat index 34900168d5856..b574e98809e73 100644 --- a/em-config.bat +++ b/em-config.bat @@ -3,7 +3,7 @@ :: Automatically generated by `create_entry_points.py`; DO NOT EDIT. :: :: To make modifications to this file, edit `tools/run_python.bat` and then run -:: `tools/create_entry_points.py` +:: `tools/maint/create_entry_points.py` :: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, :: or there will be a parsing error. diff --git a/emar b/emar index 1a3a1c9691685..eef0f00c6730f 100755 --- a/emar +++ b/emar @@ -9,7 +9,7 @@ # Automatically generated by `create_entry_points.py`; DO NOT EDIT. # # To make modifications to this file, edit `tools/run_python.sh` and then run -# `tools/create_entry_points.py` +# `tools/maint/create_entry_points.py` # $PYTHON -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal # of cpython used in cross compilation via setup.py. diff --git a/emar.bat b/emar.bat index 34900168d5856..b574e98809e73 100644 --- a/emar.bat +++ b/emar.bat @@ -3,7 +3,7 @@ :: Automatically generated by `create_entry_points.py`; DO NOT EDIT. :: :: To make modifications to this file, edit `tools/run_python.bat` and then run -:: `tools/create_entry_points.py` +:: `tools/maint/create_entry_points.py` :: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, :: or there will be a parsing error. diff --git a/embuilder b/embuilder index 1a3a1c9691685..eef0f00c6730f 100755 --- a/embuilder +++ b/embuilder @@ -9,7 +9,7 @@ # Automatically generated by `create_entry_points.py`; DO NOT EDIT. # # To make modifications to this file, edit `tools/run_python.sh` and then run -# `tools/create_entry_points.py` +# `tools/maint/create_entry_points.py` # $PYTHON -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal # of cpython used in cross compilation via setup.py. diff --git a/embuilder.bat b/embuilder.bat index 34900168d5856..b574e98809e73 100644 --- a/embuilder.bat +++ b/embuilder.bat @@ -3,7 +3,7 @@ :: Automatically generated by `create_entry_points.py`; DO NOT EDIT. :: :: To make modifications to this file, edit `tools/run_python.bat` and then run -:: `tools/create_entry_points.py` +:: `tools/maint/create_entry_points.py` :: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, :: or there will be a parsing error. diff --git a/emcmake b/emcmake index 1a3a1c9691685..eef0f00c6730f 100755 --- a/emcmake +++ b/emcmake @@ -9,7 +9,7 @@ # Automatically generated by `create_entry_points.py`; DO NOT EDIT. # # To make modifications to this file, edit `tools/run_python.sh` and then run -# `tools/create_entry_points.py` +# `tools/maint/create_entry_points.py` # $PYTHON -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal # of cpython used in cross compilation via setup.py. diff --git a/emcmake.bat b/emcmake.bat index 34900168d5856..b574e98809e73 100644 --- a/emcmake.bat +++ b/emcmake.bat @@ -3,7 +3,7 @@ :: Automatically generated by `create_entry_points.py`; DO NOT EDIT. :: :: To make modifications to this file, edit `tools/run_python.bat` and then run -:: `tools/create_entry_points.py` +:: `tools/maint/create_entry_points.py` :: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, :: or there will be a parsing error. diff --git a/emconfigure b/emconfigure index 1a3a1c9691685..eef0f00c6730f 100755 --- a/emconfigure +++ b/emconfigure @@ -9,7 +9,7 @@ # Automatically generated by `create_entry_points.py`; DO NOT EDIT. # # To make modifications to this file, edit `tools/run_python.sh` and then run -# `tools/create_entry_points.py` +# `tools/maint/create_entry_points.py` # $PYTHON -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal # of cpython used in cross compilation via setup.py. diff --git a/emconfigure.bat b/emconfigure.bat index 34900168d5856..b574e98809e73 100644 --- a/emconfigure.bat +++ b/emconfigure.bat @@ -3,7 +3,7 @@ :: Automatically generated by `create_entry_points.py`; DO NOT EDIT. :: :: To make modifications to this file, edit `tools/run_python.bat` and then run -:: `tools/create_entry_points.py` +:: `tools/maint/create_entry_points.py` :: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, :: or there will be a parsing error. diff --git a/emdump b/emdump index b60c6e0083469..82f0e77a5c669 100755 --- a/emdump +++ b/emdump @@ -9,7 +9,7 @@ # Automatically generated by `create_entry_points.py`; DO NOT EDIT. # # To make modifications to this file, edit `tools/run_python.sh` and then run -# `tools/create_entry_points.py` +# `tools/maint/create_entry_points.py` # $PYTHON -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal # of cpython used in cross compilation via setup.py. diff --git a/emdump.bat b/emdump.bat index c0d7d3ecd28e8..f9fb29c0fbf08 100644 --- a/emdump.bat +++ b/emdump.bat @@ -3,7 +3,7 @@ :: Automatically generated by `create_entry_points.py`; DO NOT EDIT. :: :: To make modifications to this file, edit `tools/run_python.bat` and then run -:: `tools/create_entry_points.py` +:: `tools/maint/create_entry_points.py` :: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, :: or there will be a parsing error. diff --git a/emdwp b/emdwp index f39d54e64288c..2f93cfaded2e4 100755 --- a/emdwp +++ b/emdwp @@ -9,7 +9,7 @@ # Automatically generated by `create_entry_points.py`; DO NOT EDIT. # # To make modifications to this file, edit `tools/run_python.sh` and then run -# `tools/create_entry_points.py` +# `tools/maint/create_entry_points.py` # $PYTHON -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal # of cpython used in cross compilation via setup.py. diff --git a/emdwp.bat b/emdwp.bat index 3c056794f3564..23d1e45dfea9f 100644 --- a/emdwp.bat +++ b/emdwp.bat @@ -3,7 +3,7 @@ :: Automatically generated by `create_entry_points.py`; DO NOT EDIT. :: :: To make modifications to this file, edit `tools/run_python.bat` and then run -:: `tools/create_entry_points.py` +:: `tools/maint/create_entry_points.py` :: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, :: or there will be a parsing error. diff --git a/emmake b/emmake index 1a3a1c9691685..eef0f00c6730f 100755 --- a/emmake +++ b/emmake @@ -9,7 +9,7 @@ # Automatically generated by `create_entry_points.py`; DO NOT EDIT. # # To make modifications to this file, edit `tools/run_python.sh` and then run -# `tools/create_entry_points.py` +# `tools/maint/create_entry_points.py` # $PYTHON -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal # of cpython used in cross compilation via setup.py. diff --git a/emmake.bat b/emmake.bat index 34900168d5856..b574e98809e73 100644 --- a/emmake.bat +++ b/emmake.bat @@ -3,7 +3,7 @@ :: Automatically generated by `create_entry_points.py`; DO NOT EDIT. :: :: To make modifications to this file, edit `tools/run_python.bat` and then run -:: `tools/create_entry_points.py` +:: `tools/maint/create_entry_points.py` :: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, :: or there will be a parsing error. diff --git a/emnm b/emnm index 4920cf7017247..19fba1368d2b4 100755 --- a/emnm +++ b/emnm @@ -9,7 +9,7 @@ # Automatically generated by `create_entry_points.py`; DO NOT EDIT. # # To make modifications to this file, edit `tools/run_python.sh` and then run -# `tools/create_entry_points.py` +# `tools/maint/create_entry_points.py` # $PYTHON -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal # of cpython used in cross compilation via setup.py. diff --git a/emnm.bat b/emnm.bat index 4257155a7a8d9..e3b5824748a65 100644 --- a/emnm.bat +++ b/emnm.bat @@ -3,7 +3,7 @@ :: Automatically generated by `create_entry_points.py`; DO NOT EDIT. :: :: To make modifications to this file, edit `tools/run_python.bat` and then run -:: `tools/create_entry_points.py` +:: `tools/maint/create_entry_points.py` :: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, :: or there will be a parsing error. diff --git a/emprofile b/emprofile index 998a39e28d0cf..7a35f7a83c39d 100755 --- a/emprofile +++ b/emprofile @@ -9,7 +9,7 @@ # Automatically generated by `create_entry_points.py`; DO NOT EDIT. # # To make modifications to this file, edit `tools/run_python.sh` and then run -# `tools/create_entry_points.py` +# `tools/maint/create_entry_points.py` # $PYTHON -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal # of cpython used in cross compilation via setup.py. diff --git a/emprofile.bat b/emprofile.bat index 5908117caad95..c28cf0878c659 100644 --- a/emprofile.bat +++ b/emprofile.bat @@ -3,7 +3,7 @@ :: Automatically generated by `create_entry_points.py`; DO NOT EDIT. :: :: To make modifications to this file, edit `tools/run_python.bat` and then run -:: `tools/create_entry_points.py` +:: `tools/maint/create_entry_points.py` :: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, :: or there will be a parsing error. diff --git a/emranlib b/emranlib index 1a3a1c9691685..eef0f00c6730f 100755 --- a/emranlib +++ b/emranlib @@ -9,7 +9,7 @@ # Automatically generated by `create_entry_points.py`; DO NOT EDIT. # # To make modifications to this file, edit `tools/run_python.sh` and then run -# `tools/create_entry_points.py` +# `tools/maint/create_entry_points.py` # $PYTHON -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal # of cpython used in cross compilation via setup.py. diff --git a/emranlib.bat b/emranlib.bat index 34900168d5856..b574e98809e73 100644 --- a/emranlib.bat +++ b/emranlib.bat @@ -3,7 +3,7 @@ :: Automatically generated by `create_entry_points.py`; DO NOT EDIT. :: :: To make modifications to this file, edit `tools/run_python.bat` and then run -:: `tools/create_entry_points.py` +:: `tools/maint/create_entry_points.py` :: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, :: or there will be a parsing error. diff --git a/emrun b/emrun index 1a3a1c9691685..eef0f00c6730f 100755 --- a/emrun +++ b/emrun @@ -9,7 +9,7 @@ # Automatically generated by `create_entry_points.py`; DO NOT EDIT. # # To make modifications to this file, edit `tools/run_python.sh` and then run -# `tools/create_entry_points.py` +# `tools/maint/create_entry_points.py` # $PYTHON -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal # of cpython used in cross compilation via setup.py. diff --git a/emrun.bat b/emrun.bat index 34900168d5856..b574e98809e73 100644 --- a/emrun.bat +++ b/emrun.bat @@ -3,7 +3,7 @@ :: Automatically generated by `create_entry_points.py`; DO NOT EDIT. :: :: To make modifications to this file, edit `tools/run_python.bat` and then run -:: `tools/create_entry_points.py` +:: `tools/maint/create_entry_points.py` :: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, :: or there will be a parsing error. diff --git a/emscons b/emscons index 1a3a1c9691685..eef0f00c6730f 100755 --- a/emscons +++ b/emscons @@ -9,7 +9,7 @@ # Automatically generated by `create_entry_points.py`; DO NOT EDIT. # # To make modifications to this file, edit `tools/run_python.sh` and then run -# `tools/create_entry_points.py` +# `tools/maint/create_entry_points.py` # $PYTHON -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal # of cpython used in cross compilation via setup.py. diff --git a/emscons.bat b/emscons.bat index 34900168d5856..b574e98809e73 100644 --- a/emscons.bat +++ b/emscons.bat @@ -3,7 +3,7 @@ :: Automatically generated by `create_entry_points.py`; DO NOT EDIT. :: :: To make modifications to this file, edit `tools/run_python.bat` and then run -:: `tools/create_entry_points.py` +:: `tools/maint/create_entry_points.py` :: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, :: or there will be a parsing error. diff --git a/emsize b/emsize index 1a3a1c9691685..eef0f00c6730f 100755 --- a/emsize +++ b/emsize @@ -9,7 +9,7 @@ # Automatically generated by `create_entry_points.py`; DO NOT EDIT. # # To make modifications to this file, edit `tools/run_python.sh` and then run -# `tools/create_entry_points.py` +# `tools/maint/create_entry_points.py` # $PYTHON -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal # of cpython used in cross compilation via setup.py. diff --git a/emsize.bat b/emsize.bat index 34900168d5856..b574e98809e73 100644 --- a/emsize.bat +++ b/emsize.bat @@ -3,7 +3,7 @@ :: Automatically generated by `create_entry_points.py`; DO NOT EDIT. :: :: To make modifications to this file, edit `tools/run_python.bat` and then run -:: `tools/create_entry_points.py` +:: `tools/maint/create_entry_points.py` :: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, :: or there will be a parsing error. diff --git a/emstrip b/emstrip index 1a3a1c9691685..eef0f00c6730f 100755 --- a/emstrip +++ b/emstrip @@ -9,7 +9,7 @@ # Automatically generated by `create_entry_points.py`; DO NOT EDIT. # # To make modifications to this file, edit `tools/run_python.sh` and then run -# `tools/create_entry_points.py` +# `tools/maint/create_entry_points.py` # $PYTHON -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal # of cpython used in cross compilation via setup.py. diff --git a/emstrip.bat b/emstrip.bat index 34900168d5856..b574e98809e73 100644 --- a/emstrip.bat +++ b/emstrip.bat @@ -3,7 +3,7 @@ :: Automatically generated by `create_entry_points.py`; DO NOT EDIT. :: :: To make modifications to this file, edit `tools/run_python.bat` and then run -:: `tools/create_entry_points.py` +:: `tools/maint/create_entry_points.py` :: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, :: or there will be a parsing error. diff --git a/emsymbolizer b/emsymbolizer index 1a3a1c9691685..eef0f00c6730f 100755 --- a/emsymbolizer +++ b/emsymbolizer @@ -9,7 +9,7 @@ # Automatically generated by `create_entry_points.py`; DO NOT EDIT. # # To make modifications to this file, edit `tools/run_python.sh` and then run -# `tools/create_entry_points.py` +# `tools/maint/create_entry_points.py` # $PYTHON -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal # of cpython used in cross compilation via setup.py. diff --git a/emsymbolizer.bat b/emsymbolizer.bat index 34900168d5856..b574e98809e73 100644 --- a/emsymbolizer.bat +++ b/emsymbolizer.bat @@ -3,7 +3,7 @@ :: Automatically generated by `create_entry_points.py`; DO NOT EDIT. :: :: To make modifications to this file, edit `tools/run_python.bat` and then run -:: `tools/create_entry_points.py` +:: `tools/maint/create_entry_points.py` :: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, :: or there will be a parsing error. diff --git a/system/bin/sdl-config b/system/bin/sdl-config index 1a3a1c9691685..eef0f00c6730f 100755 --- a/system/bin/sdl-config +++ b/system/bin/sdl-config @@ -9,7 +9,7 @@ # Automatically generated by `create_entry_points.py`; DO NOT EDIT. # # To make modifications to this file, edit `tools/run_python.sh` and then run -# `tools/create_entry_points.py` +# `tools/maint/create_entry_points.py` # $PYTHON -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal # of cpython used in cross compilation via setup.py. diff --git a/system/bin/sdl-config.bat b/system/bin/sdl-config.bat index 34900168d5856..b574e98809e73 100644 --- a/system/bin/sdl-config.bat +++ b/system/bin/sdl-config.bat @@ -3,7 +3,7 @@ :: Automatically generated by `create_entry_points.py`; DO NOT EDIT. :: :: To make modifications to this file, edit `tools/run_python.bat` and then run -:: `tools/create_entry_points.py` +:: `tools/maint/create_entry_points.py` :: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, :: or there will be a parsing error. diff --git a/system/bin/sdl2-config b/system/bin/sdl2-config index 1a3a1c9691685..eef0f00c6730f 100755 --- a/system/bin/sdl2-config +++ b/system/bin/sdl2-config @@ -9,7 +9,7 @@ # Automatically generated by `create_entry_points.py`; DO NOT EDIT. # # To make modifications to this file, edit `tools/run_python.sh` and then run -# `tools/create_entry_points.py` +# `tools/maint/create_entry_points.py` # $PYTHON -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal # of cpython used in cross compilation via setup.py. diff --git a/system/bin/sdl2-config.bat b/system/bin/sdl2-config.bat index 34900168d5856..b574e98809e73 100644 --- a/system/bin/sdl2-config.bat +++ b/system/bin/sdl2-config.bat @@ -3,7 +3,7 @@ :: Automatically generated by `create_entry_points.py`; DO NOT EDIT. :: :: To make modifications to this file, edit `tools/run_python.bat` and then run -:: `tools/create_entry_points.py` +:: `tools/maint/create_entry_points.py` :: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, :: or there will be a parsing error. diff --git a/tools/check_clean.py b/test/check_clean.py similarity index 100% rename from tools/check_clean.py rename to test/check_clean.py diff --git a/test/runner b/test/runner index 1a3a1c9691685..eef0f00c6730f 100755 --- a/test/runner +++ b/test/runner @@ -9,7 +9,7 @@ # Automatically generated by `create_entry_points.py`; DO NOT EDIT. # # To make modifications to this file, edit `tools/run_python.sh` and then run -# `tools/create_entry_points.py` +# `tools/maint/create_entry_points.py` # $PYTHON -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal # of cpython used in cross compilation via setup.py. diff --git a/test/runner.bat b/test/runner.bat index 34900168d5856..b574e98809e73 100644 --- a/test/runner.bat +++ b/test/runner.bat @@ -3,7 +3,7 @@ :: Automatically generated by `create_entry_points.py`; DO NOT EDIT. :: :: To make modifications to this file, edit `tools/run_python.bat` and then run -:: `tools/create_entry_points.py` +:: `tools/maint/create_entry_points.py` :: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, :: or there will be a parsing error. diff --git a/tools/file_packager b/tools/file_packager index 1a3a1c9691685..eef0f00c6730f 100755 --- a/tools/file_packager +++ b/tools/file_packager @@ -9,7 +9,7 @@ # Automatically generated by `create_entry_points.py`; DO NOT EDIT. # # To make modifications to this file, edit `tools/run_python.sh` and then run -# `tools/create_entry_points.py` +# `tools/maint/create_entry_points.py` # $PYTHON -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal # of cpython used in cross compilation via setup.py. diff --git a/tools/file_packager.bat b/tools/file_packager.bat index 34900168d5856..b574e98809e73 100644 --- a/tools/file_packager.bat +++ b/tools/file_packager.bat @@ -3,7 +3,7 @@ :: Automatically generated by `create_entry_points.py`; DO NOT EDIT. :: :: To make modifications to this file, edit `tools/run_python.bat` and then run -:: `tools/create_entry_points.py` +:: `tools/maint/create_entry_points.py` :: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, :: or there will be a parsing error. diff --git a/tools/find_bigfuncs.py b/tools/find_bigfuncs.py deleted file mode 100644 index 7919bae2696bf..0000000000000 --- a/tools/find_bigfuncs.py +++ /dev/null @@ -1,119 +0,0 @@ -# Copyright 2013 The Emscripten Authors. All rights reserved. -# Emscripten is available under two separate licenses, the MIT license and the -# University of Illinois/NCSA Open Source License. Both these licenses can be -# found in the LICENSE file. - -"""Tool to find or compare big functions in a js or ll file -""" - -import sys - - -def humanbytes(nbytes): - if nbytes > 9 * 1024 * 1024: - return '{}MB'.format(nbytes / 1024 / 1024) - elif nbytes > 9 * 1024: - return '{}KB'.format(nbytes / 1024) - else: - return '{}B'.format(nbytes) - - -def processfile(filename): - start = None - curr = None - nbytes = None - data = {} - for i, line in enumerate(open(filename)): - if line.startswith(('function ', 'define ', ' (func ')) and '}' not in line: - start = i - curr = line - nbytes = len(line) - elif line.startswith(('}', ' )')) and curr: - nlines = i - start - data[curr] = (nlines, nbytes + 1) - curr = None - start = None - elif curr: - nbytes += len(line) - return data - - -def common_compare(data1, data2): - fns1 = set(data1.keys()) - fns2 = set(data2.keys()) - commonfns = fns1.intersection(fns2) - commonlinediff = 0 - commonbytediff = 0 - for fn in commonfns: - d1 = data1[fn] - d2 = data2[fn] - commonlinediff += d2[0] - d1[0] - commonbytediff += d2[1] - d1[1] - linesword = 'more' if commonlinediff >= 0 else 'less' - bytesword = 'more' if commonbytediff >= 0 else 'less' - print('file 2 has {} lines {} than file 1 in {} common functions'.format(abs(commonlinediff), linesword, len(commonfns))) - print('file 2 has {} {} than file 1 in {} common functions'.format(humanbytes(abs(commonbytediff)), bytesword, len(commonfns))) - - -def uniq_compare(data1, data2): - fns1 = set(data1.keys()) - fns2 = set(data2.keys()) - uniqfns1 = fns1 - fns2 - uniqfns2 = fns2 - fns1 - uniqlines1 = 0 - uniqbytes1 = 0 - uniqlines2 = 0 - uniqbytes2 = 0 - for fn in uniqfns1: - d = data1[fn] - uniqlines1 += d[0] - uniqbytes1 += d[1] - for fn in uniqfns2: - d = data2[fn] - uniqlines2 += d[0] - uniqbytes2 += d[1] - uniqcountdiff = len(uniqfns2) - len(uniqfns1) - assert len(fns2) - len(fns1) == uniqcountdiff - uniqlinediff = uniqlines2 - uniqlines1 - uniqbytediff = uniqbytes2 - uniqbytes1 - countword = 'more' if uniqcountdiff >= 0 else 'less' - linesword = 'more' if uniqlinediff >= 0 else 'less' - bytesword = 'more' if uniqbytediff >= 0 else 'less' - print('file 2 has {} functions {} than file 1 overall (unique: {} vs {})'.format(abs(uniqcountdiff), countword, len(uniqfns2), len(uniqfns1))) - print('file 2 has {} lines {} than file 1 overall in unique functions'.format(abs(uniqlinediff), linesword)) - print('file 2 has {} {} than file 1 overall in unique functions'.format(humanbytes(abs(uniqbytediff)), bytesword)) - - -def list_bigfuncs(data): - data = list(data.items()) - data.sort(key=lambda f_d: f_d[1][0]) - print(''.join(['%6d lines (%6s) : %s' % (d[0], humanbytes(d[1]), f) for f, d in data])) - - -def main(): - if len(sys.argv) < 2 or len(sys.argv) > 3 or sys.argv[1] == '--help': - print('Usage:') - print(' {} file1 - list functions in a file in ascending order of size'.format(sys.argv[0])) - print(' {} file1 file2 - compare functions across two files'.format(sys.argv[0])) - return 1 - - if len(sys.argv) == 2: - filename = sys.argv[1] - data = processfile(filename) - list_bigfuncs(data) - return 0 - - if len(sys.argv) == 3: - filename1 = sys.argv[1] - data1 = processfile(filename1) - filename2 = sys.argv[2] - data2 = processfile(filename2) - uniq_compare(data1, data2) - common_compare(data1, data2) - return 0 - - assert False - - -if __name__ == '__main__': - sys.exit(main()) diff --git a/tools/find_bigvars.py b/tools/find_bigvars.py deleted file mode 100644 index 3a40b879e239f..0000000000000 --- a/tools/find_bigvars.py +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright 2013 The Emscripten Authors. All rights reserved. -# Emscripten is available under two separate licenses, the MIT license and the -# University of Illinois/NCSA Open Source License. Both these licenses can be -# found in the LICENSE file. - -"""Simple tool to find functions with lots of vars. -""" - -import sys - -filename = sys.argv[1] -i = 0 -curr = None -data = [] -size = 0 -for line in open(filename): - i += 1 - if line.startswith('function '): - size = len(line.split(',')) # params - curr = line - elif line.strip().startswith('var '): - size += len(line.split(',')) + 1 # vars - elif line.startswith('}') and curr: - data.append([curr, size]) - curr = None -data.sort(key=lambda x: x[1]) -print(''.join('%6d : %s' % (x[1], x[0]) for x in data)) diff --git a/tools/add_license.py b/tools/maint/add_license.py similarity index 98% rename from tools/add_license.py rename to tools/maint/add_license.py index 079b3bb37c11c..afd27ba03afd6 100755 --- a/tools/add_license.py +++ b/tools/maint/add_license.py @@ -11,7 +11,7 @@ import subprocess script_dir = os.path.dirname(os.path.abspath(__file__)) -__rootpath__ = os.path.dirname(script_dir) +__rootpath__ = os.path.dirname(os.path.dirname(script_dir)) cpp_license = '''\ // Copyright %s The Emscripten Authors. All rights reserved. diff --git a/tools/create_entry_points.py b/tools/maint/create_entry_points.py similarity index 96% rename from tools/create_entry_points.py rename to tools/maint/create_entry_points.py index 877b20afe3022..228713ee6fbaa 100755 --- a/tools/create_entry_points.py +++ b/tools/maint/create_entry_points.py @@ -56,7 +56,7 @@ 'emnm': 'tools/emnm', } -tools_dir = os.path.dirname(os.path.abspath(__file__)) +tools_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) def main(): diff --git a/tools/simde_update.py b/tools/maint/simde_update.py similarity index 95% rename from tools/simde_update.py rename to tools/maint/simde_update.py index 6a284650f6ee6..0909be03ddef7 100755 --- a/tools/simde_update.py +++ b/tools/maint/simde_update.py @@ -16,13 +16,13 @@ from os import path __scriptdir__ = os.path.dirname(os.path.abspath(__file__)) -__rootdir__ = os.path.dirname(__scriptdir__) +__rootdir__ = os.path.dirname(os.path.dirname(__scriptdir__)) sys.path.append(__rootdir__) from tools.shared import get_emscripten_temp_dir tmpdir = get_emscripten_temp_dir() -emdir = path.join(path.dirname(path.realpath(__file__)), "..") +emdir = __rootdir__ def main(): diff --git a/tools/run_python.bat b/tools/run_python.bat index 34900168d5856..b574e98809e73 100644 --- a/tools/run_python.bat +++ b/tools/run_python.bat @@ -3,7 +3,7 @@ :: Automatically generated by `create_entry_points.py`; DO NOT EDIT. :: :: To make modifications to this file, edit `tools/run_python.bat` and then run -:: `tools/create_entry_points.py` +:: `tools/maint/create_entry_points.py` :: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, :: or there will be a parsing error. diff --git a/tools/run_python.sh b/tools/run_python.sh index 1a3a1c9691685..eef0f00c6730f 100755 --- a/tools/run_python.sh +++ b/tools/run_python.sh @@ -9,7 +9,7 @@ # Automatically generated by `create_entry_points.py`; DO NOT EDIT. # # To make modifications to this file, edit `tools/run_python.sh` and then run -# `tools/create_entry_points.py` +# `tools/maint/create_entry_points.py` # $PYTHON -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal # of cpython used in cross compilation via setup.py. diff --git a/tools/webidl_binder b/tools/webidl_binder index 1a3a1c9691685..eef0f00c6730f 100755 --- a/tools/webidl_binder +++ b/tools/webidl_binder @@ -9,7 +9,7 @@ # Automatically generated by `create_entry_points.py`; DO NOT EDIT. # # To make modifications to this file, edit `tools/run_python.sh` and then run -# `tools/create_entry_points.py` +# `tools/maint/create_entry_points.py` # $PYTHON -E will not ignore _PYTHON_SYSCONFIGDATA_NAME an internal # of cpython used in cross compilation via setup.py. diff --git a/tools/webidl_binder.bat b/tools/webidl_binder.bat index 34900168d5856..b574e98809e73 100644 --- a/tools/webidl_binder.bat +++ b/tools/webidl_binder.bat @@ -3,7 +3,7 @@ :: Automatically generated by `create_entry_points.py`; DO NOT EDIT. :: :: To make modifications to this file, edit `tools/run_python.bat` and then run -:: `tools/create_entry_points.py` +:: `tools/maint/create_entry_points.py` :: N.b. In Windows .bat scripts, the ':' character cannot appear inside any if () blocks, :: or there will be a parsing error. From f00fb16add7b64861a92db7d9f101b57dbd58f95 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 22 May 2023 17:00:14 -0700 Subject: [PATCH 0271/1523] Use CLOCK_MONOTONIC to implement emscripten_get_now in standalone mode (#19416) --- system/lib/standalone/standalone.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/system/lib/standalone/standalone.c b/system/lib/standalone/standalone.c index d9de42f4c9c30..44e1912d2b2d2 100644 --- a/system/lib/standalone/standalone.c +++ b/system/lib/standalone/standalone.c @@ -153,7 +153,11 @@ int emscripten_resize_heap(size_t size) { } double emscripten_get_now(void) { - return (1000ll * clock()) / (double)CLOCKS_PER_SEC; + struct timespec ts; + if (clock_gettime(CLOCK_MONOTONIC, &ts)) { + return 0; + } + return (double)ts.tv_sec + (double)ts.tv_nsec / 1000000000; } // C++ ABI From b814b59890c5d1eeb5a012d262235d254e7ece17 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 22 May 2023 17:38:01 -0700 Subject: [PATCH 0272/1523] WasmFS test adjustments (#19420) Skip part of test_readdir to get it passing, and skip test_fs_no_main entirely since it only tests internals of the JS FS code. --- .circleci/config.yml | 1 + test/dirent/test_readdir.c | 7 +++++++ test/test_core.py | 8 +++++++- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index af753c2e14c36..8919ec0f54086 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -507,6 +507,7 @@ jobs: wasmfs.test_emscripten_get_now wasmfs.test_dyncall_specific_minimal_runtime wasmfs.test_fcntl_misc + wasmfs.test_readdir_rawfs wasmfs.test_utime wasmfs.test_unistd_unlink wasmfs.test_unistd_access diff --git a/test/dirent/test_readdir.c b/test/dirent/test_readdir.c index 0a0dff4bededc..762084602e911 100644 --- a/test/dirent/test_readdir.c +++ b/test/dirent/test_readdir.c @@ -143,7 +143,14 @@ void test() { //printf("name_at_loc: %s\n", name_at_loc); assert(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..") || !strcmp(ent->d_name, "file.txt")); ent = readdir(dir); +#ifndef WASMFS_NODERAWFS + // WasmFS + NODERAWFS lacks ino numbers in directory listings, see + // https://github.com/emscripten-core/emscripten/issues/19418 + // This is not an issue for "." and ".." (the other checks before and after + // us) since "." and ".." are added by WasmFS code itself; only "file.txt" is + // added from the node JS API, and as a result it has inode 0. assert(ent && ent->d_ino); +#endif assert(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..") || !strcmp(ent->d_name, "file.txt")); seekdir(dir, loc); ent = readdir(dir); diff --git a/test/test_core.py b/test/test_core.py index 5481e965b48c8..7abd9ccf7653b 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -5805,6 +5805,11 @@ def test_fileno(self): @also_with_noderawfs def test_readdir(self): + if self.get_setting('WASMFS') and self.get_setting('NODERAWFS'): + # WasmFS + NODERAWFS lacks ino numbers in directory listings, see + # https://github.com/emscripten-core/emscripten/issues/19418 + # We need to tell the test we are in this mode so it can ignore them. + self.emcc_args += ['-DWASMFS_NODERAWFS'] self.do_run_in_out_file_test('dirent/test_readdir.c') @also_with_wasm_bigint @@ -6043,12 +6048,13 @@ def test_fs_mmap(self, fs): self.emcc_args += ['-sWASMFS', '-sFORCE_FILESYSTEM'] self.do_run_in_out_file_test('fs/test_mmap.c', emcc_args=['-D' + fs]) + @no_wasmfs('wasmfs will (?) need a non-JS mechanism to ignore permissions during startup') @parameterized({ '': [], 'minimal_runtime': ['-sMINIMAL_RUNTIME=1'] }) def test_fs_no_main(self, *args): - # library_fs.js uses hooks to enable ignoreing of permisions up until ATMAINs are run. This + # library_fs.js uses hooks to enable ignoring of permisions up until ATMAINs are run. This # test verified that they work correctly, even in programs without a main function. create_file('pre.js', ''' Module['preRun'] = function() { From d748e5ddb791f08897febf42020b0f17a508574e Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 22 May 2023 17:58:59 -0700 Subject: [PATCH 0273/1523] Rebaseline codesize expectations. NFC --- test/other/metadce/test_metadce_hello_dylink.jssize | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/other/metadce/test_metadce_hello_dylink.jssize b/test/other/metadce/test_metadce_hello_dylink.jssize index f14659634d305..5b4e31ba26409 100644 --- a/test/other/metadce/test_metadce_hello_dylink.jssize +++ b/test/other/metadce/test_metadce_hello_dylink.jssize @@ -1 +1 @@ -15054 +15075 From 84aa67e620145403cde4666c0fb26044342e1fa6 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 22 May 2023 18:26:16 -0700 Subject: [PATCH 0274/1523] Remove use of process.hrtime under node (#19415) This was originally added back in 477cde821d, but since 8.5.0 node has supported `performance.now`. The minimum version of node we support is currently 10.19.0. --- src/deterministic.js | 1 - src/library.js | 22 +++++++++---------- .../test_metadce_minimal_pthreads.jssize | 2 +- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/deterministic.js b/src/deterministic.js index fe7936507859d..6d168821c2334 100644 --- a/src/deterministic.js +++ b/src/deterministic.js @@ -12,7 +12,6 @@ Math.random = () => { var TIME = 10000; Date.now = () => TIME++; if (typeof performance == 'object') performance.now = Date.now; -if (ENVIRONMENT_IS_NODE) process.hrtime = Date.now; Module['thisProgram'] = 'thisProgram'; // for consistency between different builds than between runs of the same build diff --git a/src/library.js b/src/library.js index 75c97e6ebfac1..678f8ffcdacd8 100644 --- a/src/library.js +++ b/src/library.js @@ -2337,13 +2337,12 @@ mergeInto(LibraryManager.library, { }, emscripten_get_now: ';' + -#if ENVIRONMENT_MAY_BE_NODE - "if (ENVIRONMENT_IS_NODE) {\n" + - " _emscripten_get_now = () => {\n" + - " var t = process.hrtime();\n" + - " return t[0] * 1e3 + t[1] / 1e6;\n" + - " };\n" + - "} else " + +#if ENVIRONMENT_MAY_BE_NODE && MIN_NODE_VERSION < 160000 +// The performance global was added to node in v16.0.0: +// https://nodejs.org/api/globals.html#performance + "if (ENVIRONMENT_IS_NODE) {\n" + + " global.performance = require('perf_hooks').performance;\n" + + "}" + #endif #if PTHREADS && !AUDIO_WORKLET // Pthreads need their clocks synchronized to the execution of the main thread, so, when using them, @@ -2369,7 +2368,7 @@ mergeInto(LibraryManager.library, { "}", #else // Modern environment where performance.now() is supported: - // N.B. a shorter form "_emscripten_get_now = return performance.now;" is unfortunately not allowed even in current browsers (e.g. FF Nightly 75). + // N.B. a shorter form "_emscripten_get_now = performance.now;" is unfortunately not allowed even in current browsers (e.g. FF Nightly 75). "_emscripten_get_now = () => performance.now();\n", #endif #endif @@ -2378,19 +2377,18 @@ mergeInto(LibraryManager.library, { #if ENVIRONMENT_MAY_BE_NODE if (ENVIRONMENT_IS_NODE) { return 1; // nanoseconds - } else + } #endif #if ENVIRONMENT_MAY_BE_SHELL if (typeof dateNow != 'undefined') { return 1000; // microseconds (1/1000 of a millisecond) - } else + } #endif #if MIN_IE_VERSION <= 9 || MIN_FIREFOX_VERSION <= 14 || MIN_CHROME_VERSION <= 23 || MIN_SAFARI_VERSION <= 80400 // https://caniuse.com/#feat=high-resolution-time if (typeof performance == 'object' && performance && typeof performance['now'] == 'function') { return 1000; // microseconds (1/1000 of a millisecond) - } else { - return 1000*1000; // milliseconds } + return 1000*1000; // milliseconds #else // Modern environment where performance.now() is supported: return 1000; // microseconds (1/1000 of a millisecond) diff --git a/test/other/metadce/test_metadce_minimal_pthreads.jssize b/test/other/metadce/test_metadce_minimal_pthreads.jssize index 5f9626305d9a4..13dac5d04b508 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.jssize +++ b/test/other/metadce/test_metadce_minimal_pthreads.jssize @@ -1 +1 @@ -15426 +15415 From 3b7cce5ddd348c682d0c120b790bb21580a55f1b Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 23 May 2023 08:08:52 -0700 Subject: [PATCH 0275/1523] WasmFS: Fix __syscall_utimensat to handle nonstandard linux behavior (#19421) Musl and Linux allow that syscall to get a null path and to then behave as if AT_EMPTY_PATH were passed, but without passing that flag. That is, if the path is null then the syscall is to operate on the FD (which might be anything, and not just a directory, as the parameter normally is). Another option to fix this might be to modify musl's source code to not do that in futimens or utimensat but I think it's better to avoid modifing musl source code. With this, wasmfs.test_futimens passes. --- .circleci/config.yml | 1 + system/lib/wasmfs/syscalls.cpp | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 8919ec0f54086..07b92ef18286f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -524,6 +524,7 @@ jobs: wasmfs.test_getcwd_with_non_ascii_name wasmfs.test_stat wasmfs.test_fstatat + wasmfs.test_futimens wasmfs.test_unistd_links_memfs wasmfs.test_fcntl_open wasmfs.test_freetype" diff --git a/system/lib/wasmfs/syscalls.cpp b/system/lib/wasmfs/syscalls.cpp index 9458ecb3710f4..7c3c4a8ac6bf2 100644 --- a/system/lib/wasmfs/syscalls.cpp +++ b/system/lib/wasmfs/syscalls.cpp @@ -1089,8 +1089,14 @@ int __syscall_utimensat(int dirFD, intptr_t path_, intptr_t times_, int flags) { return -EINVAL; } + // Add AT_EMPTY_PATH as Linux (and so, musl, and us) has a nonstandard + // behavior in which an empty path means to operate on whatever is in dirFD + // (directory or not), which is exactly the behavior of AT_EMPTY_PATH (but + // without passing that in). See "C library/kernel ABI differences" in + // https://man7.org/linux/man-pages/man2/utimensat.2.html + // // TODO: Handle AT_SYMLINK_NOFOLLOW once we traverse symlinks correctly. - auto parsed = path::parseFile(path, dirFD); + auto parsed = path::getFileAt(dirFD, path, flags | AT_EMPTY_PATH); if (auto err = parsed.getError()) { return err; } From 2a6918e98e19914b06db7ca366a0abdd16e606c5 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 23 May 2023 08:21:20 -0700 Subject: [PATCH 0276/1523] Use JS multi-line strings in src/library.js (#19424) --- src/library.js | 51 +++++++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/src/library.js b/src/library.js index 678f8ffcdacd8..eddc4376868b7 100644 --- a/src/library.js +++ b/src/library.js @@ -2336,42 +2336,47 @@ mergeInto(LibraryManager.library, { return Math.random(); }, - emscripten_get_now: ';' + + emscripten_get_now: `; #if ENVIRONMENT_MAY_BE_NODE && MIN_NODE_VERSION < 160000 -// The performance global was added to node in v16.0.0: -// https://nodejs.org/api/globals.html#performance - "if (ENVIRONMENT_IS_NODE) {\n" + - " global.performance = require('perf_hooks').performance;\n" + - "}" + + // The performance global was added to node in v16.0.0: + // https://nodejs.org/api/globals.html#performance + if (ENVIRONMENT_IS_NODE) { + global.performance = require('perf_hooks').performance; + } #endif #if PTHREADS && !AUDIO_WORKLET -// Pthreads need their clocks synchronized to the execution of the main thread, so, when using them, -// make sure to adjust all timings to the respective time origins. - "_emscripten_get_now = () => performance.timeOrigin + performance.now();\n", + // Pthreads need their clocks synchronized to the execution of the main + // thread, so, when using them, make sure to adjust all timings to the + // respective time origins. + _emscripten_get_now = () => performance.timeOrigin + performance.now(); #else #if ENVIRONMENT_MAY_BE_SHELL - "if (typeof dateNow != 'undefined') {\n" + - " _emscripten_get_now = dateNow;\n" + - "} else " + + if (typeof dateNow != 'undefined') { + _emscripten_get_now = dateNow; + } else #endif #if MIN_IE_VERSION <= 9 || MIN_FIREFOX_VERSION <= 14 || MIN_CHROME_VERSION <= 23 || MIN_SAFARI_VERSION <= 80400 || AUDIO_WORKLET // https://caniuse.com/#feat=high-resolution-time -// AudioWorkletGlobalScope does not have performance.now() (https://github.com/WebAudio/web-audio-api/issues/2527), so if building with -// Audio Worklets enabled, do a dynamic check for its presence. - "if (typeof performance != 'undefined' && performance.now) {\n" + + // AudioWorkletGlobalScope does not have performance.now() + // (https://github.com/WebAudio/web-audio-api/issues/2527), so if building + // with + // Audio Worklets enabled, do a dynamic check for its presence. + if (typeof performance != 'undefined' && performance.now) { #if PTHREADS - " _emscripten_get_now = () => performance.timeOrigin + performance.now();\n" + + _emscripten_get_now = () => performance.timeOrigin + performance.now(); #else - " _emscripten_get_now = () => performance.now();\n" + + _emscripten_get_now = () => performance.now(); #endif - "} else {\n" + - " _emscripten_get_now = Date.now;\n" + - "}", + } else { + _emscripten_get_now = Date.now; + } #else - // Modern environment where performance.now() is supported: - // N.B. a shorter form "_emscripten_get_now = performance.now;" is unfortunately not allowed even in current browsers (e.g. FF Nightly 75). - "_emscripten_get_now = () => performance.now();\n", + // Modern environment where performance.now() is supported: + // N.B. a shorter form "_emscripten_get_now = performance.now;" is + // unfortunately not allowed even in current browsers (e.g. FF Nightly 75). + _emscripten_get_now = () => performance.now(); #endif #endif +`, emscripten_get_now_res: function() { // return resolution of get_now, in nanoseconds #if ENVIRONMENT_MAY_BE_NODE From 4bec9b179a7d6329a84545851deb1a9da9b5c4f7 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 23 May 2023 11:57:57 -0700 Subject: [PATCH 0277/1523] CI: Update node canary version (#19429) It looks like maybe they only make a certain number of canary builds available since the URL for the version we were using stopped working. --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 07b92ef18286f..a266c855f0011 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -101,7 +101,7 @@ commands: description: "install canary version of node" steps: - install-node-version: - node_version: "20.0.0-v8-canary202302081604228b65" + node_version: "20.0.0-v8-canary2023041819be670741" canary: true install-v8: description: "install v8 using jsvu" From ac86000d6d520f097d11ca78729458cee4bcf206 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 23 May 2023 13:12:10 -0700 Subject: [PATCH 0278/1523] Fix regression in fetch API use of custom requestMethod (#19428) In #19336 (which was supposed to be NFC) I mistakenly started reading `emscripten_fetch_attr_t.requestMethod` as a pointer, but this member is a C array type so should not be dereferenced as a pointer. Fixes: #19399 --- src/Fetch.js | 17 +++++----- test/common.py | 15 ++++++++- test/fetch/test_fetch_post.c | 64 ++++++++++++++++++++++++++++++++++++ test/test_browser.py | 3 ++ 4 files changed, 89 insertions(+), 10 deletions(-) create mode 100644 test/fetch/test_fetch_post.c diff --git a/src/Fetch.js b/src/Fetch.js index 0fb95e324bb51..04f27e5779255 100644 --- a/src/Fetch.js +++ b/src/Fetch.js @@ -245,7 +245,7 @@ function fetchXHR(fetch, onsuccess, onerror, onprogress, onreadystatechange) { var url_ = UTF8ToString(url); var fetch_attr = fetch + {{{ C_STRUCTS.emscripten_fetch_t.__attributes }}}; - var requestMethod = UTF8ToString({{{ makeGetValue('fetch_attr', C_STRUCTS.emscripten_fetch_attr_t.requestMethod, '*') }}}); + var requestMethod = UTF8ToString(fetch_attr + {{{ C_STRUCTS.emscripten_fetch_attr_t.requestMethod }}}); if (!requestMethod) requestMethod = 'GET'; var timeoutMsecs = {{{ makeGetValue('fetch_attr', C_STRUCTS.emscripten_fetch_attr_t.timeoutMSecs, 'u32') }}}; var userName = {{{ makeGetValue('fetch_attr', C_STRUCTS.emscripten_fetch_attr_t.userName, '*') }}}; @@ -444,17 +444,11 @@ function startFetch(fetch, successcb, errorcb, progresscb, readystatechangecb) { {{{ runtimeKeepalivePush() }}} var fetch_attr = fetch + {{{ C_STRUCTS.emscripten_fetch_t.__attributes }}}; - var requestMethod = UTF8ToString(fetch_attr); var onsuccess = HEAPU32[fetch_attr + {{{ C_STRUCTS.emscripten_fetch_attr_t.onsuccess }}} >> 2]; var onerror = HEAPU32[fetch_attr + {{{ C_STRUCTS.emscripten_fetch_attr_t.onerror }}} >> 2]; var onprogress = HEAPU32[fetch_attr + {{{ C_STRUCTS.emscripten_fetch_attr_t.onprogress }}} >> 2]; var onreadystatechange = HEAPU32[fetch_attr + {{{ C_STRUCTS.emscripten_fetch_attr_t.onreadystatechange }}} >> 2]; var fetchAttributes = HEAPU32[fetch_attr + {{{ C_STRUCTS.emscripten_fetch_attr_t.attributes }}} >> 2]; -#if FETCH_SUPPORT_INDEXEDDB - var fetchAttrPersistFile = !!(fetchAttributes & {{{ cDefs.EMSCRIPTEN_FETCH_PERSIST_FILE }}}); - var fetchAttrNoDownload = !!(fetchAttributes & {{{ cDefs.EMSCRIPTEN_FETCH_NO_DOWNLOAD }}}); -#endif - var fetchAttrReplace = !!(fetchAttributes & {{{ cDefs.EMSCRIPTEN_FETCH_REPLACE }}}); var fetchAttrSynchronous = !!(fetchAttributes & {{{ cDefs.EMSCRIPTEN_FETCH_SYNCHRONOUS }}}); function doCallback(f) { @@ -546,10 +540,15 @@ function startFetch(fetch, successcb, errorcb, progresscb, readystatechangecb) { fetchXHR(fetch, cacheResultAndReportSuccess, reportError, reportProgress, reportReadyStateChange); }; + var requestMethod = UTF8ToString(fetch_attr + {{{ C_STRUCTS.emscripten_fetch_attr_t.requestMethod }}}); + var fetchAttrReplace = !!(fetchAttributes & {{{ cDefs.EMSCRIPTEN_FETCH_REPLACE }}}); + var fetchAttrPersistFile = !!(fetchAttributes & {{{ cDefs.EMSCRIPTEN_FETCH_PERSIST_FILE }}}); + var fetchAttrNoDownload = !!(fetchAttributes & {{{ cDefs.EMSCRIPTEN_FETCH_NO_DOWNLOAD }}}); if (requestMethod === 'EM_IDB_STORE') { // TODO(?): Here we perform a clone of the data, because storing shared typed arrays to IndexedDB does not seem to be allowed. - var ptr = HEAPU32[fetch_attr + {{{ C_STRUCTS.emscripten_fetch_attr_t.requestData }}} >> 2]; - fetchCacheData(Fetch.dbInstance, fetch, HEAPU8.slice(ptr, ptr + HEAPU32[fetch_attr + {{{ C_STRUCTS.emscripten_fetch_attr_t.requestDataSize }}} >> 2]), reportSuccess, reportError); + var ptr = {{{ makeGetValue('fetch_attr', C_STRUCTS.emscripten_fetch_attr_t.requestData, '*') }}}; + var size = {{{ makeGetValue('fetch_attr', C_STRUCTS.emscripten_fetch_attr_t.requestDataSize, '*') }}}; + fetchCacheData(Fetch.dbInstance, fetch, HEAPU8.slice(ptr, ptr + size), reportSuccess, reportError); } else if (requestMethod === 'EM_IDB_DELETE') { fetchDeleteCachedData(Fetch.dbInstance, fetch, reportSuccess, reportError); } else if (!fetchAttrReplace) { diff --git a/test/common.py b/test/common.py index b23c88c4e7edc..700fe801ac17c 100644 --- a/test/common.py +++ b/test/common.py @@ -8,7 +8,7 @@ from pathlib import Path from subprocess import PIPE, STDOUT from typing import Dict, Tuple -from urllib.parse import unquote, unquote_plus +from urllib.parse import unquote, unquote_plus, urlparse, parse_qs from http.server import HTTPServer, SimpleHTTPRequestHandler import contextlib import difflib @@ -1522,6 +1522,19 @@ def end_headers(self): self.send_header('Cache-Control', 'no-cache, no-store, must-revalidate') return SimpleHTTPRequestHandler.end_headers(self) + def do_POST(self): + urlinfo = urlparse(self.path) + query = parse_qs(urlinfo.query) + # Mirror behaviour of emrun which is to write POST'd files to dump_out/ by default + if query['file']: + print('do_POST: got file: %s' % query['file']) + ensure_dir('dump_out') + filename = os.path.join('dump_out', query['file'][0]) + contentLength = int(self.headers['Content-Length']) + write_binary(filename, self.rfile.read(contentLength)) + self.send_response(200) + self.end_headers() + def do_GET(self): if self.path == '/run_harness': if DEBUG: diff --git a/test/fetch/test_fetch_post.c b/test/fetch/test_fetch_post.c new file mode 100644 index 0000000000000..e4e9a5b0a9a7a --- /dev/null +++ b/test/fetch/test_fetch_post.c @@ -0,0 +1,64 @@ +// Copyright 2023 The Emscripten Authors. All rights reserved. +// Emscripten is available under two separate licenses, the MIT license and the +// University of Illinois/NCSA Open Source License. Both these licenses can be +// found in the LICENSE file. + +// Upload a file by POST'ing with ?file=xx in the query string and then +// attempt to download the file + +#include +#include +#include +#include +#include +#include + +void onError(emscripten_fetch_t *fetch) { + printf("onError: %d %s\n", fetch->status, fetch->statusText); + assert(false); +} + +void onGetSuccess(emscripten_fetch_t *fetch) { + printf("onGetSuccess URL=%s status=%d numBytes=%llu\n", + fetch->url, + fetch->status, + fetch->numBytes); + assert(fetch->status == 200); + printf("data: %.*s\n", (int)fetch->numBytes, fetch->data); + assert(strncmp(fetch->data, "Hello, world!", fetch->numBytes) == 0); + exit(0); +} + +void doGet() { + emscripten_fetch_attr_t attr; + emscripten_fetch_attr_init(&attr); + attr.attributes = EMSCRIPTEN_FETCH_LOAD_TO_MEMORY; + attr.onsuccess = onGetSuccess; + attr.onerror = onError; + emscripten_fetch(&attr, "dump_out/newfile.txt"); +} + +void onPostSuccess(emscripten_fetch_t *fetch) { + printf("onPostSuccess URL=%s status=%d\n", fetch->url, fetch->status); + assert(fetch->status == 200); + // The data is now available at fetch->data[0] through fetch->data[fetch->numBytes-1]; + emscripten_fetch_close(fetch); // Free data associated with the fetch. + + // Now attempt to GET the POST'ed file + doGet(); +} + +int main() { + // Upload a file using `POST` with `?file=` + emscripten_fetch_attr_t attr; + emscripten_fetch_attr_init(&attr); + strcpy(attr.requestMethod, "POST"); + attr.onsuccess = onPostSuccess; + attr.onerror = onError; + attr.requestData = "Hello, world!"; + attr.requestDataSize = strlen(attr.requestData); + emscripten_fetch(&attr, "?file=newfile.txt"); + + // This return code should be ignored + return 99; +} diff --git a/test/test_browser.py b/test/test_browser.py index 13e34f5ed7669..ee1b984c2dba9 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -4751,6 +4751,9 @@ def test_fetch_idb_delete(self): shutil.copyfile(test_file('gears.png'), 'gears.png') self.btest_exit('fetch/idb_delete.cpp', args=['-pthread', '-sFETCH_DEBUG', '-sFETCH', '-sWASM=0', '-sPROXY_TO_PTHREAD']) + def test_fetch_post(self): + self.btest_exit('fetch/test_fetch_post.c', args=['-sFETCH']) + @requires_threads def test_pthread_locale(self): self.emcc_args.append('-I' + path_from_root('system/lib/libc/musl/src/internal')) From 47a64e6949ef0957c3ce2d27772a5ecf116e4b5c Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 23 May 2023 15:50:16 -0700 Subject: [PATCH 0279/1523] Use cDefs in JS library files. NFC (#19422) --- src/generated_struct_info32.json | 5 ++ src/generated_struct_info64.json | 5 ++ src/library_egl.js | 4 +- src/library_glfw.js | 4 +- src/library_openal.js | 86 ++++++++++++++++---------------- src/library_sdl.js | 4 +- src/struct_info.json | 7 ++- 7 files changed, 65 insertions(+), 50 deletions(-) diff --git a/src/generated_struct_info32.json b/src/generated_struct_info32.json index 375664fbb7650..6dccf9239d95e 100644 --- a/src/generated_struct_info32.json +++ b/src/generated_struct_info32.json @@ -21,6 +21,7 @@ "AL_DOPPLER_FACTOR": 49152, "AL_FALSE": 0, "AL_GAIN": 4106, + "AL_INITIAL": 4113, "AL_INVALID_ENUM": 40962, "AL_INVALID_NAME": 40961, "AL_INVALID_OPERATION": 40964, @@ -28,8 +29,12 @@ "AL_NONE": 0, "AL_NO_ERROR": 0, "AL_ORIENTATION": 4111, + "AL_PAUSED": 4115, + "AL_PLAYING": 4114, "AL_POSITION": 4100, "AL_SPEED_OF_SOUND": 49155, + "AL_STATIC": 4136, + "AL_STOPPED": 4116, "AL_TRUE": 1, "AL_VELOCITY": 4102, "AT_EMPTY_PATH": 4096, diff --git a/src/generated_struct_info64.json b/src/generated_struct_info64.json index dc16a1f78977e..5d0f76cad2120 100644 --- a/src/generated_struct_info64.json +++ b/src/generated_struct_info64.json @@ -21,6 +21,7 @@ "AL_DOPPLER_FACTOR": 49152, "AL_FALSE": 0, "AL_GAIN": 4106, + "AL_INITIAL": 4113, "AL_INVALID_ENUM": 40962, "AL_INVALID_NAME": 40961, "AL_INVALID_OPERATION": 40964, @@ -28,8 +29,12 @@ "AL_NONE": 0, "AL_NO_ERROR": 0, "AL_ORIENTATION": 4111, + "AL_PAUSED": 4115, + "AL_PLAYING": 4114, "AL_POSITION": 4100, "AL_SPEED_OF_SOUND": 49155, + "AL_STATIC": 4136, + "AL_STOPPED": 4116, "AL_TRUE": 1, "AL_VELOCITY": 4102, "AT_EMPTY_PATH": 4096, diff --git a/src/library_egl.js b/src/library_egl.js index 423479536bcb1..01b5ec4736bed 100644 --- a/src/library_egl.js +++ b/src/library_egl.js @@ -576,8 +576,8 @@ var LibraryEGL = { EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); return 0; } - if (interval == 0) _emscripten_set_main_loop_timing(0/*EM_TIMING_SETTIMEOUT*/, 0); - else _emscripten_set_main_loop_timing(1/*EM_TIMING_RAF*/, interval); + if (interval == 0) _emscripten_set_main_loop_timing({{{ cDefs.EM_TIMING_SETTIMEOUT }}}, 0); + else _emscripten_set_main_loop_timing({{{ cDefs.EM_TIMING_RAF }}}, interval); EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); return 1; diff --git a/src/library_glfw.js b/src/library_glfw.js index 39f64da3342b3..5fbb1bc3a3e6c 100644 --- a/src/library_glfw.js +++ b/src/library_glfw.js @@ -1236,8 +1236,8 @@ var LibraryGLFW = { glfwSwapInterval__deps: ['emscripten_set_main_loop_timing'], glfwSwapInterval: function(interval) { interval = Math.abs(interval); // GLFW uses negative values to enable GLX_EXT_swap_control_tear, which we don't have, so just treat negative and positive the same. - if (interval == 0) _emscripten_set_main_loop_timing(0/*EM_TIMING_SETTIMEOUT*/, 0); - else _emscripten_set_main_loop_timing(1/*EM_TIMING_RAF*/, interval); + if (interval == 0) _emscripten_set_main_loop_timing({{{ cDefs.EM_TIMING_SETTIMEOUT }}}, 0); + else _emscripten_set_main_loop_timing({{{ cDefs.EM_TIMING_RAF }}}, interval); }, #if USE_GLFW == 3 diff --git a/src/library_openal.js b/src/library_openal.js index 44c1713c8bcab..8248e62c2dbbf 100644 --- a/src/library_openal.js +++ b/src/library_openal.js @@ -90,7 +90,7 @@ var LibraryOpenAL = { // If we are animating using the requestAnimationFrame method, then the main loop does not run when in the background. // To give a perfect glitch-free audio stop when switching from foreground to background, we need to avoid updating // audio altogether when in the background, so detect that case and kill audio buffer streaming if so. - if (Browser.mainLoop.timingMode === 1 /* EM_TIMING_RAF */ && document['visibilityState'] != 'visible') { + if (Browser.mainLoop.timingMode === {{{ cDefs.EM_TIMING_RAF }}} && document['visibilityState'] != 'visible') { return; } @@ -107,10 +107,10 @@ var LibraryOpenAL = { // to OpenAL parameters, such as pitch, may require the web audio queue to be flushed and rescheduled. scheduleSourceAudio: function(src, lookahead) { // See comment on scheduleContextAudio above. - if (Browser.mainLoop.timingMode === 1 /*EM_TIMING_RAF*/ && document['visibilityState'] != 'visible') { + if (Browser.mainLoop.timingMode === {{{ cDefs.EM_TIMING_RAF }}} && document['visibilityState'] != 'visible') { return; } - if (src.state !== 0x1012 /* AL_PLAYING */) { + if (src.state !== {{{ cDefs.AL_PLAYING }}}) { return; } @@ -161,7 +161,7 @@ var LibraryOpenAL = { var duration = 0.0; // If the source is a looping static buffer, use native looping for gapless playback - if (src.type === 0x1028 /* AL_STATIC */ && src.looping) { + if (src.type === {{{ cDefs.AL_STATIC }}} && src.looping) { duration = Number.POSITIVE_INFINITY; audioSrc.loop = true; if (buf.audioBuf._loopStart) { @@ -215,7 +215,7 @@ var LibraryOpenAL = { // Advance the state of a source forward to the current time updateSourceTime: function(src) { var currentTime = src.context.audioCtx.currentTime; - if (src.state !== 0x1012 /* AL_PLAYING */) { + if (src.state !== {{{ cDefs.AL_PLAYING }}}) { return currentTime; } @@ -246,8 +246,8 @@ var LibraryOpenAL = { if (src.bufsProcessed >= src.bufQueue.length && !src.looping) { // The source has played its entire queue and is non-looping, so just mark it as stopped. - AL.setSourceState(src, 0x1014 /* AL_STOPPED */); - } else if (src.type === 0x1028 /* AL_STATIC */ && src.looping) { + AL.setSourceState(src, {{{ cDefs.AL_STOPPED }}}); + } else if (src.type === {{{ cDefs.AL_STATIC }}} && src.looping) { // If the source is a looping static buffer, determine the buffer offset based on the loop points var buf = src.bufQueue[0]; if (buf.length === 0) { @@ -276,7 +276,7 @@ var LibraryOpenAL = { // We need to determine what state we would be in by this point in time so that when we next schedule // audio playback, it will be just as if no underrun occurred. - if (src.type !== 0x1028 /* AL_STATIC */ && src.looping) { + if (src.type !== {{{ cDefs.AL_STATIC }}} && src.looping) { // if the source is a looping buffer queue, let's first calculate the queue duration, so we can // quickly fast forward past any full loops of the queue and only worry about the remainder. var srcDuration = AL.sourceDuration(src) / src.playbackRate; @@ -293,7 +293,7 @@ var LibraryOpenAL = { if (src.looping) { src.bufsProcessed %= src.bufQueue.length; } else { - AL.setSourceState(src, 0x1014 /* AL_STOPPED */); + AL.setSourceState(src, {{{ cDefs.AL_STOPPED }}}); break; } } @@ -339,8 +339,8 @@ var LibraryOpenAL = { }, setSourceState: function(src, state) { - if (state === 0x1012 /* AL_PLAYING */) { - if (src.state === 0x1012 /* AL_PLAYING */ || src.state == 0x1014 /* AL_STOPPED */) { + if (state === {{{ cDefs.AL_PLAYING }}}) { + if (src.state === {{{ cDefs.AL_PLAYING }}} || src.state == {{{ cDefs.AL_STOPPED }}}) { src.bufsProcessed = 0; src.bufOffset = 0.0; #if OPENAL_DEBUG @@ -354,23 +354,23 @@ var LibraryOpenAL = { AL.stopSourceAudio(src); - src.state = 0x1012 /* AL_PLAYING */; + src.state = {{{ cDefs.AL_PLAYING }}}; src.bufStartTime = Number.NEGATIVE_INFINITY; AL.scheduleSourceAudio(src); - } else if (state === 0x1013 /* AL_PAUSED */) { - if (src.state === 0x1012 /* AL_PLAYING */) { + } else if (state === {{{ cDefs.AL_PAUSED }}}) { + if (src.state === {{{ cDefs.AL_PLAYING }}}) { // Store off the current offset to restore with on resume. AL.updateSourceTime(src); AL.stopSourceAudio(src); - src.state = 0x1013 /* AL_PAUSED */; + src.state = {{{ cDefs.AL_PAUSED }}}; #if OPENAL_DEBUG dbg(`setSourceState() pausing source ${src.id} at ${src.bufOffset}`); #endif } - } else if (state === 0x1014 /* AL_STOPPED */) { - if (src.state !== 0x1011 /* AL_INITIAL */) { - src.state = 0x1014 /* AL_STOPPED */; + } else if (state === {{{ cDefs.AL_STOPPED }}}) { + if (src.state !== {{{ cDefs.AL_INITIAL }}}) { + src.state = {{{ cDefs.AL_STOPPED }}}; src.bufsProcessed = src.bufQueue.length; src.bufStartTime = Number.NEGATIVE_INFINITY; src.bufOffset = 0.0; @@ -379,9 +379,9 @@ var LibraryOpenAL = { dbg(`setSourceState() stopping source ${src.id}`); #endif } - } else if (state === 0x1011 /* AL_INITIAL */) { - if (src.state !== 0x1011 /* AL_INITIAL */) { - src.state = 0x1011 /* AL_INITIAL */; + } else if (state === {{{ cDefs.AL_INITIAL }}}) { + if (src.state !== {{{ cDefs.AL_INITIAL }}}) { + src.state = {{{ cDefs.AL_INITIAL }}}; src.bufsProcessed = 0; src.bufStartTime = Number.NEGATIVE_INFINITY; src.bufOffset = 0.0; @@ -670,7 +670,7 @@ var LibraryOpenAL = { }, updateSourceRate: function(src) { - if (src.state === 0x1012 /* AL_PLAYING */) { + if (src.state === {{{ cDefs.AL_PLAYING }}}) { // clear scheduled buffers AL.cancelPendingSourceAudio(src); @@ -680,7 +680,7 @@ var LibraryOpenAL = { } var duration; - if (src.type === 0x1028 /* AL_STATIC */ && src.looping) { + if (src.type === {{{ cDefs.AL_STATIC }}} && src.looping) { duration = Number.POSITIVE_INFINITY; } else { // audioSrc._duration is expressed after factoring in playbackRate, so when changing playback rate, need @@ -720,9 +720,9 @@ var LibraryOpenAL = { }, sourceSeek: function(src, offset) { - var playing = src.state == 0x1012 /* AL_PLAYING */; + var playing = src.state == {{{ cDefs.AL_PLAYING }}}; if (playing) { - AL.setSourceState(src, 0x1011 /* AL_INITIAL */); + AL.setSourceState(src, {{{ cDefs.AL_INITIAL }}}); } if (src.bufQueue[src.bufsProcessed].audioBuf !== null) { @@ -736,7 +736,7 @@ var LibraryOpenAL = { } if (playing) { - AL.setSourceState(src, 0x1012 /* AL_PLAYING */); + AL.setSourceState(src, {{{ cDefs.AL_PLAYING }}}); } }, @@ -1081,7 +1081,7 @@ var LibraryOpenAL = { case 0x1007 /* AL_LOOPING */: return src.looping; case 0x1009 /* AL_BUFFER */: - if (src.type === 0x1028 /* AL_STATIC */) { + if (src.type === {{{ cDefs.AL_STATIC }}}) { return src.bufQueue[0].id; } return 0; @@ -1287,7 +1287,7 @@ var LibraryOpenAL = { if (value === {{{ cDefs.AL_TRUE }}}) { src.looping = true; AL.updateSourceTime(src); - if (src.type === 0x1028 /* AL_STATIC */ && src.audioQueue.length > 0) { + if (src.type === {{{ cDefs.AL_STATIC }}} && src.audioQueue.length > 0) { var audioSrc = src.audioQueue[0]; audioSrc.loop = true; audioSrc._duration = Number.POSITIVE_INFINITY; @@ -1295,7 +1295,7 @@ var LibraryOpenAL = { } else if (value === {{{ cDefs.AL_FALSE }}}) { src.looping = false; var currentTime = AL.updateSourceTime(src); - if (src.type === 0x1028 /* AL_STATIC */ && src.audioQueue.length > 0) { + if (src.type === {{{ cDefs.AL_STATIC }}} && src.audioQueue.length > 0) { var audioSrc = src.audioQueue[0]; audioSrc.loop = false; audioSrc._duration = src.bufQueue[0].audioBuf.duration / src.playbackRate; @@ -1310,7 +1310,7 @@ var LibraryOpenAL = { } break; case 0x1009 /* AL_BUFFER */: - if (src.state === 0x1012 /* AL_PLAYING */ || src.state === 0x1013 /* AL_PAUSED */) { + if (src.state === {{{ cDefs.AL_PLAYING }}} || src.state === {{{ cDefs.AL_PAUSED }}}) { #if OPENAL_DEBUG dbg(funcname + '(AL_BUFFER) called while source is playing or paused'); #endif @@ -1345,7 +1345,7 @@ var LibraryOpenAL = { buf.refCount++; src.bufQueue = [buf]; src.bufsProcessed = 0; - src.type = 0x1028 /* AL_STATIC */; + src.type = {{{ cDefs.AL_STATIC }}}; } AL.initSourcePanner(src); @@ -2818,7 +2818,7 @@ var LibraryOpenAL = { context: AL.currentCtx, id: AL.newId(), type: 0x1030 /* AL_UNDETERMINED */, - state: 0x1011 /* AL_INITIAL */, + state: {{{ cDefs.AL_INITIAL }}}, bufQueue: [AL.buffers[0]], audioQueue: [], looping: false, @@ -2876,7 +2876,7 @@ var LibraryOpenAL = { for (var i = 0; i < count; ++i) { var srcId = {{{ makeGetValue('pSourceIds', 'i*4', 'i32') }}}; - AL.setSourceState(AL.currentCtx.sources[srcId], 0x1014 /* AL_STOPPED */); + AL.setSourceState(AL.currentCtx.sources[srcId], {{{ cDefs.AL_STOPPED }}}); _alSourcei(srcId, 0x1009 /* AL_BUFFER */, 0); delete AL.currentCtx.sources[srcId]; AL.freeIds.push(srcId); @@ -4056,7 +4056,7 @@ var LibraryOpenAL = { AL.currentCtx.err = {{{ cDefs.AL_INVALID_NAME }}}; return; } - if (src.type === 0x1028 /* AL_STATIC */) { + if (src.type === {{{ cDefs.AL_STATIC }}}) { #if OPENAL_DEBUG dbg('alSourceQueueBuffers() called while a static buffer is bound'); #endif @@ -4181,7 +4181,7 @@ var LibraryOpenAL = { AL.currentCtx.err = {{{ cDefs.AL_INVALID_NAME }}}; return; } - AL.setSourceState(src, 0x1012 /* AL_PLAYING */); + AL.setSourceState(src, {{{ cDefs.AL_PLAYING }}}); }, alSourcePlayv__proxy: 'sync', @@ -4210,7 +4210,7 @@ var LibraryOpenAL = { for (var i = 0; i < count; ++i) { var srcId = {{{ makeGetValue('pSourceIds', 'i*4', 'i32') }}}; - AL.setSourceState(AL.currentCtx.sources[srcId], 0x1012 /* AL_PLAYING */); + AL.setSourceState(AL.currentCtx.sources[srcId], {{{ cDefs.AL_PLAYING }}}); } }, @@ -4230,7 +4230,7 @@ var LibraryOpenAL = { AL.currentCtx.err = {{{ cDefs.AL_INVALID_NAME }}}; return; } - AL.setSourceState(src, 0x1014 /* AL_STOPPED */); + AL.setSourceState(src, {{{ cDefs.AL_STOPPED }}}); }, alSourceStopv__proxy: 'sync', @@ -4259,7 +4259,7 @@ var LibraryOpenAL = { for (var i = 0; i < count; ++i) { var srcId = {{{ makeGetValue('pSourceIds', 'i*4', 'i32') }}}; - AL.setSourceState(AL.currentCtx.sources[srcId], 0x1014 /* AL_STOPPED */); + AL.setSourceState(AL.currentCtx.sources[srcId], {{{ cDefs.AL_STOPPED }}}); } }, @@ -4280,9 +4280,9 @@ var LibraryOpenAL = { return; } // Stop the source first to clear the source queue - AL.setSourceState(src, 0x1014 /* AL_STOPPED */); + AL.setSourceState(src, {{{ cDefs.AL_STOPPED }}}); // Now set the state of AL_INITIAL according to the specification - AL.setSourceState(src, 0x1011 /* AL_INITIAL */); + AL.setSourceState(src, {{{ cDefs.AL_INITIAL }}}); }, alSourceRewindv__proxy: 'sync', @@ -4311,7 +4311,7 @@ var LibraryOpenAL = { for (var i = 0; i < count; ++i) { var srcId = {{{ makeGetValue('pSourceIds', 'i*4', 'i32') }}}; - AL.setSourceState(AL.currentCtx.sources[srcId], 0x1011 /* AL_INITIAL */); + AL.setSourceState(AL.currentCtx.sources[srcId], {{{ cDefs.AL_INITIAL }}}); } }, @@ -4331,7 +4331,7 @@ var LibraryOpenAL = { AL.currentCtx.err = {{{ cDefs.AL_INVALID_NAME }}}; return; } - AL.setSourceState(src, 0x1013 /* AL_PAUSED */); + AL.setSourceState(src, {{{ cDefs.AL_PAUSED }}}); }, alSourcePausev__proxy: 'sync', @@ -4360,7 +4360,7 @@ var LibraryOpenAL = { for (var i = 0; i < count; ++i) { var srcId = {{{ makeGetValue('pSourceIds', 'i*4', 'i32') }}}; - AL.setSourceState(AL.currentCtx.sources[srcId], 0x1013 /* AL_PAUSED */); + AL.setSourceState(AL.currentCtx.sources[srcId], {{{ cDefs.AL_PAUSED }}}); } }, diff --git a/src/library_sdl.js b/src/library_sdl.js index 0ac3546a16ab6..c1b178125ef73 100644 --- a/src/library_sdl.js +++ b/src/library_sdl.js @@ -3387,13 +3387,13 @@ var LibrarySDL = { SDL_GL_GetSwapInterval__proxy: 'sync', SDL_GL_GetSwapInterval: function() { - if (Browser.mainLoop.timingMode == 1/*EM_TIMING_RAF*/) return Browser.mainLoop.timingValue; + if (Browser.mainLoop.timingMode == {{{ cDefs.EM_TIMING_RAF }}}) return Browser.mainLoop.timingValue; else return 0; }, SDL_GL_SetSwapInterval__deps: ['emscripten_set_main_loop_timing'], SDL_GL_SetSwapInterval: function(state) { - _emscripten_set_main_loop_timing(1/*EM_TIMING_RAF*/, state); + _emscripten_set_main_loop_timing({{{ cDefs.EM_TIMING_RAF }}}, state); }, SDL_SetWindowTitle__proxy: 'sync', diff --git a/src/struct_info.json b/src/struct_info.json index a48592641fcfc..4e91b13591db1 100644 --- a/src/struct_info.json +++ b/src/struct_info.json @@ -1124,7 +1124,12 @@ "AL_INVALID_ENUM", "AL_INVALID_NAME", "AL_INVALID_OPERATION", - "AL_INVALID_VALUE" + "AL_INVALID_VALUE", + "AL_PLAYING", + "AL_PAUSED", + "AL_STOPPED", + "AL_INITIAL", + "AL_STATIC" ] }, { From f016cc00bacf23888580b4485972fdf1ad7f3200 Mon Sep 17 00:00:00 2001 From: Alexey Sokolov Date: Wed, 24 May 2023 00:02:21 +0100 Subject: [PATCH 0280/1523] Remove my Gentoo overlay (#19432) The package doesn't work anymore, producing errors about missing includes, and I can't make it work anymore. --- site/source/docs/getting_started/downloads.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/site/source/docs/getting_started/downloads.rst b/site/source/docs/getting_started/downloads.rst index cd764db4ce456..a32153dc5d7d0 100644 --- a/site/source/docs/getting_started/downloads.rst +++ b/site/source/docs/getting_started/downloads.rst @@ -260,7 +260,3 @@ The following is a partial list of such unofficial emscripten packages: **Arch Linux** - package info: https://github.com/archlinux/svntogit-community/tree/packages/emscripten/trunk - maintainer: Sven-Hendrik Haase - -**Gentoo Linux** (custom overlay) - - package info: `dev-util/emscripten` in `darthgandalf-overlay `_ - - maintainer: @DarthGandalf From 673b8464be8ec35472243e04ec3a525151d6fdc0 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 23 May 2023 16:39:47 -0700 Subject: [PATCH 0281/1523] Remove stale comment. NFC (#19434) --- src/library.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/library.js b/src/library.js index eddc4376868b7..45cfdc3f698c3 100644 --- a/src/library.js +++ b/src/library.js @@ -567,8 +567,6 @@ mergeInto(LibraryManager.library, { return ret; }, - // TODO: Initialize these to defaults on startup from system settings. - // Note: glibc has one fewer underscore for all of these. Also used in other related functions (timegm) _tzset_js__deps: ['$stringToNewUTF8'], _tzset_js__internal: true, _tzset_js: function(timezone, daylight, tzname) { From 2082352238c695d1c483a648d28017a4f3da3544 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 24 May 2023 08:03:49 -0700 Subject: [PATCH 0282/1523] Remove `RUNTIME_LOGGING` setting. NFC (#19437) This duplicates the behaviour of `RUNTIME_DEBUG` and is not tested anywhere. Make it an alias for `RUNTIME_DEBUG` and use `dbg()` rather than `err()` to do ths logging. --- src/postamble.js | 12 ++++++------ src/preamble.js | 16 ++++++++-------- src/settings.js | 7 +------ 3 files changed, 15 insertions(+), 20 deletions(-) diff --git a/src/postamble.js b/src/postamble.js index 91e91f003d977..8e01e640c3516 100644 --- a/src/postamble.js +++ b/src/postamble.js @@ -145,8 +145,8 @@ function run() { #endif if (runDependencies > 0) { -#if RUNTIME_LOGGING - err('run() called, but dependencies remain, so not running'); +#if RUNTIME_DEBUG + dbg('run() called, but dependencies remain, so not running'); #endif return; } @@ -171,8 +171,8 @@ function run() { // Loading dylibs can add run dependencies. if (runDependencies > 0) { -#if RUNTIME_LOGGING - err('loadDylibs added run() dependencies, not running yet'); +#if RUNTIME_DEBUG + dbg('loadDylibs added run() dependencies, not running yet'); #endif return; } @@ -206,8 +206,8 @@ function run() { // a preRun added a dependency, run will be called later if (runDependencies > 0) { -#if RUNTIME_LOGGING - err('run() called, but dependencies remain, so not running'); +#if RUNTIME_DEBUG + dbg('run() called, but dependencies remain, so not running'); #endif return; } diff --git a/src/preamble.js b/src/preamble.js index 51783e5a5f386..70097ae03387c 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -233,8 +233,8 @@ function initRuntime() { #endif #if STACK_OVERFLOW_CHECK >= 2 -#if RUNTIME_LOGGING - err('__set_stack_limits: ' + _emscripten_stack_get_base() + ', ' + _emscripten_stack_get_end()); +#if RUNTIME_DEBUG + dbg('__set_stack_limits: ' + _emscripten_stack_get_base() + ', ' + _emscripten_stack_get_end()); #endif ___set_stack_limits(_emscripten_stack_get_base(), _emscripten_stack_get_end()); #endif @@ -759,8 +759,8 @@ function instantiateSync(file, info) { cachedCodeFile = locateFile(cachedCodeFile); var hasCached = fs.existsSync(cachedCodeFile); if (hasCached) { -#if RUNTIME_LOGGING - err('NODE_CODE_CACHING: loading module'); +#if RUNTIME_DEBUG + dbg('NODE_CODE_CACHING: loading module'); #endif try { module = v8.deserialize(fs.readFileSync(cachedCodeFile)); @@ -775,8 +775,8 @@ function instantiateSync(file, info) { module = new WebAssembly.Module(binary); } if (ENVIRONMENT_IS_NODE && !hasCached) { -#if RUNTIME_LOGGING - err('NODE_CODE_CACHING: saving module'); +#if RUNTIME_DEBUG + dbg('NODE_CODE_CACHING: saving module'); #endif fs.writeFileSync(cachedCodeFile, v8.serialize(module)); } @@ -1130,8 +1130,8 @@ function createWasm() { #endif #if WASM_ASYNC_COMPILATION -#if RUNTIME_LOGGING - err('asynchronously preparing wasm'); +#if RUNTIME_DEBUG + dbg('asynchronously preparing wasm'); #endif #if MODULARIZE // If instantiation fails, reject the module ready promise. diff --git a/src/settings.js b/src/settings.js index cd78d210233b5..2ad08b4866b11 100644 --- a/src/settings.js +++ b/src/settings.js @@ -50,12 +50,6 @@ // [link] var ASSERTIONS = 1; -// Whether extra logging should be enabled. -// This logging isn't quite assertion-quality in that it isn't necessarily a -// symptom that something is wrong. -// [link] -var RUNTIME_LOGGING = false; - // Chooses what kind of stack smash checks to emit to generated code: // Building with ASSERTIONS=1 causes STACK_OVERFLOW_CHECK default to 1. // Since ASSERTIONS=1 is the default at -O0, which itself is the default @@ -2135,4 +2129,5 @@ var LEGACY_SETTINGS = [ ['USE_PTHREADS', [0, 1], 'No longer needed. Use -pthread instead'], ['USES_DYNAMIC_ALLOC', [1], 'No longer supported. Use -sMALLOC=none'], ['REVERSE_DEPS', ['auto', 'all', 'none'], 'No longer needed'], + ['RUNTIME_LOGGING', 'RUNTIME_DEBUG'], ]; From 6ab22a7821d3e6bf08de529f20840fec116a0f0c Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 24 May 2023 08:04:56 -0700 Subject: [PATCH 0283/1523] Improvements to DYLINK_DEBUG. NFC (#19436) Split out from #19390 --- emcc.py | 22 ++++++------- src/library_dylink.js | 31 ++++++++++--------- src/settings.js | 2 +- .../metadce/test_metadce_hello_dylink.jssize | 2 +- 4 files changed, 30 insertions(+), 27 deletions(-) diff --git a/emcc.py b/emcc.py index 77e5d0d0cc0ed..1e9f7753ec547 100755 --- a/emcc.py +++ b/emcc.py @@ -1782,17 +1782,17 @@ def phase_linker_setup(options, state, newargs): options.post_js.append(utils.path_from_root('src/cpuprofiler.js')) if not settings.RUNTIME_DEBUG: - settings.RUNTIME_DEBUG = (settings.LIBRARY_DEBUG or - settings.GL_DEBUG or - settings.DYLINK_DEBUG or - settings.OPENAL_DEBUG or - settings.SYSCALL_DEBUG or - settings.WEBSOCKET_DEBUG or - settings.SOCKET_DEBUG or - settings.FETCH_DEBUG or - settings.EXCEPTION_DEBUG or - settings.PTHREADS_DEBUG or - settings.ASYNCIFY_DEBUG) + settings.RUNTIME_DEBUG = bool(settings.LIBRARY_DEBUG or + settings.GL_DEBUG or + settings.DYLINK_DEBUG or + settings.OPENAL_DEBUG or + settings.SYSCALL_DEBUG or + settings.WEBSOCKET_DEBUG or + settings.SOCKET_DEBUG or + settings.FETCH_DEBUG or + settings.EXCEPTION_DEBUG or + settings.PTHREADS_DEBUG or + settings.ASYNCIFY_DEBUG) if options.memory_profiler: settings.MEMORYPROFILER = 1 diff --git a/src/library_dylink.js b/src/library_dylink.js index 3c5861181fdb7..7c1daba178e73 100644 --- a/src/library_dylink.js +++ b/src/library_dylink.js @@ -26,8 +26,11 @@ var LibraryDylink = { // promises to run in series. wasmPlugin['promiseChainEnd'] = wasmPlugin['promiseChainEnd'].then( () => loadWebAssemblyModule(byteArray, {loadAsync: true, nodelete: true})).then( - (module) => { - preloadedWasm[name] = module; + (exports) => { +#if DYLINK_DEBUG + dbg(`registering preloadedWasm: ${name}`); +#endif + preloadedWasm[name] = exports; onload(byteArray); }, (error) => { @@ -110,7 +113,7 @@ var LibraryDylink = { var rtn = GOT[symName]; if (!rtn) { rtn = GOT[symName] = new WebAssembly.Global({'value': '{{{ POINTER_WASM_TYPE }}}', 'mutable': true}); -#if DYLINK_DEBUG +#if DYLINK_DEBUG == 2 dbg("new GOT entry: " + symName); #endif } @@ -171,12 +174,12 @@ var LibraryDylink = { GOT[symName] = new WebAssembly.Global({'value': '{{{ POINTER_WASM_TYPE }}}', 'mutable': true}); } if (replace || GOT[symName].value == 0) { -#if DYLINK_DEBUG +#if DYLINK_DEBUG == 2 dbg(`updateGOT: before: ${symName} : ${GOT[symName].value}`); #endif if (typeof value == 'function') { GOT[symName].value = {{{ to64('addFunction(value)') }}}; -#if DYLINK_DEBUG +#if DYLINK_DEBUG == 2 dbg(`updateGOT: FUNC: ${symName} : ${GOT[symName].value}`); #endif } else if (typeof value == {{{ POINTER_JS_TYPE }}}) { @@ -184,7 +187,7 @@ var LibraryDylink = { } else { err(`unhandled export type for '${symName}': ${typeof value}`); } -#if DYLINK_DEBUG +#if DYLINK_DEBUG == 2 dbg(`updateGOT: after: ${symName} : ${GOT[symName].value} (${value})`); #endif } @@ -248,13 +251,13 @@ var LibraryDylink = { #if ASSERTIONS assert(value, `undefined symbol '${symName}'. 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 -#if DYLINK_DEBUG +#if DYLINK_DEBUG == 2 dbg(`assigning dynamic symbol from main module: ${symName} -> ${prettyPrint(value)}`); #endif if (typeof value == 'function') { /** @suppress {checkTypes} */ GOT[symName].value = {{{ to64('addFunction(value, value.sig)') }}}; -#if DYLINK_DEBUG +#if DYLINK_DEBUG == 2 dbg(`assigning table entry for : ${symName} -> ${GOT[symName].value}`); #endif } else if (typeof value == 'number') { @@ -989,12 +992,12 @@ var LibraryDylink = { function getExports() { #if FILESYSTEM // lookup preloaded cache first - if (preloadedWasm[libName]) { + var preloaded = preloadedWasm[libName]; #if DYLINK_DEBUG - dbg(`using preloaded module for: ${libName}`); + dbg(`checking preloadedWasm: ${libName}: ${preloaded ? 'found' : 'not found'}`); #endif - var libModule = preloadedWasm[libName]; - return flags.loadAsync ? Promise.resolve(libModule) : libModule; + if (preloaded) { + return flags.loadAsync ? Promise.resolve(preloaded) : preloaded; } #endif @@ -1037,7 +1040,7 @@ var LibraryDylink = { $loadDylibs__deps: ['$loadDynamicLibrary', '$reportUndefinedSymbols'], $loadDylibs: function() { #if DYLINK_DEBUG - dbg('loadDylibs'); + dbg(`loadDylibs: ${dynamicLibraries}`); #endif if (!dynamicLibraries.length) { #if DYLINK_DEBUG @@ -1058,7 +1061,7 @@ var LibraryDylink = { reportUndefinedSymbols(); removeRunDependency('loadDylibs'); #if DYLINK_DEBUG - dbg('loadDylibs done!'); + dbg('loadDylibs done!'); #endif }); }, diff --git a/src/settings.js b/src/settings.js index 2ad08b4866b11..d341bb8dafb7a 100644 --- a/src/settings.js +++ b/src/settings.js @@ -338,7 +338,7 @@ var SOCKET_DEBUG = false; // Log dynamic linker information // [link] -var DYLINK_DEBUG = false; +var DYLINK_DEBUG = 0; // Register file system callbacks using trackingDelegate in library_fs.js // [link] diff --git a/test/other/metadce/test_metadce_hello_dylink.jssize b/test/other/metadce/test_metadce_hello_dylink.jssize index 5b4e31ba26409..5da2a4f7c562e 100644 --- a/test/other/metadce/test_metadce_hello_dylink.jssize +++ b/test/other/metadce/test_metadce_hello_dylink.jssize @@ -1 +1 @@ -15075 +15060 From f512e51b68cf7867d41d2706684ec6e2f4aa6647 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 24 May 2023 10:47:27 -0700 Subject: [PATCH 0284/1523] WasmFS: Avoid malloc in FS.readFile (#19435) The dependency on malloc there caused a WASI test to fail. It looks like the WASI test binary doesn't have malloc in it, but this is a post-link test so we can't add malloc. In any case, we don't use malloc in other similar places in the file, so switch to a stack allocation which also gets the test passing. Also add a missing dep on malloc in FORCE_FILESYSTEM mode, as the advanced JS APIs do actually require it. --- src/library_wasmfs.js | 8 +++----- test/test_other.py | 1 + 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/library_wasmfs.js b/src/library_wasmfs.js index 5d3d2f750decc..c4009e3355fa1 100644 --- a/src/library_wasmfs.js +++ b/src/library_wasmfs.js @@ -14,7 +14,6 @@ FS.createPreloadedFile = FS_createPreloadedFile; '$wasmFSPreloadedFiles', '$wasmFSPreloadedDirs', '$PATH', - '$stringToNewUTF8', '$stringToUTF8OnStack', '$withStackSave', '$readI53FromI64', @@ -22,6 +21,7 @@ FS.createPreloadedFile = FS_createPreloadedFile; '$FS_getMode', #if FORCE_FILESYSTEM '$FS_modeStringToFlags', + 'malloc', #endif ], $FS : { @@ -49,10 +49,9 @@ FS.createPreloadedFile = FS_createPreloadedFile; throw new Error('Invalid encoding type "' + opts.encoding + '"'); } - var pathName = stringToNewUTF8(path); - // Copy the file into a JS buffer on the heap. - var buf = __wasmfs_read_file(pathName); + var buf = withStackSave(() => __wasmfs_read_file(stringToUTF8OnStack(path))); + // The signed integer length resides in the first 8 bytes of the buffer. var length = {{{ makeGetValue('buf', '0', 'i53') }}}; @@ -63,7 +62,6 @@ FS.createPreloadedFile = FS_createPreloadedFile; ret = UTF8ArrayToString(ret, 0); } - _free(pathName); _free(buf); return ret; }, diff --git a/test/test_other.py b/test/test_other.py index 2781163ff71f6..3cbe043529f50 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -13286,6 +13286,7 @@ def test_wasi_std_io_stdout(self): def test_wasi_std_io_stderr(self): self.run_wasi_test_suite_test('std_io_stderr') + @also_with_wasmfs @requires_node def test_wasi_clock_res_get(self): self.run_wasi_test_suite_test('wasi_clock_res_get') From cf7029ed4054452a55ec583730214751609b1544 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 24 May 2023 14:24:50 -0700 Subject: [PATCH 0285/1523] Fix dependency in library_dylink.js. NFC (#19441) Also move the function in question so it is declared alongside its users (its was previously in a different `#if` block). Split out from #19390 --- src/library_dylink.js | 69 ++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/src/library_dylink.js b/src/library_dylink.js index 7c1daba178e73..05155ad9f3aeb 100644 --- a/src/library_dylink.js +++ b/src/library_dylink.js @@ -66,13 +66,47 @@ var LibraryDylink = { return true; }, + // Dynamic version of shared.py:make_invoke. This is needed for invokes + // that originate from side modules since these are not known at JS + // generation time. +#if !DISABLE_EXCEPTION_CATCHING || SUPPORT_LONGJMP == 'emscripten' + $createInvokeFunction__internal: true, + $createInvokeFunction__deps: ['$dynCall', 'setThrew'], + $createInvokeFunction: function(sig) { + return function() { + var sp = stackSave(); + try { + return dynCall(sig, arguments[0], Array.prototype.slice.call(arguments, 1)); + } catch(e) { + stackRestore(sp); + // Create a try-catch guard that rethrows the Emscripten EH exception. +#if EXCEPTION_STACK_TRACES + // Exceptions thrown from C++ and longjmps will be an instance of + // EmscriptenEH. + if (!(e instanceof EmscriptenEH)) throw e; +#else + // Exceptions thrown from C++ will be a pointer (number) and longjmp + // will throw the number Infinity. Use the compact and fast "e !== e+0" + // test to check if e was not a Number. + if (e !== e+0) throw e; +#endif + _setThrew(1, 0); + } + } + }, +#endif + // Resolve a global symbol by name. This is used during module loading to // resolve imports, and by `dlsym` when used with `RTLD_DEFAULT`. // Returns both the resolved symbol (i.e. a function or a global) along with // the canonical name of the symbol (in some cases is modify the symbol as // part of the loop process, so that actual symbol looked up has a different // name). - $resolveGlobalSymbol__deps: ['$isSymbolDefined'], + $resolveGlobalSymbol__deps: ['$isSymbolDefined', +#if !DISABLE_EXCEPTION_CATCHING || SUPPORT_LONGJMP == 'emscripten' + '$createInvokeFunction', +#endif + ], $resolveGlobalSymbol__internal: true, $resolveGlobalSymbol: function(symName, direct = false) { var sym; @@ -340,36 +374,6 @@ var LibraryDylink = { }); }, - // Dynamic version of shared.py:make_invoke. This is needed for invokes - // that originate from side modules since these are not known at JS - // generation time. -#if !DISABLE_EXCEPTION_CATCHING || SUPPORT_LONGJMP == 'emscripten' - $createInvokeFunction__internal: true, - $createInvokeFunction__deps: ['$dynCall', 'setThrew'], - $createInvokeFunction: function(sig) { - return function() { - var sp = stackSave(); - try { - return dynCall(sig, arguments[0], Array.prototype.slice.call(arguments, 1)); - } catch(e) { - stackRestore(sp); - // Create a try-catch guard that rethrows the Emscripten EH exception. -#if EXCEPTION_STACK_TRACES - // Exceptions thrown from C++ and longjmps will be an instance of - // EmscriptenEH. - if (!(e instanceof EmscriptenEH)) throw e; -#else - // Exceptions thrown from C++ will be a pointer (number) and longjmp - // will throw the number Infinity. Use the compact and fast "e !== e+0" - // test to check if e was not a Number. - if (e !== e+0) throw e; -#endif - _setThrew(1, 0); - } - } - }, -#endif - // We support some amount of allocation during startup in the case of // dynamic linking, which needs to allocate memory for dynamic libraries that // are loaded. That has to happen before the main program can start to run, @@ -617,9 +621,6 @@ var LibraryDylink = { '$alignMemory', '$zeroMemory', '$currentModuleWeakSymbols', '$alignMemory', '$zeroMemory', '$updateTableMap', -#if !DISABLE_EXCEPTION_CATCHING || SUPPORT_LONGJMP == 'emscripten' - '$createInvokeFunction', -#endif ], $loadWebAssemblyModule: function(binary, flags, localScope, handle) { var metadata = getDylinkMetadata(binary); From e9d83ba74406bace9f89ee0cbbe817ccd5edf4f3 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 24 May 2023 16:26:32 -0700 Subject: [PATCH 0286/1523] WasmFS: Support LSan (#19443) This is a rather tricky problem, since * LSan needs WasmFS to be alive in order to printf. * WasmFS allocates during startup. * LSan starts up at the first allocation, which ends up inside WasmFS, so LSan starts up first. * As a result LSan shuts down last due to the order of atexits, which is after WasmFS shut down, so it can't print. That is, the order of events is * WasmFS begins to start up, and allocates an innocent vector or such. * LSan gets called from the allocation and it starts up and does an atexit. * WasmFS finishes starting up and does its own atexit for its destructor automatically. * WasmFS's atexit gets called. * LSan's atexit gets called, but at this time without WasmFS being alive we can't print. I considered other options here, like some special destructor / atexit reordering, but everything was much more complex. The other other viable option I can think of is to make LSan not print using printf, e.g., if it printed using emscripten_console_* then that might work, at least on the web, but not in standalone mode, and also it would be an intrusive change to the LSan codebase. --- system/lib/wasmfs/wasmfs.cpp | 25 +++++++++++++++++++++++++ test/test_other.py | 1 + 2 files changed, 26 insertions(+) diff --git a/system/lib/wasmfs/wasmfs.cpp b/system/lib/wasmfs/wasmfs.cpp index 2c3f396f48cb9..4f92a99461ccf 100644 --- a/system/lib/wasmfs/wasmfs.cpp +++ b/system/lib/wasmfs/wasmfs.cpp @@ -43,7 +43,32 @@ WasmFS::WasmFS() : rootDirectory(initRootDirectory()), cwd(rootDirectory) { preloadFiles(); } +// Manual integration with LSan. LSan installs itself during startup at the +// first allocation, which happens inside WasmFS code (since the WasmFS global +// object creates some data structures). As a result LSan's atexit() destructor +// will be called last, after WasmFS is cleaned up, since atexit() calls work +// are FIFO (like a stack). But that is a problem, since if WasmFS has shut +// down and deallocated itself then the leak code cannot actually print any of +// its findings, if it has any. To avoid that, define the LSan entry point as a +// weak symbol, and call it; if LSan is not enabled this can be optimized out, +// and if LSan is enabled then we'll check for leaks right at the start of the +// WasmFS destructor, which is the last time during which it is valid to print. +// (Note that this means we can't find leaks inside WasmFS code itself, but that +// seems fundamentally impossible for the above reasons, unless we made LSan log +// its findings in a way that does not depend on normal file I/O.) +__attribute__((weak)) extern "C" void __lsan_do_leak_check(void) { +} + WasmFS::~WasmFS() { + // See comment above on this function. + // + // Note that it is ok for us to call it here, as LSan internally makes all + // calls after the first into no-ops. That is, calling it here makes the one + // time that leak checks are run be done here, or potentially earlier, but not + // later; and as mentioned in the comment above, this is the latest possible + // time for the checks to run (since right after this nothing can be printed). + __lsan_do_leak_check(); + // Flush musl libc streams. // TODO: Integrate musl exit() which would call this for us. That might also // help with destructor priority - we need to happen last. diff --git a/test/test_other.py b/test/test_other.py index 3cbe043529f50..e80065a82a5e1 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -10398,6 +10398,7 @@ def test_malloc_none(self): 'c': ['c', []], 'cpp': ['cpp', []], 'growth': ['cpp', ['-sALLOW_MEMORY_GROWTH']], + 'wasmfs': ['c', ['-sWASMFS']], }) def test_lsan_leaks(self, ext, args): self.do_runf(test_file('other/test_lsan_leaks.' + ext), From 129567b12a57c9ff3d5cb29727df2d3ff76d29b2 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 25 May 2023 09:20:13 -0700 Subject: [PATCH 0287/1523] Improve logging/debugging related to dynamic linking/pthreads. NFC (#19446) These are all the NFC parts of #19390. --- src/library_dylink.js | 16 ++++++++++++---- src/parseTools.js | 2 +- src/worker.js | 2 +- test/test_other.py | 3 ++- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/library_dylink.js b/src/library_dylink.js index 05155ad9f3aeb..4b20a464d00dc 100644 --- a/src/library_dylink.js +++ b/src/library_dylink.js @@ -359,7 +359,14 @@ var LibraryDylink = { loadedLibsByName: {}, // handle -> dso; Used by dlsym loadedLibsByHandle: {}, - init: () => newDSO('__main__', {{{ cDefs.RTLD_DEFAULT }}}, wasmImports), + init: () => { +#if ASSERTIONS + // This function needs to run after the initial wasmImports object + // as been created. + assert(wasmImports); +#endif + newDSO('__main__', {{{ cDefs.RTLD_DEFAULT }}}, wasmImports); + }, }, $dlSetError__internal: true, @@ -1040,9 +1047,6 @@ var LibraryDylink = { $loadDylibs__internal: true, $loadDylibs__deps: ['$loadDynamicLibrary', '$reportUndefinedSymbols'], $loadDylibs: function() { -#if DYLINK_DEBUG - dbg(`loadDylibs: ${dynamicLibraries}`); -#endif if (!dynamicLibraries.length) { #if DYLINK_DEBUG dbg('loadDylibs: no libraries to preload'); @@ -1051,6 +1055,10 @@ var LibraryDylink = { return; } +#if DYLINK_DEBUG + dbg(`loadDylibs: ${dynamicLibraries}`); +#endif + // Load binaries asynchronously addRunDependency('loadDylibs'); dynamicLibraries.reduce((chain, lib) => { diff --git a/src/parseTools.js b/src/parseTools.js index 167767e0f2915..12393c071ae21 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -746,7 +746,7 @@ function makeRemovedModuleAPIAssert(moduleName, localName) { function checkReceiving(name) { // ALL_INCOMING_MODULE_JS_API contains all valid incoming module API symbols // so calling makeModuleReceive* with a symbol not in this list is an error - assert(ALL_INCOMING_MODULE_JS_API.has(name)); + assert(ALL_INCOMING_MODULE_JS_API.has(name), `${name} is not part of INCOMING_MODULE_JS_API`); } // Make code to receive a value on the incoming Module object. diff --git a/src/worker.js b/src/worker.js index 4c8fe3cebc4f7..7d653fb0505f5 100644 --- a/src/worker.js +++ b/src/worker.js @@ -81,7 +81,7 @@ var out = () => { throw 'out() is not defined in worker.js.'; } #endif var err = threadPrintErr; self.alert = threadAlert; -#if RUNTIME_DEBUG +#if ASSERTIONS || RUNTIME_DEBUG var dbg = threadPrintErr; #endif diff --git a/test/test_other.py b/test/test_other.py index e80065a82a5e1..0c446b3e757e2 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -2331,7 +2331,8 @@ def test_undefined_symbols(self, action): print('checking "%s" %s' % (args, value)) extra = ['-s', action + '_ON_UNDEFINED_SYMBOLS=%d' % value] if action else [] proc = self.run_process([EMXX, '-sUSE_SDL', 'main.cpp'] + extra + args, stderr=PIPE, check=False) - print(proc.stderr) + if common.EMTEST_VERBOSE: + print(proc.stderr) if value or action is None: # The default is that we error in undefined symbols self.assertContained('undefined symbol: something', proc.stderr) From 32043824e01ec6154b700bc410f30473fb277732 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 25 May 2023 10:26:54 -0700 Subject: [PATCH 0288/1523] WasmFS: Do not include library_syscall.js (#19442) 99% of that file is FS-related syscalls which WasmFS does not want anyhow. The remaining 2 syscalls, newselect and fadvise, can be implemented in a trivial way for now. (newselect can't work anyhow until we have sockets support in WasmFS; and fadvise was already trivial in JS.) With that in place, a test checking MAIN_MODULE=1 + WasmFS is added which verifies there are no linker errors due to this refactoring. This PR makes progress towards building MAIN_MODULE=1 + WasmFS + closure, but that does not pass yet. This PR includes a movement of wrapSyscallFunction to a more central location, which is now necessary as the old position in library_syscall is no longer included in all builds. --- src/library.js | 110 +++++++++++++++++++++++++++++++++ src/library_syscall.js | 108 -------------------------------- src/modules.js | 5 +- system/lib/wasmfs/syscalls.cpp | 13 ++++ test/test_other.py | 1 + 5 files changed, 128 insertions(+), 109 deletions(-) diff --git a/src/library.js b/src/library.js index 45cfdc3f698c3..85362403beff2 100644 --- a/src/library.js +++ b/src/library.js @@ -3745,3 +3745,113 @@ DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.push( '$lengthBytesUTF8', ); #endif + +function wrapSyscallFunction(x, library, isWasi) { + if (x[0] === '$' || isJsLibraryConfigIdentifier(x)) { + return; + } + + var t = library[x]; + if (typeof t == 'string') return; + t = t.toString(); + + // If a syscall uses FS, but !SYSCALLS_REQUIRE_FILESYSTEM, then the user + // has disabled the filesystem or we have proven some other way that this will + // not be called in practice, and do not need that code. + if (!SYSCALLS_REQUIRE_FILESYSTEM && t.includes('FS.')) { + t = modifyFunction(t, function(name, args, body) { + return 'function ' + name + '(' + args + ') {\n' + + (ASSERTIONS ? "abort('it should not be possible to operate on streams when !SYSCALLS_REQUIRE_FILESYSTEM');\n" : '') + + '}'; + }); + } + + var isVariadic = !isWasi && t.includes(', varargs'); +#if SYSCALLS_REQUIRE_FILESYSTEM == 0 + var canThrow = false; +#else + var canThrow = library[x + '__nothrow'] !== true; +#endif + + if (!library[x + '__deps']) library[x + '__deps'] = []; + +#if PURE_WASI + // In PURE_WASI mode we can't assume the wasm binary was built by emscripten + // and politely notify us on memory growth. Instead we have to check for + // possible memory growth on each syscall. + var pre = '\nif (!HEAPU8.byteLength) _emscripten_notify_memory_growth(0);\n' + library[x + '__deps'].push('emscripten_notify_memory_growth'); +#else + var pre = ''; +#endif + var post = ''; + if (isVariadic) { + pre += 'SYSCALLS.varargs = varargs;\n'; + } + +#if SYSCALL_DEBUG + if (isVariadic) { + if (canThrow) { + post += 'finally { SYSCALLS.varargs = undefined; }\n'; + } else { + post += 'SYSCALLS.varargs = undefined;\n'; + } + } + pre += "dbg('syscall! " + x + ": [' + Array.prototype.slice.call(arguments) + ']');\n"; + pre += "var canWarn = true;\n"; + pre += "var ret = (function() {\n"; + post += "})();\n"; + post += "if (ret && ret < 0 && canWarn) {\n"; + post += " dbg('error: syscall may have failed with ' + (-ret) + ' (' + ERRNO_MESSAGES[-ret] + ')');\n"; + post += "}\n"; + post += "dbg('syscall return: ' + ret);\n"; + post += "return ret;\n"; +#endif + delete library[x + '__nothrow']; + var handler = ''; + if (canThrow) { + pre += 'try {\n'; + handler += + "} catch (e) {\n" + + " if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;\n"; +#if SYSCALL_DEBUG + handler += + " dbg('error: syscall failed with ' + e.errno + ' (' + ERRNO_MESSAGES[e.errno] + ')');\n" + + " canWarn = false;\n"; +#endif + // Musl syscalls are negated. + if (isWasi) { + handler += " return e.errno;\n"; + } else { + // Musl syscalls are negated. + handler += " return -e.errno;\n"; + } + handler += "}\n"; + } + post = handler + post; + + if (pre || post) { + t = modifyFunction(t, function(name, args, body) { + return `function ${name}(${args}) {\n${pre}${body}${post}}\n`; + }); + } + + library[x] = eval('(' + t + ')'); + if (!WASMFS) { + library[x + '__deps'].push('$SYSCALLS'); + } +#if PTHREADS + // Most syscalls need to happen on the main JS thread (e.g. because the + // filesystem is in JS and on that thread). Proxy synchronously to there. + // There are some exceptions, syscalls that we know are ok to just run in + // any thread; those are marked as not being proxied with + // __proxy: false + // A syscall without a return value could perhaps be proxied asynchronously + // instead of synchronously, and marked with + // __proxy: 'async' + // (but essentially all syscalls do have return values). + if (library[x + '__proxy'] === undefined) { + library[x + '__proxy'] = 'sync'; + } +#endif +} diff --git a/src/library_syscall.js b/src/library_syscall.js index 129151e09abb3..2365cd2352805 100644 --- a/src/library_syscall.js +++ b/src/library_syscall.js @@ -968,114 +968,6 @@ var SyscallsLibrary = { }, }; -function wrapSyscallFunction(x, library, isWasi) { - if (x[0] === '$' || isJsLibraryConfigIdentifier(x)) { - return; - } - - var t = library[x]; - if (typeof t == 'string') return; - t = t.toString(); - - // If a syscall uses FS, but !SYSCALLS_REQUIRE_FILESYSTEM, then the user - // has disabled the filesystem or we have proven some other way that this will - // not be called in practice, and do not need that code. - if (!SYSCALLS_REQUIRE_FILESYSTEM && t.includes('FS.')) { - t = modifyFunction(t, function(name, args, body) { - return 'function ' + name + '(' + args + ') {\n' + - (ASSERTIONS ? "abort('it should not be possible to operate on streams when !SYSCALLS_REQUIRE_FILESYSTEM');\n" : '') + - '}'; - }); - } - - var isVariadic = !isWasi && t.includes(', varargs'); -#if SYSCALLS_REQUIRE_FILESYSTEM == 0 - var canThrow = false; -#else - var canThrow = library[x + '__nothrow'] !== true; -#endif - - if (!library[x + '__deps']) library[x + '__deps'] = []; - -#if PURE_WASI - // In PURE_WASI mode we can't assume the wasm binary was built by emscripten - // and politely notify us on memory growth. Instead we have to check for - // possible memory growth on each syscall. - var pre = '\nif (!HEAPU8.byteLength) _emscripten_notify_memory_growth(0);\n' - library[x + '__deps'].push('emscripten_notify_memory_growth'); -#else - var pre = ''; -#endif - var post = ''; - if (isVariadic) { - pre += 'SYSCALLS.varargs = varargs;\n'; - } - -#if SYSCALL_DEBUG - if (isVariadic) { - if (canThrow) { - post += 'finally { SYSCALLS.varargs = undefined; }\n'; - } else { - post += 'SYSCALLS.varargs = undefined;\n'; - } - } - pre += "dbg('syscall! " + x + ": [' + Array.prototype.slice.call(arguments) + ']');\n"; - pre += "var canWarn = true;\n"; - pre += "var ret = (function() {\n"; - post += "})();\n"; - post += "if (ret && ret < 0 && canWarn) {\n"; - post += " dbg('error: syscall may have failed with ' + (-ret) + ' (' + ERRNO_MESSAGES[-ret] + ')');\n"; - post += "}\n"; - post += "dbg('syscall return: ' + ret);\n"; - post += "return ret;\n"; -#endif - delete library[x + '__nothrow']; - var handler = ''; - if (canThrow) { - pre += 'try {\n'; - handler += - "} catch (e) {\n" + - " if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;\n"; -#if SYSCALL_DEBUG - handler += - " dbg('error: syscall failed with ' + e.errno + ' (' + ERRNO_MESSAGES[e.errno] + ')');\n" + - " canWarn = false;\n"; -#endif - // Musl syscalls are negated. - if (isWasi) { - handler += " return e.errno;\n"; - } else { - // Musl syscalls are negated. - handler += " return -e.errno;\n"; - } - handler += "}\n"; - } - post = handler + post; - - if (pre || post) { - t = modifyFunction(t, function(name, args, body) { - return `function ${name}(${args}) {\n${pre}${body}${post}}\n`; - }); - } - - library[x] = eval('(' + t + ')'); - library[x + '__deps'].push('$SYSCALLS'); -#if PTHREADS - // Most syscalls need to happen on the main JS thread (e.g. because the - // filesystem is in JS and on that thread). Proxy synchronously to there. - // There are some exceptions, syscalls that we know are ok to just run in - // any thread; those are marked as not being proxied with - // __proxy: false - // A syscall without a return value could perhaps be proxied asynchronously - // instead of synchronously, and marked with - // __proxy: 'async' - // (but essentially all syscalls do have return values). - if (library[x + '__proxy'] === undefined) { - library[x + '__proxy'] = 'sync'; - } -#endif -} - for (var x in SyscallsLibrary) { wrapSyscallFunction(x, SyscallsLibrary, false); } diff --git a/src/modules.js b/src/modules.js index 02fab14098467..8bfc03827c121 100644 --- a/src/modules.js +++ b/src/modules.js @@ -46,7 +46,6 @@ global.LibraryManager = { 'library_math.js', 'library_path.js', 'library_strings.js', - 'library_syscall.js', 'library_html5.js', 'library_stack_trace.js', 'library_wasi.js', @@ -77,6 +76,10 @@ global.LibraryManager = { libraries.push('library_autodebug.js'); } + if (!WASMFS) { + libraries.push('library_syscall.js'); + } + if (FILESYSTEM) { libraries.push('library_fs_shared.js'); if (WASMFS) { diff --git a/system/lib/wasmfs/syscalls.cpp b/system/lib/wasmfs/syscalls.cpp index 7c3c4a8ac6bf2..86304095fc808 100644 --- a/system/lib/wasmfs/syscalls.cpp +++ b/system/lib/wasmfs/syscalls.cpp @@ -1727,4 +1727,17 @@ int __syscall_recvmsg( return -ENOSYS; } +int __syscall_fadvise64(int fd, uint64_t offset, uint64_t length, int advice) { + // Advice is currently ignored. TODO some backends might use it + return 0; +} + +int __syscall__newselect(int nfds, intptr_t readfds_, intptr_t writefds_, intptr_t exceptfds_, intptr_t timeout_) { + // TODO: Implement this syscall. For now, we return an error code, + // specifically ENOMEM which is valid per the docs: + // ENOMEM Unable to allocate memory for internal tables + // https://man7.org/linux/man-pages/man2/select.2.html + return -ENOMEM; +} + } // extern "C" diff --git a/test/test_other.py b/test/test_other.py index 0c446b3e757e2..70f5fcb5fbca7 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -12808,6 +12808,7 @@ def test_memory64(self): # Verfy that MAIN_MODULE=1 (which includes all symbols from all libraries) # works with -sPROXY_POSIX_SOCKETS and -Oz, both of which affect linking of # system libraries in different ways. + @also_with_wasmfs def test_dylink_proxy_posix_sockets_oz(self): self.do_runf(test_file('hello_world.cpp'), emcc_args=['-lwebsocket.js', '-sMAIN_MODULE=1', '-sPROXY_POSIX_SOCKETS', '-Oz']) From 9663a7d6a738bb51b551845faedea4c202ea053a Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 25 May 2023 11:33:40 -0700 Subject: [PATCH 0289/1523] Make emscripten_err/out/dbg public and documented (#19445) --- ChangeLog.md | 3 + site/source/docs/api_reference/console.h.rst | 56 +++++++++++++++++++ site/source/docs/api_reference/html5.h.rst | 27 --------- site/source/docs/api_reference/index.rst | 4 ++ src/library.js | 6 +- src/library_sigs.js | 6 +- system/include/emscripten/console.h | 43 ++++++++------ system/include/emscripten/html5.h | 4 +- system/lib/libc/dynlink.c | 8 +-- system/lib/libc/emscripten_console.c | 12 ++-- .../src/cxa_exception_emscripten.cpp | 2 +- system/lib/pthread/emscripten_tls_init.c | 2 +- system/lib/pthread/pthread_create.c | 2 +- system/lib/standalone/standalone.c | 4 +- system/lib/wasmfs/special_files.cpp | 4 +- test/core/pthread/test_pthread_keepalive.c | 8 +-- test/core/test_setjmp_noleak.c | 10 ++-- test/other/test_dbg.c | 4 +- test/pthread/emscripten_thread_sleep.c | 2 +- .../pthread/test_pthread_busy_wait_atexit.cpp | 2 +- test/pthread/test_pthread_proxying.c | 6 +- test/test_core.py | 2 +- test/test_other.py | 6 +- 23 files changed, 133 insertions(+), 90 deletions(-) create mode 100644 site/source/docs/api_reference/console.h.rst diff --git a/ChangeLog.md b/ChangeLog.md index 658a00d4cdc8d..7949267b9b88f 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -20,6 +20,9 @@ See docs/process.md for more on how version tagging works. 3.1.40 (in development) ----------------------- +- The `_emscripten_out()`, `_emscripten_err()` and `_emscripten_dbg()` functions + declared in `emscripten/console.h` no longer have the underscore prefix and + are now documented. (#19445) 3.1.39 - 05/18/23 ----------------- diff --git a/site/source/docs/api_reference/console.h.rst b/site/source/docs/api_reference/console.h.rst new file mode 100644 index 0000000000000..ecc27a4522605 --- /dev/null +++ b/site/source/docs/api_reference/console.h.rst @@ -0,0 +1,56 @@ +.. _console-h: + +========= +console.h +========= + +Functions +--------- + +.. c:function:: void emscripten_console_log(const char *utf8String) + + Prints a string using ``console.log()``. + + :param utf8String: A string encoded as UTF-8. + + +.. c:function:: void emscripten_console_warn(const char *utf8String) + + Prints a string using ``console.warn()``. + + :param utf8String: A string encoded as UTF-8. + + +.. c:function:: void emscripten_console_error(const char *utf8String) + + Prints a string using ``console.error()``. + + :param utf8String: A string encoded as UTF-8. + + +.. c:function:: void emscripten_out(const char *utf8String) + + Prints a string using the `out()` JS function, which by default will write to + the console (or stdout), but can be overridden by via the ``print`` attribute + on the ``Module`` object. + + :param utf8String: A string encoded as UTF-8. + + +.. c:function:: void emscripten_err(const char *utf8String) + + Prints a string using the `err()` JS function, which by default will write to + the console (or stderr), but can be overridden by via the ``printErr`` + attribute on the ``Module`` object. + + :param utf8String: A string encoded as UTF-8. + + +.. c:function:: void emscripten_dbg(const char *utf8String) + + Prints the string using the `dbg()` JS function, which by will write to the + console (or stdout). Just like the `dbg()` JS function this symbol is + only avilable in debug builds (i.e. when linking with `-sASSERTIONS` or + equivelently `-O0`). + + :param utf8String: A string encoded as UTF-8. diff --git a/site/source/docs/api_reference/html5.h.rst b/site/source/docs/api_reference/html5.h.rst index 778a2dcf46bd1..50cc91cd0fbae 100644 --- a/site/source/docs/api_reference/html5.h.rst +++ b/site/source/docs/api_reference/html5.h.rst @@ -2375,33 +2375,6 @@ Functions :returns: A high precision wallclock time value in msecs. -Console -======= - -Functions ---------- - -.. c:function:: void emscripten_console_log(const char *utf8String) - - Prints a string using ``console.log()``. - - :param utf8String: A string encoded as UTF-8. - - -.. c:function:: void emscripten_console_warn(const char *utf8String) - - Prints a string using ``console.warn()``. - - :param utf8String: A string encoded as UTF-8. - - -.. c:function:: void emscripten_console_error(const char *utf8String) - - Prints a string using ``console.error()``. - - :param utf8String: A string encoded as UTF-8. - - Throw ===== diff --git a/site/source/docs/api_reference/index.rst b/site/source/docs/api_reference/index.rst index a5ba715e4ea02..fadf07606095d 100644 --- a/site/source/docs/api_reference/index.rst +++ b/site/source/docs/api_reference/index.rst @@ -13,6 +13,9 @@ high level it consists of: - :ref:`html5-h`: Low level glue bindings for interfacing with HTML5 APIs from native code. +- :ref:`console-h`: + Functions to writing to the console and stdout/stderr. + - :ref:`preamble-js`: APIs for working with compiled code from JavaScript. @@ -60,6 +63,7 @@ high level it consists of: emscripten.h html5.h + console.h preamble.js Filesystem-API fetch diff --git a/src/library.js b/src/library.js index 85362403beff2..f9c5e62bab149 100644 --- a/src/library.js +++ b/src/library.js @@ -3357,16 +3357,16 @@ mergeInto(LibraryManager.library, { _exit(status); }, - _emscripten_out: function(str) { + emscripten_out: function(str) { out(UTF8ToString(str)); }, - _emscripten_err: function(str) { + emscripten_err: function(str) { err(UTF8ToString(str)); }, #if ASSERTIONS || RUNTIME_DEBUG - _emscripten_dbg: function(str) { + emscripten_dbg: function(str) { dbg(UTF8ToString(str)); }, #endif diff --git a/src/library_sigs.js b/src/library_sigs.js index 4f4785f8da05b..6db3813f7704d 100644 --- a/src/library_sigs.js +++ b/src/library_sigs.js @@ -299,11 +299,9 @@ sigs = { _embind_register_value_object_field__sig: 'vpppppppppp', _embind_register_void__sig: 'vpp', _emscripten_create_wasm_worker__sig: 'ipi', - _emscripten_dbg__sig: 'vp', _emscripten_dlopen_js__sig: 'vpppp', _emscripten_dlsync_threads__sig: 'v', _emscripten_dlsync_threads_async__sig: 'vppp', - _emscripten_err__sig: 'vp', _emscripten_fetch_free__sig: 'vi', _emscripten_fetch_get_response_headers__sig: 'pipp', _emscripten_fetch_get_response_headers_length__sig: 'pi', @@ -311,7 +309,6 @@ sigs = { _emscripten_get_now_is_monotonic__sig: 'i', _emscripten_get_progname__sig: 'vpi', _emscripten_notify_mailbox_postmessage__sig: 'vppp', - _emscripten_out__sig: 'vp', _emscripten_push_main_loop_blocker__sig: 'vppp', _emscripten_push_uncounted_main_loop_blocker__sig: 'vppp', _emscripten_set_offscreencanvas_size__sig: 'ipii', @@ -590,12 +587,14 @@ sigs = { emscripten_current_thread_is_audio_worklet__sig: 'i', emscripten_current_thread_is_wasm_worker__sig: 'i', emscripten_date_now__sig: 'd', + emscripten_dbg__sig: 'vp', emscripten_debugger__sig: 'v', emscripten_destroy_audio_context__sig: 'vi', emscripten_destroy_web_audio_node__sig: 'vi', emscripten_destroy_worker__sig: 'vi', emscripten_dlopen__sig: 'vpippp', emscripten_enter_soft_fullscreen__sig: 'ipp', + emscripten_err__sig: 'vp', emscripten_exit_fullscreen__sig: 'i', emscripten_exit_pointerlock__sig: 'i', emscripten_exit_soft_fullscreen__sig: 'i', @@ -677,6 +676,7 @@ sigs = { emscripten_navigator_hardware_concurrency__sig: 'i', emscripten_notify_memory_growth__sig: 'vp', emscripten_num_logical_cores__sig: 'i', + emscripten_out__sig: 'vp', emscripten_pause_main_loop__sig: 'v', emscripten_pc_get_column__sig: 'ip', emscripten_pc_get_file__sig: 'pp', diff --git a/system/include/emscripten/console.h b/system/include/emscripten/console.h index 0197113274202..f9d43f31cc632 100644 --- a/system/include/emscripten/console.h +++ b/system/include/emscripten/console.h @@ -15,25 +15,34 @@ void emscripten_console_log(const char *utf8String __attribute__((nonnull))); void emscripten_console_warn(const char *utf8String __attribute__((nonnull))); void emscripten_console_error(const char *utf8String __attribute__((nonnull))); -// Write to the out() and err() hooks directly (defined in shell.js). -// These have different behavior compared to console.log/err. -// Under node, they write to stdout and stderr which is a more direct way to -// write output especially in worker threads. -// The default behavior of these functions can be overridden by print and -// printErr, if provided on the Module object. -// These functions are mainly intended for internal use. -// See https://github.com/emscripten-core/emscripten/issues/14804 -void _emscripten_out(const char *utf8String __attribute__((nonnull))); -void _emscripten_err(const char *utf8String __attribute__((nonnull))); -void _emscripten_dbg(const char *utf8String __attribute__((nonnull))); +// Write to the out(), err() and dbg() JS functions directly. +// These are defined an defined in shell.js and have different behavior compared +// to console.log/err. Under node, they write to stdout and stderr which is a +// more direct way to write output especially from worker threads. The default +// behavior of these functions can be overridden by print and printErr, if +// provided on the Module object. These functions are mainly intended for +// internal use. +void emscripten_out(const char *utf8String __attribute__((nonnull))); +void emscripten_err(const char *utf8String __attribute__((nonnull))); +void emscripten_dbg(const char *utf8String __attribute__((nonnull))); + +// Legacy/internal names for the above +#define _emscripten_out(x) emscripten_out(x) +#define _emscripten_err(x) emscripten_err(x) +#define _emscripten_dbg(x) emscripten_dbg(x) // Similar to the above functions but operate with printf-like semantics. -void emscripten_console_logf(const char *utf8String __attribute__((nonnull)), ...) __attribute__((__format__(printf, 1, 2))); -void emscripten_console_warnf(const char *utf8String __attribute__((nonnull)), ...) __attribute__((__format__(printf, 1, 2))); -void emscripten_console_errorf(const char *utf8String __attribute__((nonnull)), ...)__attribute__((__format__(printf, 1, 2))); -void _emscripten_outf(const char *utf8String __attribute__((nonnull)), ...) __attribute__((__format__(printf, 1, 2))); -void _emscripten_errf(const char *utf8String __attribute__((nonnull)), ...) __attribute__((__format__(printf, 1, 2))); -void _emscripten_dbgf(const char *utf8String __attribute__((nonnull)), ...) __attribute__((__format__(printf, 1, 2))); +void emscripten_console_logf(const char *format __attribute__((nonnull)), ...) __attribute__((__format__(printf, 1, 2))); +void emscripten_console_warnf(const char *format __attribute__((nonnull)), ...) __attribute__((__format__(printf, 1, 2))); +void emscripten_console_errorf(const char *format __attribute__((nonnull)), ...)__attribute__((__format__(printf, 1, 2))); +void emscripten_outf(const char *format __attribute__((nonnull)), ...) __attribute__((__format__(printf, 1, 2))); +void emscripten_errf(const char *format __attribute__((nonnull)), ...) __attribute__((__format__(printf, 1, 2))); +void emscripten_dbgf(const char *format __attribute__((nonnull)), ...) __attribute__((__format__(printf, 1, 2))); + +// Legacy/internal names for the above +#define _emscripten_outf(format, ...) emscripten_outf(format, ##__VA_ARGS__) +#define _emscripten_errf(format, ...) emscripten_errf(format, ##__VA_ARGS__) +#define _emscripten_dbgf(format, ...) emscripten_dbgf(format, ##__VA_ARGS__) #ifdef __cplusplus } diff --git a/system/include/emscripten/html5.h b/system/include/emscripten/html5.h index 1b3481d7f83ff..8cae18c13126d 100644 --- a/system/include/emscripten/html5.h +++ b/system/include/emscripten/html5.h @@ -24,10 +24,8 @@ extern "C" { /* * This file defines Emscripten low-level glue bindings for interfacing with HTML5 APIs * - * Documentation for the public APIs defined in this file must be updated in: + * Documentation for the public APIs defined in this file must be updated in: * site/source/docs/api_reference/html5.h.rst - * A prebuilt local version of the documentation is available at: - * site/build/text/docs/api_reference/html5.h.txt * You can also build docs locally as HTML or other formats in site/ * An online HTML version (which may be of a different version of Emscripten) * is up at http://kripken.github.io/emscripten-site/docs/api_reference/html5.h.html diff --git a/system/lib/libc/dynlink.c b/system/lib/libc/dynlink.c index c3e421b417a22..d3ea861731d76 100644 --- a/system/lib/libc/dynlink.c +++ b/system/lib/libc/dynlink.c @@ -34,7 +34,7 @@ //#define DYLINK_DEBUG #ifdef DYLINK_DEBUG -#define dbg(fmt, ...) _emscripten_dbgf(fmt, ##__VA_ARGS__) +#define dbg(fmt, ...) emscripten_dbgf(fmt, ##__VA_ARGS__) #else #define dbg(fmt, ...) #endif @@ -244,7 +244,7 @@ static void dlsync_next(struct dlevent* dlevent, em_promise_t promise) { dbg("calling _dlsym_catchup_js ...."); void* success = _dlsym_catchup_js(dlevent->dso, dlevent->sym_index); if (!success) { - _emscripten_errf("_dlsym_catchup_js failed: %s", dlerror()); + emscripten_errf("_dlsym_catchup_js failed: %s", dlerror()); sync_one_onerror(dlevent->dso, promise); return; } @@ -288,7 +288,7 @@ bool _emscripten_dlsync_self() { p->sym_index); void* success = _dlsym_catchup_js(p->dso, p->sym_index); if (!success) { - _emscripten_errf("_dlsym_catchup_js failed: %s", dlerror()); + emscripten_errf("_dlsym_catchup_js failed: %s", dlerror()); return false; } } else { @@ -306,7 +306,7 @@ bool _emscripten_dlsync_self() { // TODO(sbc): Ideally this would never happen and we could/should // abort, but on the main thread (where we don't have sync xhr) its // often not possible to syncronously load side module. - _emscripten_errf("_dlopen_js failed: %s", dlerror()); + emscripten_errf("_dlopen_js failed: %s", dlerror()); return false; } } diff --git a/system/lib/libc/emscripten_console.c b/system/lib/libc/emscripten_console.c index c74995bb7ba92..618297a112274 100644 --- a/system/lib/libc/emscripten_console.c +++ b/system/lib/libc/emscripten_console.c @@ -41,25 +41,25 @@ void emscripten_console_warnf(const char* fmt, ...) { va_end(ap); } -void _emscripten_outf(const char* fmt, ...) { +void emscripten_outf(const char* fmt, ...) { va_list ap; va_start(ap, fmt); - vlogf(fmt, ap, &_emscripten_out); + vlogf(fmt, ap, &emscripten_out); va_end(ap); } -void _emscripten_errf(const char* fmt, ...) { +void emscripten_errf(const char* fmt, ...) { va_list ap; va_start(ap, fmt); - vlogf(fmt, ap, &_emscripten_err); + vlogf(fmt, ap, &emscripten_err); va_end(ap); } #ifndef NDEBUG -void _emscripten_dbgf(const char* fmt, ...) { +void emscripten_dbgf(const char* fmt, ...) { va_list ap; va_start(ap, fmt); - vlogf(fmt, ap, &_emscripten_dbg); + vlogf(fmt, ap, &emscripten_dbg); va_end(ap); } #endif diff --git a/system/lib/libcxxabi/src/cxa_exception_emscripten.cpp b/system/lib/libcxxabi/src/cxa_exception_emscripten.cpp index 195dcdae8ac23..fef9bf9a0e90d 100644 --- a/system/lib/libcxxabi/src/cxa_exception_emscripten.cpp +++ b/system/lib/libcxxabi/src/cxa_exception_emscripten.cpp @@ -21,7 +21,7 @@ // Define to enable extra debugging on stderr. #if EXCEPTIONS_DEBUG #include "emscripten/console.h" -#define DEBUG _emscripten_errf +#define DEBUG emscripten_errf #else #define DEBUG(...) #endif diff --git a/system/lib/pthread/emscripten_tls_init.c b/system/lib/pthread/emscripten_tls_init.c index 6734fde05201a..d7d4cefcc6704 100644 --- a/system/lib/pthread/emscripten_tls_init.c +++ b/system/lib/pthread/emscripten_tls_init.c @@ -16,7 +16,7 @@ // Uncomment to trace TLS allocations. // #define DEBUG_TLS #ifdef DEBUG_TLS -#define dbg(fmt, ...) _emscripten_dbgf(fmt, ##__VA_ARGS__) +#define dbg(fmt, ...) emscripten_dbgf(fmt, ##__VA_ARGS__) #else #define dbg(fmt, ...) #endif diff --git a/system/lib/pthread/pthread_create.c b/system/lib/pthread/pthread_create.c index 3d6f712387e91..080466fc2c8d2 100644 --- a/system/lib/pthread/pthread_create.c +++ b/system/lib/pthread/pthread_create.c @@ -23,7 +23,7 @@ // Comment this line to enable tracing of thread creation and destruction: // #define PTHREAD_DEBUG #ifdef PTHREAD_DEBUG -#define dbg(fmt, ...) _emscripten_dbgf(fmt, ##__VA_ARGS__) +#define dbg(fmt, ...) emscripten_dbgf(fmt, ##__VA_ARGS__) #else #define dbg(fmt, ...) #endif diff --git a/system/lib/standalone/standalone.c b/system/lib/standalone/standalone.c index 44e1912d2b2d2..5b9c66564e06b 100644 --- a/system/lib/standalone/standalone.c +++ b/system/lib/standalone/standalone.c @@ -212,9 +212,9 @@ static void wasi_writeln(__wasi_fd_t fd, const char* buffer) { imported__wasi_fd_write(fd, iovs, 2, &nwritten); } -void _emscripten_out(const char* text) { wasi_writeln(1, text); } +void emscripten_out(const char* text) { wasi_writeln(1, text); } -void _emscripten_err(const char* text) { wasi_writeln(2, text); } +void emscripten_err(const char* text) { wasi_writeln(2, text); } // In the non-standalone build we define this helper function in JS to avoid // signture mismatch issues. diff --git a/system/lib/wasmfs/special_files.cpp b/system/lib/wasmfs/special_files.cpp index 01691950b0b6d..478bbd35a7667 100644 --- a/system/lib/wasmfs/special_files.cpp +++ b/system/lib/wasmfs/special_files.cpp @@ -113,7 +113,7 @@ class StdoutFile : public WritingStdFile { // This is confirmed to occur when running with EXIT_RUNTIME and // PROXY_TO_PTHREAD. This results in only a single console.log statement // being outputted. The solution for now is to use out() and err() instead. - return writeToJS(buf, len, &_emscripten_out, writeBuffer); + return writeToJS(buf, len, &emscripten_out, writeBuffer); } public: @@ -127,7 +127,7 @@ class StderrFile : public WritingStdFile { // emscripten_err does. // This will not show in HTML - a console.warn in a worker is // sufficient. This would be a change from the current FS. - return writeToJS(buf, len, &_emscripten_err, writeBuffer); + return writeToJS(buf, len, &emscripten_err, writeBuffer); } public: diff --git a/test/core/pthread/test_pthread_keepalive.c b/test/core/pthread/test_pthread_keepalive.c index 73ba48dcaecdc..728a28ef4e45f 100644 --- a/test/core/pthread/test_pthread_keepalive.c +++ b/test/core/pthread/test_pthread_keepalive.c @@ -17,7 +17,7 @@ pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; bool running = false; void timeout(void* arg) { - _emscripten_errf("timeout"); + emscripten_err("timeout"); pthread_mutex_lock(&mutex); running = true; pthread_mutex_unlock(&mutex); @@ -26,18 +26,18 @@ void timeout(void* arg) { void* thread_main(void* arg) { // Keep the thread runtime alive for now. - _emscripten_errf("thread_main"); + emscripten_err("thread_main"); emscripten_runtime_keepalive_push(); emscripten_set_timeout(timeout, 0, NULL); return NULL; } void say_hello(void* arg) { - _emscripten_errf("say_hello"); + emscripten_err("say_hello"); } void keepalive_pop(void* arg) { - _emscripten_errf("keepalive_pop"); + emscripten_err("keepalive_pop"); // After this the called, thread should exit (become joinable). emscripten_runtime_keepalive_pop(); } diff --git a/test/core/test_setjmp_noleak.c b/test/core/test_setjmp_noleak.c index d8ed549d55030..7577c0342a5a1 100644 --- a/test/core/test_setjmp_noleak.c +++ b/test/core/test_setjmp_noleak.c @@ -8,7 +8,7 @@ jmp_buf env; void luaWork(int d){ int x; - _emscripten_outf("d is at %d", d); + emscripten_outf("d is at %d", d); assert(d <= 10); longjmp(env, 1); @@ -16,14 +16,14 @@ void luaWork(int d){ void dump() { struct mallinfo m = mallinfo(); - _emscripten_outf("dump: %d , %d", m.arena, m.uordblks); + emscripten_outf("dump: %d , %d", m.arena, m.uordblks); } void work(int n) { - _emscripten_outf("work %d", n); + emscripten_outf("work %d", n); dump(); - _emscripten_outf("calling luaWork with n=%d", n); + emscripten_outf("calling luaWork with n=%d", n); if (!setjmp(env)){ luaWork(n); } @@ -38,5 +38,5 @@ int main() { dump(); struct mallinfo m2 = mallinfo(); assert(m1.uordblks == m2.uordblks); - _emscripten_out("ok."); + emscripten_out("ok."); } diff --git a/test/other/test_dbg.c b/test/other/test_dbg.c index ba18a9b38789b..b72f2070fb783 100644 --- a/test/other/test_dbg.c +++ b/test/other/test_dbg.c @@ -12,8 +12,8 @@ int main() { printf("hello, world!\n"); #ifndef NDEBUG // This symbol is only available in debug builds (i.e. -sASSERTIONS) - _emscripten_dbg("native dbg message"); - _emscripten_dbgf("formatted: %d", 42); + emscripten_dbg("native dbg message"); + emscripten_dbgf("formatted: %d", 42); #endif return 0; } diff --git a/test/pthread/emscripten_thread_sleep.c b/test/pthread/emscripten_thread_sleep.c index d8b6b662c0fce..d0183fb121da1 100644 --- a/test/pthread/emscripten_thread_sleep.c +++ b/test/pthread/emscripten_thread_sleep.c @@ -17,7 +17,7 @@ void Sleep(double msecs) void *thread_main(void *arg) { - _emscripten_out("hello from thread!"); + emscripten_out("hello from thread!"); Sleep(1); Sleep(10); diff --git a/test/pthread/test_pthread_busy_wait_atexit.cpp b/test/pthread/test_pthread_busy_wait_atexit.cpp index 9969940b27f82..00ca44b81cfec 100644 --- a/test/pthread/test_pthread_busy_wait_atexit.cpp +++ b/test/pthread/test_pthread_busy_wait_atexit.cpp @@ -14,7 +14,7 @@ void exit_handler() { void* thread_main(void*) { // Avoid using printf here since stdio is proxied back to the // main thread which is busy looping - _emscripten_out("in thread"); + emscripten_out("in thread"); atexit(exit_handler); done = true; return NULL; diff --git a/test/pthread/test_pthread_proxying.c b/test/pthread/test_pthread_proxying.c index 8920da0be653e..aec43d5617407 100644 --- a/test/pthread/test_pthread_proxying.c +++ b/test/pthread/test_pthread_proxying.c @@ -27,17 +27,17 @@ em_proxying_queue* proxy_queue = NULL; _Atomic int should_quit = 0; void* looper_main(void* arg) { - _emscripten_errf("looper_main"); + emscripten_err("looper_main"); while (!should_quit) { emscripten_proxy_execute_queue(proxy_queue); sched_yield(); } - _emscripten_errf("quitting looper"); + emscripten_err("quitting looper"); return NULL; } void* returner_main(void* queue) { - _emscripten_errf("returner_main"); + emscripten_err("returner_main"); emscripten_exit_with_live_runtime(); } diff --git a/test/test_core.py b/test/test_core.py index 7abd9ccf7653b..4022a5d558428 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -7557,7 +7557,7 @@ def test_embind_2(self, args): return (100 - t) * a + t * b; } EMSCRIPTEN_BINDINGS(my_module) { - _emscripten_err("test bindings"); + emscripten_err("test bindings"); function("lerp", &lerp); } int main(int argc, char **argv) { diff --git a/test/test_other.py b/test/test_other.py index 70f5fcb5fbca7..9c149a68d1d19 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -2028,7 +2028,7 @@ def test_dylink_pthread_comdat(self, flipped): Foo g_foo; int main() { - _emscripten_outf("main: Foo typeid: %s", typeid(Foo).name()); + emscripten_outf("main: Foo typeid: %s", typeid(Foo).name()); Foo().method(); return 0; @@ -2040,7 +2040,7 @@ def test_dylink_pthread_comdat(self, flipped): #include void Foo::method() const { - _emscripten_outf("side: Foo typeid: %s", typeid(Foo).name()); + emscripten_outf("side: Foo typeid: %s", typeid(Foo).name()); } ''') if flipped: @@ -5932,7 +5932,7 @@ def test_pthread_print_override_modularize(self): #include int main() { - _emscripten_out("hello, world!"); + emscripten_out("hello, world!"); return 0; } ''') From db6f0ef4185268ead296f439d5dbd3dbde83fe27 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 25 May 2023 15:30:01 -0700 Subject: [PATCH 0290/1523] WasmFS: Fix 4 closure errors due to outdated type annotations (#19451) --- src/library_wasmfs_node.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/library_wasmfs_node.js b/src/library_wasmfs_node.js index 39ddb60b6c07a..7c1acee184b6d 100644 --- a/src/library_wasmfs_node.js +++ b/src/library_wasmfs_node.js @@ -50,6 +50,9 @@ mergeInto(LibraryManager.library, { return wasmfsNodeFixStat(stat); }, + // Ignore closure type errors due to outdated readdirSync annotations, see + // https://github.com/google/closure-compiler/pull/4093 + _wasmfs_node_readdir__docs: '/** @suppress {checkTypes} */', _wasmfs_node_readdir__deps: ['$wasmfsNodeConvertNodeCode'], _wasmfs_node_readdir: function(path_p, vec) { let path = UTF8ToString(path_p); From b56605ea3f3fd5a4331b3ce357df89ccb0828feb Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 25 May 2023 15:37:37 -0700 Subject: [PATCH 0291/1523] Move loading of initial dynamic libraries to before `run` (#19450) Previously we were calling `loadDylibs` in the `run` function but we can call it earlier as soon as the main module is instantiated. This saves a little on code size since it relies on the existing `runDependencies` mechanism. Split out from #19390 --- emcc.py | 4 ++ src/library.js | 22 +++++++++++ src/library_dylink.js | 24 +++++------- src/library_pthread.js | 39 +++++++++---------- src/postamble.js | 28 ------------- src/postamble_minimal.js | 2 +- src/preamble.js | 18 ++++----- .../metadce/test_metadce_hello_dylink.jssize | 2 +- .../test_metadce_minimal_pthreads.jssize | 2 +- test/other/test_unoptimized_code_size.js.size | 2 +- ...t_unoptimized_code_size_no_asserts.js.size | 2 +- .../test_unoptimized_code_size_strict.js.size | 2 +- 12 files changed, 69 insertions(+), 78 deletions(-) diff --git a/emcc.py b/emcc.py index 1e9f7753ec547..7107ff56bdc28 100755 --- a/emcc.py +++ b/emcc.py @@ -2076,6 +2076,7 @@ def phase_linker_setup(options, state, newargs): assert not settings.SIDE_MODULE if settings.MAIN_MODULE == 1: settings.INCLUDE_FULL_LIBRARY = 1 + # Called from preamble.js once the main module is instantiated. settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['$loadDylibs'] settings.REQUIRED_EXPORTS += ['malloc'] @@ -2195,6 +2196,9 @@ def phase_linker_setup(options, state, newargs): else: settings.REQUIRED_EXPORTS += ['emscripten_stack_init'] + if settings.STACK_OVERFLOW_CHECK >= 2: + settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['$setStackLimits'] + if settings.MODULARIZE: if settings.PROXY_TO_WORKER: exit_with_error('-sMODULARIZE is not compatible with --proxy-to-worker (if you want to run in a worker with -sMODULARIZE, you likely want to do the worker side setup manually)') diff --git a/src/library.js b/src/library.js index f9c5e62bab149..4e2796d15106a 100644 --- a/src/library.js +++ b/src/library.js @@ -21,6 +21,7 @@ // new function with an '_', it will not be found. mergeInto(LibraryManager.library, { + $ptrToString: function(ptr) { #if ASSERTIONS assert(typeof ptr === 'number'); @@ -559,6 +560,27 @@ mergeInto(LibraryManager.library, { return buf; }, +#if STACK_OVERFLOW_CHECK >= 2 + // Set stack limits used by binaryen's `StackCheck` pass. +#if MAIN_MODULE + $setStackLimits__deps: ['$setDylinkStackLimits'], +#endif + $setStackLimits: function() { + var stackLow = _emscripten_stack_get_base(); + var stackHigh = _emscripten_stack_get_end(); +#if RUNTIME_DEBUG + dbg(`setStackLimits: ${ptrToString(stackLow)}, ${ptrToString(stackHigh)}`); +#endif +#if MAIN_MODULE + // With dynamic linking we could have any number of pre-loaded libraries + // that each need to have their stack limits set. + setDylinkStackLimits(stackLow, stackHigh); +#else + ___set_stack_limits(stackLow, stackHigh); +#endif + }, +#endif + $withStackSave__internal: true, $withStackSave: function(f) { var stack = stackSave(); diff --git a/src/library_dylink.js b/src/library_dylink.js index 4b20a464d00dc..efe508620c8a7 100644 --- a/src/library_dylink.js +++ b/src/library_dylink.js @@ -767,12 +767,10 @@ var LibraryDylink = { reportUndefinedSymbols(); } #if STACK_OVERFLOW_CHECK >= 2 - if (moduleExports['__set_stack_limits']) { -#if PTHREADS - // When we are on an uninitialized pthread we delay calling - // __set_stack_limits until $setDylinkStackLimits. - if (!ENVIRONMENT_IS_PTHREAD || runtimeInitialized) -#endif + // If the runtime has already been initialized we set the stack limits + // now. Othwerwise this is delayed until `setDylinkStackLimits` is + // called after initialization. + if (moduleExports['__set_stack_limits'] && runtimeInitialized) { moduleExports['__set_stack_limits']({{{ to64('_emscripten_stack_get_base()') }}}, {{{ to64('_emscripten_stack_get_end()') }}}); } #endif @@ -871,20 +869,18 @@ var LibraryDylink = { return loadModule(); }, -#if STACK_OVERFLOW_CHECK >= 2 && PTHREADS - // With PTHREADS we load libraries before we are running a pthread and - // therefore before we have a stack. Instead we delay calling - // `__set_stack_limits` until we start running a thread. We also need to call - // this again for each new thread that the runs on a worker (since each thread - // has its own separate stack region). +#if STACK_OVERFLOW_CHECK >= 2 + // Sometimes we load libraries before runtime initialization. In this case + // we delay calling __set_stack_limits (which must be called for each + // module). $setDylinkStackLimits: function(stackTop, stackMax) { for (var name in LDSO.loadedLibsByName) { #if DYLINK_DEBUG - dbg(`setDylinkStackLimits[${name}]`); + dbg(`setDylinkStackLimits for '${name}'`); #endif var lib = LDSO.loadedLibsByName[name]; if (lib.exports['__set_stack_limits']) { - lib.exports['__set_stack_limits'](stackTop, stackMax); + lib.exports['__set_stack_limits']({{{ to64("stackTop") }}}, {{{ to64("stackMax") }}}); } } }, diff --git a/src/library_pthread.js b/src/library_pthread.js index 3ead63051ca96..ab30f07a0409a 100644 --- a/src/library_pthread.js +++ b/src/library_pthread.js @@ -105,6 +105,14 @@ var LibraryPThread = { PThread.allocateUnusedWorker(); } #endif +#if !MINIMAL_RUNTIME + // MINIMAL_RUNTIME takes care of calling loadWasmModuleToAllWorkers + // in postamble_minimal.js + addOnPreRun(() => { + addRunDependency('loading-workers') + PThread.loadWasmModuleToAllWorkers(() => removeRunDependency('loading-workers')); + }); +#endif #if MAIN_MODULE PThread.outstandingPromises = {}; // Finished threads are threads that have finished running but we not yet @@ -1043,39 +1051,30 @@ var LibraryPThread = { return func.apply(null, emscripten_receive_on_main_thread_js_callArgs); }, -#if STACK_OVERFLOW_CHECK >= 2 && MAIN_MODULE - $establishStackSpace__deps: ['$setDylinkStackLimits'], -#endif $establishStackSpace__internal: true, $establishStackSpace: function() { var pthread_ptr = _pthread_self(); - var stackTop = {{{ makeGetValue('pthread_ptr', C_STRUCTS.pthread.stack, 'i32') }}}; + var stackHigh = {{{ makeGetValue('pthread_ptr', C_STRUCTS.pthread.stack, 'i32') }}}; var stackSize = {{{ makeGetValue('pthread_ptr', C_STRUCTS.pthread.stack_size, 'i32') }}}; - var stackMax = stackTop - stackSize; + var stackLow = stackHigh - stackSize; #if PTHREADS_DEBUG - dbg('establishStackSpace: ' + ptrToString(stackTop) + ' -> ' + ptrToString(stackMax)); + dbg('establishStackSpace: ' + ptrToString(stackHigh) + ' -> ' + ptrToString(stackLow)); #endif #if ASSERTIONS - assert(stackTop != 0); - assert(stackMax != 0); - assert(stackTop > stackMax, 'stackTop must be higher then stackMax'); + assert(stackHigh != 0); + assert(stackLow != 0); + assert(stackHigh > stackLow, 'stackHigh must be higher then stackLow'); #endif // Set stack limits used by `emscripten/stack.h` function. These limits are // cached in wasm-side globals to make checks as fast as possible. - _emscripten_stack_set_limits(stackTop, stackMax); + _emscripten_stack_set_limits(stackHigh, stackLow); + #if STACK_OVERFLOW_CHECK >= 2 - // Set stack limits used by binaryen's `StackCheck` pass. - // TODO(sbc): Can this be combined with the above. - ___set_stack_limits(stackTop, stackMax); -#if MAIN_MODULE - // With dynamic linking we could have any number of pre-loaded libraries - // that each need to have their stack limits set. - setDylinkStackLimits(stackTop, stackMax); -#endif -#endif + setStackLimits(); +#endif STACK_OVERFLOW_CHECK // Call inside wasm module to set up the stack frame for this pthread in wasm module scope - stackRestore(stackTop); + stackRestore(stackHigh); #if STACK_OVERFLOW_CHECK // Write the stack cookie last, after we have set up the proper bounds and diff --git a/src/postamble.js b/src/postamble.js index 8e01e640c3516..712165158661e 100644 --- a/src/postamble.js +++ b/src/postamble.js @@ -131,13 +131,6 @@ function stackCheckInit() { } #endif -#if RELOCATABLE -var dylibsLoaded = false; -#if '$LDSO' in addedLibraryItems -LDSO.init(); -#endif -#endif - #if MAIN_READS_PARAMS function run(args = arguments_) { #else @@ -158,27 +151,6 @@ function run() { stackCheckInit(); #endif -#if RELOCATABLE - if (!dylibsLoaded) { - // Loading of dynamic libraries needs to happen on each thread, so we can't - // use the normal __ATPRERUN__ mechanism. -#if MAIN_MODULE - loadDylibs(); -#else - reportUndefinedSymbols(); -#endif - dylibsLoaded = true; - - // Loading dylibs can add run dependencies. - if (runDependencies > 0) { -#if RUNTIME_DEBUG - dbg('loadDylibs added run() dependencies, not running yet'); -#endif - return; - } - } -#endif - #if WASM_WORKERS if (ENVIRONMENT_IS_WASM_WORKER) { #if MODULARIZE diff --git a/src/postamble_minimal.js b/src/postamble_minimal.js index e8d50122f579f..ea234e32d7f96 100644 --- a/src/postamble_minimal.js +++ b/src/postamble_minimal.js @@ -72,7 +72,7 @@ function initRuntime(asm) { _emscripten_stack_init(); writeStackCookie(); #if STACK_OVERFLOW_CHECK >= 2 - ___set_stack_limits(_emscripten_stack_get_base(), _emscripten_stack_get_end()); + setStackLimits(); #endif #endif diff --git a/src/preamble.js b/src/preamble.js index 70097ae03387c..1406eb45d97b3 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -233,11 +233,9 @@ function initRuntime() { #endif #if STACK_OVERFLOW_CHECK >= 2 -#if RUNTIME_DEBUG - dbg('__set_stack_limits: ' + _emscripten_stack_get_base() + ', ' + _emscripten_stack_get_end()); -#endif - ___set_stack_limits(_emscripten_stack_get_base(), _emscripten_stack_get_end()); + setStackLimits(); #endif + #if RELOCATABLE callRuntimeCallbacks(__RELOC_FUNCS__); #endif @@ -980,6 +978,12 @@ function createWasm() { } #endif mergeLibSymbols(exports, 'main') +#if '$LDSO' in addedLibraryItems + LDSO.init(); +#endif + loadDylibs(); +#elif RELOCATABLE + reportUndefinedSymbols(); #endif #if MEMORY64 @@ -1047,13 +1051,7 @@ function createWasm() { // We now have the Wasm module loaded up, keep a reference to the compiled module so we can post it to the workers. wasmModule = module; #endif - -#if PTHREADS - PThread.loadWasmModuleToAllWorkers(() => removeRunDependency('wasm-instantiate')); -#else // singlethreaded build: removeRunDependency('wasm-instantiate'); -#endif // ~PTHREADS - return exports; } // wait for the pthread pool (if any) diff --git a/test/other/metadce/test_metadce_hello_dylink.jssize b/test/other/metadce/test_metadce_hello_dylink.jssize index 5da2a4f7c562e..d7c41b7d32c0c 100644 --- a/test/other/metadce/test_metadce_hello_dylink.jssize +++ b/test/other/metadce/test_metadce_hello_dylink.jssize @@ -1 +1 @@ -15060 +15023 diff --git a/test/other/metadce/test_metadce_minimal_pthreads.jssize b/test/other/metadce/test_metadce_minimal_pthreads.jssize index 13dac5d04b508..51cd2147d6059 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.jssize +++ b/test/other/metadce/test_metadce_minimal_pthreads.jssize @@ -1 +1 @@ -15415 +15456 diff --git a/test/other/test_unoptimized_code_size.js.size b/test/other/test_unoptimized_code_size.js.size index cc84a949cd741..068c130d5b5bd 100644 --- a/test/other/test_unoptimized_code_size.js.size +++ b/test/other/test_unoptimized_code_size.js.size @@ -1 +1 @@ -59630 +59629 diff --git a/test/other/test_unoptimized_code_size_no_asserts.js.size b/test/other/test_unoptimized_code_size_no_asserts.js.size index 5ff8d77a15fd1..2a7a3ea68f817 100644 --- a/test/other/test_unoptimized_code_size_no_asserts.js.size +++ b/test/other/test_unoptimized_code_size_no_asserts.js.size @@ -1 +1 @@ -33256 +33255 diff --git a/test/other/test_unoptimized_code_size_strict.js.size b/test/other/test_unoptimized_code_size_strict.js.size index 7b6c1d7f7e426..bf3a0db19d3b5 100644 --- a/test/other/test_unoptimized_code_size_strict.js.size +++ b/test/other/test_unoptimized_code_size_strict.js.size @@ -1 +1 @@ -58572 +58571 From 38e4b1f90574efac77b39063f9e29a5c33a877ba Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 24 May 2023 16:23:17 -0700 Subject: [PATCH 0292/1523] Feedback from #19450 --- src/library.js | 1 - src/library_dylink.js | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/library.js b/src/library.js index 4e2796d15106a..4d8ad4a2c469d 100644 --- a/src/library.js +++ b/src/library.js @@ -21,7 +21,6 @@ // new function with an '_', it will not be found. mergeInto(LibraryManager.library, { - $ptrToString: function(ptr) { #if ASSERTIONS assert(typeof ptr === 'number'); diff --git a/src/library_dylink.js b/src/library_dylink.js index efe508620c8a7..63e98421e1dcc 100644 --- a/src/library_dylink.js +++ b/src/library_dylink.js @@ -768,7 +768,7 @@ var LibraryDylink = { } #if STACK_OVERFLOW_CHECK >= 2 // If the runtime has already been initialized we set the stack limits - // now. Othwerwise this is delayed until `setDylinkStackLimits` is + // now. Otherwise this is delayed until `setDylinkStackLimits` is // called after initialization. if (moduleExports['__set_stack_limits'] && runtimeInitialized) { moduleExports['__set_stack_limits']({{{ to64('_emscripten_stack_get_base()') }}}, {{{ to64('_emscripten_stack_get_end()') }}}); From c79b0b10c1de93f3ab3f31acc80098af4bacdd8d Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 25 May 2023 16:58:56 -0700 Subject: [PATCH 0293/1523] More usage of JS string template literals. NFC (#19449) --- src/library.js | 8 +-- src/library_fs.js | 2 +- src/library_html5.js | 11 ++- src/library_html5_webgl.js | 14 ++-- src/library_openal.js | 36 +++++----- src/library_pthread.js | 2 +- src/library_syscall.js | 24 +++---- src/library_wasi.js | 16 ++--- src/library_websocket.js | 72 +++++++++---------- src/runtime_stack_check.js | 6 +- src/worker.js | 4 +- .../metadce/test_metadce_cxx_ctors1.jssize | 2 +- .../metadce/test_metadce_cxx_ctors2.jssize | 2 +- .../metadce/test_metadce_cxx_except.jssize | 2 +- .../test_metadce_cxx_except_wasm.jssize | 2 +- .../metadce/test_metadce_cxx_mangle.jssize | 2 +- .../metadce/test_metadce_cxx_noexcept.jssize | 2 +- .../metadce/test_metadce_hello_O0.jssize | 2 +- .../metadce/test_metadce_hello_O1.jssize | 2 +- .../metadce/test_metadce_hello_O2.jssize | 2 +- .../metadce/test_metadce_hello_O3.jssize | 2 +- .../metadce/test_metadce_hello_Os.jssize | 2 +- .../metadce/test_metadce_hello_Oz.jssize | 2 +- .../metadce/test_metadce_hello_dylink.jssize | 2 +- .../test_metadce_libcxxabi_message_O3.jssize | 2 +- ...dce_libcxxabi_message_O3_standalone.jssize | 2 +- test/other/metadce/test_metadce_mem_O3.jssize | 2 +- .../metadce/test_metadce_mem_O3_grow.jssize | 2 +- ...test_metadce_mem_O3_grow_standalone.jssize | 2 +- .../test_metadce_mem_O3_standalone.jssize | 2 +- ...test_metadce_mem_O3_standalone_narg.jssize | 2 +- ...metadce_mem_O3_standalone_narg_flto.jssize | 2 +- .../metadce/test_metadce_minimal_O0.jssize | 2 +- .../test_metadce_minimal_pthreads.jssize | 2 +- test/other/test_unoptimized_code_size.js.size | 2 +- ...t_unoptimized_code_size_no_asserts.js.size | 2 +- .../test_unoptimized_code_size_strict.js.size | 2 +- 37 files changed, 123 insertions(+), 124 deletions(-) diff --git a/src/library.js b/src/library.js index 4d8ad4a2c469d..84ce2af8c81d4 100644 --- a/src/library.js +++ b/src/library.js @@ -3818,14 +3818,14 @@ function wrapSyscallFunction(x, library, isWasi) { post += 'SYSCALLS.varargs = undefined;\n'; } } - pre += "dbg('syscall! " + x + ": [' + Array.prototype.slice.call(arguments) + ']');\n"; + pre += `dbg('syscall! ${x}: [' + Array.prototype.slice.call(arguments) + ']');\n`; pre += "var canWarn = true;\n"; pre += "var ret = (function() {\n"; post += "})();\n"; post += "if (ret && ret < 0 && canWarn) {\n"; - post += " dbg('error: syscall may have failed with ' + (-ret) + ' (' + ERRNO_MESSAGES[-ret] + ')');\n"; + post += " dbg(`error: syscall may have failed with ${-ret} (${ERRNO_MESSAGES[-ret]})`);\n"; post += "}\n"; - post += "dbg('syscall return: ' + ret);\n"; + post += "dbg(`syscall return: ${ret}`);\n"; post += "return ret;\n"; #endif delete library[x + '__nothrow']; @@ -3837,7 +3837,7 @@ function wrapSyscallFunction(x, library, isWasi) { " if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e;\n"; #if SYSCALL_DEBUG handler += - " dbg('error: syscall failed with ' + e.errno + ' (' + ERRNO_MESSAGES[e.errno] + ')');\n" + + " dbg(`error: syscall failed with ${e.errno} (${ERRNO_MESSAGES[e.errno]})`);\n" + " canWarn = false;\n"; #endif // Musl syscalls are negated. diff --git a/src/library_fs.js b/src/library_fs.js index 79970eb6a955f..4bc32ffcfd439 100644 --- a/src/library_fs.js +++ b/src/library_fs.js @@ -1079,7 +1079,7 @@ FS.staticInit();` + if (!(path in FS.readFiles)) { FS.readFiles[path] = 1; #if FS_DEBUG - dbg("FS.trackingDelegate error on read file: " + path); + dbg(`FS.trackingDelegate error on read file: ${path}`); #endif } } diff --git a/src/library_html5.js b/src/library_html5.js index 319ebbc998289..55b10673ac304 100644 --- a/src/library_html5.js +++ b/src/library_html5.js @@ -2335,15 +2335,14 @@ var LibraryHTML5 = { // TODO: Perhaps autoResizeViewport should only be true if FBO 0 is currently active? autoResizeViewport = (prevViewport[0] === 0 && prevViewport[1] === 0 && prevViewport[2] === canvas.width && prevViewport[3] === canvas.height); #if GL_DEBUG - dbg('Resizing canvas from ' + canvas.width + 'x' + canvas.height + ' to ' + width + 'x' + height + '. Previous GL viewport size was ' - + prevViewport + ', so autoResizeViewport=' + autoResizeViewport); + dbg(`Resizing canvas from ${canvas.width}x${canvas.height} to ${width}x${height}. Previous GL viewport size was ${prevViewport}, so autoResizeViewport=${autoResizeViewport}`); #endif } canvas.width = width; canvas.height = height; if (autoResizeViewport) { #if GL_DEBUG - dbg('Automatically resizing GL viewport to cover whole render target ' + width + 'x' + height); + dbg(`Automatically resizing GL viewport to cover whole render target ${width}x${height}`); #endif // TODO: Add -sCANVAS_RESIZE_SETS_GL_VIEWPORT=0/1 option (default=1). This is commonly done and several graphics engines depend on this, // but this can be quite disruptive. @@ -2408,7 +2407,7 @@ var LibraryHTML5 = { emscripten_set_canvas_element_size__deps: ['$JSEvents', '$setCanvasElementSizeCallingThread', '$setCanvasElementSizeMainThread', '$findCanvasEventTarget'], emscripten_set_canvas_element_size: function(target, width, height) { #if GL_DEBUG - dbg('emscripten_set_canvas_element_size(target='+target+',width='+width+',height='+height); + dbg(`emscripten_set_canvas_element_size(target=${target},width=${width},height=${height}`); #endif var canvas = findCanvasEventTarget(target); if (canvas) { @@ -2420,7 +2419,7 @@ var LibraryHTML5 = { emscripten_set_canvas_element_size__deps: ['$JSEvents', '$findCanvasEventTarget'], emscripten_set_canvas_element_size: function(target, width, height) { #if GL_DEBUG - dbg('emscripten_set_canvas_element_size(target='+target+',width='+width+',height='+height); + dbg(`emscripten_set_canvas_element_size(target=${target},width=${width},height=${height}`); #endif var canvas = findCanvasEventTarget(target); if (!canvas) return {{{ cDefs.EMSCRIPTEN_RESULT_UNKNOWN_TARGET }}}; @@ -2436,7 +2435,7 @@ var LibraryHTML5 = { $setCanvasElementSize__deps: ['emscripten_set_canvas_element_size', '$withStackSave', '$stringToUTF8OnStack'], $setCanvasElementSize: function(target, width, height) { #if GL_DEBUG - dbg('setCanvasElementSize(target='+target+',width='+width+',height='+height); + dbg(`setCanvasElementSize(target=${target},width=${width},height=${height}`); #endif if (!target.controlTransferredOffscreen) { target.width = width; diff --git a/src/library_html5_webgl.js b/src/library_html5_webgl.js index 5295453c5bc97..47c212d5f2fb4 100644 --- a/src/library_html5_webgl.js +++ b/src/library_html5_webgl.js @@ -117,7 +117,7 @@ var LibraryHtml5WebGL = { // then this can be avoided, since OffscreenCanvas enables explicit swap control. #if GL_DEBUG if (contextAttributes.proxyContextToMainThread === {{{ cDefs.EMSCRIPTEN_WEBGL_CONTEXT_PROXY_ALWAYS }}}) dbg('EMSCRIPTEN_WEBGL_CONTEXT_PROXY_ALWAYS enabled, proxying WebGL rendering from pthread to main thread.'); - if (!canvas && contextAttributes.proxyContextToMainThread === {{{ cDefs.EMSCRIPTEN_WEBGL_CONTEXT_PROXY_FALLBACK }}}) dbg('Specified canvas target "' + targetStr + '" is not an OffscreenCanvas in the current pthread, but EMSCRIPTEN_WEBGL_CONTEXT_PROXY_FALLBACK is set. Proxying WebGL rendering from pthread to main thread.'); + if (!canvas && contextAttributes.proxyContextToMainThread === {{{ cDefs.EMSCRIPTEN_WEBGL_CONTEXT_PROXY_FALLBACK }}}) dbg(`Specified canvas target "${targetStr}" is not an OffscreenCanvas in the current pthread, but EMSCRIPTEN_WEBGL_CONTEXT_PROXY_FALLBACK is set. Proxying WebGL rendering from pthread to main thread.`); dbg('Performance warning: forcing renderViaOffscreenBackBuffer=true and preserveDrawingBuffer=true since proxying WebGL rendering.'); #endif // We will be proxying - if OffscreenCanvas is supported, we can proxy a bit more efficiently by avoiding having to create an Offscreen FBO. @@ -132,7 +132,7 @@ var LibraryHtml5WebGL = { if (!canvas) { #if GL_DEBUG - dbg('emscripten_webgl_create_context failed: Unknown canvas target "' + targetStr + '"!'); + dbg(`emscripten_webgl_create_context failed: Unknown canvas target "${targetStr}"!`); #endif return 0; } @@ -141,8 +141,8 @@ var LibraryHtml5WebGL = { if (canvas.offscreenCanvas) canvas = canvas.offscreenCanvas; #if GL_DEBUG - if (typeof OffscreenCanvas != 'undefined' && canvas instanceof OffscreenCanvas) dbg('emscripten_webgl_create_context: Creating an OffscreenCanvas-based WebGL context on target "' + targetStr + '"'); - else if (typeof HTMLCanvasElement != 'undefined' && canvas instanceof HTMLCanvasElement) dbg('emscripten_webgl_create_context: Creating an HTMLCanvasElement-based WebGL context on target "' + targetStr + '"'); + if (typeof OffscreenCanvas != 'undefined' && canvas instanceof OffscreenCanvas) dbg(`emscripten_webgl_create_context: Creating an OffscreenCanvas-based WebGL context on target "${targetStr}"`); + else if (typeof HTMLCanvasElement != 'undefined' && canvas instanceof HTMLCanvasElement) dbg(`emscripten_webgl_create_context: Creating an HTMLCanvasElement-based WebGL context on target "${targetStr}"`); #endif if (contextAttributes.explicitSwapControl) { @@ -166,7 +166,7 @@ var LibraryHtml5WebGL = { if (canvas.transferControlToOffscreen) { #if GL_DEBUG - dbg('explicitSwapControl requested: canvas.transferControlToOffscreen() on canvas "' + targetStr + '" to get .commit() function and not rely on implicit WebGL swap'); + dbg(`explicitSwapControl requested: canvas.transferControlToOffscreen() on canvas "${targetStr}" to get .commit() function and not rely on implicit WebGL swap`); #endif if (!canvas.controlTransferredOffscreen) { GL.offscreenCanvases[canvas.id] = { @@ -177,7 +177,7 @@ var LibraryHtml5WebGL = { canvas.controlTransferredOffscreen = true; } else if (!GL.offscreenCanvases[canvas.id]) { #if GL_DEBUG - dbg('OffscreenCanvas is supported, and canvas "' + canvas.id + '" has already before been transferred offscreen, but there is no known OffscreenCanvas with that name!'); + dbg(`OffscreenCanvas is supported, and canvas "${canvas.id}" has already before been transferred offscreen, but there is no known OffscreenCanvas with that name!`); #endif return 0; } @@ -248,7 +248,7 @@ var LibraryHtml5WebGL = { emscripten_webgl_do_commit_frame: function() { #if TRACE_WEBGL_CALLS var threadId = (typeof _pthread_self != 'undefined') ? _pthread_self : function() { return 1; }; - err('[Thread ' + threadId() + ', GL ctx: ' + GL.currentContext.handle + ']: emscripten_webgl_do_commit_frame()'); + err(`[Thread ${threadId()}, GL ctx: ${GL.currentContext.handle}]: emscripten_webgl_do_commit_frame()`); #endif if (!GL.currentContext || !GL.currentContext.GLctx) { #if GL_DEBUG diff --git a/src/library_openal.js b/src/library_openal.js index 8248e62c2dbbf..029d2a7a81cb3 100644 --- a/src/library_openal.js +++ b/src/library_openal.js @@ -747,7 +747,7 @@ var LibraryOpenAL = { getGlobalParam: function(funcname, param) { if (!AL.currentCtx) { #if OPENAL_DEBUG - dbg(funcname + '() called without a valid context'); + dbg(`${funcname}() called without a valid context`); #endif return null; } @@ -761,7 +761,7 @@ var LibraryOpenAL = { return AL.currentCtx.distanceModel; default: #if OPENAL_DEBUG - dbg(`${funcname}() param ${ptrToString(param}`) + ' is unknown or not implemented'); + dbg(`${funcname}() param ${ptrToString(param} is unknown or not implemented`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return null; @@ -771,7 +771,7 @@ var LibraryOpenAL = { setGlobalParam: function(funcname, param, value) { if (!AL.currentCtx) { #if OPENAL_DEBUG - dbg(funcname + '() called without a valid context'); + dbg(`${funcname}() called without a valid context`); #endif return; } @@ -833,7 +833,7 @@ var LibraryOpenAL = { getListenerParam: function(funcname, param) { if (!AL.currentCtx) { #if OPENAL_DEBUG - dbg(funcname + '() called without a valid context'); + dbg(`${funcname}() called without a valid context`); #endif return null; } @@ -859,7 +859,7 @@ var LibraryOpenAL = { setListenerParam: function(funcname, param, value) { if (!AL.currentCtx) { #if OPENAL_DEBUG - dbg(funcname + '() called without a valid context'); + dbg(`${funcname}() called without a valid context`); #endif return; } @@ -943,14 +943,14 @@ var LibraryOpenAL = { getBufferParam: function(funcname, bufferId, param) { if (!AL.currentCtx) { #if OPENAL_DEBUG - dbg(funcname + '() called without a valid context'); + dbg(`${funcname}() called without a valid context`); #endif return; } var buf = AL.buffers[bufferId]; if (!buf || bufferId === 0) { #if OPENAL_DEBUG - dbg(funcname + '() called with an invalid buffer'); + dbg(`${funcname}() called with an invalid buffer`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_NAME }}}; return; @@ -985,14 +985,14 @@ var LibraryOpenAL = { setBufferParam: function(funcname, bufferId, param, value) { if (!AL.currentCtx) { #if OPENAL_DEBUG - dbg(funcname + '() called without a valid context'); + dbg(`${funcname}() called without a valid context`); #endif return; } var buf = AL.buffers[bufferId]; if (!buf || bufferId === 0) { #if OPENAL_DEBUG - dbg(funcname + '() called with an invalid buffer'); + dbg(`${funcname}() called with an invalid buffer`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_NAME }}}; return; @@ -1027,7 +1027,7 @@ var LibraryOpenAL = { } if (buf.refCount > 0) { #if OPENAL_DEBUG - dbg(funcname + '() param AL_LOOP_POINTS_SOFT set on bound buffer'); + dbg(`${funcname}() param AL_LOOP_POINTS_SOFT set on bound buffer`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_OPERATION }}}; return; @@ -1050,14 +1050,14 @@ var LibraryOpenAL = { getSourceParam: function(funcname, sourceId, param) { if (!AL.currentCtx) { #if OPENAL_DEBUG - dbg(funcname + '() called without a valid context'); + dbg(`${funcname}() called without a valid context`); #endif return null; } var src = AL.currentCtx.sources[sourceId]; if (!src) { #if OPENAL_DEBUG - dbg(funcname + '() called with an invalid source'); + dbg(`${funcname}() called with an invalid source`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_NAME }}}; return null; @@ -1161,7 +1161,7 @@ var LibraryOpenAL = { setSourceParam: function(funcname, sourceId, param, value) { if (!AL.currentCtx) { #if OPENAL_DEBUG - dbg(funcname + '() called without a valid context'); + dbg(`${funcname}() called without a valid context`); #endif return; } @@ -1312,7 +1312,7 @@ var LibraryOpenAL = { case 0x1009 /* AL_BUFFER */: if (src.state === {{{ cDefs.AL_PLAYING }}} || src.state === {{{ cDefs.AL_PAUSED }}}) { #if OPENAL_DEBUG - dbg(funcname + '(AL_BUFFER) called while source is playing or paused'); + dbg(`${funcname}(AL_BUFFER) called while source is playing or paused`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_OPERATION }}}; return; @@ -1511,7 +1511,7 @@ var LibraryOpenAL = { case 0x200A /* AL_SAMPLE_LENGTH_SOFT */: case 0x200B /* AL_SEC_LENGTH_SOFT */: #if OPENAL_DEBUG - dbg(funcname + '() param AL_*_LENGTH_SOFT is read only'); + dbg(`${funcname}() param AL_*_LENGTH_SOFT is read only`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_OPERATION }}}; break; @@ -1539,7 +1539,7 @@ var LibraryOpenAL = { break; default: #if OPENAL_DEBUG - dbg(`${funcname}() param ${ptrToString(param)}' is unknown or not implemented`); + dbg(`${funcname}() param ${ptrToString(param)} is unknown or not implemented`); #endif AL.currentCtx.err = {{{ cDefs.AL_INVALID_ENUM }}}; return; @@ -1622,7 +1622,7 @@ var LibraryOpenAL = { resolvedDeviceName = UTF8ToString(pDeviceName); if (resolvedDeviceName !== AL.CAPTURE_DEVICE_NAME) { #if OPENAL_DEBUG - dbg('alcCaptureOpenDevice() with invalid device name \''+resolvedDeviceName+'\''); + dbg(`alcCaptureOpenDevice() with invalid device name '${resolvedDeviceName}'`); #endif // ALC_OUT_OF_MEMORY // From the programmer's guide, ALC_OUT_OF_MEMORY's meaning is @@ -2015,7 +2015,7 @@ var LibraryOpenAL = { case 'u8' : setSample = setU8Sample ; break; default: #if OPENAL_DEBUG - dbg('Internal error: Unknown sample type \''+c.requestedSampleType+'\''); + dbg(`Internal error: Unknown sample type '${c.requestedSampleType}'`); #endif return; } diff --git a/src/library_pthread.js b/src/library_pthread.js index ab30f07a0409a..b652ede6558f2 100644 --- a/src/library_pthread.js +++ b/src/library_pthread.js @@ -1188,7 +1188,7 @@ var LibraryPThread = { } #if PTHREADS_DEBUG - dbg('_emscripten_dlsync_threads_async: waiting on ' + promises.length + ' promises'); + dbg(`_emscripten_dlsync_threads_async: waiting on ${promises.length} promises`); #endif // Once all promises are resolved then we know all threads are in sync and // we can call the callback. diff --git a/src/library_syscall.js b/src/library_syscall.js index 2365cd2352805..3a5d7694b6326 100644 --- a/src/library_syscall.js +++ b/src/library_syscall.js @@ -100,14 +100,14 @@ var SyscallsLibrary = { SYSCALLS.varargs += 4; var ret = {{{ makeGetValue('SYSCALLS.varargs', '-4', 'i32') }}}; #if SYSCALL_DEBUG - dbg(' (raw: "' + ret + '")'); + dbg(` (raw: "${ret}")`); #endif return ret; }, getStr: function(ptr) { var ret = UTF8ToString(ptr); #if SYSCALL_DEBUG - dbg(' (str: "' + ret + '")'); + dbg(` (str: "${ret}")`); #endif return ret; }, @@ -117,7 +117,7 @@ var SyscallsLibrary = { var stream = FS.getStream(fd); if (!stream) throw new FS.ErrnoError({{{ cDefs.EBADF }}}); #if SYSCALL_DEBUG - dbg(' (stream: "' + stream.path + '")'); + dbg(` (stream: "${stream.path}")`); #endif return stream; }, @@ -277,7 +277,7 @@ var SyscallsLibrary = { var socket = SOCKFS.getSocket(fd); if (!socket) throw new FS.ErrnoError({{{ cDefs.EBADF }}}); #if SYSCALL_DEBUG - dbg(' (socket: "' + socket.path + '")'); + dbg(` (socket: "${socket.path}")`); #endif return socket; }, @@ -419,13 +419,13 @@ var SyscallsLibrary = { // concatenate scatter-gather arrays into one message buffer var total = 0; for (var i = 0; i < num; i++) { - total += {{{ makeGetValue('iov', '(' + C_STRUCTS.iovec.__size__ + ' * i) + ' + C_STRUCTS.iovec.iov_len, 'i32') }}}; + total += {{{ makeGetValue('iov', `(${C_STRUCTS.iovec.__size__} * i) + ${C_STRUCTS.iovec.iov_len}`, 'i32') }}}; } var view = new Uint8Array(total); var offset = 0; for (var i = 0; i < num; i++) { - var iovbase = {{{ makeGetValue('iov', '(' + C_STRUCTS.iovec.__size__ + ' * i) + ' + C_STRUCTS.iovec.iov_base, POINTER_TYPE) }}}; - var iovlen = {{{ makeGetValue('iov', '(' + C_STRUCTS.iovec.__size__ + ' * i) + ' + C_STRUCTS.iovec.iov_len, 'i32') }}}; + var iovbase = {{{ makeGetValue('iov', `(${C_STRUCTS.iovec.__size__} * i) + ${C_STRUCTS.iovec.iov_base}`, POINTER_TYPE) }}}; + var iovlen = {{{ makeGetValue('iov', `(${C_STRUCTS.iovec.__size__} * i) + ${C_STRUCTS.iovec.iov_len}`, 'i32') }}}; for (var j = 0; j < iovlen; j++) { view[offset++] = {{{ makeGetValue('iovbase', 'j', 'i8') }}}; } @@ -441,7 +441,7 @@ var SyscallsLibrary = { // get the total amount of data we can read across all arrays var total = 0; for (var i = 0; i < num; i++) { - total += {{{ makeGetValue('iov', '(' + C_STRUCTS.iovec.__size__ + ' * i) + ' + C_STRUCTS.iovec.iov_len, 'i32') }}}; + total += {{{ makeGetValue('iov', `(${C_STRUCTS.iovec.__size__} * i) + ${C_STRUCTS.iovec.iov_len}`, 'i32') }}}; } // try to read total data var msg = sock.sock_ops.recvmsg(sock, total); @@ -467,8 +467,8 @@ var SyscallsLibrary = { var bytesRead = 0; var bytesRemaining = msg.buffer.byteLength; for (var i = 0; bytesRemaining > 0 && i < num; i++) { - var iovbase = {{{ makeGetValue('iov', '(' + C_STRUCTS.iovec.__size__ + ' * i) + ' + C_STRUCTS.iovec.iov_base, POINTER_TYPE) }}}; - var iovlen = {{{ makeGetValue('iov', '(' + C_STRUCTS.iovec.__size__ + ' * i) + ' + C_STRUCTS.iovec.iov_len, 'i32') }}}; + var iovbase = {{{ makeGetValue('iov', `(${C_STRUCTS.iovec.__size__} * i) + ${C_STRUCTS.iovec.iov_base}`, POINTER_TYPE) }}}; + var iovlen = {{{ makeGetValue('iov', `(${C_STRUCTS.iovec.__size__} * i) + ${C_STRUCTS.iovec.iov_len}`, 'i32') }}}; if (!iovlen) { continue; } @@ -744,7 +744,7 @@ var SyscallsLibrary = { return -1; default: { #if SYSCALL_DEBUG - dbg('warning: fcntl unrecognized command ' + cmd); + dbg(`warning: fcntl unrecognized command ${cmd}`); #endif return -{{{ cDefs.EINVAL }}}; } @@ -839,7 +839,7 @@ var SyscallsLibrary = { var allowEmpty = flags & {{{ cDefs.AT_EMPTY_PATH }}}; flags = flags & (~{{{ cDefs.AT_SYMLINK_NOFOLLOW | cDefs.AT_EMPTY_PATH | cDefs.AT_NO_AUTOMOUNT }}}); #if ASSERTIONS - assert(!flags, 'unknown flags in __syscall_newfstatat: ' + flags); + assert(!flags, `unknown flags in __syscall_newfstatat: ${flags}`); #endif path = SYSCALLS.calculateAt(dirfd, path, allowEmpty); return SYSCALLS.doStat(nofollow ? FS.lstat : FS.stat, path, buf); diff --git a/src/library_wasi.js b/src/library_wasi.js index 4d7d7c16271a0..71d26ddc691c4 100644 --- a/src/library_wasi.js +++ b/src/library_wasi.js @@ -9,7 +9,7 @@ var WasiLibrary = { $ExitStatus__docs: '/** @constructor */', $ExitStatus: function(status) { this.name = 'ExitStatus'; - this.message = 'Program terminated with exit(' + status + ')'; + this.message = `Program terminated with exit(${status})`; this.status = status; }, proc_exit__deps: ['$ExitStatus'], @@ -18,10 +18,10 @@ var WasiLibrary = { proc_exit__nothrow: true, proc_exit: function(code) { #if MINIMAL_RUNTIME - throw 'exit(' + code + ')'; + throw `exit(${code})`; #else #if RUNTIME_DEBUG - dbg('proc_exit: ' + code); + dbg(`proc_exit: ${code}`); #endif EXITSTATUS = code; if (!keepRuntimeAlive()) { @@ -80,7 +80,7 @@ var WasiLibrary = { } var strings = []; for (var x in env) { - strings.push(x + '=' + env[x]); + strings.push(`${x}=${env[x]}`); } getEnvStrings.strings = strings; } @@ -383,7 +383,7 @@ var WasiLibrary = { $wasiRightsToMuslOFlags: function(rights) { #if SYSCALL_DEBUG - dbg('wasiRightsToMuslOFlags: ' + rights); + dbg(`wasiRightsToMuslOFlags: ${rights}`); #endif if ((rights & {{{ cDefs.__WASI_RIGHTS_FD_READ }}}) && (rights & {{{ cDefs.__WASI_RIGHTS_FD_WRITE }}})) { return {{{ cDefs.O_RDWR }}}; @@ -431,11 +431,11 @@ var WasiLibrary = { var pathname = UTF8ToString(path, path_len); var musl_oflags = wasiRightsToMuslOFlags(Number(fs_rights_base)); #if SYSCALL_DEBUG - dbg("oflags1: 0x" + musl_oflags.toString(16)); + dbg(`oflags1: ${ptrToString(musl_oflags)}`); #endif musl_oflags |= wasiOFlagsToMuslOFlags(Number(oflags)); #if SYSCALL_DEBUG - dbg("oflags2: 0x" + musl_oflags.toString(16)); + dbg(`oflags2: ${ptrToString(musl_oflags)}`); #endif var stream = FS.open(pathname, musl_oflags); {{{ makeSetValue('opened_fd', '0', 'stream.fd', 'i32') }}}; @@ -452,7 +452,7 @@ var WasiLibrary = { var preopen_path = preopens[fd]; stringToUTF8Array(preopen_path, HEAP8, path, path_len) #if SYSCALL_DEBUG - dbg('fd_prestat_dir_name -> "' + preopen_path + '"'); + dbg(`fd_prestat_dir_name -> "${preopen_path}"`); #endif return 0; }, diff --git a/src/library_websocket.js b/src/library_websocket.js index 736894584247f..c824644bc3a7e 100644 --- a/src/library_websocket.js +++ b/src/library_websocket.js @@ -16,7 +16,7 @@ var LibraryWebSocket = { var socket = WS.sockets[socketId]; if (!socket) { #if WEBSOCKET_DEBUG - dbg('emscripten_websocket_get_ready_state(): Invalid socket ID ' + socketId + ' specified!'); + dbg(`emscripten_websocket_get_ready_state(): Invalid socket ID ${socketId} specified!`); #endif return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}}; } @@ -31,7 +31,7 @@ var LibraryWebSocket = { var socket = WS.sockets[socketId]; if (!socket) { #if WEBSOCKET_DEBUG - dbg('emscripten_websocket_get_buffered_amount(): Invalid socket ID ' + socketId + ' specified!'); + dbg(`emscripten_websocket_get_buffered_amount(): Invalid socket ID ${socketId} specified!`); #endif return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}}; } @@ -46,7 +46,7 @@ var LibraryWebSocket = { var socket = WS.sockets[socketId]; if (!socket) { #if WEBSOCKET_DEBUG - dbg('emscripten_websocket_get_extensions(): Invalid socket ID ' + socketId + ' specified!'); + dbg(`emscripten_websocket_get_extensions(): Invalid socket ID ${socketId} specified!`); #endif return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}}; } @@ -61,7 +61,7 @@ var LibraryWebSocket = { var socket = WS.sockets[socketId]; if (!socket) { #if WEBSOCKET_DEBUG - dbg('emscripten_websocket_get_extensions_length(): Invalid socket ID ' + socketId + ' specified!'); + dbg(`emscripten_websocket_get_extensions_length(): Invalid socket ID ${socketId} specified!`); #endif return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}}; } @@ -76,7 +76,7 @@ var LibraryWebSocket = { var socket = WS.sockets[socketId]; if (!socket) { #if WEBSOCKET_DEBUG - dbg('emscripten_websocket_get_protocol(): Invalid socket ID ' + socketId + ' specified!'); + dbg(`emscripten_websocket_get_protocol(): Invalid socket ID ${socketId} specified!`); #endif return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}}; } @@ -91,7 +91,7 @@ var LibraryWebSocket = { var socket = WS.sockets[socketId]; if (!socket) { #if WEBSOCKET_DEBUG - dbg('emscripten_websocket_get_protocol_length(): Invalid socket ID ' + socketId + ' specified!'); + dbg(`emscripten_websocket_get_protocol_length(): Invalid socket ID ${socketId} specified!`); #endif return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}}; } @@ -106,7 +106,7 @@ var LibraryWebSocket = { var socket = WS.sockets[socketId]; if (!socket) { #if WEBSOCKET_DEBUG - dbg('emscripten_websocket_get_url(): Invalid socket ID ' + socketId + ' specified!'); + dbg(`emscripten_websocket_get_url(): Invalid socket ID ${socketId} specified!`); #endif return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}}; } @@ -121,7 +121,7 @@ var LibraryWebSocket = { var socket = WS.sockets[socketId]; if (!socket) { #if WEBSOCKET_DEBUG - dbg('emscripten_websocket_get_url_length(): Invalid socket ID ' + socketId + ' specified!'); + dbg(`emscripten_websocket_get_url_length(): Invalid socket ID ${socketId} specified!`); #endif return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}}; } @@ -142,17 +142,17 @@ var LibraryWebSocket = { var socket = WS.sockets[socketId]; if (!socket) { #if WEBSOCKET_DEBUG - dbg('emscripten_websocket_set_onopen_callback(): Invalid socket ID ' + socketId + ' specified!'); + dbg(`emscripten_websocket_set_onopen_callback(): Invalid socket ID ${socketId} specified!`); #endif return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}}; } #if WEBSOCKET_DEBUG - dbg('emscripten_websocket_set_onopen_callback(socketId='+socketId+',userData='+userData+',callbackFunc='+callbackFunc+')'); + dbg(`emscripten_websocket_set_onopen_callback(socketId=${socketId},userData=${userData},callbackFunc='+callbackFunc})`); #endif socket.onopen = function(e) { #if WEBSOCKET_DEBUG - dbg('websocket event "open": socketId='+socketId+',userData='+userData+',callbackFunc='+callbackFunc+')'); + dbg(`websocket event "open": socketId=${socketId},userData=${userData},callbackFunc=${callbackFunc})`); #endif HEAPU32[WS.socketEvent>>2] = socketId; {{{ makeDynCall('iiii', 'callbackFunc') }}}(0/*TODO*/, WS.socketEvent, userData); @@ -168,17 +168,17 @@ var LibraryWebSocket = { var socket = WS.sockets[socketId]; if (!socket) { #if WEBSOCKET_DEBUG - dbg('emscripten_websocket_set_onerror_callback(): Invalid socket ID ' + socketId + ' specified!'); + dbg(`emscripten_websocket_set_onerror_callback(): Invalid socket ID ${socketId} specified!`); #endif return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}}; } #if WEBSOCKET_DEBUG - dbg('emscripten_websocket_set_onerror_callback(socketId='+socketId+',userData='+userData+',callbackFunc='+callbackFunc+')'); + dbg(`emscripten_websocket_set_onerror_callback(socketId=${socketId},userData=${userData},callbackFunc=${callbackFunc})`); #endif socket.onerror = function(e) { #if WEBSOCKET_DEBUG - dbg('websocket event "error": socketId='+socketId+',userData='+userData+',callbackFunc='+callbackFunc+')'); + dbg(`websocket event "error": socketId=${socketId},userData=${userData},callbackFunc=${callbackFunc})`); #endif HEAPU32[WS.socketEvent>>2] = socketId; {{{ makeDynCall('iiii', 'callbackFunc') }}}(0/*TODO*/, WS.socketEvent, userData); @@ -194,17 +194,17 @@ var LibraryWebSocket = { var socket = WS.sockets[socketId]; if (!socket) { #if WEBSOCKET_DEBUG - dbg('emscripten_websocket_set_onclose_callback(): Invalid socket ID ' + socketId + ' specified!'); + dbg(`emscripten_websocket_set_onclose_callback(): Invalid socket ID ${socketId} specified!`); #endif return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}}; } #if WEBSOCKET_DEBUG - dbg('emscripten_websocket_set_onclose_callback(socketId='+socketId+',userData='+userData+',callbackFunc='+callbackFunc+')'); + dbg(`emscripten_websocket_set_onclose_callback(socketId=${socketId},userData=${userData},callbackFunc=${callbackFunc})`); #endif socket.onclose = function(e) { #if WEBSOCKET_DEBUG - dbg('websocket event "close": socketId='+socketId+',userData='+userData+',callbackFunc='+callbackFunc+')'); + dbg(`websocket event "close": socketId=${socketId},userData=${userData},callbackFunc=${callbackFunc})`); #endif HEAPU32[WS.socketEvent>>2] = socketId; HEAPU32[(WS.socketEvent+4)>>2] = e.wasClean; @@ -223,25 +223,25 @@ var LibraryWebSocket = { var socket = WS.sockets[socketId]; if (!socket) { #if WEBSOCKET_DEBUG - dbg('emscripten_websocket_set_onmessage_callback(): Invalid socket ID ' + socketId + ' specified!'); + dbg(`emscripten_websocket_set_onmessage_callback(): Invalid socket ID ${socketId} specified!`); #endif return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}}; } #if WEBSOCKET_DEBUG - dbg('emscripten_websocket_set_onmessage_callback(socketId='+socketId+',userData='+userData+',callbackFunc='+callbackFunc+')'); + dbg(`emscripten_websocket_set_onmessage_callback(socketId=${socketId},userData=${userData},callbackFunc=${callbackFunc})`); #endif socket.onmessage = function(e) { #if WEBSOCKET_DEBUG == 2 - dbg('websocket event "message": socketId='+socketId+',userData='+userData+',callbackFunc='+callbackFunc+')'); + dbg(`websocket event "message": socketId=${socketId},userData=${userData},callbackFunc=${callbackFunc})`); #endif HEAPU32[WS.socketEvent>>2] = socketId; if (typeof e.data == 'string') { var buf = stringToNewUTF8(e.data); var len = lengthBytesUTF8(e.data)+1; #if WEBSOCKET_DEBUG - var s = (e.data.length < 256) ? e.data : (e.data.substr(0, 256) + ' (' + (e.data.length-256) + ' more characters)'); - dbg('WebSocket onmessage, received data: "' + e.data + '", ' + e.data.length + ' chars, ' + len + ' bytes encoded as UTF-8: "' + s + '"'); + var s = (e.data.length < 256) ? e.data : (e.data.substr(0, 256) + ` (${e.data.length-256} more characters)`); + dbg(`WebSocket onmessage, received data: "${e.data}", ${e.data.length} chars, ${len} bytes encoded as UTF-8: "${s}"`); #endif HEAPU32[(WS.socketEvent+12)>>2] = 1; // text data } else { @@ -249,12 +249,12 @@ var LibraryWebSocket = { var buf = _malloc(len); HEAP8.set(new Uint8Array(e.data), buf); #if WEBSOCKET_DEBUG - var s = 'WebSocket onmessage, received data: ' + len + ' bytes of binary:'; + var s = `WebSocket onmessage, received data: ${len} bytes of binary:`; for (var i = 0; i < Math.min(len, 256); ++i) s += ' ' + HEAPU8[buf+i].toString(16); s += ', "'; for (var i = 0; i < Math.min(len, 256); ++i) s += (HEAPU8[buf+i] >= 32 && HEAPU8[buf+i] <= 127) ? String.fromCharCode(HEAPU8[buf+i]) : '\uFFFD'; s += '"'; - if (len > 256) s + ' ... (' + (len - 256) + ' more bytes)'; + if (len > 256) s + ` ... (${len - 256} more bytes)`; dbg(s); #endif @@ -298,7 +298,7 @@ var LibraryWebSocket = { WS.sockets[socketId] = socket; #if WEBSOCKET_DEBUG - dbg('emscripten_websocket_new(url='+url+', protocols=' + (protocols?UTF8ToString(protocols).split(','):'null') + '): created socket ID ' + socketId + ')'); + dbg(`emscripten_websocket_new(url=${url}, protocols=${protocols ? UTF8ToString(protocols).split(',') : 'null'}): created socket ID ${socketId})`); #endif return socketId; }, @@ -309,17 +309,17 @@ var LibraryWebSocket = { var socket = WS.sockets[socketId]; if (!socket) { #if WEBSOCKET_DEBUG - dbg('emscripten_websocket_send_utf8_text(): Invalid socket ID ' + socketId + ' specified!'); + dbg(`emscripten_websocket_send_utf8_text(): Invalid socket ID ${socketId} specified!`); #endif return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}}; } var str = UTF8ToString(textData); #if WEBSOCKET_DEBUG == 2 - dbg('emscripten_websocket_send_utf8_text(socketId='+socketId+',textData='+ str.length + ' chars, "' + str +'")'); + dbg(`emscripten_websocket_send_utf8_text(socketId=${socketId},textData=${str.length} chars, "${str}")`); #else #if WEBSOCKET_DEBUG - dbg('emscripten_websocket_send_utf8_text(socketId='+socketId+',textData='+ str.length + ' chars, "' + ((str.length > 8) ? (str.substring(0,8) + '...') : str) + '")'); + dbg(`emscripten_websocket_send_utf8_text(socketId=${socketId},textData=${str.length} ' chars, "${(str.length > 8) ? (str.substring(0,8) + '...') : str}")`); #endif #endif socket.send(str); @@ -332,20 +332,20 @@ var LibraryWebSocket = { var socket = WS.sockets[socketId]; if (!socket) { #if WEBSOCKET_DEBUG - dbg('emscripten_websocket_send_binary(): Invalid socket ID ' + socketId + ' specified!'); + dbg(`emscripten_websocket_send_binary(): Invalid socket ID ${socketId} specified!`); #endif return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}}; } #if WEBSOCKET_DEBUG - var s = 'data: ' + dataLength + ' bytes of binary:'; + var s = `data: ${dataLength} bytes of binary:`; for (var i = 0; i < Math.min(dataLength, 256); ++i) s += ' '+ HEAPU8[binaryData+i].toString(16); s += ', "'; for (var i = 0; i < Math.min(dataLength, 256); ++i) s += (HEAPU8[binaryData+i] >= 32 && HEAPU8[binaryData+i] <= 127) ? String.fromCharCode(HEAPU8[binaryData+i]) : '\uFFFD'; s += '"'; - if (dataLength > 256) s + ' ... (' + (dataLength - 256) + ' more bytes)'; + if (dataLength > 256) s + ` ... (${dataLength - 256} more bytes)`; - dbg('emscripten_websocket_send_binary(socketId='+socketId+',binaryData='+binaryData+ ',dataLength='+dataLength+'), ' + s); + dbg(`emscripten_websocket_send_binary(socketId=${socketId},binaryData=${binaryData},dataLength=${dataLength}), ${s}`); #endif #if SHARED_MEMORY // TODO: This is temporary to cast a shared Uint8Array to a non-shared Uint8Array. This could be removed if WebSocket API is improved @@ -363,14 +363,14 @@ var LibraryWebSocket = { var socket = WS.sockets[socketId]; if (!socket) { #if WEBSOCKET_DEBUG - dbg('emscripten_websocket_close(): Invalid socket ID ' + socketId + ' specified!'); + dbg(`emscripten_websocket_close(): Invalid socket ID ${socketId} specified!`); #endif return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}}; } var reasonStr = reason ? UTF8ToString(reason) : undefined; #if WEBSOCKET_DEBUG - dbg('emscripten_websocket_close(socketId='+socketId+',code='+code+',reason='+reasonStr+')'); + dbg(`emscripten_websocket_close(socketId=${socketId},code=${code},reason=${reasonStr})`); #endif // According to WebSocket specification, only close codes that are recognized have integer values // 1000-4999, with 3000-3999 and 4000-4999 denoting user-specified close codes: @@ -389,13 +389,13 @@ var LibraryWebSocket = { var socket = WS.sockets[socketId]; if (!socket) { #if WEBSOCKET_DEBUG - dbg('emscripten_websocket_delete(): Invalid socket ID ' + socketId + ' specified!'); + dbg(`emscripten_websocket_delete(): Invalid socket ID ${socketId} specified!`); #endif return {{{ cDefs.EMSCRIPTEN_RESULT_INVALID_TARGET }}}; } #if WEBSOCKET_DEBUG - dbg('emscripten_websocket_delete(socketId='+socketId+')'); + dbg(`emscripten_websocket_delete(socketId=${socketId})`); #endif socket.onopen = socket.onerror = socket.onclose = socket.onmessage = null; delete WS.sockets[socketId]; diff --git a/src/runtime_stack_check.js b/src/runtime_stack_check.js index f38c7a45f42ee..87fbd455e748b 100644 --- a/src/runtime_stack_check.js +++ b/src/runtime_stack_check.js @@ -9,7 +9,7 @@ function writeStackCookie() { var max = _emscripten_stack_get_end(); #if RUNTIME_DEBUG - dbg('writeStackCookie: ' + max.toString(16)); + dbg(`writeStackCookie: ${ptrToString(max)}`); #endif #if ASSERTIONS assert((max & 3) == 0); @@ -37,7 +37,7 @@ function checkStackCookie() { #endif var max = _emscripten_stack_get_end(); #if RUNTIME_DEBUG - dbg('checkStackCookie: ' + max.toString(16)); + dbg(`checkStackCookie: ${ptrToString(max)}`); #endif // See writeStackCookie(). if (max == 0) { @@ -46,7 +46,7 @@ function checkStackCookie() { var cookie1 = {{{ makeGetValue('max', 0, 'u32') }}}; var cookie2 = {{{ makeGetValue('max', 4, 'u32') }}}; if (cookie1 != 0x02135467 || cookie2 != 0x89BACDFE) { - abort('Stack overflow! Stack cookie has been overwritten at ' + ptrToString(max) + ', expected hex dwords 0x89BACDFE and 0x2135467, but received ' + ptrToString(cookie2) + ' ' + ptrToString(cookie1)); + abort(`Stack overflow! Stack cookie has been overwritten at ${ptrToString(max)}, expected hex dwords 0x89BACDFE and 0x2135467, but received ${ptrToString(cookie2)} ${ptrToString(cookie1)}`); } #if !USE_ASAN && !SAFE_HEAP // ASan and SAFE_HEAP check address 0 themselves // Also test the global address 0 for integrity. diff --git a/src/worker.js b/src/worker.js index 7d653fb0505f5..2ea3d308e9726 100644 --- a/src/worker.js +++ b/src/worker.js @@ -231,7 +231,7 @@ function handleMessage(e) { if (!initializedJS) { #if EMBIND #if PTHREADS_DEBUG - dbg('Pthread 0x' + Module['_pthread_self']().toString(16) + ' initializing embind.'); + dbg(`Pthread 0x${Module['_pthread_self']().toString(16)} initializing embind.`); #endif // Embind must initialize itself on all threads, as it generates support JS. // We only do this once per worker since they get reused @@ -250,7 +250,7 @@ function handleMessage(e) { throw ex; } #if RUNTIME_DEBUG - dbg('Pthread 0x' + Module['_pthread_self']().toString(16) + ' completed its main entry point with an `unwind`, keeping the worker alive for asynchronous operation.'); + dbg(`Pthread 0x${Module['_pthread_self']().toString(16)} completed its main entry point with an 'unwind', keeping the worker alive for asynchronous operation.`); #endif } } else if (e.data.cmd === 'cancel') { // Main thread is asking for a pthread_cancel() on this thread. diff --git a/test/other/metadce/test_metadce_cxx_ctors1.jssize b/test/other/metadce/test_metadce_cxx_ctors1.jssize index b7e08511e13c3..eea1943fcbc9c 100644 --- a/test/other/metadce/test_metadce_cxx_ctors1.jssize +++ b/test/other/metadce/test_metadce_cxx_ctors1.jssize @@ -1 +1 @@ -25948 +25951 diff --git a/test/other/metadce/test_metadce_cxx_ctors2.jssize b/test/other/metadce/test_metadce_cxx_ctors2.jssize index 5c59d01da814e..ad25afec9bd0f 100644 --- a/test/other/metadce/test_metadce_cxx_ctors2.jssize +++ b/test/other/metadce/test_metadce_cxx_ctors2.jssize @@ -1 +1 @@ -25912 +25915 diff --git a/test/other/metadce/test_metadce_cxx_except.jssize b/test/other/metadce/test_metadce_cxx_except.jssize index 3bd99284499e0..06894f9ebcd20 100644 --- a/test/other/metadce/test_metadce_cxx_except.jssize +++ b/test/other/metadce/test_metadce_cxx_except.jssize @@ -1 +1 @@ -30462 +30465 diff --git a/test/other/metadce/test_metadce_cxx_except_wasm.jssize b/test/other/metadce/test_metadce_cxx_except_wasm.jssize index dabbf8a07d891..df6c1c2881565 100644 --- a/test/other/metadce/test_metadce_cxx_except_wasm.jssize +++ b/test/other/metadce/test_metadce_cxx_except_wasm.jssize @@ -1 +1 @@ -25757 +25760 diff --git a/test/other/metadce/test_metadce_cxx_mangle.jssize b/test/other/metadce/test_metadce_cxx_mangle.jssize index 74bf7aad77fdc..9ad174d57612b 100644 --- a/test/other/metadce/test_metadce_cxx_mangle.jssize +++ b/test/other/metadce/test_metadce_cxx_mangle.jssize @@ -1 +1 @@ -30461 +30464 diff --git a/test/other/metadce/test_metadce_cxx_noexcept.jssize b/test/other/metadce/test_metadce_cxx_noexcept.jssize index b7e08511e13c3..eea1943fcbc9c 100644 --- a/test/other/metadce/test_metadce_cxx_noexcept.jssize +++ b/test/other/metadce/test_metadce_cxx_noexcept.jssize @@ -1 +1 @@ -25948 +25951 diff --git a/test/other/metadce/test_metadce_hello_O0.jssize b/test/other/metadce/test_metadce_hello_O0.jssize index 6b5b7088d354d..c03b18578f88b 100644 --- a/test/other/metadce/test_metadce_hello_O0.jssize +++ b/test/other/metadce/test_metadce_hello_O0.jssize @@ -1 +1 @@ -23843 +23828 diff --git a/test/other/metadce/test_metadce_hello_O1.jssize b/test/other/metadce/test_metadce_hello_O1.jssize index 1c35f29ce93d9..8d7a41cfdf9a7 100644 --- a/test/other/metadce/test_metadce_hello_O1.jssize +++ b/test/other/metadce/test_metadce_hello_O1.jssize @@ -1 +1 @@ -8365 +8360 diff --git a/test/other/metadce/test_metadce_hello_O2.jssize b/test/other/metadce/test_metadce_hello_O2.jssize index ae46500945d0d..638de7309a0eb 100644 --- a/test/other/metadce/test_metadce_hello_O2.jssize +++ b/test/other/metadce/test_metadce_hello_O2.jssize @@ -1 +1 @@ -5945 +5944 diff --git a/test/other/metadce/test_metadce_hello_O3.jssize b/test/other/metadce/test_metadce_hello_O3.jssize index 7974cb622864c..f6cc210c14d5d 100644 --- a/test/other/metadce/test_metadce_hello_O3.jssize +++ b/test/other/metadce/test_metadce_hello_O3.jssize @@ -1 +1 @@ -5771 +5770 diff --git a/test/other/metadce/test_metadce_hello_Os.jssize b/test/other/metadce/test_metadce_hello_Os.jssize index 7974cb622864c..f6cc210c14d5d 100644 --- a/test/other/metadce/test_metadce_hello_Os.jssize +++ b/test/other/metadce/test_metadce_hello_Os.jssize @@ -1 +1 @@ -5771 +5770 diff --git a/test/other/metadce/test_metadce_hello_Oz.jssize b/test/other/metadce/test_metadce_hello_Oz.jssize index bb28ca38928b1..07176ad9c13dc 100644 --- a/test/other/metadce/test_metadce_hello_Oz.jssize +++ b/test/other/metadce/test_metadce_hello_Oz.jssize @@ -1 +1 @@ -5730 +5729 diff --git a/test/other/metadce/test_metadce_hello_dylink.jssize b/test/other/metadce/test_metadce_hello_dylink.jssize index d7c41b7d32c0c..22327905f9c6a 100644 --- a/test/other/metadce/test_metadce_hello_dylink.jssize +++ b/test/other/metadce/test_metadce_hello_dylink.jssize @@ -1 +1 @@ -15023 +15022 diff --git a/test/other/metadce/test_metadce_libcxxabi_message_O3.jssize b/test/other/metadce/test_metadce_libcxxabi_message_O3.jssize index 2e3f3cf6bd9e6..89810b1541216 100644 --- a/test/other/metadce/test_metadce_libcxxabi_message_O3.jssize +++ b/test/other/metadce/test_metadce_libcxxabi_message_O3.jssize @@ -1 +1 @@ -5041 +5040 diff --git a/test/other/metadce/test_metadce_libcxxabi_message_O3_standalone.jssize b/test/other/metadce/test_metadce_libcxxabi_message_O3_standalone.jssize index f00811b24122b..800920fac0dbc 100644 --- a/test/other/metadce/test_metadce_libcxxabi_message_O3_standalone.jssize +++ b/test/other/metadce/test_metadce_libcxxabi_message_O3_standalone.jssize @@ -1 +1 @@ -5109 +5108 diff --git a/test/other/metadce/test_metadce_mem_O3.jssize b/test/other/metadce/test_metadce_mem_O3.jssize index 6bb6c758c86e7..a37e2a8309c39 100644 --- a/test/other/metadce/test_metadce_mem_O3.jssize +++ b/test/other/metadce/test_metadce_mem_O3.jssize @@ -1 +1 @@ -5981 +5980 diff --git a/test/other/metadce/test_metadce_mem_O3_grow.jssize b/test/other/metadce/test_metadce_mem_O3_grow.jssize index 9e39e40188fb3..21faf3262f93b 100644 --- a/test/other/metadce/test_metadce_mem_O3_grow.jssize +++ b/test/other/metadce/test_metadce_mem_O3_grow.jssize @@ -1 +1 @@ -6317 +6316 diff --git a/test/other/metadce/test_metadce_mem_O3_grow_standalone.jssize b/test/other/metadce/test_metadce_mem_O3_grow_standalone.jssize index 500e5046a5549..1e587493b7d85 100644 --- a/test/other/metadce/test_metadce_mem_O3_grow_standalone.jssize +++ b/test/other/metadce/test_metadce_mem_O3_grow_standalone.jssize @@ -1 +1 @@ -5707 +5706 diff --git a/test/other/metadce/test_metadce_mem_O3_standalone.jssize b/test/other/metadce/test_metadce_mem_O3_standalone.jssize index 92048a505a35e..142e175a948df 100644 --- a/test/other/metadce/test_metadce_mem_O3_standalone.jssize +++ b/test/other/metadce/test_metadce_mem_O3_standalone.jssize @@ -1 +1 @@ -5629 +5628 diff --git a/test/other/metadce/test_metadce_mem_O3_standalone_narg.jssize b/test/other/metadce/test_metadce_mem_O3_standalone_narg.jssize index f00811b24122b..800920fac0dbc 100644 --- a/test/other/metadce/test_metadce_mem_O3_standalone_narg.jssize +++ b/test/other/metadce/test_metadce_mem_O3_standalone_narg.jssize @@ -1 +1 @@ -5109 +5108 diff --git a/test/other/metadce/test_metadce_mem_O3_standalone_narg_flto.jssize b/test/other/metadce/test_metadce_mem_O3_standalone_narg_flto.jssize index f00811b24122b..800920fac0dbc 100644 --- a/test/other/metadce/test_metadce_mem_O3_standalone_narg_flto.jssize +++ b/test/other/metadce/test_metadce_mem_O3_standalone_narg_flto.jssize @@ -1 +1 @@ -5109 +5108 diff --git a/test/other/metadce/test_metadce_minimal_O0.jssize b/test/other/metadce/test_metadce_minimal_O0.jssize index 841285e9cb5f4..07037931b8d2a 100644 --- a/test/other/metadce/test_metadce_minimal_O0.jssize +++ b/test/other/metadce/test_metadce_minimal_O0.jssize @@ -1 +1 @@ -20092 +20082 diff --git a/test/other/metadce/test_metadce_minimal_pthreads.jssize b/test/other/metadce/test_metadce_minimal_pthreads.jssize index 51cd2147d6059..ac12ab7bdaaaf 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.jssize +++ b/test/other/metadce/test_metadce_minimal_pthreads.jssize @@ -1 +1 @@ -15456 +15455 diff --git a/test/other/test_unoptimized_code_size.js.size b/test/other/test_unoptimized_code_size.js.size index 068c130d5b5bd..e07df7bc51fa5 100644 --- a/test/other/test_unoptimized_code_size.js.size +++ b/test/other/test_unoptimized_code_size.js.size @@ -1 +1 @@ -59629 +59614 diff --git a/test/other/test_unoptimized_code_size_no_asserts.js.size b/test/other/test_unoptimized_code_size_no_asserts.js.size index 2a7a3ea68f817..152491c03fc16 100644 --- a/test/other/test_unoptimized_code_size_no_asserts.js.size +++ b/test/other/test_unoptimized_code_size_no_asserts.js.size @@ -1 +1 @@ -33255 +33250 diff --git a/test/other/test_unoptimized_code_size_strict.js.size b/test/other/test_unoptimized_code_size_strict.js.size index bf3a0db19d3b5..693120d11bc44 100644 --- a/test/other/test_unoptimized_code_size_strict.js.size +++ b/test/other/test_unoptimized_code_size_strict.js.size @@ -1 +1 @@ -58571 +58556 From ceb2e284a2a714d9261ccb8d8721e5f92bb3cde7 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 25 May 2023 23:14:34 -0700 Subject: [PATCH 0294/1523] Share side modules with worker threads via postMessage (#19390) Any side modules that are loaded at the time of worker creation are shared with the worker via the initial postMessage. As a followup we should extend this to modules that are loaded after the worker is created but before the pthread runs (for example when a module is loaded while a worker is unused). Fixes: #18552 --- src/library_dylink.js | 40 +++++++++++++++---- src/library_pthread.js | 5 ++- src/postamble.js | 6 +++ src/worker.js | 5 ++- .../metadce/test_metadce_hello_dylink.jssize | 2 +- test/test_core.py | 32 +++++++++------ test/test_other.py | 10 ++++- 7 files changed, 75 insertions(+), 25 deletions(-) diff --git a/src/library_dylink.js b/src/library_dylink.js index 63e98421e1dcc..d7676cdc2036e 100644 --- a/src/library_dylink.js +++ b/src/library_dylink.js @@ -25,7 +25,7 @@ var LibraryDylink = { // than just running the promises in parallel, this makes a chain of // promises to run in series. wasmPlugin['promiseChainEnd'] = wasmPlugin['promiseChainEnd'].then( - () => loadWebAssemblyModule(byteArray, {loadAsync: true, nodelete: true})).then( + () => loadWebAssemblyModule(byteArray, {loadAsync: true, nodelete: true}, name)).then( (exports) => { #if DYLINK_DEBUG dbg(`registering preloadedWasm: ${name}`); @@ -618,6 +618,7 @@ var LibraryDylink = { // promise that resolves to its exports if the loadAsync flag is set. $loadWebAssemblyModule__docs: ` /** + * @param {string=} libName * @param {Object=} localScope * @param {number=} handle */`, @@ -629,7 +630,10 @@ var LibraryDylink = { '$currentModuleWeakSymbols', '$alignMemory', '$zeroMemory', '$updateTableMap', ], - $loadWebAssemblyModule: function(binary, flags, localScope, handle) { + $loadWebAssemblyModule: function(binary, flags, libName, localScope, handle) { +#if DYLINK_DEBUG + dbg(`loadWebAssemblyModule: ${libName}`); +#endif var metadata = getDylinkMetadata(binary); currentModuleWeakSymbols = metadata.weakImports; #if ASSERTIONS @@ -752,10 +756,20 @@ var LibraryDylink = { '{{{ WASI_MODULE_NAME }}}': proxy, }; - function postInstantiation(instance) { + function postInstantiation(module, instance) { #if ASSERTIONS // the table should be unchanged assert(wasmTable === originalTable); +#endif +#if PTHREADS + if (!ENVIRONMENT_IS_PTHREAD && libName) { +#if DYLINK_DEBUG + dbg(`registering sharedModules: ${libName}`) +#endif + // cache all loaded modules in `sharedModules`, which gets passed + // to new workers when they are created. + sharedModules[libName] = module; + } #endif // add new entries to functionsInTableMap updateTableMap(tableBase, metadata.tableSize); @@ -844,16 +858,16 @@ var LibraryDylink = { if (flags.loadAsync) { if (binary instanceof WebAssembly.Module) { var instance = new WebAssembly.Instance(binary, info); - return Promise.resolve(postInstantiation(instance)); + return Promise.resolve(postInstantiation(binary, instance)); } return WebAssembly.instantiate(binary, info).then( - (result) => postInstantiation(result.instance) + (result) => postInstantiation(result.module, result.instance) ); } var module = binary instanceof WebAssembly.Module ? binary : new WebAssembly.Module(binary); var instance = new WebAssembly.Instance(module, info); - return postInstantiation(instance); + return postInstantiation(module, instance); } // now load needed libraries and the module itself. @@ -968,6 +982,16 @@ var LibraryDylink = { // libName -> libData function loadLibData() { +#if PTHREADS + var sharedMod = sharedModules[libName]; +#if DYLINK_DEBUG + dbg(`checking sharedModules: ${libName}: ${sharedMod ? 'found' : 'not found'}`); +#endif + if (sharedMod) { + return flags.loadAsync ? Promise.resolve(sharedMod) : sharedMod; + } +#endif + // for wasm, we can use fetch for async, but for fs mode we can only imitate it if (handle) { var data = {{{ makeGetValue('handle', C_STRUCTS.dso.file_data, '*') }}}; @@ -1007,10 +1031,10 @@ var LibraryDylink = { // module not preloaded - load lib data and create new module from it if (flags.loadAsync) { - return loadLibData().then((libData) => loadWebAssemblyModule(libData, flags, localScope, handle)); + return loadLibData().then((libData) => loadWebAssemblyModule(libData, flags, libName, localScope, handle)); } - return loadWebAssemblyModule(loadLibData(), flags, localScope, handle); + return loadWebAssemblyModule(loadLibData(), flags, libName, localScope, handle); } // module for lib is loaded - update the dso & global namespace diff --git a/src/library_pthread.js b/src/library_pthread.js index b652ede6558f2..0712790944f3b 100644 --- a/src/library_pthread.js +++ b/src/library_pthread.js @@ -410,7 +410,9 @@ var LibraryPThread = { 'wasmOffsetConverter': wasmOffsetConverter, #endif #if MAIN_MODULE - 'dynamicLibraries': Module['dynamicLibraries'], + // Share all modules that have been loaded so far. New workers + // won't start running threads until these are all loaded. + 'sharedModules': sharedModules, #endif #if ASSERTIONS 'workerID': worker.workerID, @@ -431,6 +433,7 @@ var LibraryPThread = { ) { return onMaybeReady(); } + let pthreadPoolReady = Promise.all(PThread.unusedWorkers.map(PThread.loadWasmModuleToWorker)); #if PTHREAD_POOL_DELAY_LOAD // PTHREAD_POOL_DELAY_LOAD means we want to proceed synchronously without diff --git a/src/postamble.js b/src/postamble.js index 712165158661e..6ec0203723863 100644 --- a/src/postamble.js +++ b/src/postamble.js @@ -131,6 +131,12 @@ function stackCheckInit() { } #endif +#if MAIN_MODULE && PTHREADS +// Map of modules to be shared with new threads. This gets populated by the +// main thread and shared with all new workers. +var sharedModules = Module['sharedModules'] || []; +#endif + #if MAIN_READS_PARAMS function run(args = arguments_) { #else diff --git a/src/worker.js b/src/worker.js index 2ea3d308e9726..263354a0961e3 100644 --- a/src/worker.js +++ b/src/worker.js @@ -151,7 +151,10 @@ function handleMessage(e) { #endif // MINIMAL_RUNTIME #if MAIN_MODULE - Module['dynamicLibraries'] = e.data.dynamicLibraries; + Module['sharedModules'] = e.data.sharedModules; +#if RUNTIME_DEBUG + dbg(`received ${Object.keys(e.data.sharedModules).length} shared modules: ${Object.keys(e.data.sharedModules)}`); +#endif #endif // Use `const` here to ensure that the variable is scoped only to diff --git a/test/other/metadce/test_metadce_hello_dylink.jssize b/test/other/metadce/test_metadce_hello_dylink.jssize index 22327905f9c6a..7f12f36736685 100644 --- a/test/other/metadce/test_metadce_hello_dylink.jssize +++ b/test/other/metadce/test_metadce_hello_dylink.jssize @@ -1 +1 @@ -15022 +15031 diff --git a/test/test_core.py b/test/test_core.py index 4022a5d558428..0a12125c2a05a 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -9474,34 +9474,40 @@ def test_pthread_dylink_main_module_1(self): self.do_runf(test_file('hello_world.c')) @needs_dylink - @node_pthreads - def test_Module_dynamicLibraries_pthreads(self): + @parameterized({ + '': ([],), + 'pthreads': (['-sPROXY_TO_PTHREAD', '-sEXIT_RUNTIME', '-pthread', '-Wno-experimental'],) + }) + def test_Module_dynamicLibraries(self, args): # test that Module.dynamicLibraries works with pthreads - self.emcc_args += ['-pthread', '-Wno-experimental'] + self.emcc_args += args self.emcc_args += ['--pre-js', 'pre.js'] - self.set_setting('PROXY_TO_PTHREAD') - self.set_setting('EXIT_RUNTIME') # This test is for setting dynamicLibraries at runtime so we don't # want emscripten loading `liblib.so` automatically (which it would # do without this setting. self.set_setting('NO_AUTOLOAD_DYLIBS') create_file('pre.js', ''' - if (typeof importScripts == 'undefined') { // !ENVIRONMENT_IS_WORKER - // Load liblib.so by default on non-workers - Module['dynamicLibraries'] = ['liblib.so']; - } else { - // Verify whether the main thread passes Module.dynamicLibraries to the worker - assert(Module['dynamicLibraries'].includes('liblib.so')); - } + Module['dynamicLibraries'] = ['liblib.so']; ''') + if args: + self.setup_node_pthreads() + create_file('post.js', ''' + if (ENVIRONMENT_IS_PTHREAD) { + err('sharedModules: ' + Object.keys(sharedModules)); + assert('liblib.so' in sharedModules); + assert(sharedModules['liblib.so'] instanceof WebAssembly.Module); + } + ''') + self.emcc_args += ['--post-js', 'post.js'] + self.dylink_test( r''' #include int side(); int main() { - printf("result is %d", side()); + printf("result is %d\n", side()); return 0; } ''', diff --git a/test/test_other.py b/test/test_other.py index 9c149a68d1d19..669f776d79a94 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -13473,12 +13473,20 @@ def test_preload_module(self, args): struct stat statbuf; assert(stat("/library.so", &statbuf) == 0); - // Check that it was preloaded + // Check that it was preloaded. + // The preloading actually only happens on the main thread where the filesystem + // lives. On worker threads the module object is shared via preloadedModules. if (emscripten_is_main_runtime_thread()) { int found = EM_ASM_INT( return preloadedWasm['/library.so'] !== undefined; ); assert(found); + } else { + int found = EM_ASM_INT( + err(sharedModules); + return sharedModules['/library.so'] !== undefined; + ); + assert(found); } void *lib_handle = dlopen("/library.so", RTLD_NOW); assert(lib_handle); From bb5cedccc02025fa595db1848aa8c5c2fcb18b91 Mon Sep 17 00:00:00 2001 From: jameshu15869 <55058507+jameshu15869@users.noreply.github.com> Date: Fri, 26 May 2023 12:38:03 -0400 Subject: [PATCH 0295/1523] WasmFS JS API: Implement close (#19431) Add ErrnoError throwing in the JS API as well, to match the old FS as much as possible. --- emcc.py | 1 + src/library_wasmfs.js | 30 ++++++++++++++++- system/lib/wasmfs/js_api.cpp | 10 +++++- test/fs/test_fs_js_api.c | 63 ++++++++++++++++++++++++++++++++++++ test/fs/test_open_wasmfs.c | 38 ---------------------- test/test_core.py | 7 ++-- 6 files changed, 105 insertions(+), 44 deletions(-) create mode 100644 test/fs/test_fs_js_api.c delete mode 100644 test/fs/test_open_wasmfs.c diff --git a/emcc.py b/emcc.py index 7107ff56bdc28..45fe35e8834b0 100755 --- a/emcc.py +++ b/emcc.py @@ -2311,6 +2311,7 @@ def phase_linker_setup(options, state, newargs): settings.REQUIRED_EXPORTS += [ '_wasmfs_write_file', '_wasmfs_open', + '_wasmfs_close', '_wasmfs_mkdir', '_wasmfs_unlink', '_wasmfs_chdir', diff --git a/src/library_wasmfs.js b/src/library_wasmfs.js index c4009e3355fa1..366297e3819ad 100644 --- a/src/library_wasmfs.js +++ b/src/library_wasmfs.js @@ -8,6 +8,7 @@ mergeInto(LibraryManager.library, { $wasmFSPreloadedFiles: [], $wasmFSPreloadedDirs: [], $FS__postset: ` +FS.init(); FS.createPreloadedFile = FS_createPreloadedFile; `, $FS__deps: [ @@ -25,6 +26,30 @@ FS.createPreloadedFile = FS_createPreloadedFile; #endif ], $FS : { + init: () => { + FS.ensureErrnoError(); + }, + ErrnoError: null, + handleError: (returnValue) => { + // Assume errors correspond to negative returnValues + // since some functions like _wasmfs_open() return positive + // numbers on success (some callers of this function may need to negate the parameter). + if (returnValue < 0) { + throw new FS.ErrnoError(-returnValue); + } + + return returnValue; + }, + ensureErrnoError: () => { + if (FS.ErrnoError) return; + FS.ErrnoError = /** @this{Object} */ function ErrnoError(code) { + this.errno = code; + this.message = 'FS error'; + this.name = "ErrnoError"; + } + FS.ErrnoError.prototype = new Error(); + FS.ErrnoError.prototype.constructor = FS.ErrnoError; + }, createDataFile: (parent, name, data, canRead, canWrite, canOwn) => { // Data files must be cached until the file system itself has been initialized. var mode = FS_getMode(canRead, canWrite); @@ -95,11 +120,14 @@ FS.createPreloadedFile = FS_createPreloadedFile; mode = typeof mode == 'undefined' ? 438 /* 0666 */ : mode; return withStackSave(() => { var buffer = stringToUTF8OnStack(path); - return __wasmfs_open({{{ to64('buffer') }}}, flags, mode); + return FS.handleError(__wasmfs_open({{{ to64('buffer') }}}, flags, mode)); }) }, // TODO: create // TODO: close + close: (fd) => { + return FS.handleError(-__wasmfs_close(fd)); + }, unlink: (path) => { return withStackSave(() => { var buffer = stringToUTF8OnStack(path); diff --git a/system/lib/wasmfs/js_api.cpp b/system/lib/wasmfs/js_api.cpp index f9de0e65ad37f..b091b20b049ad 100644 --- a/system/lib/wasmfs/js_api.cpp +++ b/system/lib/wasmfs/js_api.cpp @@ -116,7 +116,11 @@ int _wasmfs_mkdir(char* path, int mode) { int _wasmfs_rmdir(char* path){ return __syscall_unlinkat(AT_FDCWD, (intptr_t)path, AT_REMOVEDIR); } int _wasmfs_open(char* path, int flags, mode_t mode) { - return __syscall_openat(AT_FDCWD, (intptr_t)path, flags, mode); + int err = __syscall_openat(AT_FDCWD, (intptr_t)path, flags, mode); + if (err == -1) { + return -errno; + } + return err; } int _wasmfs_unlink(char* path) { @@ -133,6 +137,10 @@ int _wasmfs_chmod(char* path, mode_t mode) { return __syscall_chmod((intptr_t)path, mode); } +int _wasmfs_close(int fd) { + return __wasi_fd_close(fd); +} + // Helper method that identifies what a path is: // ENOENT - if nothing exists there // EISDIR - if it is a directory diff --git a/test/fs/test_fs_js_api.c b/test/fs/test_fs_js_api.c new file mode 100644 index 0000000000000..5627a73d2a5a3 --- /dev/null +++ b/test/fs/test_fs_js_api.c @@ -0,0 +1,63 @@ +#include +#include + +int main() { + /********** test FS.open() **********/ + EM_ASM( + FS.writeFile('testfile', 'a=1\nb=2\n'); + var readStream = FS.open('testfile', 'r'); + var writeStream = FS.open('testfile', 'w'); + var writePlusStream = FS.open('testfile', 'w+'); + var appendStream = FS.open('testfile', 'a'); +#if WASMFS + assert(readStream >= 0); + assert(writeStream >= 0); + assert(writePlusStream >= 0); + assert(appendStream >= 0); +#else + assert(readStream && readStream.fd >= 0); + assert(writeStream && writeStream.fd >= 0); + assert(writePlusStream && writePlusStream.fd >= 0); + assert(appendStream && appendStream.fd >= 0); +#endif + + var ex; + try { + FS.open('filenothere', 'r'); + } catch(err) { + ex = err; + } + assert(ex.name === "ErrnoError" && ex.errno === 44 /* ENOENT */); + + var createFileNotHere = FS.open('filenothere', 'w+'); +#if WASMFS + assert(createFileNotHere >= 0); +#else + assert(createFileNotHere && createFileNotHere.fd >= 0); +#endif + ); + + /********** test FS.close() **********/ + EM_ASM( + FS.writeFile("closetestfile", 'a=1\nb=2\n'); + FS.mkdir("/testdir"); + var file = FS.open("closetestfile", "r"); + var error = FS.close(file); + assert(!error); + + file = FS.open("/testdir", "r"); + error = FS.close(file); + assert(!error); + + var ex; + try { + FS.close(file); + } catch(err) { + ex = err; + } + + assert(ex.name === "ErrnoError" && ex.errno === 8 /* EBADF */) + ); + + puts("success"); +} diff --git a/test/fs/test_open_wasmfs.c b/test/fs/test_open_wasmfs.c deleted file mode 100644 index 91ad3fc936e64..0000000000000 --- a/test/fs/test_open_wasmfs.c +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2023 The Emscripten Authors. All rights reserved. - * Emscripten is available under two separate licenses, the MIT license and the - * University of Illinois/NCSA Open Source License. Both these licenses can be - * found in the LICENSE file. - */ - -#include -#include -#include - - -int main() { - EM_ASM( - FS.writeFile('testfile', 'a=1\nb=2\n'); - var readStream = FS.open('testfile', 'r'); - assert(readStream >= 0); - - var writeStream = FS.open('testfile', 'w'); - assert(writeStream >= 0); - - var writePlusStream = FS.open('testfile', 'w+'); - assert(writePlusStream >= 0); - - var appendStream = FS.open('testfile', 'a'); - assert(appendStream >= 0); - - var notFound = FS.open('filenothere', 'r'); - assert(notFound < 0); - - var createFileNotHere = FS.open('filenothere', 'w+'); - assert(createFileNotHere >= 0); - ); - puts("success"); - - - return 0; -} diff --git a/test/test_core.py b/test/test_core.py index 0a12125c2a05a..a5aa6d328ec7e 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -6014,10 +6014,9 @@ def test_fs_trackingdelegate(self): def test_fs_writeFile(self): self.do_run_in_out_file_test('fs/test_writeFile.cpp') - def test_fs_open_wasmfs(self): - self.emcc_args += ['-sWASMFS'] - self.emcc_args += ['-sFORCE_FILESYSTEM'] - self.do_runf(test_file('fs/test_open_wasmfs.c'), 'success') + def test_fs_js_api(self): + self.set_setting("FORCE_FILESYSTEM") + self.do_runf(test_file('fs/test_fs_js_api.c'), 'success') def test_fs_write(self): self.do_run_in_out_file_test('fs/test_write.cpp') From 5c27e79dd0a9c4e27ef2326841698cdd4f6b5784 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 26 May 2023 16:36:13 -0700 Subject: [PATCH 0296/1523] Fix test_pthread_dlopen_many (#19459) When a thread sync was cancelled (due to a thread exit prior to performing the task) we were treating that as an error, but we should treat that as success. I was able to reproduce the issue by running this test a few times in a row. I confirmed that it did not happen in 160 runs after this fix. Fixes: #18887 --- system/lib/libc/dynlink.c | 20 +++++++++++++++----- test/test_core.py | 1 - 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/system/lib/libc/dynlink.c b/system/lib/libc/dynlink.c index d3ea861731d76..82c7a2d120afa 100644 --- a/system/lib/libc/dynlink.c +++ b/system/lib/libc/dynlink.c @@ -333,11 +333,21 @@ static void do_thread_sync_out(void* arg) { *result = _emscripten_dlsync_self(); } -// Called once _emscripten_proxy_dlsync completes -static void done_thread_sync(void* arg) { +// Called when a thread exists prior to being able to completely sync operation. +// We can just ignore this case and report success. +static void thread_sync_cancelled(void* arg) { + struct promise_result* info = arg; + dbg("thread_sync_cancelled: promise=%p result=%i", info->promise, info->result); + emscripten_promise_resolve(info->promise, EM_PROMISE_FULFILL, NULL); + emscripten_promise_destroy(info->promise); + free(info); +} + +// Called once do_thread_sync completes +static void thread_sync_done(void* arg) { struct promise_result* info = arg; em_promise_t promise = info->promise; - dbg("done_thread_sync: promise=%p result=%i", promise, info->result); + dbg("thread_sync_done: promise=%p result=%i", promise, info->result); if (info->result) { emscripten_promise_resolve(promise, EM_PROMISE_FULFILL, NULL); } else { @@ -389,8 +399,8 @@ int _emscripten_proxy_dlsync_async(pthread_t target_thread, em_promise_t promise int rtn = emscripten_proxy_callback(dlopen_proxying_queue, target_thread, do_thread_sync, - done_thread_sync, - done_thread_sync, + thread_sync_done, + thread_sync_cancelled, info); if (!rtn) { // If we failed to proxy, then the target thread is no longer alive and no diff --git a/test/test_core.py b/test/test_core.py index a5aa6d328ec7e..e1779e02bc436 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -9412,7 +9412,6 @@ def test_pthread_dlopen(self): @needs_dylink @node_pthreads - @disabled('https://github.com/emscripten-core/emscripten/issues/18887') def test_pthread_dlopen_many(self): nthreads = 10 self.emcc_args += ['-Wno-experimental', '-pthread'] From 137fea518f015409bfafeff81740e27b85828bd7 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 30 May 2023 13:44:20 -0700 Subject: [PATCH 0297/1523] Rebaseline codesize expectations. NFC --- test/code_size/hello_webgl2_wasm.json | 8 ++++---- test/code_size/hello_webgl2_wasm2js.json | 8 ++++---- test/code_size/hello_webgl_wasm.json | 8 ++++---- test/code_size/hello_webgl_wasm2js.json | 8 ++++---- test/other/metadce/test_metadce_cxx_ctors1.size | 2 +- test/other/metadce/test_metadce_cxx_ctors2.size | 2 +- test/other/metadce/test_metadce_cxx_except.size | 2 +- test/other/metadce/test_metadce_cxx_except_wasm.size | 2 +- test/other/metadce/test_metadce_cxx_mangle.size | 2 +- test/other/metadce/test_metadce_cxx_noexcept.size | 2 +- test/other/metadce/test_metadce_hello_O0.size | 2 +- test/other/metadce/test_metadce_hello_O1.size | 2 +- test/other/metadce/test_metadce_hello_O2.size | 2 +- test/other/metadce/test_metadce_hello_O3.size | 2 +- test/other/metadce/test_metadce_hello_Os.size | 2 +- test/other/metadce/test_metadce_hello_dylink.size | 2 +- test/other/test_unoptimized_code_size.wasm.size | 2 +- .../other/test_unoptimized_code_size_no_asserts.wasm.size | 2 +- test/other/test_unoptimized_code_size_strict.wasm.size | 2 +- 19 files changed, 31 insertions(+), 31 deletions(-) diff --git a/test/code_size/hello_webgl2_wasm.json b/test/code_size/hello_webgl2_wasm.json index 405f3b72043b7..d15f161407b87 100644 --- a/test/code_size/hello_webgl2_wasm.json +++ b/test/code_size/hello_webgl2_wasm.json @@ -3,8 +3,8 @@ "a.html.gz": 379, "a.js": 4971, "a.js.gz": 2430, - "a.wasm": 10505, - "a.wasm.gz": 6720, - "total": 16045, - "total_gz": 9529 + "a.wasm": 10482, + "a.wasm.gz": 6707, + "total": 16022, + "total_gz": 9516 } diff --git a/test/code_size/hello_webgl2_wasm2js.json b/test/code_size/hello_webgl2_wasm2js.json index ccf1b754ee15a..c7c3da01de188 100644 --- a/test/code_size/hello_webgl2_wasm2js.json +++ b/test/code_size/hello_webgl2_wasm2js.json @@ -1,10 +1,10 @@ { "a.html": 567, "a.html.gz": 379, - "a.js": 18284, - "a.js.gz": 8070, + "a.js": 18252, + "a.js.gz": 8055, "a.mem": 3171, "a.mem.gz": 2713, - "total": 22022, - "total_gz": 11162 + "total": 21990, + "total_gz": 11147 } diff --git a/test/code_size/hello_webgl_wasm.json b/test/code_size/hello_webgl_wasm.json index 1f8742c004762..86d566419f1a9 100644 --- a/test/code_size/hello_webgl_wasm.json +++ b/test/code_size/hello_webgl_wasm.json @@ -3,8 +3,8 @@ "a.html.gz": 379, "a.js": 4450, "a.js.gz": 2250, - "a.wasm": 10505, - "a.wasm.gz": 6720, - "total": 15524, - "total_gz": 9349 + "a.wasm": 10482, + "a.wasm.gz": 6707, + "total": 15501, + "total_gz": 9336 } diff --git a/test/code_size/hello_webgl_wasm2js.json b/test/code_size/hello_webgl_wasm2js.json index b487536835b53..0ce1b1997c10a 100644 --- a/test/code_size/hello_webgl_wasm2js.json +++ b/test/code_size/hello_webgl_wasm2js.json @@ -1,10 +1,10 @@ { "a.html": 567, "a.html.gz": 379, - "a.js": 17756, - "a.js.gz": 7893, + "a.js": 17724, + "a.js.gz": 7870, "a.mem": 3171, "a.mem.gz": 2713, - "total": 21494, - "total_gz": 10985 + "total": 21462, + "total_gz": 10962 } diff --git a/test/other/metadce/test_metadce_cxx_ctors1.size b/test/other/metadce/test_metadce_cxx_ctors1.size index b05d1e60b163f..a751951678a8a 100644 --- a/test/other/metadce/test_metadce_cxx_ctors1.size +++ b/test/other/metadce/test_metadce_cxx_ctors1.size @@ -1 +1 @@ -123501 +123500 diff --git a/test/other/metadce/test_metadce_cxx_ctors2.size b/test/other/metadce/test_metadce_cxx_ctors2.size index 54432ac3ea7c6..3ebdccfec042e 100644 --- a/test/other/metadce/test_metadce_cxx_ctors2.size +++ b/test/other/metadce/test_metadce_cxx_ctors2.size @@ -1 +1 @@ -123406 +123405 diff --git a/test/other/metadce/test_metadce_cxx_except.size b/test/other/metadce/test_metadce_cxx_except.size index 27e59ea3c5748..bbb6a46ebe329 100644 --- a/test/other/metadce/test_metadce_cxx_except.size +++ b/test/other/metadce/test_metadce_cxx_except.size @@ -1 +1 @@ -166244 +166243 diff --git a/test/other/metadce/test_metadce_cxx_except_wasm.size b/test/other/metadce/test_metadce_cxx_except_wasm.size index c12915789fd0c..7e8ea52edc262 100644 --- a/test/other/metadce/test_metadce_cxx_except_wasm.size +++ b/test/other/metadce/test_metadce_cxx_except_wasm.size @@ -1 +1 @@ -137052 +137051 diff --git a/test/other/metadce/test_metadce_cxx_mangle.size b/test/other/metadce/test_metadce_cxx_mangle.size index 0b5a6778421cd..48c940a866845 100644 --- a/test/other/metadce/test_metadce_cxx_mangle.size +++ b/test/other/metadce/test_metadce_cxx_mangle.size @@ -1 +1 @@ -221331 +221330 diff --git a/test/other/metadce/test_metadce_cxx_noexcept.size b/test/other/metadce/test_metadce_cxx_noexcept.size index f1f3cc0e66cda..8501f8ab25781 100644 --- a/test/other/metadce/test_metadce_cxx_noexcept.size +++ b/test/other/metadce/test_metadce_cxx_noexcept.size @@ -1 +1 @@ -126298 +126297 diff --git a/test/other/metadce/test_metadce_hello_O0.size b/test/other/metadce/test_metadce_hello_O0.size index 9124a7bee78bd..e8b15f251ccec 100644 --- a/test/other/metadce/test_metadce_hello_O0.size +++ b/test/other/metadce/test_metadce_hello_O0.size @@ -1 +1 @@ -12125 +12123 diff --git a/test/other/metadce/test_metadce_hello_O1.size b/test/other/metadce/test_metadce_hello_O1.size index 3d212cf499fea..49ce078f63b5e 100644 --- a/test/other/metadce/test_metadce_hello_O1.size +++ b/test/other/metadce/test_metadce_hello_O1.size @@ -1 +1 @@ -2415 +2413 diff --git a/test/other/metadce/test_metadce_hello_O2.size b/test/other/metadce/test_metadce_hello_O2.size index 8cb1ed86567e4..fc7bdcf6f40e7 100644 --- a/test/other/metadce/test_metadce_hello_O2.size +++ b/test/other/metadce/test_metadce_hello_O2.size @@ -1 +1 @@ -2056 +2055 diff --git a/test/other/metadce/test_metadce_hello_O3.size b/test/other/metadce/test_metadce_hello_O3.size index c102fe8faa1e0..2358ac3b44c5e 100644 --- a/test/other/metadce/test_metadce_hello_O3.size +++ b/test/other/metadce/test_metadce_hello_O3.size @@ -1 +1 @@ -1756 +1755 diff --git a/test/other/metadce/test_metadce_hello_Os.size b/test/other/metadce/test_metadce_hello_Os.size index 461033f7a6258..c439d95d8e000 100644 --- a/test/other/metadce/test_metadce_hello_Os.size +++ b/test/other/metadce/test_metadce_hello_Os.size @@ -1 +1 @@ -1748 +1747 diff --git a/test/other/metadce/test_metadce_hello_dylink.size b/test/other/metadce/test_metadce_hello_dylink.size index dcb81b5dcf759..6b4f6ad29f670 100644 --- a/test/other/metadce/test_metadce_hello_dylink.size +++ b/test/other/metadce/test_metadce_hello_dylink.size @@ -1 +1 @@ -9515 +9514 diff --git a/test/other/test_unoptimized_code_size.wasm.size b/test/other/test_unoptimized_code_size.wasm.size index 8b328036fbc18..39fb891cb1844 100644 --- a/test/other/test_unoptimized_code_size.wasm.size +++ b/test/other/test_unoptimized_code_size.wasm.size @@ -1 +1 @@ -12158 +12156 diff --git a/test/other/test_unoptimized_code_size_no_asserts.wasm.size b/test/other/test_unoptimized_code_size_no_asserts.wasm.size index d32c904557015..9a1c49f077bd0 100644 --- a/test/other/test_unoptimized_code_size_no_asserts.wasm.size +++ b/test/other/test_unoptimized_code_size_no_asserts.wasm.size @@ -1 +1 @@ -11605 +11603 diff --git a/test/other/test_unoptimized_code_size_strict.wasm.size b/test/other/test_unoptimized_code_size_strict.wasm.size index 8b328036fbc18..39fb891cb1844 100644 --- a/test/other/test_unoptimized_code_size_strict.wasm.size +++ b/test/other/test_unoptimized_code_size_strict.wasm.size @@ -1 +1 @@ -12158 +12156 From fce0b3a5c9529089225574f128c9a403848b5ddf Mon Sep 17 00:00:00 2001 From: jameshu15869 <55058507+jameshu15869@users.noreply.github.com> Date: Tue, 30 May 2023 18:15:12 -0400 Subject: [PATCH 0298/1523] WasmFS JS API: *chmod (#19427) Add lchmod, fchmod. Add error handling to existing chmod. Fix chmod symlink behavior of link following. --- emcc.py | 2 + src/library_wasmfs.js | 13 +++++- system/lib/wasmfs/js_api.cpp | 8 ++++ system/lib/wasmfs/syscalls.cpp | 3 +- test/test_core.py | 2 +- test/unistd/access.c | 72 ++++++++++++++++++++++++++++++---- 6 files changed, 87 insertions(+), 13 deletions(-) diff --git a/emcc.py b/emcc.py index 45fe35e8834b0..3bf0b3ae307b6 100755 --- a/emcc.py +++ b/emcc.py @@ -2318,6 +2318,8 @@ def phase_linker_setup(options, state, newargs): '_wasmfs_rmdir', '_wasmfs_symlink', '_wasmfs_chmod', + '_wasmfs_fchmod', + '_wasmfs_lchmod', '_wasmfs_identify', '_wasmfs_readdir_start', '_wasmfs_readdir_get', diff --git a/src/library_wasmfs.js b/src/library_wasmfs.js index 366297e3819ad..bdc52ca75ee11 100644 --- a/src/library_wasmfs.js +++ b/src/library_wasmfs.js @@ -177,13 +177,22 @@ FS.createPreloadedFile = FS_createPreloadedFile; // TODO: stat // TODO: lstat chmod: (path, mode) => { - return withStackSave(() => { + return FS.handleError(withStackSave(() => { var buffer = stringToUTF8OnStack(path); return __wasmfs_chmod(buffer, mode); - }); + })); }, // TODO: lchmod + lchmod: (path, mode) => { + return FS.handleError(withStackSave(() => { + var buffer = stringToUTF8OnStack(path); + return __wasmfs_lchmod(buffer, mode); + })); + }, // TODO: fchmod + fchmod: (fd, mode) => { + return FS.handleError(__wasmfs_fchmod(fd, mode)); + }, // TDOO: chown // TODO: lchown // TODO: fchown diff --git a/system/lib/wasmfs/js_api.cpp b/system/lib/wasmfs/js_api.cpp index b091b20b049ad..b6fb0ce0f05fe 100644 --- a/system/lib/wasmfs/js_api.cpp +++ b/system/lib/wasmfs/js_api.cpp @@ -137,6 +137,14 @@ int _wasmfs_chmod(char* path, mode_t mode) { return __syscall_chmod((intptr_t)path, mode); } +int _wasmfs_fchmod(int fd, mode_t mode) { + return __syscall_fchmod(fd, mode); +} + +int _wasmfs_lchmod(char* path, mode_t mode) { + return __syscall_fchmodat(AT_FDCWD, (intptr_t)path, mode, AT_SYMLINK_NOFOLLOW); +} + int _wasmfs_close(int fd) { return __wasi_fd_close(fd); } diff --git a/system/lib/wasmfs/syscalls.cpp b/system/lib/wasmfs/syscalls.cpp index 86304095fc808..e2a65381c76b2 100644 --- a/system/lib/wasmfs/syscalls.cpp +++ b/system/lib/wasmfs/syscalls.cpp @@ -1132,8 +1132,7 @@ int __syscall_fchmodat(int dirfd, intptr_t path, int mode, ...) { // TODO: Test this case. return -EINVAL; } - // TODO: Handle AT_SYMLINK_NOFOLLOW once we traverse symlinks correctly. - auto parsed = path::parseFile((char*)path, dirfd); + auto parsed = path::getFileAt(dirfd, (char*)path, flags); if (auto err = parsed.getError()) { return err; } diff --git a/test/test_core.py b/test/test_core.py index e1779e02bc436..18b1c8d2ed0a3 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -6139,7 +6139,7 @@ def test_unistd_access(self): # Node.js fs.chmod is nearly no-op on Windows # TODO: NODERAWFS in WasmFS if not WINDOWS and not self.get_setting('WASMFS'): - self.emcc_args = orig_compiler_opts + self.emcc_args = orig_compiler_opts + ['-DNODERAWFS'] self.set_setting('NODERAWFS') self.do_run_in_out_file_test('unistd/access.c') diff --git a/test/unistd/access.c b/test/unistd/access.c index b81071629eda5..e0c64e0613e0c 100644 --- a/test/unistd/access.c +++ b/test/unistd/access.c @@ -20,10 +20,11 @@ int main() { FS.mount(NODEFS, { root: '.' }, 'working'); #endif FS.chdir('working'); - FS.writeFile('forbidden', ""); FS.chmod('forbidden', 0o000); - FS.writeFile('readable', ""); FS.chmod('readable', 0o444); - FS.writeFile('writeable', ""); FS.chmod('writeable', 0o222); - FS.writeFile('allaccess', ""); FS.chmod('allaccess', 0o777); + FS.writeFile('forbidden', ""); FS.chmod('forbidden', 0000); + FS.writeFile('readable', ""); FS.chmod('readable', 0444); + FS.writeFile('writeable', ""); FS.chmod('writeable', 0222); + FS.writeFile('allaccess', ""); FS.chmod('allaccess', 0777); + FS.writeFile('fchmodtest', ""); ); // Empty path checks #9136 fix @@ -65,14 +66,69 @@ int main() { printf("F_OK(%s): %d\n", "renamedfile", faccessat(AT_FDCWD, "renamedfile", F_OK, 0)); printf("errno: %d\n", errno); + struct stat fileStats; + stat("fchmodtest", &fileStats); + chmod("fchmodtest", 0666); + assert(fileStats.st_mode & 0666); + + EM_ASM( + var fchmodstream = FS.open("fchmodtest", "r"); +#if WASMFS + FS.fchmod(fchmodstream, 0777); +#else + FS.fchmod(fchmodstream.fd, 0777); +#endif + ); + stat("fchmodtest", &fileStats); + assert(fileStats.st_mode & 0777); + + EM_ASM( + FS.symlink('writeable', 'symlinkfile'); + FS.lchmod('symlinkfile', 0777); + ); + + struct stat symlinkStats; + + lstat("symlinkfile", &symlinkStats); + assert(symlinkStats.st_mode & 0777); + + stat("writeable", &fileStats); + assert(fileStats.st_mode & 0222); + + EM_ASM( + var ex; + try { + FS.chmod("nonexistent", 0777); + } catch (err) { + ex = err; + } + assert(ex.name === "ErrnoError" && ex.errno === 44 /* ENOENT */); + + try { + FS.fchmod(99, 0777); + } catch (err) { + ex = err; + } + assert(ex.name === "ErrnoError" && ex.errno === 8 /* EBADF */); + + try { + FS.lchmod("nonexistent", 0777); + } catch (err) { + ex = err; + } + assert(ex.name === "ErrnoError" && ex.errno === 44 /* ENOENT */); + ); + + // Restore full permissions on all created files so that python test runner rmtree // won't have problems on deleting the files. On Windows, calling shutil.rmtree() // will fail if any of the files are read-only. EM_ASM( - FS.chmod('forbidden', 0o777); - FS.chmod('readable', 0o777); - FS.chmod('writeable', 0o777); - FS.chmod('allaccess', 0o777); + FS.chmod('forbidden', 0777); + FS.chmod('readable', 0777); + FS.chmod('writeable', 0777); + FS.chmod('allaccess', 0777); + FS.chmod('fchmodtest', 0777); ); return 0; From 0fb0c7afe20f5d8b8bac28a478ece07481b21dc8 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 30 May 2023 15:24:20 -0700 Subject: [PATCH 0299/1523] Remove some remaining internal uses of the old USE_PTHREADS settings. NFC (#19474) These were not showing up in tests because they only show up with `-sSTRICT` + `-O2` (or above). I'm not sure how I missed them in #18923. My guess is that they might have shown up as part of later commits. Fixes: #19471 --- src/shell_minimal_runtime.html | 2 +- test/test_other.py | 1 + tools/building.py | 4 ++-- tools/minimal_runtime_shell.py | 4 ++-- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/shell_minimal_runtime.html b/src/shell_minimal_runtime.html index f4e4a42a47f9e..4e44628aaefa1 100644 --- a/src/shell_minimal_runtime.html +++ b/src/shell_minimal_runtime.html @@ -4,7 +4,7 @@ - - - ''') - self.run_browser('a.html', '/report_result?exit:0') - # Tests that SINGLE_FILE works as intended in generated HTML (with and without Worker) def test_single_file_html(self): self.btest('single_file_static_initializer.cpp', '19', args=['-sSINGLE_FILE'], also_proxied=True) From d316e3ee42cc132733295b187c11dcf058eb5391 Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Thu, 6 Jul 2023 17:25:37 -0700 Subject: [PATCH 0522/1523] Clarify comments on Emscripten EH-based settings (#19803) The original intention was to gather all Emscripten-EH settings in one place and put a single comment block saying "The below three only apply to Emscripten EH", but when you search for a setting you just do a keyword search and it is not easy to look up to see this comment. So this makes it clear that a certain option only applies to Emscripten EH in by putting a comment in each setting. Also move `DISABLE_EXCEPTION_THROWING` up so that all three Emscripten-EH-only settings are clumped together. --- src/settings.js | 47 +++++++++++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/src/settings.js b/src/settings.js index 6056d7e1ee6a7..456badb4fb4db 100644 --- a/src/settings.js +++ b/src/settings.js @@ -641,11 +641,12 @@ var ENVIRONMENT = 'web,webview,worker,node'; // [link] var LZ4 = false; -// Emscripten exception handling options. +// Emscripten (JavaScript-based) exception handling options. // The three options below (DISABLE_EXCEPTION_CATCHING, // EXCEPTION_CATCHING_ALLOWED, and DISABLE_EXCEPTION_THROWING) only pertain to -// Emscripten exception handling and do not control the native wasm exception -// handling option (-fwasm-exceptions, internal setting: WASM_EXCEPTIONS). +// JavaScript-based exception handling and do not control the native Wasm +// exception handling option (-fwasm-exceptions, internal setting: +// WASM_EXCEPTIONS). // Disables generating code to actually catch exceptions. This disabling is on // by default as the overhead of exceptions is quite high in size and speed @@ -661,6 +662,9 @@ var LZ4 = false; // // This option is mutually exclusive with EXCEPTION_CATCHING_ALLOWED. // +// This option only applies to Emscripten (JavaScript-based) exception handling +// and does not control the native Wasm exception handling. +// // [compile+link] - affects user code at compile and system libraries at link var DISABLE_EXCEPTION_CATCHING = 1; @@ -669,9 +673,31 @@ var DISABLE_EXCEPTION_CATCHING = 1; // // This option is mutually exclusive with DISABLE_EXCEPTION_CATCHING. // +// This option only applies to Emscripten (JavaScript-based) exception handling +// and does not control the native Wasm exception handling. +// // [compile+link] - affects user code at compile and system libraries at link var EXCEPTION_CATCHING_ALLOWED = []; +// Internal: Tracks whether Emscripten should link in exception throwing (C++ +// 'throw') support library. This does not need to be set directly, but pass +// -fno-exceptions to the build disable exceptions support. (This is basically +// -fno-exceptions, but checked at final link time instead of individual .cpp +// file compile time) If the program *does* contain throwing code (some source +// files were not compiled with `-fno-exceptions`), and this flag is set at link +// time, then you will get errors on undefined symbols, as the exception +// throwing code is not linked in. If so you should either unset the option (if +// you do want exceptions) or fix the compilation of the source files so that +// indeed no exceptions are used). +// TODO(sbc): Move to settings_internal (current blocked due to use in test +// code). +// +// This option only applies to Emscripten (JavaScript-based) exception handling +// and does not control the native Wasm exception handling. +// +// [link] +var DISABLE_EXCEPTION_THROWING = false; + // Make the exception message printing function, 'getExceptionMessage' available // in the JS library for use, by adding necessary symbols to EXPORTED_FUNCTIONS // and DEFAULT_LIBRARY_FUNCS_TO_INCLUDE. @@ -709,21 +735,6 @@ var EXPORT_EXCEPTION_HANDLING_HELPERS = false; // [link] var EXCEPTION_STACK_TRACES = false; -// Internal: Tracks whether Emscripten should link in exception throwing (C++ -// 'throw') support library. This does not need to be set directly, but pass -// -fno-exceptions to the build disable exceptions support. (This is basically -// -fno-exceptions, but checked at final link time instead of individual .cpp -// file compile time) If the program *does* contain throwing code (some source -// files were not compiled with `-fno-exceptions`), and this flag is set at link -// time, then you will get errors on undefined symbols, as the exception -// throwing code is not linked in. If so you should either unset the option (if -// you do want exceptions) or fix the compilation of the source files so that -// indeed no exceptions are used). -// TODO(sbc): Move to settings_internal (current blocked due to use in test -// code). -// [link] -var DISABLE_EXCEPTION_THROWING = false; - // Emscripten throws an ExitStatus exception to unwind when exit() is called. // Without this setting enabled this can show up as a top level unhandled // exception. From da84fe73fb6705891113e1bad4e96da96109fcd4 Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Thu, 6 Jul 2023 17:34:49 -0700 Subject: [PATCH 0523/1523] [docs] Improve debugging docs (#19791) - Clarify relationship between optimization levels and debug info - Add links to Chrome devtool tutorial and other sites --- site/source/docs/porting/Debugging.rst | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/site/source/docs/porting/Debugging.rst b/site/source/docs/porting/Debugging.rst index a732178d956d2..773c2148ce566 100644 --- a/site/source/docs/porting/Debugging.rst +++ b/site/source/docs/porting/Debugging.rst @@ -22,7 +22,7 @@ This article describes the main tools and settings provided by Emscripten for de Debug information ================= -:ref:`Emcc ` strips out most of the debug information from :ref:`optimized builds ` by default. Optimisation levels :ref:`-O1 ` and above remove LLVM debug information, and also disable runtime :ref:`ASSERTIONS ` checks. From optimization level :ref:`-O2 ` the code is minified by the :term:`Closure Compiler` and becomes virtually unreadable. +:ref:`Emcc ` strips out most of the debug information from :ref:`optimized builds ` by default. The higher the optimization level, the more degraded the quality of DWARF debug information is, so we recommend using :ref:`-O0 ` or :ref:`-O1 ` for debugging purposes. :ref:`-O1 ` and above also disable runtime :ref:`ASSERTIONS ` checks. From optimization level :ref:`-O2 ` the JavaScript code is minified by the :term:`Closure Compiler` and becomes virtually unreadable. The *emcc* :ref:`-g flag ` can be used to preserve debug information in the compiled output. By default, this option includes Clang / LLVM debug information in a DWARF format in the generated WebAssembly code and preserves white-space, function names and variable names in the generated JavaScript code. @@ -30,7 +30,9 @@ The flag can also be specified with an integer level: :ref:`-g0 `, :ref The :ref:`-gsource-map ` option is similar to ``-g2`` but also generates source maps that allow you to view and debug the *C/C++ source code* in your browser's debugger. Source maps are not as powerful as DWARF which was mentioned earlier (they contain only source location info), but they are currently more widely supported. -.. note:: Some optimizations may be disabled when used in conjunction with the debug flags. For example, if you compile with ``-O3 -g`` some of the normal ``-O3`` optimizations will be disabled in order to provide the requested debugging information, such as name minification. +.. note:: Because Binaryen optimization degrades the quality of DWARF info further, ``-O1 -g`` will skip running the Binaryen optimizer (``wasm-opt``) entirely unless required by other options. You can also throw in ``-sERROR_ON_WASM_CHANGES_AFTER_LINK`` option if you want to ensure the debug info is preserved. See `Skipping Binaryen `_ for more details. + +.. note:: Some optimizations may be disabled when used in conjunction with the debug flags both in the Binaryen optimizer (even if it runs) and JavaScript optimizer. For example, if you compile with ``-O3 -g``, the Binaryen optimizer will skip some of the optimization passes that do not produce valid DWARF information, and also some of the normal JavaScript optimization will be disabled in order to better provide the requested debugging information. .. _debugging-EMCC_DEBUG: @@ -145,6 +147,16 @@ Debug printouts can even execute arbitrary JavaScript. For example:: } +Debugging with Chrome Devtools +============================== + +Chrome devtools support source-level debugging on WebAssembly files with DWARF information. To use that, you need the Wasm debugging extension plugin here: +https://goo.gle/wasm-debugging-extension + +See `Debugging WebAssembly with modern tools +`_ for the details. + + .. _handling-c-exceptions-from-javascript: Handling C++ exceptions from JavaScript @@ -354,6 +366,8 @@ Useful Links - `Blogpost about reading compiler output `_. - `GDC 2014: Getting started with asm.js and Emscripten `_ (Debugging slides). +- `Links to Wasm debugging-related documents `_ + Need help? ========== From 6c6c7c38a9e491e1c607f123ab862c8fb33de417 Mon Sep 17 00:00:00 2001 From: Brendan Dahl Date: Fri, 7 Jul 2023 09:37:42 -0700 Subject: [PATCH 0524/1523] JSPI - Fix ccall. (#19800) Add code to handle JSPI for ccall. --- .circleci/config.yml | 4 +++- src/library_ccall.js | 9 ++++++++- test/common.py | 3 +++ test/test_core.py | 14 ++++++++++---- 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 849b319e1e560..60b6131c75d27 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -655,7 +655,9 @@ jobs: other.test_native_call_before_init other.test_node_unhandled_rejection core2.test_hello_world - core0.test_pthread_join_and_asyncify" + core0.test_pthread_join_and_asyncify + core0.test_async_ccall_promise_jspi + core0.test_async_ccall_promise_exit_runtime_jspi" # Run some basic tests with the minimum version of node that we currently # support. - install-node-version: diff --git a/src/library_ccall.js b/src/library_ccall.js index fc623dc7e3b3f..71344bbe9e9fc 100644 --- a/src/library_ccall.js +++ b/src/library_ccall.js @@ -85,11 +85,14 @@ mergeInto(LibraryManager.library, { if (stack !== 0) stackRestore(stack); return convertReturnValue(ret); } +#if ASYNCIFY + var asyncMode = opts && opts.async; +#endif + #if ASYNCIFY == 1 // Keep the runtime alive through all calls. Note that this call might not be // async, but for simplicity we push and pop in all calls. runtimeKeepalivePush(); - var asyncMode = opts && opts.async; if (Asyncify.currData != previousAsync) { #if ASSERTIONS // A change in async operation happened. If there was already an async @@ -111,6 +114,10 @@ mergeInto(LibraryManager.library, { } #endif +#if ASYNCIFY == 2 + if (asyncMode) return ret.then(onDone); +#endif + ret = onDone(ret); #if ASYNCIFY == 1 // If this is an async ccall, ensure we return a promise diff --git a/test/common.py b/test/common.py index 597a29238bac9..9cbc5e00ae3da 100644 --- a/test/common.py +++ b/test/common.py @@ -656,6 +656,9 @@ def require_wasm_eh(self): self.fail('either d8 or node >= 16 required to run wasm-eh tests. Use EMTEST_SKIP_EH to skip') def require_jspi(self): + if not self.is_wasm(): + self.skipTest('JSPI is not currently supported for WASM2JS') + exp_args = ['--experimental-wasm-stack-switching', '--experimental-wasm-type-reflection'] if config.NODE_JS and config.NODE_JS in self.js_engines: version = shared.check_node_version() diff --git a/test/test_core.py b/test/test_core.py index e18c398678325..e1d96f71b470b 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -8239,12 +8239,18 @@ def test_async_ccall_good(self): self.do_runf('main.c', 'HelloWorld') @parameterized({ - '': (False,), - 'exit_runtime': (True,), + 'asyncify': (False, 1), + 'exit_runtime_asyncify': (True, 1), + 'jspi': (False, 2), + 'exit_runtime_jspi': (True, 2), }) @no_wasm64('TODO: asyncify for wasm64') - def test_async_ccall_promise(self, exit_runtime): - self.set_setting('ASYNCIFY') + def test_async_ccall_promise(self, exit_runtime, asyncify): + if asyncify == 2: + self.require_jspi() + self.emcc_args += ['-Wno-experimental'] + self.set_setting('ASYNCIFY_EXPORTS', ['stringf', 'floatf']) + self.set_setting('ASYNCIFY', asyncify) self.set_setting('EXIT_RUNTIME') self.set_setting('ASSERTIONS') self.set_setting('INVOKE_RUN', 0) From 91f2012043d6c673e637d56e9d4d4c1068e6c3af Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 7 Jul 2023 13:02:25 -0700 Subject: [PATCH 0525/1523] Use identifiers rather than string keys in wasmImports object. (#19808) We should get a lot more code savings from this change once we switch from using the underscore name mangling on the JS side. Once we do that most of the imports will use the abbreviated the object syntax of just `foo,` rather then `foo = _foo,` --- emscripten.py | 8 +++++-- .../optimizer/applyDCEGraphRemovals-output.js | 4 ++-- test/optimizer/applyDCEGraphRemovals.js | 2 +- .../applyImportAndExportNameChanges-output.js | 22 +++++++++---------- .../applyImportAndExportNameChanges.js | 22 +++++++++---------- ...applyImportAndExportNameChanges2-output.js | 16 +++++++------- .../applyImportAndExportNameChanges2.js | 16 +++++++------- ...al-runtime-applyDCEGraphRemovals-output.js | 4 ++-- .../minimal-runtime-applyDCEGraphRemovals.js | 2 +- test/other/test_unoptimized_code_size.js.size | 2 +- ...t_unoptimized_code_size_no_asserts.js.size | 2 +- .../test_unoptimized_code_size_strict.js.size | 2 +- tools/acorn-optimizer.js | 6 ++--- 13 files changed, 56 insertions(+), 52 deletions(-) diff --git a/emscripten.py b/emscripten.py index 399cc1a14cc30..cf778bd8f41bd 100644 --- a/emscripten.py +++ b/emscripten.py @@ -719,8 +719,12 @@ def create_sending(metadata, library_symbols): continue send_items_map[demangled] = f - sorted_keys = sorted(send_items_map.keys()) - return '{\n ' + ',\n '.join('"' + k + '": ' + send_items_map[k] for k in sorted_keys) + '\n}' + sorted_items = sorted(send_items_map.items()) + prefix = '' + if settings.USE_CLOSURE_COMPILER: + # This prevents closure compiler from minifying the field names in this object. + prefix = '/** @export */\n ' + return '{\n ' + ',\n '.join(f'{prefix}{k}: {v}' for k, v in sorted_items) + '\n}' def make_export_wrappers(exports, delay_assignment): diff --git a/test/optimizer/applyDCEGraphRemovals-output.js b/test/optimizer/applyDCEGraphRemovals-output.js index c89e6ca2c5bb3..f0e92efe82b9e 100644 --- a/test/optimizer/applyDCEGraphRemovals-output.js +++ b/test/optimizer/applyDCEGraphRemovals-output.js @@ -1,8 +1,8 @@ var name; var wasmImports = { - "save1": 1, - "save2": 2 + save1: 1, + save2: 2 }; var expD1 = Module["expD1"] = asm["expD1"]; diff --git a/test/optimizer/applyDCEGraphRemovals.js b/test/optimizer/applyDCEGraphRemovals.js index da70864d4fdbe..64264dac31cea 100644 --- a/test/optimizer/applyDCEGraphRemovals.js +++ b/test/optimizer/applyDCEGraphRemovals.js @@ -1,5 +1,5 @@ var name; -var wasmImports = { 'save1': 1, 'number': 33, 'name': name, 'func': function() {}, 'save2': 2 }; +var wasmImports = { save1: 1, number: 33, name: name, func: function() {}, save2: 2 }; // exports gotten directly var expD1 = Module['expD1'] = asm['expD1']; diff --git a/test/optimizer/applyImportAndExportNameChanges-output.js b/test/optimizer/applyImportAndExportNameChanges-output.js index 80877c9ec3b4a..d8e836a4f4f1a 100644 --- a/test/optimizer/applyImportAndExportNameChanges-output.js +++ b/test/optimizer/applyImportAndExportNameChanges-output.js @@ -1,17 +1,17 @@ var name; var wasmImports = { - "a": 1, - "A": 33, - "b": ___syscall6, - "__setErrNo": ___setErrNo, - "memset": _memset, - "sbrk": _sbrk, - "memcpy": _memcpy, - "emscripten_memcpy_big": _emscripten_memcpy_big, - "c": ___syscall54, - "d": ___syscall140, - "q": ___syscall146 + a: 1, + A: 33, + b: ___syscall6, + __setErrNo: ___setErrNo, + memset: _memset, + sbrk: _sbrk, + memcpy: _memcpy, + emscripten_memcpy_big: _emscripten_memcpy_big, + c: ___syscall54, + d: ___syscall140, + q: ___syscall146 }; var expD1 = Module["expD1"] = asm["c"]; diff --git a/test/optimizer/applyImportAndExportNameChanges.js b/test/optimizer/applyImportAndExportNameChanges.js index 6d117f864e0b8..39754cc73ff19 100644 --- a/test/optimizer/applyImportAndExportNameChanges.js +++ b/test/optimizer/applyImportAndExportNameChanges.js @@ -1,16 +1,16 @@ var name; var wasmImports = { - 'save1': 1, - 'number': 33, - "__syscall6": ___syscall6, - "__setErrNo": ___setErrNo, - "memset": _memset, - "sbrk": _sbrk, - "memcpy": _memcpy, - "emscripten_memcpy_big": _emscripten_memcpy_big, - "__syscall54": ___syscall54, - "__syscall140": ___syscall140, - "__syscall146": ___syscall146 + save1: 1, + number: 33, + __syscall6: ___syscall6, + __setErrNo: ___setErrNo, + memset: _memset, + sbrk: _sbrk, + memcpy: _memcpy, + emscripten_memcpy_big: _emscripten_memcpy_big, + __syscall54: ___syscall54, + __syscall140: ___syscall140, + __syscall146: ___syscall146 }; // exports diff --git a/test/optimizer/applyImportAndExportNameChanges2-output.js b/test/optimizer/applyImportAndExportNameChanges2-output.js index bd0b98dfc96b9..03d3dfdbb746e 100644 --- a/test/optimizer/applyImportAndExportNameChanges2-output.js +++ b/test/optimizer/applyImportAndExportNameChanges2-output.js @@ -213,14 +213,14 @@ if (ENVIRONMENT_IS_NODE) { } var wasmImports = { - "b": abort, - "h": ___syscall140, - "a": ___syscall146, - "g": ___syscall54, - "f": ___syscall6, - "e": _emscripten_get_now, - "d": _emscripten_memcpy_big, - "c": _emscripten_random + b: abort, + h: ___syscall140, + a: ___syscall146, + g: ___syscall54, + f: ___syscall6, + e: _emscripten_get_now, + d: _emscripten_memcpy_big, + c: _emscripten_random }; function run() { diff --git a/test/optimizer/applyImportAndExportNameChanges2.js b/test/optimizer/applyImportAndExportNameChanges2.js index df3fe427f54ab..4fb4dfe147c4a 100644 --- a/test/optimizer/applyImportAndExportNameChanges2.js +++ b/test/optimizer/applyImportAndExportNameChanges2.js @@ -204,14 +204,14 @@ if (ENVIRONMENT_IS_NODE) { _emscripten_get_now = Date.now } var wasmImports = { - "abort": abort, - "___syscall140": ___syscall140, - "___syscall146": ___syscall146, - "___syscall54": ___syscall54, - "___syscall6": ___syscall6, - "_emscripten_get_now": _emscripten_get_now, - "_emscripten_memcpy_big": _emscripten_memcpy_big, - "_emscripten_random": _emscripten_random + abort: abort, + ___syscall140: ___syscall140, + ___syscall146: ___syscall146, + ___syscall54: ___syscall54, + ___syscall6: ___syscall6, + _emscripten_get_now: _emscripten_get_now, + _emscripten_memcpy_big: _emscripten_memcpy_big, + _emscripten_random: _emscripten_random }; function run() { diff --git a/test/optimizer/minimal-runtime-applyDCEGraphRemovals-output.js b/test/optimizer/minimal-runtime-applyDCEGraphRemovals-output.js index 595a2e893ef72..465ce4410ab35 100644 --- a/test/optimizer/minimal-runtime-applyDCEGraphRemovals-output.js +++ b/test/optimizer/minimal-runtime-applyDCEGraphRemovals-output.js @@ -1,8 +1,8 @@ var name; var wasmImports = { - "save1": 1, - "save2": 2 + save1: 1, + save2: 2 }; WebAssembly.instantiate(Module["wasm"], imports).then(output => { diff --git a/test/optimizer/minimal-runtime-applyDCEGraphRemovals.js b/test/optimizer/minimal-runtime-applyDCEGraphRemovals.js index 5432f7387bf59..73f6d28da9ebd 100644 --- a/test/optimizer/minimal-runtime-applyDCEGraphRemovals.js +++ b/test/optimizer/minimal-runtime-applyDCEGraphRemovals.js @@ -1,5 +1,5 @@ var name; -var wasmImports = { 'save1': 1, 'number': 33, 'name': name, 'func': function() {}, 'save2': 2 }; +var wasmImports = { save1: 1, number: 33, name: name, func: function() {}, save2: 2 }; // exports gotten directly in the minimal runtime style WebAssembly.instantiate(Module["wasm"], imports).then((output) => { diff --git a/test/other/test_unoptimized_code_size.js.size b/test/other/test_unoptimized_code_size.js.size index bbedf496809bb..b65021da9a4c0 100644 --- a/test/other/test_unoptimized_code_size.js.size +++ b/test/other/test_unoptimized_code_size.js.size @@ -1 +1 @@ -59025 +59021 diff --git a/test/other/test_unoptimized_code_size_no_asserts.js.size b/test/other/test_unoptimized_code_size_no_asserts.js.size index 6b72f1f895df1..ded36227e9536 100644 --- a/test/other/test_unoptimized_code_size_no_asserts.js.size +++ b/test/other/test_unoptimized_code_size_no_asserts.js.size @@ -1 +1 @@ -32448 +32444 diff --git a/test/other/test_unoptimized_code_size_strict.js.size b/test/other/test_unoptimized_code_size_strict.js.size index 90fcd4b619638..e0d0b82fafd55 100644 --- a/test/other/test_unoptimized_code_size_strict.js.size +++ b/test/other/test_unoptimized_code_size_strict.js.size @@ -1 +1 @@ -57991 +57987 diff --git a/tools/acorn-optimizer.js b/tools/acorn-optimizer.js index 9e7a49d664e7a..6c5ce3e0ee5e5 100755 --- a/tools/acorn-optimizer.js +++ b/tools/acorn-optimizer.js @@ -513,8 +513,8 @@ function applyImportAndExportNameChanges(ast) { if (isWasmImportsAssign(node)) { const assignedObject = getWasmImportsValue(node); assignedObject.properties.forEach((item) => { - if (mapping[item.key.value]) { - setLiteralValue(item.key, mapping[item.key.value]); + if (mapping[item.key.name]) { + item.key.name = mapping[item.key.name]; } }); } else if (node.type === 'AssignmentExpression') { @@ -982,7 +982,7 @@ function applyDCEGraphRemovals(ast) { if (isWasmImportsAssign(node)) { const assignedObject = getWasmImportsValue(node); assignedObject.properties = assignedObject.properties.filter((item) => { - const name = item.key.value; + const name = item.key.name; const value = item.value; const full = 'emcc$import$' + name; return !(unused.has(full) && !hasSideEffects(value)); From 75fc6cd58c3b9ce6eb08f6a25b6a5681f7423214 Mon Sep 17 00:00:00 2001 From: Kevin Yin Date: Fri, 7 Jul 2023 15:11:36 -0700 Subject: [PATCH 0526/1523] Document that clang-format may clobber javascript and how to work around this (#19810) --- .clang-format | 1 + .../connecting_cpp_and_javascript/Interacting-with-code.rst | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/.clang-format b/.clang-format index 67b2920e310f9..a60db77c9266d 100644 --- a/.clang-format +++ b/.clang-format @@ -8,6 +8,7 @@ ConstructorInitializerIndentWidth: 2 SpaceAfterTemplateKeyword: false BinPackArguments: false BinPackParameters: false +WhitespaceSensitiveMacros: ['EM_ASM', 'EM_JS', 'EM_ASM_INT', 'EM_ASM_DOUBLE', 'EM_ASM_PTR', 'MAIN_THREAD_EM_ASM', 'MAIN_THREAD_EM_ASM_INT', 'MAIN_THREAD_EM_ASM_DOUBLE', 'MAIN_THREAD_EM_ASM_DOUBLE', 'MAIN_THREAD_ASYNC_EM_ASM'] --- Language: JavaScript BasedOnStyle: LLVM diff --git a/site/source/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.rst b/site/source/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.rst index b7096e81623af..4f3ed1b7dd2f5 100644 --- a/site/source/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.rst +++ b/site/source/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.rst @@ -347,6 +347,11 @@ See the :c:macro:`emscripten.h docs ` for more details. single quotes('). Double quotes(") will cause a syntax error that is not detected by the compiler and is only shown when looking at a JavaScript console while running the offending code. + - clang-format may clobber Javascript constructions, such as ``=>`` + turning to ``= >``. To avoid this, add to your ``.clang-format``: + ``WhitespaceSensitiveMacros: ['EM_ASM', 'EM_JS', 'EM_ASM_INT', 'EM_ASM_DOUBLE', 'EM_ASM_PTR', 'MAIN_THREAD_EM_ASM', 'MAIN_THREAD_EM_ASM_INT', 'MAIN_THREAD_EM_ASM_DOUBLE', 'MAIN_THREAD_EM_ASM_DOUBLE', 'MAIN_THREAD_ASYNC_EM_ASM']``. + Or, turn `clang-format off`_ by writing ``// clang-format off`` + before the ``EM_ASM`` section and ``// clang-format on`` after it. .. _implement-c-in-javascript: @@ -814,6 +819,7 @@ you can give it a try. See `Emnapi documentation`_ for more details. .. _test/test_core.py: https://github.com/emscripten-core/emscripten/blob/1.29.12/tests/test_core.py#L4597 .. _Box2D: https://github.com/kripken/box2d.js/#box2djs .. _Bullet: https://github.com/kripken/ammo.js/#ammojs +.. _clang-format off: https://clang.llvm.org/docs/ClangFormatStyleOptions.html#disabling-formatting-on-a-piece-of-code .. _Emnapi: https://github.com/toyobayashi/emnapi .. _Node-API: https://nodejs.org/dist/latest/docs/api/n-api.html .. _Emnapi documentation: https://emnapi-docs.vercel.app/guide/getting-started.html From 589de20b1c32e6dbd173bf05ce76cdd54d23f45e Mon Sep 17 00:00:00 2001 From: Brendan Dahl Date: Fri, 7 Jul 2023 15:15:25 -0700 Subject: [PATCH 0527/1523] embind: Generate TS definitions for more bindings. (#19787) * embind: Generate TS definitions for more bindings. Supports embind's: - constants - enums - value arrays - value objects - smart pointers * embind: Use const/let everywhere in embind_ts. --- src/embind/embind_ts.js | 232 ++++++++++++++++++++++++++++++++--- test/other/embind_tsgen.cpp | 107 ++++++++++++++++ test/other/embind_tsgen.d.ts | 63 ++++++++++ 3 files changed, 387 insertions(+), 15 deletions(-) diff --git a/src/embind/embind_ts.js b/src/embind/embind_ts.js index dcec1e89333b1..de6645848b505 100644 --- a/src/embind/embind_ts.js +++ b/src/embind/embind_ts.js @@ -31,8 +31,8 @@ var LibraryEmbind = { printSignature(nameMap, out) { out.push('('); - let argOut = []; - for (let arg of this.argumentTypes) { + const argOut = []; + for (const arg of this.argumentTypes) { argOut.push(`${arg.name}: ${nameMap(arg.type)}`); } out.push(argOut.join(', ')); @@ -67,7 +67,7 @@ var LibraryEmbind = { out.push(` extends ${this.base.name}`); } out.push(' {\n'); - for (let method of this.methods) { + for (const method of this.methods) { out.push(' '); method.printFunction(nameMap, out); } @@ -78,11 +78,87 @@ var LibraryEmbind = { printModuleEntry(nameMap, out) { out.push(` ${this.name}: {new`); // TODO Handle constructor overloading - let constructor = this.constructors[this.constructors.length > 1 ? 1 : 0]; + const constructor = this.constructors[this.constructors.length > 1 ? 1 : 0]; constructor.printSignature(nameMap, out); out.push('};\n'); } }, + $ConstantDefinition: class ConstantDefinition { + constructor(type, name) { + this.type = type; + this.name = name; + } + + printModuleEntry(nameMap, out) { + out.push(` ${this.name}: ${nameMap(this.type)};\n`); + } + }, + $EnumDefinition: class EnumDefinition { + constructor(typeId, name) { + this.typeId = typeId; + this.name = name; + this.items = []; + } + + print(nameMap, out) { + out.push(`export interface ${this.name}Value {\n`); + out.push(' value: T;\n}\n'); + out.push(`export type ${this.name} = `); + const outItems = []; + for (const [name, value] of this.items) { + outItems.push(`${this.name}Value<${value}>`); + } + out.push(outItems.join('|')); + out.push(';\n\n'); + } + + printModuleEntry(nameMap, out) { + out.push(` ${this.name}: {`); + const outItems = []; + for (const [name, value] of this.items) { + outItems.push(`${name}: ${this.name}Value<${value}>`); + } + out.push(outItems.join(', ')); + out.push('};\n'); + } + }, + $ValueArrayDefinition: class ValueArrayDefinition { + constructor(typeId, name) { + this.typeId = typeId; + this.name = name; + this.elementTypeIds = []; + this.elements = []; + } + + print(nameMap, out) { + out.push(`export type ${this.name} = [ `); + const outElements = []; + for (const type of this.elements) { + outElements.push(nameMap(type)); + } + out.push(outElements.join(', ')) + out.push(' ];\n\n'); + } + }, + $ValueObjectDefinition: class ValueObjectDefinition { + constructor(typeId, name) { + this.typeId = typeId; + this.name = name; + this.fieldTypeIds = []; + this.fieldNames = []; + this.fields = []; + } + + print(nameMap, out) { + out.push(`export type ${this.name} = {\n`); + const outFields = []; + for (const {name, type} of this.fields) { + outFields.push(` ${name}: ${nameMap(type)}`); + } + out.push(outFields.join(',\n')) + out.push('\n};\n\n'); + } + }, $TsPrinter: class TsPrinter { constructor(definitions) { this.definitions = definitions; @@ -145,22 +221,22 @@ var LibraryEmbind = { }, $createFunctionDefinition__deps: ['$FunctionDefinition', '$heap32VectorToArray', '$readLatin1String', '$Argument', '$whenDependentTypesAreResolved'], $createFunctionDefinition: function(name, argCount, rawArgTypesAddr, hasThis, cb) { - var argTypes = heap32VectorToArray(argCount, rawArgTypesAddr); + const argTypes = heap32VectorToArray(argCount, rawArgTypesAddr); name = readLatin1String(name); whenDependentTypesAreResolved([], argTypes, function(argTypes) { - var returnType = argTypes[0]; - var thisType = null; - var argStart = 1; + const returnType = argTypes[0]; + let thisType = null; + let argStart = 1; if (hasThis) { thisType = argTypes[1]; argStart = 2; } - let args = []; - for (var i = argStart; i < argTypes.length; i++) { + const args = []; + for (let i = argStart; i < argTypes.length; i++) { args.push(new Argument(`_${i - argStart}`, argTypes[i])); } - var funcDef = new FunctionDefinition(name, returnType, args, thisType); + const funcDef = new FunctionDefinition(name, returnType, args, thisType); cb(funcDef); return []; }); @@ -222,7 +298,7 @@ var LibraryEmbind = { [rawType, rawPointerType, rawConstPointerType], baseClassRawType ? [baseClassRawType] : [], function(base) { - var classDef = new ClassDefinition(rawType, name, base.length ? base[0] : null); + const classDef = new ClassDefinition(rawType, name, base.length ? base[0] : null); moduleDefinitions.push(classDef); return [classDef, classDef, classDef]; } @@ -257,18 +333,144 @@ var LibraryEmbind = { isPureVirtual, isAsync) { createFunctionDefinition(methodName, argCount, rawArgTypesAddr, true, (funcDef) => { - let classDef = funcDef.thisType; + const classDef = funcDef.thisType; classDef.methods.push(funcDef); }); }, + _embind_register_enum__deps: ['$readLatin1String', '$EnumDefinition', '$moduleDefinitions'], + _embind_register_enum: function(rawType, name, size, isSigned) { + name = readLatin1String(name); + const enumDef = new EnumDefinition(rawType, name); + registerType(rawType, enumDef); + moduleDefinitions.push(enumDef); + }, + _embind_register_enum_value__deps: ['$readLatin1String', '$requireRegisteredType'], + _embind_register_enum_value: function(rawEnumType, name, enumValue) { + name = readLatin1String(name); + const enumDef = requireRegisteredType(rawEnumType, name); + enumDef.items.push([name, enumValue]); + }, + _embind_register_constant__deps: ['$readLatin1String', '$ConstantDefinition', '$whenDependentTypesAreResolved', '$moduleDefinitions'], + _embind_register_constant: function(name, typeId, value) { + name = readLatin1String(name); + whenDependentTypesAreResolved([], [typeId], function(types) { + const def = new ConstantDefinition(types[0], name); + moduleDefinitions.push(def); + return []; + }); + }, + _embind_register_value_array__deps: [ + '$readLatin1String', '$ValueArrayDefinition', '$tupleRegistrations'], + _embind_register_value_array: function( + rawType, + name, + constructorSignature, + rawConstructor, + destructorSignature, + rawDestructor + ) { + name = readLatin1String(name); + const valueArray = new ValueArrayDefinition(rawType, name); + tupleRegistrations[rawType] = valueArray; + }, + _embind_register_value_array_element__deps: ['$tupleRegistrations'], + _embind_register_value_array_element: function( + rawTupleType, + getterReturnType, + getterSignature, + getter, + getterContext, + setterArgumentType, + setterSignature, + setter, + setterContext + ) { + const valueArray = tupleRegistrations[rawTupleType]; + assert(getterReturnType === setterArgumentType, 'Mismatched getter and setter types are not supported.'); + valueArray.elementTypeIds.push(getterReturnType); + }, + _embind_finalize_value_array__deps: ['$whenDependentTypesAreResolved', '$moduleDefinitions', '$tupleRegistrations'], + _embind_finalize_value_array: function(rawTupleType) { + const valueArray = tupleRegistrations[rawTupleType]; + delete tupleRegistrations[rawTupleType]; + whenDependentTypesAreResolved([rawTupleType], valueArray.elementTypeIds, function(types) { + moduleDefinitions.push(valueArray); + valueArray.elements = types; + return [valueArray]; + }); + }, + _embind_register_value_object__deps: ['$readLatin1String', '$ValueObjectDefinition', '$structRegistrations'], + _embind_register_value_object: function( + rawType, + name, + constructorSignature, + rawConstructor, + destructorSignature, + rawDestructor + ) { + name = readLatin1String(name); + const valueObject = new ValueObjectDefinition(rawType, name); + structRegistrations[rawType] = valueObject; + }, + _embind_register_value_object_field__deps: [ + '$readLatin1String', '$structRegistrations'], + _embind_register_value_object_field: function( + structType, + fieldName, + getterReturnType, + getterSignature, + getter, + getterContext, + setterArgumentType, + setterSignature, + setter, + setterContext + ) { + const valueObject = structRegistrations[structType]; + assert(getterReturnType === setterArgumentType, 'Mismatched getter and setter types are not supported.'); + valueObject.fieldTypeIds.push(getterReturnType); + valueObject.fieldNames.push(readLatin1String(fieldName)); + }, + _embind_finalize_value_object__deps: ['$moduleDefinitions', '$whenDependentTypesAreResolved', '$structRegistrations'], + _embind_finalize_value_object: function(structType) { + const valueObject = structRegistrations[structType]; + delete structRegistrations[structType]; + whenDependentTypesAreResolved([structType], valueObject.fieldTypeIds, function(types) { + moduleDefinitions.push(valueObject); + for (let i = 0; i < types.length; i++) { + valueObject.fields.push({ + name: valueObject.fieldNames[i], + type: types[i], + }); + } + return [valueObject]; + }); + }, + _embind_register_smart_ptr__deps: ['$whenDependentTypesAreResolved'], + _embind_register_smart_ptr: function(rawType, + rawPointeeType, + name, + sharingPolicy, + getPointeeSignature, + rawGetPointee, + constructorSignature, + rawConstructor, + shareSignature, + rawShare, + destructorSignature, + rawDestructor) { + whenDependentTypesAreResolved([rawType], [rawPointeeType], function(pointeeType) { + return [pointeeType[0]]; + }); + }, $embindEmitTypes__deps: ['$awaitingDependencies', '$throwBindingError', '$getTypeName', '$moduleDefinitions', '$TsPrinter'], $embindEmitTypes__postset: 'addOnInit(embindEmitTypes);', $embindEmitTypes: function() { - for (var typeId in awaitingDependencies) { + for (const typeId in awaitingDependencies) { throwBindingError(`Missing type definition for '${getTypeName(typeId)}'`); } - var printer = new TsPrinter(moduleDefinitions); + const printer = new TsPrinter(moduleDefinitions); printer.print(); }, }; diff --git a/test/other/embind_tsgen.cpp b/test/other/embind_tsgen.cpp index fe930c8cfc55a..111a7b2abaea6 100644 --- a/test/other/embind_tsgen.cpp +++ b/test/other/embind_tsgen.cpp @@ -13,8 +13,63 @@ class Test { int const_fn() const { return 0; } }; + +Test class_returning_fn() { return Test(); } + +std::unique_ptr class_unique_ptr_returning_fn() { + return std::make_unique(); +} + +class Foo { + public: + void process(const Test& input) {} +}; + +enum Bar { kValueOne, kValueTwo, kValueThree }; + +Bar enum_returning_fn() { return kValueOne; } + +struct ValArr { + int x, y, z; +}; + +struct ValObj { + Foo foo; + Bar bar; +}; + +class ClassWithConstructor { + public: + ClassWithConstructor(int, const ValArr&) {} + + int fn(int x) { return 0; } +}; + +class ClassWithSmartPtrConstructor { + public: + ClassWithSmartPtrConstructor(int, const ValArr&) {} + + int fn(int x) { return 0; } +}; + +int smart_ptr_function(std::shared_ptr) { + return 0; +} + int global_fn(int, int) { return 0; } +class BaseClass { + public: + virtual ~BaseClass() = default; + virtual int fn(int x) { return 0; } +}; + +class DerivedClass : public BaseClass { + public: + int fn(int x) override { return 1; } + int fn2(int x) { return 2; } +}; + EMSCRIPTEN_BINDINGS(Test) { class_("Test") .function("functionOne", &Test::function_one) @@ -24,7 +79,59 @@ EMSCRIPTEN_BINDINGS(Test) { .function("constFn", &Test::const_fn) ; + function("class_returning_fn", &class_returning_fn); + function("class_unique_ptr_returning_fn", + &class_unique_ptr_returning_fn); + + constant("an_int", 5); + constant("a_bool", false); + constant("an_enum", Bar::kValueOne); + constant("a_class_instance", Test()); + + enum_("Bar") + .value("valueOne", Bar::kValueOne) + .value("valueTwo", Bar::kValueTwo) + .value("valueThree", Bar::kValueThree); + + function("enum_returning_fn", &enum_returning_fn); + + value_array("ValArr") + .element(&ValArr::x) + .element(&ValArr::y) + .element(&ValArr::z); + + value_array>("ValArrIx") + .element(emscripten::index<0>()) + .element(emscripten::index<1>()) + .element(emscripten::index<2>()) + .element(emscripten::index<3>()); + + value_object("ValObj") + .field("foo", &ValObj::foo) + .field("bar", &ValObj::bar); + + register_vector("IntVec"); + + class_("Foo").function("process", &Foo::process); + function("global_fn", &global_fn); + + class_("ClassWithConstructor") + .constructor() + .function("fn", &ClassWithConstructor::fn); + + class_("ClassWithSmartPtrConstructor") + .smart_ptr_constructor( + "ClassWithSmartPtrConstructor", + &std::make_shared) + .function("fn", &ClassWithSmartPtrConstructor::fn); + + function("smart_ptr_function", &smart_ptr_function); + + class_("BaseClass").function("fn", &BaseClass::fn); + + class_>("DerivedClass") + .function("fn2", &DerivedClass::fn2); } int main() { diff --git a/test/other/embind_tsgen.d.ts b/test/other/embind_tsgen.d.ts index 6ad2fe91f2f38..ec2a265d99995 100644 --- a/test/other/embind_tsgen.d.ts +++ b/test/other/embind_tsgen.d.ts @@ -7,7 +7,70 @@ export interface Test { delete(): void; } +export interface BarValue { + value: T; +} +export type Bar = BarValue<0>|BarValue<1>|BarValue<2>; + +export type ValArrIx = [ Bar, Bar, Bar, Bar ]; + +export interface IntVec { + push_back(_0: number): void; + resize(_0: number, _1: number): void; + size(): number; + set(_0: number, _1: number): boolean; + get(_0: number): any; + delete(): void; +} + +export interface Foo { + process(_0: Test): void; + delete(): void; +} + +export type ValObj = { + foo: Foo, + bar: Bar +}; + +export interface ClassWithConstructor { + fn(_0: number): number; + delete(): void; +} + +export interface ClassWithSmartPtrConstructor { + fn(_0: number): number; + delete(): void; +} + +export interface BaseClass { + fn(_0: number): number; + delete(): void; +} + +export interface DerivedClass extends BaseClass { + fn2(_0: number): number; + delete(): void; +} + +export type ValArr = [ number, number, number ]; + export interface MainModule { Test: {new(): Test}; + class_returning_fn(): Test; + class_unique_ptr_returning_fn(): Test; + a_class_instance: Test; + an_enum: Bar; + Bar: {valueOne: BarValue<0>, valueTwo: BarValue<1>, valueThree: BarValue<2>}; + enum_returning_fn(): Bar; + IntVec: {new(): IntVec}; + Foo: {new(): Foo}; + ClassWithConstructor: {new(_0: number, _1: ValArr): ClassWithConstructor}; + ClassWithSmartPtrConstructor: {new(_0: number, _1: ValArr): ClassWithSmartPtrConstructor}; + BaseClass: {new(): BaseClass}; + DerivedClass: {new(): DerivedClass}; + a_bool: boolean; + an_int: number; global_fn(_0: number, _1: number): number; + smart_ptr_function(_0: ClassWithSmartPtrConstructor): number; } From fb04dc6e255b3468f3ed8140e33402973947b9a7 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 7 Jul 2023 15:19:13 -0700 Subject: [PATCH 0528/1523] Update terser to v5.18.2 and verify optional chaining support (#19805) Fixes: #15827 --- ...applyImportAndExportNameChanges2-output.js | 4 +- ...al-runtime-applyDCEGraphRemovals-output.js | 4 +- .../test_metadce_minimal_pthreads.jssize | 2 +- third_party/terser/README.md | 8 +- third_party/terser/terser.js | 52561 +++++++++------- tools/acorn-optimizer.js | 28 +- tools/unsafe_optimizations.js | 9 +- 7 files changed, 30976 insertions(+), 21640 deletions(-) diff --git a/test/optimizer/applyImportAndExportNameChanges2-output.js b/test/optimizer/applyImportAndExportNameChanges2-output.js index 03d3dfdbb746e..a2d41cf3f95ab 100644 --- a/test/optimizer/applyImportAndExportNameChanges2-output.js +++ b/test/optimizer/applyImportAndExportNameChanges2-output.js @@ -264,7 +264,7 @@ var imports = { var ___errno_location, _llvm_bswap_i32, _main, _memcpy, _memset, dynCall_ii, dynCall_iiii; -WebAssembly.instantiate(Module["wasm"], imports).then(output => { +WebAssembly.instantiate(Module["wasm"], imports).then((output => { var asm = output.instance.exports; ___errno_location = asm["j"]; _llvm_bswap_i32 = asm["k"]; @@ -275,4 +275,4 @@ WebAssembly.instantiate(Module["wasm"], imports).then(output => { dynCall_iiii = asm["p"]; initRuntime(asm); ready(); -}); +})); diff --git a/test/optimizer/minimal-runtime-applyDCEGraphRemovals-output.js b/test/optimizer/minimal-runtime-applyDCEGraphRemovals-output.js index 465ce4410ab35..7607038014f8c 100644 --- a/test/optimizer/minimal-runtime-applyDCEGraphRemovals-output.js +++ b/test/optimizer/minimal-runtime-applyDCEGraphRemovals-output.js @@ -5,14 +5,14 @@ var wasmImports = { save2: 2 }; -WebAssembly.instantiate(Module["wasm"], imports).then(output => { +WebAssembly.instantiate(Module["wasm"], imports).then((output => { asm = output.instance.exports; expD1 = asm["expD1"]; expD2 = asm["expD2"]; expD3 = asm["expD3"]; initRuntime(asm); ready(); -}); +})); expD1; diff --git a/test/other/metadce/test_metadce_minimal_pthreads.jssize b/test/other/metadce/test_metadce_minimal_pthreads.jssize index 157d7144163c0..b348f398ae4b1 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.jssize +++ b/test/other/metadce/test_metadce_minimal_pthreads.jssize @@ -1 +1 @@ -15050 +15052 diff --git a/third_party/terser/README.md b/third_party/terser/README.md index 9705a262ba917..bae2adf9c6c60 100644 --- a/third_party/terser/README.md +++ b/third_party/terser/README.md @@ -1,5 +1,5 @@ -Bundled version of terser 4.1.0 with emscripten patches -======================================================= +Bundled version of terser 5.18.2 with emscripten patches +======================================================== We maintain a few downstream patches to terser which means we can't use the version published in npm. @@ -13,5 +13,5 @@ To make changes to this code please submit patches to https://github.com/emscripten-core/terser/ and then re-create this bundle using the following steps: - $ npx rollup -c - $ cp dist/bundle.js $EMSCRIPTEN_ROOT/third_party/terser/terser.js + $ CI=1 npx rollup -c + $ cp dist/bundle.min.js $EMSCRIPTEN_ROOT/third_party/terser/terser.js diff --git a/third_party/terser/terser.js b/third_party/terser/terser.js index 7ec5e7239a97d..e15f713bd67cc 100644 --- a/third_party/terser/terser.js +++ b/third_party/terser/terser.js @@ -1,21680 +1,31021 @@ (function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : - typeof define === 'function' && define.amd ? define(['exports'], factory) : - (global = global || self, factory(global.Terser = {})); -}(this, (function (exports) { 'use strict'; - - /*********************************************************************** - - A JavaScript tokenizer / parser / beautifier / compressor. - https://github.com/mishoo/UglifyJS2 - - -------------------------------- (C) --------------------------------- - - Author: Mihai Bazon - - http://mihai.bazon.net/blog - - Distributed under the BSD license: - - Copyright 2012 (c) Mihai Bazon - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - * Redistributions of source code must retain the above - copyright notice, this list of conditions and the following - disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials - provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY - EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - SUCH DAMAGE. - - ***********************************************************************/ - - function characters(str) { - return str.split(""); - } - - function member(name, array) { - return array.includes(name); - } - - class DefaultsError extends Error { - constructor(msg, defs) { - super(); - - this.name = "DefaultsError"; - this.message = msg; - this.defs = defs; - } - } - - function defaults(args, defs, croak) { - if (args === true) - args = {}; - var ret = args || {}; - if (croak) for (var i in ret) if (HOP(ret, i) && !HOP(defs, i)) - throw new DefaultsError("`" + i + "` is not a supported option", defs); - for (var i in defs) if (HOP(defs, i)) { - ret[i] = (args && HOP(args, i)) ? args[i] : defs[i]; - } - return ret; - } - - function noop() {} - function return_false() { return false; } - function return_true() { return true; } - function return_this() { return this; } - function return_null() { return null; } - - var MAP = (function() { - function MAP(a, f, backwards) { - var ret = [], top = [], i; - function doit() { - var val = f(a[i], i); - var is_last = val instanceof Last; - if (is_last) val = val.v; - if (val instanceof AtTop) { - val = val.v; - if (val instanceof Splice) { - top.push.apply(top, backwards ? val.v.slice().reverse() : val.v); - } else { - top.push(val); - } - } else if (val !== skip) { - if (val instanceof Splice) { - ret.push.apply(ret, backwards ? val.v.slice().reverse() : val.v); - } else { - ret.push(val); - } - } - return is_last; - } - if (Array.isArray(a)) { - if (backwards) { - for (i = a.length; --i >= 0;) if (doit()) break; - ret.reverse(); - top.reverse(); - } else { - for (i = 0; i < a.length; ++i) if (doit()) break; - } - } else { - for (i in a) if (HOP(a, i)) if (doit()) break; - } - return top.concat(ret); - } - MAP.at_top = function(val) { return new AtTop(val); }; - MAP.splice = function(val) { return new Splice(val); }; - MAP.last = function(val) { return new Last(val); }; - var skip = MAP.skip = {}; - function AtTop(val) { this.v = val; } - function Splice(val) { this.v = val; } - function Last(val) { this.v = val; } - return MAP; - })(); - - function push_uniq(array, el) { - if (!array.includes(el)) - array.push(el); - } - - function string_template(text, props) { - return text.replace(/{(.+?)}/g, function(str, p) { - return props && props[p]; - }); - } - - function remove(array, el) { - for (var i = array.length; --i >= 0;) { - if (array[i] === el) array.splice(i, 1); - } - } - - function mergeSort(array, cmp) { - if (array.length < 2) return array.slice(); - function merge(a, b) { - var r = [], ai = 0, bi = 0, i = 0; - while (ai < a.length && bi < b.length) { - cmp(a[ai], b[bi]) <= 0 - ? r[i++] = a[ai++] - : r[i++] = b[bi++]; - } - if (ai < a.length) r.push.apply(r, a.slice(ai)); - if (bi < b.length) r.push.apply(r, b.slice(bi)); - return r; - } - function _ms(a) { - if (a.length <= 1) - return a; - var m = Math.floor(a.length / 2), left = a.slice(0, m), right = a.slice(m); - left = _ms(left); - right = _ms(right); - return merge(left, right); - } - return _ms(array); - } - - function makePredicate(words) { - if (!Array.isArray(words)) words = words.split(" "); - - return new Set(words); - } - - function map_add(map, key, value) { - if (map.has(key)) { - map.get(key).push(value); - } else { - map.set(key, [ value ]); - } - } - - function HOP(obj, prop) { - return Object.prototype.hasOwnProperty.call(obj, prop); - } - - function keep_name(keep_setting, name) { - return keep_setting === true - || (keep_setting instanceof RegExp && keep_setting.test(name)); - } - - /*********************************************************************** - - A JavaScript tokenizer / parser / beautifier / compressor. - https://github.com/mishoo/UglifyJS2 - - -------------------------------- (C) --------------------------------- - - Author: Mihai Bazon - - http://mihai.bazon.net/blog - - Distributed under the BSD license: - - Copyright 2012 (c) Mihai Bazon - Parser based on parse-js (http://marijn.haverbeke.nl/parse-js/). - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - * Redistributions of source code must retain the above - copyright notice, this list of conditions and the following - disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials - provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY - EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - SUCH DAMAGE. - - ***********************************************************************/ - - var KEYWORDS = "break case catch class const continue debugger default delete do else export extends finally for function if in instanceof let new return switch throw try typeof var void while with"; - var KEYWORDS_ATOM = "false null true"; - var RESERVED_WORDS = "enum implements import interface package private protected public static super this " + KEYWORDS_ATOM + " " + KEYWORDS; - var KEYWORDS_BEFORE_EXPRESSION = "return new delete throw else case yield await"; - - KEYWORDS = makePredicate(KEYWORDS); - RESERVED_WORDS = makePredicate(RESERVED_WORDS); - KEYWORDS_BEFORE_EXPRESSION = makePredicate(KEYWORDS_BEFORE_EXPRESSION); - KEYWORDS_ATOM = makePredicate(KEYWORDS_ATOM); - - var OPERATOR_CHARS = makePredicate(characters("+-*&%=<>!?|~^")); - - var RE_NUM_LITERAL = /[0-9a-f]/i; - var RE_HEX_NUMBER = /^0x[0-9a-f]+$/i; - var RE_OCT_NUMBER = /^0[0-7]+$/; - var RE_ES6_OCT_NUMBER = /^0o[0-7]+$/i; - var RE_BIN_NUMBER = /^0b[01]+$/i; - var RE_DEC_NUMBER = /^\d*\.?\d*(?:e[+-]?\d*(?:\d\.?|\.?\d)\d*)?$/i; - var RE_BIG_INT = /^(0[xob])?[0-9]+n$/i; - - var OPERATORS = makePredicate([ - "in", - "instanceof", - "typeof", - "new", - "void", - "delete", - "++", - "--", - "+", - "-", - "!", - "~", - "&", - "|", - "^", - "*", - "**", - "/", - "%", - ">>", - "<<", - ">>>", - "<", - ">", - "<=", - ">=", - "==", - "===", - "!=", - "!==", - "?", - "=", - "+=", - "-=", - "/=", - "*=", - "**=", - "%=", - ">>=", - "<<=", - ">>>=", - "|=", - "^=", - "&=", - "&&", - "||" - ]); - - var WHITESPACE_CHARS = makePredicate(characters(" \u00a0\n\r\t\f\u000b\u200b\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000\uFEFF")); - - var NEWLINE_CHARS = makePredicate(characters("\n\r\u2028\u2029")); - - var PUNC_AFTER_EXPRESSION = makePredicate(characters(";]),:")); - - var PUNC_BEFORE_EXPRESSION = makePredicate(characters("[{(,;:")); - - var PUNC_CHARS = makePredicate(characters("[]{}(),;:")); - - /* -----[ Tokenizer ]----- */ - - // surrogate safe regexps adapted from https://github.com/mathiasbynens/unicode-8.0.0/tree/89b412d8a71ecca9ed593d9e9fa073ab64acfebe/Binary_Property - var UNICODE = { - ID_Start: /[A-Za-z\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0-\u08B4\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2118-\u211D\u2124\u2126\u2128\u212A-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309B-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FD5\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AD\uA7B0-\uA7B7\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1F\uDF30-\uDF4A\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE4\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC03-\uDC37\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE80-\uDEAA\uDF00-\uDF19]|\uD806[\uDCA0-\uDCDF\uDCFF\uDEC0-\uDEF8]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50\uDF93-\uDF9F]|\uD82C[\uDC00\uDC01]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB]|\uD83A[\uDC00-\uDCC4]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1]|\uD87E[\uDC00-\uDE1D]/, - ID_Continue: /[0-9A-Z_a-z\xAA\xB5\xB7\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u08A0-\u08B4\u08E3-\u0963\u0966-\u096F\u0971-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0AF9\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C00-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58-\u0C5A\u0C60-\u0C63\u0C66-\u0C6F\u0C81-\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D01-\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D57\u0D5F-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DE6-\u0DEF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1369-\u1371\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191E\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19DA\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1AB0-\u1ABD\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1CD0-\u1CD2\u1CD4-\u1CF6\u1CF8\u1CF9\u1D00-\u1DF5\u1DFC-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2118-\u211D\u2124\u2126\u2128\u212A-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FD5\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AD\uA7B0-\uA7B7\uA7F7-\uA827\uA840-\uA873\uA880-\uA8C4\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA8FD\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uA9E0-\uA9FE\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE2F\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDDFD\uDE80-\uDE9C\uDEA0-\uDED0\uDEE0\uDF00-\uDF1F\uDF30-\uDF4A\uDF50-\uDF7A\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCA0-\uDCA9\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00-\uDE03\uDE05\uDE06\uDE0C-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE38-\uDE3A\uDE3F\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE6\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC00-\uDC46\uDC66-\uDC6F\uDC7F-\uDCBA\uDCD0-\uDCE8\uDCF0-\uDCF9\uDD00-\uDD34\uDD36-\uDD3F\uDD50-\uDD73\uDD76\uDD80-\uDDC4\uDDCA-\uDDCC\uDDD0-\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE37\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEEA\uDEF0-\uDEF9\uDF00-\uDF03\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3C-\uDF44\uDF47\uDF48\uDF4B-\uDF4D\uDF50\uDF57\uDF5D-\uDF63\uDF66-\uDF6C\uDF70-\uDF74]|\uD805[\uDC80-\uDCC5\uDCC7\uDCD0-\uDCD9\uDD80-\uDDB5\uDDB8-\uDDC0\uDDD8-\uDDDD\uDE00-\uDE40\uDE44\uDE50-\uDE59\uDE80-\uDEB7\uDEC0-\uDEC9\uDF00-\uDF19\uDF1D-\uDF2B\uDF30-\uDF39]|\uD806[\uDCA0-\uDCE9\uDCFF\uDEC0-\uDEF8]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE60-\uDE69\uDED0-\uDEED\uDEF0-\uDEF4\uDF00-\uDF36\uDF40-\uDF43\uDF50-\uDF59\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50-\uDF7E\uDF8F-\uDF9F]|\uD82C[\uDC00\uDC01]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99\uDC9D\uDC9E]|\uD834[\uDD65-\uDD69\uDD6D-\uDD72\uDD7B-\uDD82\uDD85-\uDD8B\uDDAA-\uDDAD\uDE42-\uDE44]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB\uDFCE-\uDFFF]|\uD836[\uDE00-\uDE36\uDE3B-\uDE6C\uDE75\uDE84\uDE9B-\uDE9F\uDEA1-\uDEAF]|\uD83A[\uDC00-\uDCC4\uDCD0-\uDCD6]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1]|\uD87E[\uDC00-\uDE1D]|\uDB40[\uDD00-\uDDEF]/, - }; - - function get_full_char(str, pos) { - var char = str.charAt(pos); - if (is_surrogate_pair_head(char)) { - var next = str.charAt(pos + 1); - if (is_surrogate_pair_tail(next)) { - return char + next; - } - } - if (is_surrogate_pair_tail(char)) { - var prev = str.charAt(pos - 1); - if (is_surrogate_pair_head(prev)) { - return prev + char; - } - } - return char; - } - - function get_full_char_code(str, pos) { - // https://en.wikipedia.org/wiki/Universal_Character_Set_characters#Surrogates - if (is_surrogate_pair_head(str.charAt(pos))) { - return 0x10000 + (str.charCodeAt(pos) - 0xd800 << 10) + str.charCodeAt(pos + 1) - 0xdc00; - } - return str.charCodeAt(pos); - } - - function get_full_char_length(str) { - var surrogates = 0; - - for (var i = 0; i < str.length; i++) { - if (is_surrogate_pair_head(str.charCodeAt(i))) { - if (is_surrogate_pair_tail(str.charCodeAt(i + 1))) { - surrogates++; - i++; - } - } - } - - return str.length - surrogates; - } - - function from_char_code(code) { - // Based on https://github.com/mathiasbynens/String.fromCodePoint/blob/master/fromcodepoint.js - if (code > 0xFFFF) { - code -= 0x10000; - return (String.fromCharCode((code >> 10) + 0xD800) + - String.fromCharCode((code % 0x400) + 0xDC00)); - } - return String.fromCharCode(code); - } - - function is_surrogate_pair_head(code) { - if (typeof code === "string") - code = code.charCodeAt(0); - - return code >= 0xd800 && code <= 0xdbff; - } - - function is_surrogate_pair_tail(code) { - if (typeof code === "string") - code = code.charCodeAt(0); - return code >= 0xdc00 && code <= 0xdfff; - } - - function is_digit(code) { - return code >= 48 && code <= 57; - } - - function is_identifier_start(ch) { - var code = ch.charCodeAt(0); - return UNICODE.ID_Start.test(ch) || code == 36 || code == 95; - } - - function is_identifier_char(ch) { - var code = ch.charCodeAt(0); - return UNICODE.ID_Continue.test(ch) - || code == 36 - || code == 95 - || code == 8204 // \u200c: zero-width non-joiner - || code == 8205 // \u200d: zero-width joiner (in my ECMA-262 PDF, this is also 200c) - ; - } - - function is_identifier_string(str) { - return /^[a-z_$][a-z0-9_$]*$/i.test(str); - } - - function parse_js_number(num) { - if (RE_HEX_NUMBER.test(num)) { - return parseInt(num.substr(2), 16); - } else if (RE_OCT_NUMBER.test(num)) { - return parseInt(num.substr(1), 8); - } else if (RE_ES6_OCT_NUMBER.test(num)) { - return parseInt(num.substr(2), 8); - } else if (RE_BIN_NUMBER.test(num)) { - return parseInt(num.substr(2), 2); - } else if (RE_DEC_NUMBER.test(num)) { - return parseFloat(num); - } else { - var val = parseFloat(num); - if (val == num) return val; - } - } - - class JS_Parse_Error extends Error { - constructor(message, filename, line, col, pos) { - super(); - - this.name = "SyntaxError"; - this.message = message; - this.filename = filename; - this.line = line; - this.col = col; - this.pos = pos; - } - } - - function js_error(message, filename, line, col, pos) { - throw new JS_Parse_Error(message, filename, line, col, pos); - } - - function is_token(token, type, val) { - return token.type == type && (val == null || token.value == val); - } - - var EX_EOF = {}; - - function tokenizer($TEXT, filename, html5_comments, shebang) { - - var S = { - text : $TEXT, - filename : filename, - pos : 0, - tokpos : 0, - line : 1, - tokline : 0, - col : 0, - tokcol : 0, - newline_before : false, - regex_allowed : false, - brace_counter : 0, - template_braces : [], - comments_before : [], - directives : {}, - directive_stack : [] - }; - - function peek() { return get_full_char(S.text, S.pos); } - - function next(signal_eof, in_string) { - var ch = get_full_char(S.text, S.pos++); - if (signal_eof && !ch) - throw EX_EOF; - if (NEWLINE_CHARS.has(ch)) { - S.newline_before = S.newline_before || !in_string; - ++S.line; - S.col = 0; - if (!in_string && ch == "\r" && peek() == "\n") { - // treat a \r\n sequence as a single \n - ++S.pos; - ch = "\n"; - } - } else { - if (ch.length > 1) { - ++S.pos; - ++S.col; - } - ++S.col; - } - return ch; - } - - function forward(i) { - while (i-- > 0) next(); - } - - function looking_at(str) { - return S.text.substr(S.pos, str.length) == str; - } - - function find_eol() { - var text = S.text; - for (var i = S.pos, n = S.text.length; i < n; ++i) { - var ch = text[i]; - if (NEWLINE_CHARS.has(ch)) - return i; - } - return -1; - } - - function find(what, signal_eof) { - var pos = S.text.indexOf(what, S.pos); - if (signal_eof && pos == -1) throw EX_EOF; - return pos; - } - - function start_token() { - S.tokline = S.line; - S.tokcol = S.col; - S.tokpos = S.pos; - } - - var prev_was_dot = false; - var previous_token = null; - function token(type, value, is_comment) { - S.regex_allowed = ((type == "operator" && !UNARY_POSTFIX.has(value)) || - (type == "keyword" && KEYWORDS_BEFORE_EXPRESSION.has(value)) || - (type == "punc" && PUNC_BEFORE_EXPRESSION.has(value))) || - (type == "arrow"); - if (type == "punc" && value == ".") { - prev_was_dot = true; - } else if (!is_comment) { - prev_was_dot = false; - } - var ret = { - type : type, - value : value, - line : S.tokline, - col : S.tokcol, - pos : S.tokpos, - endline : S.line, - endcol : S.col, - endpos : S.pos, - nlb : S.newline_before, - file : filename - }; - if (/^(?:num|string|regexp)$/i.test(type)) { - ret.raw = $TEXT.substring(ret.pos, ret.endpos); - } - if (!is_comment) { - ret.comments_before = S.comments_before; - ret.comments_after = S.comments_before = []; - } - S.newline_before = false; - ret = new AST_Token(ret); - if (!is_comment) previous_token = ret; - return ret; - } - - function skip_whitespace() { - while (WHITESPACE_CHARS.has(peek())) - next(); - } - - function read_while(pred) { - var ret = "", ch, i = 0; - while ((ch = peek()) && pred(ch, i++)) - ret += next(); - return ret; - } - - function parse_error(err) { - js_error(err, filename, S.tokline, S.tokcol, S.tokpos); - } - - function read_num(prefix) { - var has_e = false, after_e = false, has_x = false, has_dot = prefix == ".", is_big_int = false; - var num = read_while(function(ch, i) { - if (is_big_int) return false; - - var code = ch.charCodeAt(0); - switch (code) { - case 98: case 66: // bB - return (has_x = true); // Can occur in hex sequence, don't return false yet - case 111: case 79: // oO - case 120: case 88: // xX - return has_x ? false : (has_x = true); - case 101: case 69: // eE - return has_x ? true : has_e ? false : (has_e = after_e = true); - case 45: // - - return after_e || (i == 0 && !prefix); - case 43: // + - return after_e; - case (after_e = false, 46): // . - return (!has_dot && !has_x && !has_e) ? (has_dot = true) : false; +typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@jridgewell/source-map')) : +typeof define === 'function' && define.amd ? define(['exports', '@jridgewell/source-map'], factory) : +(global = global || self, factory(global.Terser = {}, global.sourceMap)); +}(this, (function (exports, sourceMap) { 'use strict'; + +/*********************************************************************** + + A JavaScript tokenizer / parser / beautifier / compressor. + https://github.com/mishoo/UglifyJS2 + + -------------------------------- (C) --------------------------------- + + Author: Mihai Bazon + + http://mihai.bazon.net/blog + + Distributed under the BSD license: + + Copyright 2012 (c) Mihai Bazon + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + ***********************************************************************/ + +function characters(str) { + return str.split(""); +} + +function member(name, array) { + return array.includes(name); +} + +class DefaultsError extends Error { + constructor(msg, defs) { + super(); + + this.name = "DefaultsError"; + this.message = msg; + this.defs = defs; + } +} + +function defaults(args, defs, croak) { + if (args === true) { + args = {}; + } else if (args != null && typeof args === "object") { + args = {...args}; + } + + const ret = args || {}; + + if (croak) for (const i in ret) if (HOP(ret, i) && !HOP(defs, i)) { + throw new DefaultsError("`" + i + "` is not a supported option", defs); + } + + for (const i in defs) if (HOP(defs, i)) { + if (!args || !HOP(args, i)) { + ret[i] = defs[i]; + } else if (i === "ecma") { + let ecma = args[i] | 0; + if (ecma > 5 && ecma < 2015) ecma += 2009; + ret[i] = ecma; + } else { + ret[i] = (args && HOP(args, i)) ? args[i] : defs[i]; + } + } + + return ret; +} + +function noop() {} +function return_false() { return false; } +function return_true() { return true; } +function return_this() { return this; } +function return_null() { return null; } + +var MAP = (function() { + function MAP(a, tw, allow_splicing = true) { + const new_a = []; + + for (let i = 0; i < a.length; ++i) { + let item = a[i]; + let ret = item.transform(tw, allow_splicing); + + if (ret instanceof AST_Node) { + new_a.push(ret); + } else if (ret instanceof Splice) { + new_a.push(...ret.v); + } + } + + return new_a; + } + + MAP.splice = function(val) { return new Splice(val); }; + MAP.skip = {}; + function Splice(val) { this.v = val; } + return MAP; +})(); + +function make_node(ctor, orig, props) { + if (!props) props = {}; + if (orig) { + if (!props.start) props.start = orig.start; + if (!props.end) props.end = orig.end; + } + return new ctor(props); +} + +function push_uniq(array, el) { + if (!array.includes(el)) + array.push(el); +} + +function string_template(text, props) { + return text.replace(/{(.+?)}/g, function(str, p) { + return props && props[p]; + }); +} + +function remove(array, el) { + for (var i = array.length; --i >= 0;) { + if (array[i] === el) array.splice(i, 1); + } +} + +function mergeSort(array, cmp) { + if (array.length < 2) return array.slice(); + function merge(a, b) { + var r = [], ai = 0, bi = 0, i = 0; + while (ai < a.length && bi < b.length) { + cmp(a[ai], b[bi]) <= 0 + ? r[i++] = a[ai++] + : r[i++] = b[bi++]; + } + if (ai < a.length) r.push.apply(r, a.slice(ai)); + if (bi < b.length) r.push.apply(r, b.slice(bi)); + return r; + } + function _ms(a) { + if (a.length <= 1) + return a; + var m = Math.floor(a.length / 2), left = a.slice(0, m), right = a.slice(m); + left = _ms(left); + right = _ms(right); + return merge(left, right); + } + return _ms(array); +} + +function makePredicate(words) { + if (!Array.isArray(words)) words = words.split(" "); + + return new Set(words.sort()); +} + +function map_add(map, key, value) { + if (map.has(key)) { + map.get(key).push(value); + } else { + map.set(key, [ value ]); + } +} + +function map_from_object(obj) { + var map = new Map(); + for (var key in obj) { + if (HOP(obj, key) && key.charAt(0) === "$") { + map.set(key.substr(1), obj[key]); + } + } + return map; +} + +function map_to_object(map) { + var obj = Object.create(null); + map.forEach(function (value, key) { + obj["$" + key] = value; + }); + return obj; +} + +function HOP(obj, prop) { + return Object.prototype.hasOwnProperty.call(obj, prop); +} + +function keep_name(keep_setting, name) { + return keep_setting === true + || (keep_setting instanceof RegExp && keep_setting.test(name)); +} + +var lineTerminatorEscape = { + "\0": "0", + "\n": "n", + "\r": "r", + "\u2028": "u2028", + "\u2029": "u2029", +}; +function regexp_source_fix(source) { + // V8 does not escape line terminators in regexp patterns in node 12 + // We'll also remove literal \0 + return source.replace(/[\0\n\r\u2028\u2029]/g, function (match, offset) { + var escaped = source[offset - 1] == "\\" + && (source[offset - 2] != "\\" + || /(?:^|[^\\])(?:\\{2})*$/.test(source.slice(0, offset - 1))); + return (escaped ? "" : "\\") + lineTerminatorEscape[match]; + }); +} + +// Subset of regexps that is not going to cause regexp based DDOS +// https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS +const re_safe_regexp = /^[\\/|\0\s\w^$.[\]()]*$/; + +/** Check if the regexp is safe for Terser to create without risking a RegExp DOS */ +const regexp_is_safe = (source) => re_safe_regexp.test(source); + +const all_flags = "dgimsuyv"; +function sort_regexp_flags(flags) { + const existing_flags = new Set(flags.split("")); + let out = ""; + for (const flag of all_flags) { + if (existing_flags.has(flag)) { + out += flag; + existing_flags.delete(flag); + } + } + if (existing_flags.size) { + // Flags Terser doesn't know about + existing_flags.forEach(flag => { out += flag; }); + } + return out; +} + +function has_annotation(node, annotation) { + return node._annotations & annotation; +} + +function set_annotation(node, annotation) { + node._annotations |= annotation; +} + +function clear_annotation(node, annotation) { + node._annotations &= ~annotation; +} + +/*********************************************************************** + + A JavaScript tokenizer / parser / beautifier / compressor. + https://github.com/mishoo/UglifyJS2 + + -------------------------------- (C) --------------------------------- + + Author: Mihai Bazon + + http://mihai.bazon.net/blog + + Distributed under the BSD license: + + Copyright 2012 (c) Mihai Bazon + Parser based on parse-js (http://marijn.haverbeke.nl/parse-js/). + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + ***********************************************************************/ + +var LATEST_RAW = ""; // Only used for numbers and template strings +var TEMPLATE_RAWS = new Map(); // Raw template strings + +var KEYWORDS = "break case catch class const continue debugger default delete do else export extends finally for function if in instanceof let new return switch throw try typeof var void while with"; +var KEYWORDS_ATOM = "false null true"; +var RESERVED_WORDS = "enum import super this " + KEYWORDS_ATOM + " " + KEYWORDS; +var ALL_RESERVED_WORDS = "implements interface package private protected public static " + RESERVED_WORDS; +var KEYWORDS_BEFORE_EXPRESSION = "return new delete throw else case yield await"; + +KEYWORDS = makePredicate(KEYWORDS); +RESERVED_WORDS = makePredicate(RESERVED_WORDS); +KEYWORDS_BEFORE_EXPRESSION = makePredicate(KEYWORDS_BEFORE_EXPRESSION); +KEYWORDS_ATOM = makePredicate(KEYWORDS_ATOM); +ALL_RESERVED_WORDS = makePredicate(ALL_RESERVED_WORDS); + +var OPERATOR_CHARS = makePredicate(characters("+-*&%=<>!?|~^")); + +var RE_NUM_LITERAL = /[0-9a-f]/i; +var RE_HEX_NUMBER = /^0x[0-9a-f]+$/i; +var RE_OCT_NUMBER = /^0[0-7]+$/; +var RE_ES6_OCT_NUMBER = /^0o[0-7]+$/i; +var RE_BIN_NUMBER = /^0b[01]+$/i; +var RE_DEC_NUMBER = /^\d*\.?\d*(?:e[+-]?\d*(?:\d\.?|\.?\d)\d*)?$/i; +var RE_BIG_INT = /^(0[xob])?[0-9a-f]+n$/i; + +var OPERATORS = makePredicate([ + "in", + "instanceof", + "typeof", + "new", + "void", + "delete", + "++", + "--", + "+", + "-", + "!", + "~", + "&", + "|", + "^", + "*", + "**", + "/", + "%", + ">>", + "<<", + ">>>", + "<", + ">", + "<=", + ">=", + "==", + "===", + "!=", + "!==", + "?", + "=", + "+=", + "-=", + "||=", + "&&=", + "??=", + "/=", + "*=", + "**=", + "%=", + ">>=", + "<<=", + ">>>=", + "|=", + "^=", + "&=", + "&&", + "??", + "||", +]); + +var WHITESPACE_CHARS = makePredicate(characters(" \u00a0\n\r\t\f\u000b\u200b\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000\uFEFF")); + +var NEWLINE_CHARS = makePredicate(characters("\n\r\u2028\u2029")); + +var PUNC_AFTER_EXPRESSION = makePredicate(characters(";]),:")); + +var PUNC_BEFORE_EXPRESSION = makePredicate(characters("[{(,;:")); + +var PUNC_CHARS = makePredicate(characters("[]{}(),;:")); + +/* -----[ Tokenizer ]----- */ + +// surrogate safe regexps adapted from https://github.com/mathiasbynens/unicode-8.0.0/tree/89b412d8a71ecca9ed593d9e9fa073ab64acfebe/Binary_Property +var UNICODE = { + ID_Start: /[$A-Z_a-z\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0-\u08B4\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2118-\u211D\u2124\u2126\u2128\u212A-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309B-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FD5\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AD\uA7B0-\uA7B7\uA7F7-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1F\uDF30-\uDF4A\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE4\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC03-\uDC37\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE80-\uDEAA\uDF00-\uDF19]|\uD806[\uDCA0-\uDCDF\uDCFF\uDEC0-\uDEF8]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50\uDF93-\uDF9F]|\uD82C[\uDC00\uDC01]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB]|\uD83A[\uDC00-\uDCC4]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1]|\uD87E[\uDC00-\uDE1D]/, + ID_Continue: /(?:[$0-9A-Z_a-z\xAA\xB5\xB7\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0300-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u0483-\u0487\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05BD\u05BF\u05C1\u05C2\u05C4\u05C5\u05C7\u05D0-\u05EA\u05F0-\u05F2\u0610-\u061A\u0620-\u0669\u066E-\u06D3\u06D5-\u06DC\u06DF-\u06E8\u06EA-\u06FC\u06FF\u0710-\u074A\u074D-\u07B1\u07C0-\u07F5\u07FA\u0800-\u082D\u0840-\u085B\u08A0-\u08B4\u08E3-\u0963\u0966-\u096F\u0971-\u0983\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BC-\u09C4\u09C7\u09C8\u09CB-\u09CE\u09D7\u09DC\u09DD\u09DF-\u09E3\u09E6-\u09F1\u0A01-\u0A03\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A3C\u0A3E-\u0A42\u0A47\u0A48\u0A4B-\u0A4D\u0A51\u0A59-\u0A5C\u0A5E\u0A66-\u0A75\u0A81-\u0A83\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABC-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0AD0\u0AE0-\u0AE3\u0AE6-\u0AEF\u0AF9\u0B01-\u0B03\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3C-\u0B44\u0B47\u0B48\u0B4B-\u0B4D\u0B56\u0B57\u0B5C\u0B5D\u0B5F-\u0B63\u0B66-\u0B6F\u0B71\u0B82\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD0\u0BD7\u0BE6-\u0BEF\u0C00-\u0C03\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D\u0C55\u0C56\u0C58-\u0C5A\u0C60-\u0C63\u0C66-\u0C6F\u0C81-\u0C83\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBC-\u0CC4\u0CC6-\u0CC8\u0CCA-\u0CCD\u0CD5\u0CD6\u0CDE\u0CE0-\u0CE3\u0CE6-\u0CEF\u0CF1\u0CF2\u0D01-\u0D03\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D-\u0D44\u0D46-\u0D48\u0D4A-\u0D4E\u0D57\u0D5F-\u0D63\u0D66-\u0D6F\u0D7A-\u0D7F\u0D82\u0D83\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DCA\u0DCF-\u0DD4\u0DD6\u0DD8-\u0DDF\u0DE6-\u0DEF\u0DF2\u0DF3\u0E01-\u0E3A\u0E40-\u0E4E\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB9\u0EBB-\u0EBD\u0EC0-\u0EC4\u0EC6\u0EC8-\u0ECD\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F18\u0F19\u0F20-\u0F29\u0F35\u0F37\u0F39\u0F3E-\u0F47\u0F49-\u0F6C\u0F71-\u0F84\u0F86-\u0F97\u0F99-\u0FBC\u0FC6\u1000-\u1049\u1050-\u109D\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u135D-\u135F\u1369-\u1371\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176C\u176E-\u1770\u1772\u1773\u1780-\u17D3\u17D7\u17DC\u17DD\u17E0-\u17E9\u180B-\u180D\u1810-\u1819\u1820-\u1877\u1880-\u18AA\u18B0-\u18F5\u1900-\u191E\u1920-\u192B\u1930-\u193B\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19DA\u1A00-\u1A1B\u1A20-\u1A5E\u1A60-\u1A7C\u1A7F-\u1A89\u1A90-\u1A99\u1AA7\u1AB0-\u1ABD\u1B00-\u1B4B\u1B50-\u1B59\u1B6B-\u1B73\u1B80-\u1BF3\u1C00-\u1C37\u1C40-\u1C49\u1C4D-\u1C7D\u1CD0-\u1CD2\u1CD4-\u1CF6\u1CF8\u1CF9\u1D00-\u1DF5\u1DFC-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u200C\u200D\u203F\u2040\u2054\u2071\u207F\u2090-\u209C\u20D0-\u20DC\u20E1\u20E5-\u20F0\u2102\u2107\u210A-\u2113\u2115\u2118-\u211D\u2124\u2126\u2128\u212A-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2160-\u2188\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D7F-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2DE0-\u2DFF\u3005-\u3007\u3021-\u302F\u3031-\u3035\u3038-\u303C\u3041-\u3096\u3099-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FD5\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66F\uA674-\uA67D\uA67F-\uA6F1\uA717-\uA71F\uA722-\uA788\uA78B-\uA7AD\uA7B0-\uA7B7\uA7F7-\uA827\uA840-\uA873\uA880-\uA8C4\uA8D0-\uA8D9\uA8E0-\uA8F7\uA8FB\uA8FD\uA900-\uA92D\uA930-\uA953\uA960-\uA97C\uA980-\uA9C0\uA9CF-\uA9D9\uA9E0-\uA9FE\uAA00-\uAA36\uAA40-\uAA4D\uAA50-\uAA59\uAA60-\uAA76\uAA7A-\uAAC2\uAADB-\uAADD\uAAE0-\uAAEF\uAAF2-\uAAF6\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB65\uAB70-\uABEA\uABEC\uABED\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE00-\uFE0F\uFE20-\uFE2F\uFE33\uFE34\uFE4D-\uFE4F\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF3F\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD40-\uDD74\uDDFD\uDE80-\uDE9C\uDEA0-\uDED0\uDEE0\uDF00-\uDF1F\uDF30-\uDF4A\uDF50-\uDF7A\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCA0-\uDCA9\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00-\uDE03\uDE05\uDE06\uDE0C-\uDE13\uDE15-\uDE17\uDE19-\uDE33\uDE38-\uDE3A\uDE3F\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE6\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2]|\uD804[\uDC00-\uDC46\uDC66-\uDC6F\uDC7F-\uDCBA\uDCD0-\uDCE8\uDCF0-\uDCF9\uDD00-\uDD34\uDD36-\uDD3F\uDD50-\uDD73\uDD76\uDD80-\uDDC4\uDDCA-\uDDCC\uDDD0-\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE37\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEEA\uDEF0-\uDEF9\uDF00-\uDF03\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3C-\uDF44\uDF47\uDF48\uDF4B-\uDF4D\uDF50\uDF57\uDF5D-\uDF63\uDF66-\uDF6C\uDF70-\uDF74]|\uD805[\uDC80-\uDCC5\uDCC7\uDCD0-\uDCD9\uDD80-\uDDB5\uDDB8-\uDDC0\uDDD8-\uDDDD\uDE00-\uDE40\uDE44\uDE50-\uDE59\uDE80-\uDEB7\uDEC0-\uDEC9\uDF00-\uDF19\uDF1D-\uDF2B\uDF30-\uDF39]|\uD806[\uDCA0-\uDCE9\uDCFF\uDEC0-\uDEF8]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE60-\uDE69\uDED0-\uDEED\uDEF0-\uDEF4\uDF00-\uDF36\uDF40-\uDF43\uDF50-\uDF59\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDF00-\uDF44\uDF50-\uDF7E\uDF8F-\uDF9F]|\uD82C[\uDC00\uDC01]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99\uDC9D\uDC9E]|\uD834[\uDD65-\uDD69\uDD6D-\uDD72\uDD7B-\uDD82\uDD85-\uDD8B\uDDAA-\uDDAD\uDE42-\uDE44]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB\uDFCE-\uDFFF]|\uD836[\uDE00-\uDE36\uDE3B-\uDE6C\uDE75\uDE84\uDE9B-\uDE9F\uDEA1-\uDEAF]|\uD83A[\uDC00-\uDCC4\uDCD0-\uDCD6]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1]|\uD87E[\uDC00-\uDE1D]|\uDB40[\uDD00-\uDDEF])+/, +}; + +try { + UNICODE = { + // https://262.ecma-international.org/13.0/#prod-IdentifierStartChar + // $, _, ID_Start + ID_Start: new RegExp("[_$\\p{ID_Start}]", "u"), + // https://262.ecma-international.org/13.0/#prod-IdentifierPartChar + // $, zero-width-joiner, zero-width-non-joiner, ID_Continue + ID_Continue: new RegExp("[$\\u200C\\u200D\\p{ID_Continue}]+", "u"), + }; +} catch(e) { + // Could not use modern JS \p{...}. UNICODE is already defined above so let's continue +} + +function get_full_char(str, pos) { + if (is_surrogate_pair_head(str.charCodeAt(pos))) { + if (is_surrogate_pair_tail(str.charCodeAt(pos + 1))) { + return str.charAt(pos) + str.charAt(pos + 1); + } + } else if (is_surrogate_pair_tail(str.charCodeAt(pos))) { + if (is_surrogate_pair_head(str.charCodeAt(pos - 1))) { + return str.charAt(pos - 1) + str.charAt(pos); + } + } + return str.charAt(pos); +} + +function get_full_char_code(str, pos) { + // https://en.wikipedia.org/wiki/Universal_Character_Set_characters#Surrogates + if (is_surrogate_pair_head(str.charCodeAt(pos))) { + return 0x10000 + (str.charCodeAt(pos) - 0xd800 << 10) + str.charCodeAt(pos + 1) - 0xdc00; + } + return str.charCodeAt(pos); +} + +function get_full_char_length(str) { + var surrogates = 0; + + for (var i = 0; i < str.length; i++) { + if (is_surrogate_pair_head(str.charCodeAt(i)) && is_surrogate_pair_tail(str.charCodeAt(i + 1))) { + surrogates++; + i++; + } + } + + return str.length - surrogates; +} + +function from_char_code(code) { + // Based on https://github.com/mathiasbynens/String.fromCodePoint/blob/master/fromcodepoint.js + if (code > 0xFFFF) { + code -= 0x10000; + return (String.fromCharCode((code >> 10) + 0xD800) + + String.fromCharCode((code % 0x400) + 0xDC00)); + } + return String.fromCharCode(code); +} + +function is_surrogate_pair_head(code) { + return code >= 0xd800 && code <= 0xdbff; +} + +function is_surrogate_pair_tail(code) { + return code >= 0xdc00 && code <= 0xdfff; +} + +function is_digit(code) { + return code >= 48 && code <= 57; +} + +function is_identifier_start(ch) { + return UNICODE.ID_Start.test(ch); +} + +function is_identifier_char(ch) { + return UNICODE.ID_Continue.test(ch); +} + +const BASIC_IDENT = /^[a-z_$][a-z0-9_$]*$/i; + +function is_basic_identifier_string(str) { + return BASIC_IDENT.test(str); +} + +function is_identifier_string(str, allow_surrogates) { + if (BASIC_IDENT.test(str)) { + return true; + } + if (!allow_surrogates && /[\ud800-\udfff]/.test(str)) { + return false; + } + var match = UNICODE.ID_Start.exec(str); + if (!match || match.index !== 0) { + return false; + } + + str = str.slice(match[0].length); + if (!str) { + return true; + } + + match = UNICODE.ID_Continue.exec(str); + return !!match && match[0].length === str.length; +} + +function parse_js_number(num, allow_e = true) { + if (!allow_e && num.includes("e")) { + return NaN; + } + if (RE_HEX_NUMBER.test(num)) { + return parseInt(num.substr(2), 16); + } else if (RE_OCT_NUMBER.test(num)) { + return parseInt(num.substr(1), 8); + } else if (RE_ES6_OCT_NUMBER.test(num)) { + return parseInt(num.substr(2), 8); + } else if (RE_BIN_NUMBER.test(num)) { + return parseInt(num.substr(2), 2); + } else if (RE_DEC_NUMBER.test(num)) { + return parseFloat(num); + } else { + var val = parseFloat(num); + if (val == num) return val; + } +} + +class JS_Parse_Error extends Error { + constructor(message, filename, line, col, pos) { + super(); + + this.name = "SyntaxError"; + this.message = message; + this.filename = filename; + this.line = line; + this.col = col; + this.pos = pos; + } +} + +function js_error(message, filename, line, col, pos) { + throw new JS_Parse_Error(message, filename, line, col, pos); +} + +function is_token(token, type, val) { + return token.type == type && (val == null || token.value == val); +} + +var EX_EOF = {}; + +function tokenizer($TEXT, filename, html5_comments, shebang) { + var S = { + text : $TEXT, + filename : filename, + pos : 0, + tokpos : 0, + line : 1, + tokline : 0, + col : 0, + tokcol : 0, + newline_before : false, + regex_allowed : false, + brace_counter : 0, + template_braces : [], + comments_before : [], + directives : {}, + directive_stack : [] + }; + + function peek() { return get_full_char(S.text, S.pos); } + + // Used because parsing ?. involves a lookahead for a digit + function is_option_chain_op() { + const must_be_dot = S.text.charCodeAt(S.pos + 1) === 46; + if (!must_be_dot) return false; + + const cannot_be_digit = S.text.charCodeAt(S.pos + 2); + return cannot_be_digit < 48 || cannot_be_digit > 57; + } + + function next(signal_eof, in_string) { + var ch = get_full_char(S.text, S.pos++); + if (signal_eof && !ch) + throw EX_EOF; + if (NEWLINE_CHARS.has(ch)) { + S.newline_before = S.newline_before || !in_string; + ++S.line; + S.col = 0; + if (ch == "\r" && peek() == "\n") { + // treat a \r\n sequence as a single \n + ++S.pos; + ch = "\n"; + } + } else { + if (ch.length > 1) { + ++S.pos; + ++S.col; + } + ++S.col; + } + return ch; + } + + function forward(i) { + while (i--) next(); + } + + function looking_at(str) { + return S.text.substr(S.pos, str.length) == str; + } + + function find_eol() { + var text = S.text; + for (var i = S.pos, n = S.text.length; i < n; ++i) { + var ch = text[i]; + if (NEWLINE_CHARS.has(ch)) + return i; + } + return -1; + } + + function find(what, signal_eof) { + var pos = S.text.indexOf(what, S.pos); + if (signal_eof && pos == -1) throw EX_EOF; + return pos; + } + + function start_token() { + S.tokline = S.line; + S.tokcol = S.col; + S.tokpos = S.pos; + } + + var prev_was_dot = false; + var previous_token = null; + function token(type, value, is_comment) { + S.regex_allowed = ((type == "operator" && !UNARY_POSTFIX.has(value)) || + (type == "keyword" && KEYWORDS_BEFORE_EXPRESSION.has(value)) || + (type == "punc" && PUNC_BEFORE_EXPRESSION.has(value))) || + (type == "arrow"); + if (type == "punc" && (value == "." || value == "?.")) { + prev_was_dot = true; + } else if (!is_comment) { + prev_was_dot = false; + } + const line = S.tokline; + const col = S.tokcol; + const pos = S.tokpos; + const nlb = S.newline_before; + const file = filename; + let comments_before = []; + let comments_after = []; + + if (!is_comment) { + comments_before = S.comments_before; + comments_after = S.comments_before = []; + } + S.newline_before = false; + const tok = new AST_Token(type, value, line, col, pos, nlb, comments_before, comments_after, file); + + if (!is_comment) previous_token = tok; + return tok; + } + + function skip_whitespace() { + while (WHITESPACE_CHARS.has(peek())) + next(); + } + + function read_while(pred) { + var ret = "", ch, i = 0; + while ((ch = peek()) && pred(ch, i++)) + ret += next(); + return ret; + } + + function parse_error(err) { + js_error(err, filename, S.tokline, S.tokcol, S.tokpos); + } + + function read_num(prefix) { + var has_e = false, after_e = false, has_x = false, has_dot = prefix == ".", is_big_int = false, numeric_separator = false; + var num = read_while(function(ch, i) { + if (is_big_int) return false; + + var code = ch.charCodeAt(0); + switch (code) { + case 95: // _ + return (numeric_separator = true); + case 98: case 66: // bB + return (has_x = true); // Can occur in hex sequence, don't return false yet + case 111: case 79: // oO + case 120: case 88: // xX + return has_x ? false : (has_x = true); + case 101: case 69: // eE + return has_x ? true : has_e ? false : (has_e = after_e = true); + case 45: // - + return after_e || (i == 0 && !prefix); + case 43: // + + return after_e; + case (after_e = false, 46): // . + return (!has_dot && !has_x && !has_e) ? (has_dot = true) : false; + } + + if (ch === "n") { + is_big_int = true; + + return true; + } + + return RE_NUM_LITERAL.test(ch); + }); + if (prefix) num = prefix + num; + + LATEST_RAW = num; + + if (RE_OCT_NUMBER.test(num) && next_token.has_directive("use strict")) { + parse_error("Legacy octal literals are not allowed in strict mode"); + } + if (numeric_separator) { + if (num.endsWith("_")) { + parse_error("Numeric separators are not allowed at the end of numeric literals"); + } else if (num.includes("__")) { + parse_error("Only one underscore is allowed as numeric separator"); + } + num = num.replace(/_/g, ""); + } + if (num.endsWith("n")) { + const without_n = num.slice(0, -1); + const allow_e = RE_HEX_NUMBER.test(without_n); + const valid = parse_js_number(without_n, allow_e); + if (!has_dot && RE_BIG_INT.test(num) && !isNaN(valid)) + return token("big_int", without_n); + parse_error("Invalid or unexpected token"); + } + var valid = parse_js_number(num); + if (!isNaN(valid)) { + return token("num", valid); + } else { + parse_error("Invalid syntax: " + num); + } + } + + function is_octal(ch) { + return ch >= "0" && ch <= "7"; + } + + function read_escaped_char(in_string, strict_hex, template_string) { + var ch = next(true, in_string); + switch (ch.charCodeAt(0)) { + case 110 : return "\n"; + case 114 : return "\r"; + case 116 : return "\t"; + case 98 : return "\b"; + case 118 : return "\u000b"; // \v + case 102 : return "\f"; + case 120 : return String.fromCharCode(hex_bytes(2, strict_hex)); // \x + case 117 : // \u + if (peek() == "{") { + next(true); + if (peek() === "}") + parse_error("Expecting hex-character between {}"); + while (peek() == "0") next(true); // No significance + var result, length = find("}", true) - S.pos; + // Avoid 32 bit integer overflow (1 << 32 === 1) + // We know first character isn't 0 and thus out of range anyway + if (length > 6 || (result = hex_bytes(length, strict_hex)) > 0x10FFFF) { + parse_error("Unicode reference out of bounds"); + } + next(true); + return from_char_code(result); + } + return String.fromCharCode(hex_bytes(4, strict_hex)); + case 10 : return ""; // newline + case 13 : // \r + if (peek() == "\n") { // DOS newline + next(true, in_string); + return ""; + } + } + if (is_octal(ch)) { + if (template_string && strict_hex) { + const represents_null_character = ch === "0" && !is_octal(peek()); + if (!represents_null_character) { + parse_error("Octal escape sequences are not allowed in template strings"); + } + } + return read_octal_escape_sequence(ch, strict_hex); + } + return ch; + } + + function read_octal_escape_sequence(ch, strict_octal) { + // Read + var p = peek(); + if (p >= "0" && p <= "7") { + ch += next(true); + if (ch[0] <= "3" && (p = peek()) >= "0" && p <= "7") + ch += next(true); + } + + // Parse + if (ch === "0") return "\0"; + if (ch.length > 0 && next_token.has_directive("use strict") && strict_octal) + parse_error("Legacy octal escape sequences are not allowed in strict mode"); + return String.fromCharCode(parseInt(ch, 8)); + } + + function hex_bytes(n, strict_hex) { + var num = 0; + for (; n > 0; --n) { + if (!strict_hex && isNaN(parseInt(peek(), 16))) { + return parseInt(num, 16) || ""; + } + var digit = next(true); + if (isNaN(parseInt(digit, 16))) + parse_error("Invalid hex-character pattern in string"); + num += digit; + } + return parseInt(num, 16); + } + + var read_string = with_eof_error("Unterminated string constant", function() { + const start_pos = S.pos; + var quote = next(), ret = []; + for (;;) { + var ch = next(true, true); + if (ch == "\\") ch = read_escaped_char(true, true); + else if (ch == "\r" || ch == "\n") parse_error("Unterminated string constant"); + else if (ch == quote) break; + ret.push(ch); + } + var tok = token("string", ret.join("")); + LATEST_RAW = S.text.slice(start_pos, S.pos); + tok.quote = quote; + return tok; + }); + + var read_template_characters = with_eof_error("Unterminated template", function(begin) { + if (begin) { + S.template_braces.push(S.brace_counter); + } + var content = "", raw = "", ch, tok; + next(true, true); + while ((ch = next(true, true)) != "`") { + if (ch == "\r") { + if (peek() == "\n") ++S.pos; + ch = "\n"; + } else if (ch == "$" && peek() == "{") { + next(true, true); + S.brace_counter++; + tok = token(begin ? "template_head" : "template_substitution", content); + TEMPLATE_RAWS.set(tok, raw); + tok.template_end = false; + return tok; + } + + raw += ch; + if (ch == "\\") { + var tmp = S.pos; + var prev_is_tag = previous_token && (previous_token.type === "name" || previous_token.type === "punc" && (previous_token.value === ")" || previous_token.value === "]")); + ch = read_escaped_char(true, !prev_is_tag, true); + raw += S.text.substr(tmp, S.pos - tmp); + } + + content += ch; + } + S.template_braces.pop(); + tok = token(begin ? "template_head" : "template_substitution", content); + TEMPLATE_RAWS.set(tok, raw); + tok.template_end = true; + return tok; + }); + + function skip_line_comment(type) { + var regex_allowed = S.regex_allowed; + var i = find_eol(), ret; + if (i == -1) { + ret = S.text.substr(S.pos); + S.pos = S.text.length; + } else { + ret = S.text.substring(S.pos, i); + S.pos = i; + } + S.col = S.tokcol + (S.pos - S.tokpos); + S.comments_before.push(token(type, ret, true)); + S.regex_allowed = regex_allowed; + return next_token; + } + + var skip_multiline_comment = with_eof_error("Unterminated multiline comment", function() { + var regex_allowed = S.regex_allowed; + var i = find("*/", true); + var text = S.text.substring(S.pos, i).replace(/\r\n|\r|\u2028|\u2029/g, "\n"); + // update stream position + forward(get_full_char_length(text) /* text length doesn't count \r\n as 2 char while S.pos - i does */ + 2); + S.comments_before.push(token("comment2", text, true)); + S.newline_before = S.newline_before || text.includes("\n"); + S.regex_allowed = regex_allowed; + return next_token; + }); + + var read_name = with_eof_error("Unterminated identifier name", function() { + var name = [], ch, escaped = false; + var read_escaped_identifier_char = function() { + escaped = true; + next(); + if (peek() !== "u") { + parse_error("Expecting UnicodeEscapeSequence -- uXXXX or u{XXXX}"); + } + return read_escaped_char(false, true); + }; + + // Read first character (ID_Start) + if ((ch = peek()) === "\\") { + ch = read_escaped_identifier_char(); + if (!is_identifier_start(ch)) { + parse_error("First identifier char is an invalid identifier char"); + } + } else if (is_identifier_start(ch)) { + next(); + } else { + return ""; + } + + name.push(ch); + + // Read ID_Continue + while ((ch = peek()) != null) { + if ((ch = peek()) === "\\") { + ch = read_escaped_identifier_char(); + if (!is_identifier_char(ch)) { + parse_error("Invalid escaped identifier char"); + } + } else { + if (!is_identifier_char(ch)) { + break; + } + next(); + } + name.push(ch); + } + const name_str = name.join(""); + if (RESERVED_WORDS.has(name_str) && escaped) { + parse_error("Escaped characters are not allowed in keywords"); + } + return name_str; + }); + + var read_regexp = with_eof_error("Unterminated regular expression", function(source) { + var prev_backslash = false, ch, in_class = false; + while ((ch = next(true))) if (NEWLINE_CHARS.has(ch)) { + parse_error("Unexpected line terminator"); + } else if (prev_backslash) { + source += "\\" + ch; + prev_backslash = false; + } else if (ch == "[") { + in_class = true; + source += ch; + } else if (ch == "]" && in_class) { + in_class = false; + source += ch; + } else if (ch == "/" && !in_class) { + break; + } else if (ch == "\\") { + prev_backslash = true; + } else { + source += ch; + } + const flags = read_name(); + return token("regexp", "/" + source + "/" + flags); + }); + + function read_operator(prefix) { + function grow(op) { + if (!peek()) return op; + var bigger = op + peek(); + if (OPERATORS.has(bigger)) { + next(); + return grow(bigger); + } else { + return op; + } + } + return token("operator", grow(prefix || next())); + } + + function handle_slash() { + next(); + switch (peek()) { + case "/": + next(); + return skip_line_comment("comment1"); + case "*": + next(); + return skip_multiline_comment(); + } + return S.regex_allowed ? read_regexp("") : read_operator("/"); + } + + function handle_eq_sign() { + next(); + if (peek() === ">") { + next(); + return token("arrow", "=>"); + } else { + return read_operator("="); + } + } + + function handle_dot() { + next(); + if (is_digit(peek().charCodeAt(0))) { + return read_num("."); + } + if (peek() === ".") { + next(); // Consume second dot + next(); // Consume third dot + return token("expand", "..."); + } + + return token("punc", "."); + } + + function read_word() { + var word = read_name(); + if (prev_was_dot) return token("name", word); + return KEYWORDS_ATOM.has(word) ? token("atom", word) + : !KEYWORDS.has(word) ? token("name", word) + : OPERATORS.has(word) ? token("operator", word) + : token("keyword", word); + } + + function read_private_word() { + next(); + return token("privatename", read_name()); + } + + function with_eof_error(eof_error, cont) { + return function(x) { + try { + return cont(x); + } catch(ex) { + if (ex === EX_EOF) parse_error(eof_error); + else throw ex; + } + }; + } + + function next_token(force_regexp) { + if (force_regexp != null) + return read_regexp(force_regexp); + if (shebang && S.pos == 0 && looking_at("#!")) { + start_token(); + forward(2); + skip_line_comment("comment5"); + } + for (;;) { + skip_whitespace(); + start_token(); + if (html5_comments) { + if (looking_at("") && S.newline_before) { + forward(3); + skip_line_comment("comment4"); + continue; + } + } + var ch = peek(); + if (!ch) return token("eof"); + var code = ch.charCodeAt(0); + switch (code) { + case 34: case 39: return read_string(); + case 46: return handle_dot(); + case 47: { + var tok = handle_slash(); + if (tok === next_token) continue; + return tok; } + case 61: return handle_eq_sign(); + case 63: { + if (!is_option_chain_op()) break; // Handled below + + next(); // ? + next(); // . + + return token("punc", "?."); + } + case 96: return read_template_characters(true); + case 123: + S.brace_counter++; + break; + case 125: + S.brace_counter--; + if (S.template_braces.length > 0 + && S.template_braces[S.template_braces.length - 1] === S.brace_counter) + return read_template_characters(false); + break; + } + if (is_digit(code)) return read_num(); + if (PUNC_CHARS.has(ch)) return token("punc", next()); + if (OPERATOR_CHARS.has(ch)) return read_operator(); + if (code == 92 || is_identifier_start(ch)) return read_word(); + if (code == 35) return read_private_word(); + break; + } + parse_error("Unexpected character '" + ch + "'"); + } + + next_token.next = next; + next_token.peek = peek; + + next_token.context = function(nc) { + if (nc) S = nc; + return S; + }; + + next_token.add_directive = function(directive) { + S.directive_stack[S.directive_stack.length - 1].push(directive); + + if (S.directives[directive] === undefined) { + S.directives[directive] = 1; + } else { + S.directives[directive]++; + } + }; + + next_token.push_directives_stack = function() { + S.directive_stack.push([]); + }; + + next_token.pop_directives_stack = function() { + var directives = S.directive_stack[S.directive_stack.length - 1]; + + for (var i = 0; i < directives.length; i++) { + S.directives[directives[i]]--; + } + + S.directive_stack.pop(); + }; + + next_token.has_directive = function(directive) { + return S.directives[directive] > 0; + }; + + return next_token; + +} + +/* -----[ Parser (constants) ]----- */ + +var UNARY_PREFIX = makePredicate([ + "typeof", + "void", + "delete", + "--", + "++", + "!", + "~", + "-", + "+" +]); + +var UNARY_POSTFIX = makePredicate([ "--", "++" ]); + +var ASSIGNMENT = makePredicate([ "=", "+=", "-=", "??=", "&&=", "||=", "/=", "*=", "**=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&=" ]); + +var LOGICAL_ASSIGNMENT = makePredicate([ "??=", "&&=", "||=" ]); + +var PRECEDENCE = (function(a, ret) { + for (var i = 0; i < a.length; ++i) { + var b = a[i]; + for (var j = 0; j < b.length; ++j) { + ret[b[j]] = i + 1; + } + } + return ret; +})( + [ + ["||"], + ["??"], + ["&&"], + ["|"], + ["^"], + ["&"], + ["==", "===", "!=", "!=="], + ["<", ">", "<=", ">=", "in", "instanceof"], + [">>", "<<", ">>>"], + ["+", "-"], + ["*", "/", "%"], + ["**"] + ], + {} +); + +var ATOMIC_START_TOKEN = makePredicate([ "atom", "num", "big_int", "string", "regexp", "name"]); + +/* -----[ Parser ]----- */ + +function parse($TEXT, options) { + // maps start tokens to count of comments found outside of their parens + // Example: /* I count */ ( /* I don't */ foo() ) + // Useful because comments_before property of call with parens outside + // contains both comments inside and outside these parens. Used to find the + // right #__PURE__ comments for an expression + const outer_comments_before_counts = new WeakMap(); + + options = defaults(options, { + bare_returns : false, + ecma : null, // Legacy + expression : false, + filename : null, + html5_comments : true, + module : false, + shebang : true, + strict : false, + toplevel : null, + }, true); + + var S = { + input : (typeof $TEXT == "string" + ? tokenizer($TEXT, options.filename, + options.html5_comments, options.shebang) + : $TEXT), + token : null, + prev : null, + peeked : null, + in_function : 0, + in_async : -1, + in_generator : -1, + in_directives : true, + in_loop : 0, + labels : [] + }; + + S.token = next(); + + function is(type, value) { + return is_token(S.token, type, value); + } + + function peek() { return S.peeked || (S.peeked = S.input()); } + + function next() { + S.prev = S.token; + + if (!S.peeked) peek(); + S.token = S.peeked; + S.peeked = null; + S.in_directives = S.in_directives && ( + S.token.type == "string" || is("punc", ";") + ); + return S.token; + } + + function prev() { + return S.prev; + } + + function croak(msg, line, col, pos) { + var ctx = S.input.context(); + js_error(msg, + ctx.filename, + line != null ? line : ctx.tokline, + col != null ? col : ctx.tokcol, + pos != null ? pos : ctx.tokpos); + } + + function token_error(token, msg) { + croak(msg, token.line, token.col); + } + + function unexpected(token) { + if (token == null) + token = S.token; + token_error(token, "Unexpected token: " + token.type + " (" + token.value + ")"); + } + + function expect_token(type, val) { + if (is(type, val)) { + return next(); + } + token_error(S.token, "Unexpected token " + S.token.type + " «" + S.token.value + "»" + ", expected " + type + " «" + val + "»"); + } + + function expect(punc) { return expect_token("punc", punc); } + + function has_newline_before(token) { + return token.nlb || !token.comments_before.every((comment) => !comment.nlb); + } + + function can_insert_semicolon() { + return !options.strict + && (is("eof") || is("punc", "}") || has_newline_before(S.token)); + } + + function is_in_generator() { + return S.in_generator === S.in_function; + } + + function is_in_async() { + return S.in_async === S.in_function; + } + + function can_await() { + return ( + S.in_async === S.in_function + || S.in_function === 0 && S.input.has_directive("use strict") + ); + } + + function semicolon(optional) { + if (is("punc", ";")) next(); + else if (!optional && !can_insert_semicolon()) unexpected(); + } + + function parenthesised() { + expect("("); + var exp = expression(true); + expect(")"); + return exp; + } + + function embed_tokens(parser) { + return function _embed_tokens_wrapper(...args) { + const start = S.token; + const expr = parser(...args); + expr.start = start; + expr.end = prev(); + return expr; + }; + } + + function handle_regexp() { + if (is("operator", "/") || is("operator", "/=")) { + S.peeked = null; + S.token = S.input(S.token.value.substr(1)); // force regexp + } + } + + var statement = embed_tokens(function statement(is_export_default, is_for_body, is_if_body) { + handle_regexp(); + switch (S.token.type) { + case "string": + if (S.in_directives) { + var token = peek(); + if (!LATEST_RAW.includes("\\") + && (is_token(token, "punc", ";") + || is_token(token, "punc", "}") + || has_newline_before(token) + || is_token(token, "eof"))) { + S.input.add_directive(S.token.value); + } else { + S.in_directives = false; + } + } + var dir = S.in_directives, stat = simple_statement(); + return dir && stat.body instanceof AST_String ? new AST_Directive(stat.body) : stat; + case "template_head": + case "num": + case "big_int": + case "regexp": + case "operator": + case "atom": + return simple_statement(); + + case "name": + case "privatename": + if(is("privatename") && !S.in_class) + croak("Private field must be used in an enclosing class"); + + if (S.token.value == "async" && is_token(peek(), "keyword", "function")) { + next(); + next(); + if (is_for_body) { + croak("functions are not allowed as the body of a loop"); + } + return function_(AST_Defun, false, true, is_export_default); + } + if (S.token.value == "import" && !is_token(peek(), "punc", "(") && !is_token(peek(), "punc", ".")) { + next(); + var node = import_statement(); + semicolon(); + return node; + } + return is_token(peek(), "punc", ":") + ? labeled_statement() + : simple_statement(); + + case "punc": + switch (S.token.value) { + case "{": + return new AST_BlockStatement({ + start : S.token, + body : block_(), + end : prev() + }); + case "[": + case "(": + return simple_statement(); + case ";": + S.in_directives = false; + next(); + return new AST_EmptyStatement(); + default: + unexpected(); + } + + case "keyword": + switch (S.token.value) { + case "break": + next(); + return break_cont(AST_Break); + + case "continue": + next(); + return break_cont(AST_Continue); + + case "debugger": + next(); + semicolon(); + return new AST_Debugger(); + + case "do": + next(); + var body = in_loop(statement); + expect_token("keyword", "while"); + var condition = parenthesised(); + semicolon(true); + return new AST_Do({ + body : body, + condition : condition + }); + + case "while": + next(); + return new AST_While({ + condition : parenthesised(), + body : in_loop(function() { return statement(false, true); }) + }); + + case "for": + next(); + return for_(); + + case "class": + next(); + if (is_for_body) { + croak("classes are not allowed as the body of a loop"); + } + if (is_if_body) { + croak("classes are not allowed as the body of an if"); + } + return class_(AST_DefClass, is_export_default); - if (ch === "n") { - is_big_int = true; - - return true; - } + case "function": + next(); + if (is_for_body) { + croak("functions are not allowed as the body of a loop"); + } + return function_(AST_Defun, false, false, is_export_default); + + case "if": + next(); + return if_(); + + case "return": + if (S.in_function == 0 && !options.bare_returns) + croak("'return' outside of function"); + next(); + var value = null; + if (is("punc", ";")) { + next(); + } else if (!can_insert_semicolon()) { + value = expression(true); + semicolon(); + } + return new AST_Return({ + value: value + }); + + case "switch": + next(); + return new AST_Switch({ + expression : parenthesised(), + body : in_loop(switch_body_) + }); + + case "throw": + next(); + if (has_newline_before(S.token)) + croak("Illegal newline after 'throw'"); + var value = expression(true); + semicolon(); + return new AST_Throw({ + value: value + }); + + case "try": + next(); + return try_(); + + case "var": + next(); + var node = var_(); + semicolon(); + return node; + + case "let": + next(); + var node = let_(); + semicolon(); + return node; + + case "const": + next(); + var node = const_(); + semicolon(); + return node; + + case "with": + if (S.input.has_directive("use strict")) { + croak("Strict mode may not include a with statement"); + } + next(); + return new AST_With({ + expression : parenthesised(), + body : statement() + }); + + case "export": + if (!is_token(peek(), "punc", "(")) { + next(); + var node = export_statement(); + if (is("punc", ";")) semicolon(); + return node; + } + } + } + unexpected(); + }); + + function labeled_statement() { + var label = as_symbol(AST_Label); + if (label.name === "await" && is_in_async()) { + token_error(S.prev, "await cannot be used as label inside async function"); + } + if (S.labels.some((l) => l.name === label.name)) { + // ECMA-262, 12.12: An ECMAScript program is considered + // syntactically incorrect if it contains a + // LabelledStatement that is enclosed by a + // LabelledStatement with the same Identifier as label. + croak("Label " + label.name + " defined twice"); + } + expect(":"); + S.labels.push(label); + var stat = statement(); + S.labels.pop(); + if (!(stat instanceof AST_IterationStatement)) { + // check for `continue` that refers to this label. + // those should be reported as syntax errors. + // https://github.com/mishoo/UglifyJS2/issues/287 + label.references.forEach(function(ref) { + if (ref instanceof AST_Continue) { + ref = ref.label.start; + croak("Continue label `" + label.name + "` refers to non-IterationStatement.", + ref.line, ref.col, ref.pos); + } + }); + } + return new AST_LabeledStatement({ body: stat, label: label }); + } + + function simple_statement(tmp) { + return new AST_SimpleStatement({ body: (tmp = expression(true), semicolon(), tmp) }); + } + + function break_cont(type) { + var label = null, ldef; + if (!can_insert_semicolon()) { + label = as_symbol(AST_LabelRef, true); + } + if (label != null) { + ldef = S.labels.find((l) => l.name === label.name); + if (!ldef) + croak("Undefined label " + label.name); + label.thedef = ldef; + } else if (S.in_loop == 0) + croak(type.TYPE + " not inside a loop or switch"); + semicolon(); + var stat = new type({ label: label }); + if (ldef) ldef.references.push(stat); + return stat; + } + + function for_() { + var for_await_error = "`for await` invalid in this context"; + var await_tok = S.token; + if (await_tok.type == "name" && await_tok.value == "await") { + if (!can_await()) { + token_error(await_tok, for_await_error); + } + next(); + } else { + await_tok = false; + } + expect("("); + var init = null; + if (!is("punc", ";")) { + init = + is("keyword", "var") ? (next(), var_(true)) : + is("keyword", "let") ? (next(), let_(true)) : + is("keyword", "const") ? (next(), const_(true)) : + expression(true, true); + var is_in = is("operator", "in"); + var is_of = is("name", "of"); + if (await_tok && !is_of) { + token_error(await_tok, for_await_error); + } + if (is_in || is_of) { + if (init instanceof AST_Definitions) { + if (init.definitions.length > 1) + token_error(init.start, "Only one variable declaration allowed in for..in loop"); + } else if (!(is_assignable(init) || (init = to_destructuring(init)) instanceof AST_Destructuring)) { + token_error(init.start, "Invalid left-hand side in for..in loop"); + } + next(); + if (is_in) { + return for_in(init); + } else { + return for_of(init, !!await_tok); + } + } + } else if (await_tok) { + token_error(await_tok, for_await_error); + } + return regular_for(init); + } + + function regular_for(init) { + expect(";"); + var test = is("punc", ";") ? null : expression(true); + expect(";"); + var step = is("punc", ")") ? null : expression(true); + expect(")"); + return new AST_For({ + init : init, + condition : test, + step : step, + body : in_loop(function() { return statement(false, true); }) + }); + } + + function for_of(init, is_await) { + var lhs = init instanceof AST_Definitions ? init.definitions[0].name : null; + var obj = expression(true); + expect(")"); + return new AST_ForOf({ + await : is_await, + init : init, + name : lhs, + object : obj, + body : in_loop(function() { return statement(false, true); }) + }); + } + + function for_in(init) { + var obj = expression(true); + expect(")"); + return new AST_ForIn({ + init : init, + object : obj, + body : in_loop(function() { return statement(false, true); }) + }); + } + + var arrow_function = function(start, argnames, is_async) { + if (has_newline_before(S.token)) { + croak("Unexpected newline before arrow (=>)"); + } + + expect_token("arrow", "=>"); + + var body = _function_body(is("punc", "{"), false, is_async); + + var end = + body instanceof Array && body.length ? body[body.length - 1].end : + body instanceof Array ? start : + body.end; + + return new AST_Arrow({ + start : start, + end : end, + async : is_async, + argnames : argnames, + body : body + }); + }; + + var function_ = function(ctor, is_generator_property, is_async, is_export_default) { + var in_statement = ctor === AST_Defun; + var is_generator = is("operator", "*"); + if (is_generator) { + next(); + } + + var name = is("name") ? as_symbol(in_statement ? AST_SymbolDefun : AST_SymbolLambda) : null; + if (in_statement && !name) { + if (is_export_default) { + ctor = AST_Function; + } else { + unexpected(); + } + } + + if (name && ctor !== AST_Accessor && !(name instanceof AST_SymbolDeclaration)) + unexpected(prev()); + + var args = []; + var body = _function_body(true, is_generator || is_generator_property, is_async, name, args); + return new ctor({ + start : args.start, + end : body.end, + is_generator: is_generator, + async : is_async, + name : name, + argnames: args, + body : body + }); + }; + + class UsedParametersTracker { + constructor(is_parameter, strict, duplicates_ok = false) { + this.is_parameter = is_parameter; + this.duplicates_ok = duplicates_ok; + this.parameters = new Set(); + this.duplicate = null; + this.default_assignment = false; + this.spread = false; + this.strict_mode = !!strict; + } + add_parameter(token) { + if (this.parameters.has(token.value)) { + if (this.duplicate === null) { + this.duplicate = token; + } + this.check_strict(); + } else { + this.parameters.add(token.value); + if (this.is_parameter) { + switch (token.value) { + case "arguments": + case "eval": + case "yield": + if (this.strict_mode) { + token_error(token, "Unexpected " + token.value + " identifier as parameter inside strict mode"); + } + break; + default: + if (RESERVED_WORDS.has(token.value)) { + unexpected(); + } + } + } + } + } + mark_default_assignment(token) { + if (this.default_assignment === false) { + this.default_assignment = token; + } + } + mark_spread(token) { + if (this.spread === false) { + this.spread = token; + } + } + mark_strict_mode() { + this.strict_mode = true; + } + is_strict() { + return this.default_assignment !== false || this.spread !== false || this.strict_mode; + } + check_strict() { + if (this.is_strict() && this.duplicate !== null && !this.duplicates_ok) { + token_error(this.duplicate, "Parameter " + this.duplicate.value + " was used already"); + } + } + } + + function parameters(params) { + var used_parameters = new UsedParametersTracker(true, S.input.has_directive("use strict")); + + expect("("); + + while (!is("punc", ")")) { + var param = parameter(used_parameters); + params.push(param); + + if (!is("punc", ")")) { + expect(","); + } + + if (param instanceof AST_Expansion) { + break; + } + } + + next(); + } + + function parameter(used_parameters, symbol_type) { + var param; + var expand = false; + if (used_parameters === undefined) { + used_parameters = new UsedParametersTracker(true, S.input.has_directive("use strict")); + } + if (is("expand", "...")) { + expand = S.token; + used_parameters.mark_spread(S.token); + next(); + } + param = binding_element(used_parameters, symbol_type); + + if (is("operator", "=") && expand === false) { + used_parameters.mark_default_assignment(S.token); + next(); + param = new AST_DefaultAssign({ + start: param.start, + left: param, + operator: "=", + right: expression(false), + end: S.token + }); + } + + if (expand !== false) { + if (!is("punc", ")")) { + unexpected(); + } + param = new AST_Expansion({ + start: expand, + expression: param, + end: expand + }); + } + used_parameters.check_strict(); + + return param; + } + + function binding_element(used_parameters, symbol_type) { + var elements = []; + var first = true; + var is_expand = false; + var expand_token; + var first_token = S.token; + if (used_parameters === undefined) { + const strict = S.input.has_directive("use strict"); + const duplicates_ok = symbol_type === AST_SymbolVar; + used_parameters = new UsedParametersTracker(false, strict, duplicates_ok); + } + symbol_type = symbol_type === undefined ? AST_SymbolFunarg : symbol_type; + if (is("punc", "[")) { + next(); + while (!is("punc", "]")) { + if (first) { + first = false; + } else { + expect(","); + } - return RE_NUM_LITERAL.test(ch); - }); - if (prefix) num = prefix + num; - if (RE_OCT_NUMBER.test(num) && next_token.has_directive("use strict")) { - parse_error("Legacy octal literals are not allowed in strict mode"); - } - if (num.endsWith("n")) { - if (!has_dot && RE_BIG_INT.test(num)) - return token("big_int", num.replace("n", "")); - parse_error("Invalid or unexpected token"); - } - var valid = parse_js_number(num); - if (!isNaN(valid)) { - return token("num", valid); - } else { - parse_error("Invalid syntax: " + num); - } - } - - function read_escaped_char(in_string, strict_hex, template_string) { - var ch = next(true, in_string); - switch (ch.charCodeAt(0)) { - case 110 : return "\n"; - case 114 : return "\r"; - case 116 : return "\t"; - case 98 : return "\b"; - case 118 : return "\u000b"; // \v - case 102 : return "\f"; - case 120 : return String.fromCharCode(hex_bytes(2, strict_hex)); // \x - case 117 : // \u - if (peek() == "{") { - next(true); - if (peek() === "}") - parse_error("Expecting hex-character between {}"); - while (peek() == "0") next(true); // No significance - var result, length = find("}", true) - S.pos; - // Avoid 32 bit integer overflow (1 << 32 === 1) - // We know first character isn't 0 and thus out of range anyway - if (length > 6 || (result = hex_bytes(length, strict_hex)) > 0x10FFFF) { - parse_error("Unicode reference out of bounds"); - } - next(true); - return from_char_code(result); - } - return String.fromCharCode(hex_bytes(4, strict_hex)); - case 10 : return ""; // newline - case 13 : // \r - if (peek() == "\n") { // DOS newline - next(true, in_string); - return ""; - } - } - if (ch >= "0" && ch <= "7") { - if (template_string && strict_hex) { - parse_error("Octal escape sequences are not allowed in template strings"); - } - return read_octal_escape_sequence(ch, strict_hex); - } - return ch; - } - - function read_octal_escape_sequence(ch, strict_octal) { - // Read - var p = peek(); - if (p >= "0" && p <= "7") { - ch += next(true); - if (ch[0] <= "3" && (p = peek()) >= "0" && p <= "7") - ch += next(true); - } - - // Parse - if (ch === "0") return "\0"; - if (ch.length > 0 && next_token.has_directive("use strict") && strict_octal) - parse_error("Legacy octal escape sequences are not allowed in strict mode"); - return String.fromCharCode(parseInt(ch, 8)); - } - - function hex_bytes(n, strict_hex) { - var num = 0; - for (; n > 0; --n) { - if (!strict_hex && isNaN(parseInt(peek(), 16))) { - return parseInt(num, 16) || ""; - } - var digit = next(true); - if (isNaN(parseInt(digit, 16))) - parse_error("Invalid hex-character pattern in string"); - num += digit; - } - return parseInt(num, 16); - } - - var read_string = with_eof_error("Unterminated string constant", function() { - var quote = next(), ret = ""; - for (;;) { - var ch = next(true, true); - if (ch == "\\") ch = read_escaped_char(true, true); - else if (ch == "\r" || ch == "\n") parse_error("Unterminated string constant"); - else if (ch == quote) break; - ret += ch; - } - var tok = token("string", ret); - tok.quote = quote; - return tok; - }); - - var read_template_characters = with_eof_error("Unterminated template", function(begin) { - if (begin) { - S.template_braces.push(S.brace_counter); - } - var content = "", raw = "", ch, tok; - next(true, true); - while ((ch = next(true, true)) != "`") { - if (ch == "\r") { - if (peek() == "\n") ++S.pos; - ch = "\n"; - } else if (ch == "$" && peek() == "{") { - next(true, true); - S.brace_counter++; - tok = token(begin ? "template_head" : "template_substitution", content); - tok.begin = begin; - tok.raw = raw; - tok.end = false; - return tok; - } + if (is("expand", "...")) { + is_expand = true; + expand_token = S.token; + used_parameters.mark_spread(S.token); + next(); + } + if (is("punc")) { + switch (S.token.value) { + case ",": + elements.push(new AST_Hole({ + start: S.token, + end: S.token + })); + continue; + case "]": // Trailing comma after last element + break; + case "[": + case "{": + elements.push(binding_element(used_parameters, symbol_type)); + break; + default: + unexpected(); + } + } else if (is("name")) { + used_parameters.add_parameter(S.token); + elements.push(as_symbol(symbol_type)); + } else { + croak("Invalid function parameter"); + } + if (is("operator", "=") && is_expand === false) { + used_parameters.mark_default_assignment(S.token); + next(); + elements[elements.length - 1] = new AST_DefaultAssign({ + start: elements[elements.length - 1].start, + left: elements[elements.length - 1], + operator: "=", + right: expression(false), + end: S.token + }); + } + if (is_expand) { + if (!is("punc", "]")) { + croak("Rest element must be last element"); + } + elements[elements.length - 1] = new AST_Expansion({ + start: expand_token, + expression: elements[elements.length - 1], + end: expand_token + }); + } + } + expect("]"); + used_parameters.check_strict(); + return new AST_Destructuring({ + start: first_token, + names: elements, + is_array: true, + end: prev() + }); + } else if (is("punc", "{")) { + next(); + while (!is("punc", "}")) { + if (first) { + first = false; + } else { + expect(","); + } + if (is("expand", "...")) { + is_expand = true; + expand_token = S.token; + used_parameters.mark_spread(S.token); + next(); + } + if (is("name") && (is_token(peek(), "punc") || is_token(peek(), "operator")) && [",", "}", "="].includes(peek().value)) { + used_parameters.add_parameter(S.token); + var start = prev(); + var value = as_symbol(symbol_type); + if (is_expand) { + elements.push(new AST_Expansion({ + start: expand_token, + expression: value, + end: value.end, + })); + } else { + elements.push(new AST_ObjectKeyVal({ + start: start, + key: value.name, + value: value, + end: value.end, + })); + } + } else if (is("punc", "}")) { + continue; // Allow trailing hole + } else { + var property_token = S.token; + var property = as_property_name(); + if (property === null) { + unexpected(prev()); + } else if (prev().type === "name" && !is("punc", ":")) { + elements.push(new AST_ObjectKeyVal({ + start: prev(), + key: property, + value: new symbol_type({ + start: prev(), + name: property, + end: prev() + }), + end: prev() + })); + } else { + expect(":"); + elements.push(new AST_ObjectKeyVal({ + start: property_token, + quote: property_token.quote, + key: property, + value: binding_element(used_parameters, symbol_type), + end: prev() + })); + } + } + if (is_expand) { + if (!is("punc", "}")) { + croak("Rest element must be last element"); + } + } else if (is("operator", "=")) { + used_parameters.mark_default_assignment(S.token); + next(); + elements[elements.length - 1].value = new AST_DefaultAssign({ + start: elements[elements.length - 1].value.start, + left: elements[elements.length - 1].value, + operator: "=", + right: expression(false), + end: S.token + }); + } + } + expect("}"); + used_parameters.check_strict(); + return new AST_Destructuring({ + start: first_token, + names: elements, + is_array: false, + end: prev() + }); + } else if (is("name")) { + used_parameters.add_parameter(S.token); + return as_symbol(symbol_type); + } else { + croak("Invalid function parameter"); + } + } + + function params_or_seq_(allow_arrows, maybe_sequence) { + var spread_token; + var invalid_sequence; + var trailing_comma; + var a = []; + expect("("); + while (!is("punc", ")")) { + if (spread_token) unexpected(spread_token); + if (is("expand", "...")) { + spread_token = S.token; + if (maybe_sequence) invalid_sequence = S.token; + next(); + a.push(new AST_Expansion({ + start: prev(), + expression: expression(), + end: S.token, + })); + } else { + a.push(expression()); + } + if (!is("punc", ")")) { + expect(","); + if (is("punc", ")")) { + trailing_comma = prev(); + if (maybe_sequence) invalid_sequence = trailing_comma; + } + } + } + expect(")"); + if (allow_arrows && is("arrow", "=>")) { + if (spread_token && trailing_comma) unexpected(trailing_comma); + } else if (invalid_sequence) { + unexpected(invalid_sequence); + } + return a; + } + + function _function_body(block, generator, is_async, name, args) { + var loop = S.in_loop; + var labels = S.labels; + var current_generator = S.in_generator; + var current_async = S.in_async; + ++S.in_function; + if (generator) + S.in_generator = S.in_function; + if (is_async) + S.in_async = S.in_function; + if (args) parameters(args); + if (block) + S.in_directives = true; + S.in_loop = 0; + S.labels = []; + if (block) { + S.input.push_directives_stack(); + var a = block_(); + if (name) _verify_symbol(name); + if (args) args.forEach(_verify_symbol); + S.input.pop_directives_stack(); + } else { + var a = [new AST_Return({ + start: S.token, + value: expression(false), + end: S.token + })]; + } + --S.in_function; + S.in_loop = loop; + S.labels = labels; + S.in_generator = current_generator; + S.in_async = current_async; + return a; + } + + function _await_expression() { + // Previous token must be "await" and not be interpreted as an identifier + if (!can_await()) { + croak("Unexpected await expression outside async function", + S.prev.line, S.prev.col, S.prev.pos); + } + // the await expression is parsed as a unary expression in Babel + return new AST_Await({ + start: prev(), + end: S.token, + expression : maybe_unary(true), + }); + } + + function _yield_expression() { + // Previous token must be keyword yield and not be interpret as an identifier + if (!is_in_generator()) { + croak("Unexpected yield expression outside generator function", + S.prev.line, S.prev.col, S.prev.pos); + } + var start = S.token; + var star = false; + var has_expression = true; + + // Attempt to get expression or star (and then the mandatory expression) + // behind yield on the same line. + // + // If nothing follows on the same line of the yieldExpression, + // it should default to the value `undefined` for yield to return. + // In that case, the `undefined` stored as `null` in ast. + // + // Note 1: It isn't allowed for yield* to close without an expression + // Note 2: If there is a nlb between yield and star, it is interpret as + // yield * + if (can_insert_semicolon() || + (is("punc") && PUNC_AFTER_EXPRESSION.has(S.token.value))) { + has_expression = false; + + } else if (is("operator", "*")) { + star = true; + next(); + } + + return new AST_Yield({ + start : start, + is_star : star, + expression : has_expression ? expression() : null, + end : prev() + }); + } + + function if_() { + var cond = parenthesised(), body = statement(false, false, true), belse = null; + if (is("keyword", "else")) { + next(); + belse = statement(false, false, true); + } + return new AST_If({ + condition : cond, + body : body, + alternative : belse + }); + } + + function block_() { + expect("{"); + var a = []; + while (!is("punc", "}")) { + if (is("eof")) unexpected(); + a.push(statement()); + } + next(); + return a; + } + + function switch_body_() { + expect("{"); + var a = [], cur = null, branch = null, tmp; + while (!is("punc", "}")) { + if (is("eof")) unexpected(); + if (is("keyword", "case")) { + if (branch) branch.end = prev(); + cur = []; + branch = new AST_Case({ + start : (tmp = S.token, next(), tmp), + expression : expression(true), + body : cur + }); + a.push(branch); + expect(":"); + } else if (is("keyword", "default")) { + if (branch) branch.end = prev(); + cur = []; + branch = new AST_Default({ + start : (tmp = S.token, next(), expect(":"), tmp), + body : cur + }); + a.push(branch); + } else { + if (!cur) unexpected(); + cur.push(statement()); + } + } + if (branch) branch.end = prev(); + next(); + return a; + } + + function try_() { + var body, bcatch = null, bfinally = null; + body = new AST_TryBlock({ + start : S.token, + body : block_(), + end : prev(), + }); + if (is("keyword", "catch")) { + var start = S.token; + next(); + if (is("punc", "{")) { + var name = null; + } else { + expect("("); + var name = parameter(undefined, AST_SymbolCatch); + expect(")"); + } + bcatch = new AST_Catch({ + start : start, + argname : name, + body : block_(), + end : prev() + }); + } + if (is("keyword", "finally")) { + var start = S.token; + next(); + bfinally = new AST_Finally({ + start : start, + body : block_(), + end : prev() + }); + } + if (!bcatch && !bfinally) + croak("Missing catch/finally blocks"); + return new AST_Try({ + body : body, + bcatch : bcatch, + bfinally : bfinally + }); + } + + /** + * var + * vardef1 = 2, + * vardef2 = 3; + */ + function vardefs(no_in, kind) { + var var_defs = []; + var def; + for (;;) { + var sym_type = + kind === "var" ? AST_SymbolVar : + kind === "const" ? AST_SymbolConst : + kind === "let" ? AST_SymbolLet : null; + // var { a } = b + if (is("punc", "{") || is("punc", "[")) { + def = new AST_VarDef({ + start: S.token, + name: binding_element(undefined, sym_type), + value: is("operator", "=") ? (expect_token("operator", "="), expression(false, no_in)) : null, + end: prev() + }); + } else { + def = new AST_VarDef({ + start : S.token, + name : as_symbol(sym_type), + value : is("operator", "=") + ? (next(), expression(false, no_in)) + : !no_in && kind === "const" + ? croak("Missing initializer in const declaration") : null, + end : prev() + }); + if (def.name.name == "import") croak("Unexpected token: import"); + } + var_defs.push(def); + if (!is("punc", ",")) + break; + next(); + } + return var_defs; + } + + var var_ = function(no_in) { + return new AST_Var({ + start : prev(), + definitions : vardefs(no_in, "var"), + end : prev() + }); + }; + + var let_ = function(no_in) { + return new AST_Let({ + start : prev(), + definitions : vardefs(no_in, "let"), + end : prev() + }); + }; + + var const_ = function(no_in) { + return new AST_Const({ + start : prev(), + definitions : vardefs(no_in, "const"), + end : prev() + }); + }; + + var new_ = function(allow_calls) { + var start = S.token; + expect_token("operator", "new"); + if (is("punc", ".")) { + next(); + expect_token("name", "target"); + return subscripts(new AST_NewTarget({ + start : start, + end : prev() + }), allow_calls); + } + var newexp = expr_atom(false), args; + if (is("punc", "(")) { + next(); + args = expr_list(")", true); + } else { + args = []; + } + var call = new AST_New({ + start : start, + expression : newexp, + args : args, + end : prev() + }); + annotate(call); + return subscripts(call, allow_calls); + }; + + function as_atom_node() { + var tok = S.token, ret; + switch (tok.type) { + case "name": + ret = _make_symbol(AST_SymbolRef); + break; + case "num": + ret = new AST_Number({ + start: tok, + end: tok, + value: tok.value, + raw: LATEST_RAW + }); + break; + case "big_int": + ret = new AST_BigInt({ start: tok, end: tok, value: tok.value }); + break; + case "string": + ret = new AST_String({ + start : tok, + end : tok, + value : tok.value, + quote : tok.quote + }); + annotate(ret); + break; + case "regexp": + const [_, source, flags] = tok.value.match(/^\/(.*)\/(\w*)$/); + + ret = new AST_RegExp({ start: tok, end: tok, value: { source, flags } }); + break; + case "atom": + switch (tok.value) { + case "false": + ret = new AST_False({ start: tok, end: tok }); + break; + case "true": + ret = new AST_True({ start: tok, end: tok }); + break; + case "null": + ret = new AST_Null({ start: tok, end: tok }); + break; + } + break; + } + next(); + return ret; + } + + function to_fun_args(ex, default_seen_above) { + var insert_default = function(ex, default_value) { + if (default_value) { + return new AST_DefaultAssign({ + start: ex.start, + left: ex, + operator: "=", + right: default_value, + end: default_value.end + }); + } + return ex; + }; + if (ex instanceof AST_Object) { + return insert_default(new AST_Destructuring({ + start: ex.start, + end: ex.end, + is_array: false, + names: ex.properties.map(prop => to_fun_args(prop)) + }), default_seen_above); + } else if (ex instanceof AST_ObjectKeyVal) { + ex.value = to_fun_args(ex.value); + return insert_default(ex, default_seen_above); + } else if (ex instanceof AST_Hole) { + return ex; + } else if (ex instanceof AST_Destructuring) { + ex.names = ex.names.map(name => to_fun_args(name)); + return insert_default(ex, default_seen_above); + } else if (ex instanceof AST_SymbolRef) { + return insert_default(new AST_SymbolFunarg({ + name: ex.name, + start: ex.start, + end: ex.end + }), default_seen_above); + } else if (ex instanceof AST_Expansion) { + ex.expression = to_fun_args(ex.expression); + return insert_default(ex, default_seen_above); + } else if (ex instanceof AST_Array) { + return insert_default(new AST_Destructuring({ + start: ex.start, + end: ex.end, + is_array: true, + names: ex.elements.map(elm => to_fun_args(elm)) + }), default_seen_above); + } else if (ex instanceof AST_Assign) { + return insert_default(to_fun_args(ex.left, ex.right), default_seen_above); + } else if (ex instanceof AST_DefaultAssign) { + ex.left = to_fun_args(ex.left); + return ex; + } else { + croak("Invalid function parameter", ex.start.line, ex.start.col); + } + } + + var expr_atom = function(allow_calls, allow_arrows) { + if (is("operator", "new")) { + return new_(allow_calls); + } + if (is("name", "import") && is_token(peek(), "punc", ".")) { + return import_meta(allow_calls); + } + var start = S.token; + var peeked; + var async = is("name", "async") + && (peeked = peek()).value != "[" + && peeked.type != "arrow" + && as_atom_node(); + if (is("punc")) { + switch (S.token.value) { + case "(": + if (async && !allow_calls) break; + var exprs = params_or_seq_(allow_arrows, !async); + if (allow_arrows && is("arrow", "=>")) { + return arrow_function(start, exprs.map(e => to_fun_args(e)), !!async); + } + var ex = async ? new AST_Call({ + expression: async, + args: exprs + }) : exprs.length == 1 ? exprs[0] : new AST_Sequence({ + expressions: exprs + }); + if (ex.start) { + const outer_comments_before = start.comments_before.length; + outer_comments_before_counts.set(start, outer_comments_before); + ex.start.comments_before.unshift(...start.comments_before); + start.comments_before = ex.start.comments_before; + if (outer_comments_before == 0 && start.comments_before.length > 0) { + var comment = start.comments_before[0]; + if (!comment.nlb) { + comment.nlb = start.nlb; + start.nlb = false; + } + } + start.comments_after = ex.start.comments_after; + } + ex.start = start; + var end = prev(); + if (ex.end) { + end.comments_before = ex.end.comments_before; + ex.end.comments_after.push(...end.comments_after); + end.comments_after = ex.end.comments_after; + } + ex.end = end; + if (ex instanceof AST_Call) annotate(ex); + return subscripts(ex, allow_calls); + case "[": + return subscripts(array_(), allow_calls); + case "{": + return subscripts(object_or_destructuring_(), allow_calls); + } + if (!async) unexpected(); + } + if (allow_arrows && is("name") && is_token(peek(), "arrow")) { + var param = new AST_SymbolFunarg({ + name: S.token.value, + start: start, + end: start, + }); + next(); + return arrow_function(start, [param], !!async); + } + if (is("keyword", "function")) { + next(); + var func = function_(AST_Function, false, !!async); + func.start = start; + func.end = prev(); + return subscripts(func, allow_calls); + } + if (async) return subscripts(async, allow_calls); + if (is("keyword", "class")) { + next(); + var cls = class_(AST_ClassExpression); + cls.start = start; + cls.end = prev(); + return subscripts(cls, allow_calls); + } + if (is("template_head")) { + return subscripts(template_string(), allow_calls); + } + if (is("privatename")) { + if(!S.in_class) { + croak("Private field must be used in an enclosing class"); + } + + const start = S.token; + const key = new AST_SymbolPrivateProperty({ + start, + name: start.value, + end: start + }); + next(); + expect_token("operator", "in"); + + const private_in = new AST_PrivateIn({ + start, + key, + value: subscripts(as_atom_node(), allow_calls), + end: prev() + }); - raw += ch; - if (ch == "\\") { - var tmp = S.pos; - var prev_is_tag = previous_token && (previous_token.type === "name" || previous_token.type === "punc" && (previous_token.value === ")" || previous_token.value === "]")); - ch = read_escaped_char(true, !prev_is_tag, true); - raw += S.text.substr(tmp, S.pos - tmp); - } + return subscripts(private_in, allow_calls); + } + if (ATOMIC_START_TOKEN.has(S.token.type)) { + return subscripts(as_atom_node(), allow_calls); + } + unexpected(); + }; + + function template_string() { + var segments = [], start = S.token; + + segments.push(new AST_TemplateSegment({ + start: S.token, + raw: TEMPLATE_RAWS.get(S.token), + value: S.token.value, + end: S.token + })); + + while (!S.token.template_end) { + next(); + handle_regexp(); + segments.push(expression(true)); + + segments.push(new AST_TemplateSegment({ + start: S.token, + raw: TEMPLATE_RAWS.get(S.token), + value: S.token.value, + end: S.token + })); + } + next(); + + return new AST_TemplateString({ + start: start, + segments: segments, + end: S.token + }); + } + + function expr_list(closing, allow_trailing_comma, allow_empty) { + var first = true, a = []; + while (!is("punc", closing)) { + if (first) first = false; else expect(","); + if (allow_trailing_comma && is("punc", closing)) break; + if (is("punc", ",") && allow_empty) { + a.push(new AST_Hole({ start: S.token, end: S.token })); + } else if (is("expand", "...")) { + next(); + a.push(new AST_Expansion({start: prev(), expression: expression(),end: S.token})); + } else { + a.push(expression(false)); + } + } + next(); + return a; + } + + var array_ = embed_tokens(function() { + expect("["); + return new AST_Array({ + elements: expr_list("]", !options.strict, true) + }); + }); + + var create_accessor = embed_tokens((is_generator, is_async) => { + return function_(AST_Accessor, is_generator, is_async); + }); + + var object_or_destructuring_ = embed_tokens(function object_or_destructuring_() { + var start = S.token, first = true, a = []; + expect("{"); + while (!is("punc", "}")) { + if (first) first = false; else expect(","); + if (!options.strict && is("punc", "}")) + // allow trailing comma + break; + + start = S.token; + if (start.type == "expand") { + next(); + a.push(new AST_Expansion({ + start: start, + expression: expression(false), + end: prev(), + })); + continue; + } + if(is("privatename")) { + croak("private fields are not allowed in an object"); + } + var name = as_property_name(); + var value; + + // Check property and fetch value + if (!is("punc", ":")) { + var concise = concise_method_or_getset(name, start); + if (concise) { + a.push(concise); + continue; + } - content += ch; - } - S.template_braces.pop(); - tok = token(begin ? "template_head" : "template_substitution", content); - tok.begin = begin; - tok.raw = raw; - tok.end = true; - return tok; - }); - - function skip_line_comment(type) { - var regex_allowed = S.regex_allowed; - var i = find_eol(), ret; - if (i == -1) { - ret = S.text.substr(S.pos); - S.pos = S.text.length; - } else { - ret = S.text.substring(S.pos, i); - S.pos = i; - } - S.col = S.tokcol + (S.pos - S.tokpos); - S.comments_before.push(token(type, ret, true)); - S.regex_allowed = regex_allowed; - return next_token; - } - - var skip_multiline_comment = with_eof_error("Unterminated multiline comment", function() { - var regex_allowed = S.regex_allowed; - var i = find("*/", true); - var text = S.text.substring(S.pos, i).replace(/\r\n|\r|\u2028|\u2029/g, "\n"); - // update stream position - forward(get_full_char_length(text) /* text length doesn't count \r\n as 2 char while S.pos - i does */ + 2); - S.comments_before.push(token("comment2", text, true)); - S.newline_before = S.newline_before || text.includes("\n"); - S.regex_allowed = regex_allowed; - return next_token; - }); - - var read_name = with_eof_error("Unterminated identifier name", function() { - var name, ch, escaped = false; - var read_escaped_identifier_char = function() { - escaped = true; - next(); - if (peek() !== "u") { - parse_error("Expecting UnicodeEscapeSequence -- uXXXX or u{XXXX}"); - } - return read_escaped_char(false, true); - }; - - // Read first character (ID_Start) - if ((name = peek()) === "\\") { - name = read_escaped_identifier_char(); - if (!is_identifier_start(name)) { - parse_error("First identifier char is an invalid identifier char"); - } - } else if (is_identifier_start(name)) { - next(); - } else { - return ""; - } - - // Read ID_Continue - while ((ch = peek()) != null) { - if ((ch = peek()) === "\\") { - ch = read_escaped_identifier_char(); - if (!is_identifier_char(ch)) { - parse_error("Invalid escaped identifier char"); - } - } else { - if (!is_identifier_char(ch)) { - break; - } - next(); - } - name += ch; - } - if (RESERVED_WORDS.has(name) && escaped) { - parse_error("Escaped characters are not allowed in keywords"); - } - return name; - }); - - var read_regexp = with_eof_error("Unterminated regular expression", function(source) { - var prev_backslash = false, ch, in_class = false; - while ((ch = next(true))) if (NEWLINE_CHARS.has(ch)) { - parse_error("Unexpected line terminator"); - } else if (prev_backslash) { - source += "\\" + ch; - prev_backslash = false; - } else if (ch == "[") { - in_class = true; - source += ch; - } else if (ch == "]" && in_class) { - in_class = false; - source += ch; - } else if (ch == "/" && !in_class) { - break; - } else if (ch == "\\") { - prev_backslash = true; - } else { - source += ch; - } - var mods = read_name(); - try { - var regexp = new RegExp(source, mods); - regexp.raw_source = "/" + source + "/" + mods; - return token("regexp", regexp); - } catch(e) { - parse_error(e.message); - } - }); - - function read_operator(prefix) { - function grow(op) { - if (!peek()) return op; - var bigger = op + peek(); - if (OPERATORS.has(bigger)) { - next(); - return grow(bigger); - } else { - return op; - } - } - return token("operator", grow(prefix || next())); - } - - function handle_slash() { - next(); - switch (peek()) { - case "/": - next(); - return skip_line_comment("comment1"); - case "*": - next(); - return skip_multiline_comment(); - } - return S.regex_allowed ? read_regexp("") : read_operator("/"); - } - - function handle_eq_sign() { - next(); - if (peek() === ">") { - next(); - return token("arrow", "=>"); - } else { - return read_operator("="); - } - } - - function handle_dot() { - next(); - if (is_digit(peek().charCodeAt(0))) { - return read_num("."); - } - if (peek() === ".") { - next(); // Consume second dot - next(); // Consume third dot - return token("expand", "..."); - } - - return token("punc", "."); - } - - function read_word() { - var word = read_name(); - if (prev_was_dot) return token("name", word); - return KEYWORDS_ATOM.has(word) ? token("atom", word) - : !KEYWORDS.has(word) ? token("name", word) - : OPERATORS.has(word) ? token("operator", word) - : token("keyword", word); - } - - function with_eof_error(eof_error, cont) { - return function(x) { - try { - return cont(x); - } catch(ex) { - if (ex === EX_EOF) parse_error(eof_error); - else throw ex; - } - }; - } - - function next_token(force_regexp) { - if (force_regexp != null) - return read_regexp(force_regexp); - if (shebang && S.pos == 0 && looking_at("#!")) { - start_token(); - forward(2); - skip_line_comment("comment5"); - } - for (;;) { - skip_whitespace(); - start_token(); - if (html5_comments) { - if (looking_at("") && S.newline_before) { - forward(3); - skip_line_comment("comment4"); - continue; - } - } - var ch = peek(); - if (!ch) return token("eof"); - var code = ch.charCodeAt(0); - switch (code) { - case 34: case 39: return read_string(); - case 46: return handle_dot(); - case 47: { - var tok = handle_slash(); - if (tok === next_token) continue; - return tok; + value = new AST_SymbolRef({ + start: prev(), + name: name, + end: prev() + }); + } else if (name === null) { + unexpected(prev()); + } else { + next(); // `:` - see first condition + value = expression(false); + } + + // Check for default value and alter value accordingly if necessary + if (is("operator", "=")) { + next(); + value = new AST_Assign({ + start: start, + left: value, + operator: "=", + right: expression(false), + logical: false, + end: prev() + }); + } + + // Create property + const kv = new AST_ObjectKeyVal({ + start: start, + quote: start.quote, + key: name instanceof AST_Node ? name : "" + name, + value: value, + end: prev() + }); + a.push(annotate(kv)); + } + next(); + return new AST_Object({ properties: a }); + }); + + function class_(KindOfClass, is_export_default) { + var start, method, class_name, extends_, a = []; + + S.input.push_directives_stack(); // Push directive stack, but not scope stack + S.input.add_directive("use strict"); + + if (S.token.type == "name" && S.token.value != "extends") { + class_name = as_symbol(KindOfClass === AST_DefClass ? AST_SymbolDefClass : AST_SymbolClass); + } + + if (KindOfClass === AST_DefClass && !class_name) { + if (is_export_default) { + KindOfClass = AST_ClassExpression; + } else { + unexpected(); + } + } + + if (S.token.value == "extends") { + next(); + extends_ = expression(true); + } + + expect("{"); + // mark in class feild, + const save_in_class = S.in_class; + S.in_class = true; + while (is("punc", ";")) { next(); } // Leading semicolons are okay in class bodies. + while (!is("punc", "}")) { + start = S.token; + method = concise_method_or_getset(as_property_name(), start, true); + if (!method) { unexpected(); } + a.push(method); + while (is("punc", ";")) { next(); } + } + // mark in class feild, + S.in_class = save_in_class; + + S.input.pop_directives_stack(); + + next(); + + return new KindOfClass({ + start: start, + name: class_name, + extends: extends_, + properties: a, + end: prev(), + }); + } + + function concise_method_or_getset(name, start, is_class) { + const get_symbol_ast = (name, SymbolClass = AST_SymbolMethod) => { + if (typeof name === "string" || typeof name === "number") { + return new SymbolClass({ + start, + name: "" + name, + end: prev() + }); + } else if (name === null) { + unexpected(); + } + return name; + }; + + const is_not_method_start = () => + !is("punc", "(") && !is("punc", ",") && !is("punc", "}") && !is("punc", ";") && !is("operator", "="); + + var is_async = false; + var is_static = false; + var is_generator = false; + var is_private = false; + var accessor_type = null; + + if (is_class && name === "static" && is_not_method_start()) { + const static_block = class_static_block(); + if (static_block != null) { + return static_block; + } + is_static = true; + name = as_property_name(); + } + if (name === "async" && is_not_method_start()) { + is_async = true; + name = as_property_name(); + } + if (prev().type === "operator" && prev().value === "*") { + is_generator = true; + name = as_property_name(); + } + if ((name === "get" || name === "set") && is_not_method_start()) { + accessor_type = name; + name = as_property_name(); + } + if (prev().type === "privatename") { + is_private = true; + } + + const property_token = prev(); + + if (accessor_type != null) { + if (!is_private) { + const AccessorClass = accessor_type === "get" + ? AST_ObjectGetter + : AST_ObjectSetter; + + name = get_symbol_ast(name); + return annotate(new AccessorClass({ + start, + static: is_static, + key: name, + quote: name instanceof AST_SymbolMethod ? property_token.quote : undefined, + value: create_accessor(), + end: prev() + })); + } else { + const AccessorClass = accessor_type === "get" + ? AST_PrivateGetter + : AST_PrivateSetter; + + return annotate(new AccessorClass({ + start, + static: is_static, + key: get_symbol_ast(name), + value: create_accessor(), + end: prev(), + })); + } + } + + if (is("punc", "(")) { + name = get_symbol_ast(name); + const AST_MethodVariant = is_private + ? AST_PrivateMethod + : AST_ConciseMethod; + var node = new AST_MethodVariant({ + start : start, + static : is_static, + is_generator: is_generator, + async : is_async, + key : name, + quote : name instanceof AST_SymbolMethod ? + property_token.quote : undefined, + value : create_accessor(is_generator, is_async), + end : prev() + }); + return annotate(node); + } + + if (is_class) { + const key = get_symbol_ast(name, AST_SymbolClassProperty); + const quote = key instanceof AST_SymbolClassProperty + ? property_token.quote + : undefined; + const AST_ClassPropertyVariant = is_private + ? AST_ClassPrivateProperty + : AST_ClassProperty; + if (is("operator", "=")) { + next(); + return annotate( + new AST_ClassPropertyVariant({ + start, + static: is_static, + quote, + key, + value: expression(false), + end: prev() + }) + ); + } else if ( + is("name") + || is("privatename") + || is("operator", "*") + || is("punc", ";") + || is("punc", "}") + ) { + return annotate( + new AST_ClassPropertyVariant({ + start, + static: is_static, + quote, + key, + end: prev() + }) + ); + } + } + } + + function class_static_block() { + if (!is("punc", "{")) { + return null; + } + + const start = S.token; + const body = []; + + next(); + + while (!is("punc", "}")) { + body.push(statement()); + } + + next(); + + return new AST_ClassStaticBlock({ start, body, end: prev() }); + } + + function maybe_import_assertion() { + if (is("name", "assert") && !has_newline_before(S.token)) { + next(); + return object_or_destructuring_(); + } + return null; + } + + function import_statement() { + var start = prev(); + + var imported_name; + var imported_names; + if (is("name")) { + imported_name = as_symbol(AST_SymbolImport); + } + + if (is("punc", ",")) { + next(); + } + + imported_names = map_names(true); + + if (imported_names || imported_name) { + expect_token("name", "from"); + } + var mod_str = S.token; + if (mod_str.type !== "string") { + unexpected(); + } + next(); + + const assert_clause = maybe_import_assertion(); + + return new AST_Import({ + start, + imported_name, + imported_names, + module_name: new AST_String({ + start: mod_str, + value: mod_str.value, + quote: mod_str.quote, + end: mod_str, + }), + assert_clause, + end: S.token, + }); + } + + function import_meta(allow_calls) { + var start = S.token; + expect_token("name", "import"); + expect_token("punc", "."); + expect_token("name", "meta"); + return subscripts(new AST_ImportMeta({ + start: start, + end: prev() + }), allow_calls); + } + + function map_name(is_import) { + function make_symbol(type, quote) { + return new type({ + name: as_property_name(), + quote: quote || undefined, + start: prev(), + end: prev() + }); + } + + var foreign_type = is_import ? AST_SymbolImportForeign : AST_SymbolExportForeign; + var type = is_import ? AST_SymbolImport : AST_SymbolExport; + var start = S.token; + var foreign_name; + var name; + + if (is_import) { + foreign_name = make_symbol(foreign_type, start.quote); + } else { + name = make_symbol(type, start.quote); + } + if (is("name", "as")) { + next(); // The "as" word + if (is_import) { + name = make_symbol(type); + } else { + foreign_name = make_symbol(foreign_type, S.token.quote); + } + } else if (is_import) { + name = new type(foreign_name); + } else { + foreign_name = new foreign_type(name); + } + + return new AST_NameMapping({ + start: start, + foreign_name: foreign_name, + name: name, + end: prev(), + }); + } + + function map_nameAsterisk(is_import, import_or_export_foreign_name) { + var foreign_type = is_import ? AST_SymbolImportForeign : AST_SymbolExportForeign; + var type = is_import ? AST_SymbolImport : AST_SymbolExport; + var start = S.token; + var name, foreign_name; + var end = prev(); + + if (is_import) { + name = import_or_export_foreign_name; + } else { + foreign_name = import_or_export_foreign_name; + } + + name = name || new type({ + start: start, + name: "*", + end: end, + }); + + foreign_name = foreign_name || new foreign_type({ + start: start, + name: "*", + end: end, + }); + + return new AST_NameMapping({ + start: start, + foreign_name: foreign_name, + name: name, + end: end, + }); + } + + function map_names(is_import) { + var names; + if (is("punc", "{")) { + next(); + names = []; + while (!is("punc", "}")) { + names.push(map_name(is_import)); + if (is("punc", ",")) { + next(); + } + } + next(); + } else if (is("operator", "*")) { + var name; + next(); + if (is("name", "as")) { + next(); // The "as" word + name = is_import ? as_symbol(AST_SymbolImport) : as_symbol_or_string(AST_SymbolExportForeign); + } + names = [map_nameAsterisk(is_import, name)]; + } + return names; + } + + function export_statement() { + var start = S.token; + var is_default; + var exported_names; + + if (is("keyword", "default")) { + is_default = true; + next(); + } else if (exported_names = map_names(false)) { + if (is("name", "from")) { + next(); + + var mod_str = S.token; + if (mod_str.type !== "string") { + unexpected(); + } + next(); + + const assert_clause = maybe_import_assertion(); + + return new AST_Export({ + start: start, + is_default: is_default, + exported_names: exported_names, + module_name: new AST_String({ + start: mod_str, + value: mod_str.value, + quote: mod_str.quote, + end: mod_str, + }), + end: prev(), + assert_clause + }); + } else { + return new AST_Export({ + start: start, + is_default: is_default, + exported_names: exported_names, + end: prev(), + }); + } + } + + var node; + var exported_value; + var exported_definition; + if (is("punc", "{") + || is_default + && (is("keyword", "class") || is("keyword", "function")) + && is_token(peek(), "punc")) { + exported_value = expression(false); + semicolon(); + } else if ((node = statement(is_default)) instanceof AST_Definitions && is_default) { + unexpected(node.start); + } else if ( + node instanceof AST_Definitions + || node instanceof AST_Defun + || node instanceof AST_DefClass + ) { + exported_definition = node; + } else if ( + node instanceof AST_ClassExpression + || node instanceof AST_Function + ) { + exported_value = node; + } else if (node instanceof AST_SimpleStatement) { + exported_value = node.body; + } else { + unexpected(node.start); + } + + return new AST_Export({ + start: start, + is_default: is_default, + exported_value: exported_value, + exported_definition: exported_definition, + end: prev(), + assert_clause: null + }); + } + + function as_property_name() { + var tmp = S.token; + switch (tmp.type) { + case "punc": + if (tmp.value === "[") { + next(); + var ex = expression(false); + expect("]"); + return ex; + } else unexpected(tmp); + case "operator": + if (tmp.value === "*") { + next(); + return null; + } + if (!["delete", "in", "instanceof", "new", "typeof", "void"].includes(tmp.value)) { + unexpected(tmp); + } + /* falls through */ + case "name": + case "privatename": + case "string": + case "num": + case "big_int": + case "keyword": + case "atom": + next(); + return tmp.value; + default: + unexpected(tmp); + } + } + + function as_name() { + var tmp = S.token; + if (tmp.type != "name" && tmp.type != "privatename") unexpected(); + next(); + return tmp.value; + } + + function _make_symbol(type) { + var name = S.token.value; + return new (name == "this" ? AST_This : + name == "super" ? AST_Super : + type)({ + name : String(name), + start : S.token, + end : S.token + }); + } + + function _verify_symbol(sym) { + var name = sym.name; + if (is_in_generator() && name == "yield") { + token_error(sym.start, "Yield cannot be used as identifier inside generators"); + } + if (S.input.has_directive("use strict")) { + if (name == "yield") { + token_error(sym.start, "Unexpected yield identifier inside strict mode"); + } + if (sym instanceof AST_SymbolDeclaration && (name == "arguments" || name == "eval")) { + token_error(sym.start, "Unexpected " + name + " in strict mode"); + } + } + } + + function as_symbol(type, noerror) { + if (!is("name")) { + if (!noerror) croak("Name expected"); + return null; + } + var sym = _make_symbol(type); + _verify_symbol(sym); + next(); + return sym; + } + + function as_symbol_or_string(type) { + if (!is("name")) { + if (!is("string")) { + croak("Name or string expected"); + } + var tok = S.token; + var ret = new type({ + start : tok, + end : tok, + name : tok.value, + quote : tok.quote + }); + next(); + return ret; + } + var sym = _make_symbol(type); + _verify_symbol(sym); + next(); + return sym; + } + + // Annotate AST_Call, AST_Lambda or AST_New with the special comments + function annotate(node, before_token = node.start) { + var comments = before_token.comments_before; + const comments_outside_parens = outer_comments_before_counts.get(before_token); + var i = comments_outside_parens != null ? comments_outside_parens : comments.length; + while (--i >= 0) { + var comment = comments[i]; + if (/[@#]__/.test(comment.value)) { + if (/[@#]__PURE__/.test(comment.value)) { + set_annotation(node, _PURE); + break; + } + if (/[@#]__INLINE__/.test(comment.value)) { + set_annotation(node, _INLINE); + break; + } + if (/[@#]__NOINLINE__/.test(comment.value)) { + set_annotation(node, _NOINLINE); + break; + } + if (/[@#]__KEY__/.test(comment.value)) { + set_annotation(node, _KEY); + break; + } + if (/[@#]__MANGLE_PROP__/.test(comment.value)) { + set_annotation(node, _MANGLEPROP); + break; + } + } + } + return node; + } + + var subscripts = function(expr, allow_calls, is_chain) { + var start = expr.start; + if (is("punc", ".")) { + next(); + if(is("privatename") && !S.in_class) + croak("Private field must be used in an enclosing class"); + const AST_DotVariant = is("privatename") ? AST_DotHash : AST_Dot; + return subscripts(new AST_DotVariant({ + start : start, + expression : expr, + optional : false, + property : as_name(), + end : prev() + }), allow_calls, is_chain); + } + if (is("punc", "[")) { + next(); + var prop = expression(true); + expect("]"); + return subscripts(new AST_Sub({ + start : start, + expression : expr, + optional : false, + property : prop, + end : prev() + }), allow_calls, is_chain); + } + if (allow_calls && is("punc", "(")) { + next(); + var call = new AST_Call({ + start : start, + expression : expr, + optional : false, + args : call_args(), + end : prev() + }); + annotate(call); + return subscripts(call, true, is_chain); + } + + if (is("punc", "?.")) { + next(); + + let chain_contents; + + if (allow_calls && is("punc", "(")) { + next(); + + const call = new AST_Call({ + start, + optional: true, + expression: expr, + args: call_args(), + end: prev() + }); + annotate(call); + + chain_contents = subscripts(call, true, true); + } else if (is("name") || is("privatename")) { + if(is("privatename") && !S.in_class) + croak("Private field must be used in an enclosing class"); + const AST_DotVariant = is("privatename") ? AST_DotHash : AST_Dot; + chain_contents = subscripts(new AST_DotVariant({ + start, + expression: expr, + optional: true, + property: as_name(), + end: prev() + }), allow_calls, true); + } else if (is("punc", "[")) { + next(); + const property = expression(true); + expect("]"); + chain_contents = subscripts(new AST_Sub({ + start, + expression: expr, + optional: true, + property, + end: prev() + }), allow_calls, true); + } + + if (!chain_contents) unexpected(); + + if (chain_contents instanceof AST_Chain) return chain_contents; + + return new AST_Chain({ + start, + expression: chain_contents, + end: prev() + }); + } + + if (is("template_head")) { + if (is_chain) { + // a?.b`c` is a syntax error + unexpected(); + } + + return subscripts(new AST_PrefixedTemplateString({ + start: start, + prefix: expr, + template_string: template_string(), + end: prev() + }), allow_calls); + } + return expr; + }; + + function call_args() { + var args = []; + while (!is("punc", ")")) { + if (is("expand", "...")) { + next(); + args.push(new AST_Expansion({ + start: prev(), + expression: expression(false), + end: prev() + })); + } else { + args.push(expression(false)); + } + if (!is("punc", ")")) { + expect(","); + } + } + next(); + return args; + } + + var maybe_unary = function(allow_calls, allow_arrows) { + var start = S.token; + if (start.type == "name" && start.value == "await" && can_await()) { + next(); + return _await_expression(); + } + if (is("operator") && UNARY_PREFIX.has(start.value)) { + next(); + handle_regexp(); + var ex = make_unary(AST_UnaryPrefix, start, maybe_unary(allow_calls)); + ex.start = start; + ex.end = prev(); + return ex; + } + var val = expr_atom(allow_calls, allow_arrows); + while (is("operator") && UNARY_POSTFIX.has(S.token.value) && !has_newline_before(S.token)) { + if (val instanceof AST_Arrow) unexpected(); + val = make_unary(AST_UnaryPostfix, S.token, val); + val.start = start; + val.end = S.token; + next(); + } + return val; + }; + + function make_unary(ctor, token, expr) { + var op = token.value; + switch (op) { + case "++": + case "--": + if (!is_assignable(expr)) + croak("Invalid use of " + op + " operator", token.line, token.col, token.pos); + break; + case "delete": + if (expr instanceof AST_SymbolRef && S.input.has_directive("use strict")) + croak("Calling delete on expression not allowed in strict mode", expr.start.line, expr.start.col, expr.start.pos); + break; + } + return new ctor({ operator: op, expression: expr }); + } + + var expr_op = function(left, min_prec, no_in) { + var op = is("operator") ? S.token.value : null; + if (op == "in" && no_in) op = null; + if (op == "**" && left instanceof AST_UnaryPrefix + /* unary token in front not allowed - parenthesis required */ + && !is_token(left.start, "punc", "(") + && left.operator !== "--" && left.operator !== "++") + unexpected(left.start); + var prec = op != null ? PRECEDENCE[op] : null; + if (prec != null && (prec > min_prec || (op === "**" && min_prec === prec))) { + next(); + var right = expr_op(maybe_unary(true), prec, no_in); + return expr_op(new AST_Binary({ + start : left.start, + left : left, + operator : op, + right : right, + end : right.end + }), min_prec, no_in); + } + return left; + }; + + function expr_ops(no_in) { + return expr_op(maybe_unary(true, true), 0, no_in); + } + + var maybe_conditional = function(no_in) { + var start = S.token; + var expr = expr_ops(no_in); + if (is("operator", "?")) { + next(); + var yes = expression(false); + expect(":"); + return new AST_Conditional({ + start : start, + condition : expr, + consequent : yes, + alternative : expression(false, no_in), + end : prev() + }); + } + return expr; + }; + + function is_assignable(expr) { + return expr instanceof AST_PropAccess || expr instanceof AST_SymbolRef; + } + + function to_destructuring(node) { + if (node instanceof AST_Object) { + node = new AST_Destructuring({ + start: node.start, + names: node.properties.map(to_destructuring), + is_array: false, + end: node.end + }); + } else if (node instanceof AST_Array) { + var names = []; + + for (var i = 0; i < node.elements.length; i++) { + // Only allow expansion as last element + if (node.elements[i] instanceof AST_Expansion) { + if (i + 1 !== node.elements.length) { + token_error(node.elements[i].start, "Spread must the be last element in destructuring array"); + } + node.elements[i].expression = to_destructuring(node.elements[i].expression); } - case 61: return handle_eq_sign(); - case 96: return read_template_characters(true); - case 123: - S.brace_counter++; - break; - case 125: - S.brace_counter--; - if (S.template_braces.length > 0 - && S.template_braces[S.template_braces.length - 1] === S.brace_counter) - return read_template_characters(false); - break; - } - if (is_digit(code)) return read_num(); - if (PUNC_CHARS.has(ch)) return token("punc", next()); - if (OPERATOR_CHARS.has(ch)) return read_operator(); - if (code == 92 || is_identifier_start(ch)) return read_word(); - break; - } - parse_error("Unexpected character '" + ch + "'"); - } - - next_token.next = next; - next_token.peek = peek; - - next_token.context = function(nc) { - if (nc) S = nc; - return S; - }; - - next_token.add_directive = function(directive) { - S.directive_stack[S.directive_stack.length - 1].push(directive); - - if (S.directives[directive] === undefined) { - S.directives[directive] = 1; - } else { - S.directives[directive]++; - } - }; - - next_token.push_directives_stack = function() { - S.directive_stack.push([]); - }; - - next_token.pop_directives_stack = function() { - var directives = S.directive_stack[S.directive_stack.length - 1]; - - for (var i = 0; i < directives.length; i++) { - S.directives[directives[i]]--; - } - - S.directive_stack.pop(); - }; - - next_token.has_directive = function(directive) { - return S.directives[directive] > 0; - }; - - return next_token; - - } - - /* -----[ Parser (constants) ]----- */ - - var UNARY_PREFIX = makePredicate([ - "typeof", - "void", - "delete", - "--", - "++", - "!", - "~", - "-", - "+" - ]); - - var UNARY_POSTFIX = makePredicate([ "--", "++" ]); - - var ASSIGNMENT = makePredicate([ "=", "+=", "-=", "/=", "*=", "**=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&=" ]); - - var PRECEDENCE = (function(a, ret) { - for (var i = 0; i < a.length; ++i) { - var b = a[i]; - for (var j = 0; j < b.length; ++j) { - ret[b[j]] = i + 1; - } - } - return ret; - })( - [ - ["||"], - ["&&"], - ["|"], - ["^"], - ["&"], - ["==", "===", "!=", "!=="], - ["<", ">", "<=", ">=", "in", "instanceof"], - [">>", "<<", ">>>"], - ["+", "-"], - ["*", "/", "%"], - ["**"] - ], - {} - ); - - var ATOMIC_START_TOKEN = makePredicate([ "atom", "num", "big_int", "string", "regexp", "name" ]); - - /* -----[ Parser ]----- */ - - function parse($TEXT, options) { - - options = defaults(options, { - bare_returns : false, - ecma : 8, - expression : false, - filename : null, - html5_comments : true, - module : false, - shebang : true, - strict : false, - toplevel : null, - }, true); - - var S = { - input : (typeof $TEXT == "string" - ? tokenizer($TEXT, options.filename, - options.html5_comments, options.shebang) - : $TEXT), - token : null, - prev : null, - peeked : null, - in_function : 0, - in_async : -1, - in_generator : -1, - in_directives : true, - in_loop : 0, - labels : [] - }; - - S.token = next(); - - function is(type, value) { - return is_token(S.token, type, value); - } - - function peek() { return S.peeked || (S.peeked = S.input()); } - - function next() { - S.prev = S.token; - - if (!S.peeked) peek(); - S.token = S.peeked; - S.peeked = null; - S.in_directives = S.in_directives && ( - S.token.type == "string" || is("punc", ";") - ); - return S.token; - } - - function prev() { - return S.prev; - } - - function croak(msg, line, col, pos) { - var ctx = S.input.context(); - js_error(msg, - ctx.filename, - line != null ? line : ctx.tokline, - col != null ? col : ctx.tokcol, - pos != null ? pos : ctx.tokpos); - } - - function token_error(token, msg) { - croak(msg, token.line, token.col); - } - - function unexpected(token) { - if (token == null) - token = S.token; - token_error(token, "Unexpected token: " + token.type + " (" + token.value + ")"); - } - - function expect_token(type, val) { - if (is(type, val)) { - return next(); - } - token_error(S.token, "Unexpected token " + S.token.type + " «" + S.token.value + "»" + ", expected " + type + " «" + val + "»"); - } - - function expect(punc) { return expect_token("punc", punc); } - - function has_newline_before(token) { - return token.nlb || !token.comments_before.every((comment) => !comment.nlb); - } - - function can_insert_semicolon() { - return !options.strict - && (is("eof") || is("punc", "}") || has_newline_before(S.token)); - } - - function is_in_generator() { - return S.in_generator === S.in_function; - } - - function is_in_async() { - return S.in_async === S.in_function; - } - - function semicolon(optional) { - if (is("punc", ";")) next(); - else if (!optional && !can_insert_semicolon()) unexpected(); - } - - function parenthesised() { - expect("("); - var exp = expression(true); - expect(")"); - return exp; - } - - function embed_tokens(parser) { - return function() { - var start = S.token; - var expr = parser.apply(null, arguments); - var end = prev(); - expr.start = start; - expr.end = end; - return expr; - }; - } - - function handle_regexp() { - if (is("operator", "/") || is("operator", "/=")) { - S.peeked = null; - S.token = S.input(S.token.value.substr(1)); // force regexp - } - } - - var statement = embed_tokens(function(is_export_default, is_for_body, is_if_body) { - handle_regexp(); - switch (S.token.type) { - case "string": - if (S.in_directives) { - var token = peek(); - if (!S.token.raw.includes("\\") - && (is_token(token, "punc", ";") - || is_token(token, "punc", "}") - || has_newline_before(token) - || is_token(token, "eof"))) { - S.input.add_directive(S.token.value); - } else { - S.in_directives = false; - } - } - var dir = S.in_directives, stat = simple_statement(); - return dir && stat.body instanceof AST_String ? new AST_Directive(stat.body) : stat; - case "template_head": - case "num": - case "big_int": - case "regexp": - case "operator": - case "atom": - return simple_statement(); - - case "name": - if (S.token.value == "async" && is_token(peek(), "keyword", "function")) { - next(); - next(); - if (is_for_body) { - croak("functions are not allowed as the body of a loop"); - } - return function_(AST_Defun, false, true, is_export_default); - } - if (S.token.value == "import" && !is_token(peek(), "punc", "(")) { - next(); - var node = import_(); - semicolon(); - return node; - } - return is_token(peek(), "punc", ":") - ? labeled_statement() - : simple_statement(); - - case "punc": - switch (S.token.value) { - case "{": - return new AST_BlockStatement({ - start : S.token, - body : block_(), - end : prev() - }); - case "[": - case "(": - return simple_statement(); - case ";": - S.in_directives = false; - next(); - return new AST_EmptyStatement(); - default: - unexpected(); - } - case "keyword": - switch (S.token.value) { - case "break": - next(); - return break_cont(AST_Break); - - case "continue": - next(); - return break_cont(AST_Continue); - - case "debugger": - next(); - semicolon(); - return new AST_Debugger(); - - case "do": - next(); - var body = in_loop(statement); - expect_token("keyword", "while"); - var condition = parenthesised(); - semicolon(true); - return new AST_Do({ - body : body, - condition : condition - }); - - case "while": - next(); - return new AST_While({ - condition : parenthesised(), - body : in_loop(function() { return statement(false, true); }) - }); - - case "for": - next(); - return for_(); - - case "class": - next(); - if (is_for_body) { - croak("classes are not allowed as the body of a loop"); - } - if (is_if_body) { - croak("classes are not allowed as the body of an if"); - } - return class_(AST_DefClass); - - case "function": - next(); - if (is_for_body) { - croak("functions are not allowed as the body of a loop"); - } - return function_(AST_Defun, false, false, is_export_default); - - case "if": - next(); - return if_(); - - case "return": - if (S.in_function == 0 && !options.bare_returns) - croak("'return' outside of function"); - next(); - var value = null; - if (is("punc", ";")) { - next(); - } else if (!can_insert_semicolon()) { - value = expression(true); - semicolon(); - } - return new AST_Return({ - value: value - }); - - case "switch": - next(); - return new AST_Switch({ - expression : parenthesised(), - body : in_loop(switch_body_) - }); - - case "throw": - next(); - if (has_newline_before(S.token)) - croak("Illegal newline after 'throw'"); - var value = expression(true); - semicolon(); - return new AST_Throw({ - value: value - }); - - case "try": - next(); - return try_(); - - case "var": - next(); - var node = var_(); - semicolon(); - return node; - - case "let": - next(); - var node = let_(); - semicolon(); - return node; - - case "const": - next(); - var node = const_(); - semicolon(); - return node; - - case "with": - if (S.input.has_directive("use strict")) { - croak("Strict mode may not include a with statement"); - } - next(); - return new AST_With({ - expression : parenthesised(), - body : statement() - }); - - case "export": - if (!is_token(peek(), "punc", "(")) { - next(); - var node = export_(); - if (is("punc", ";")) semicolon(); - return node; - } - } - } - unexpected(); - }); - - function labeled_statement() { - var label = as_symbol(AST_Label); - if (label.name === "await" && is_in_async()) { - token_error(S.prev, "await cannot be used as label inside async function"); - } - if (S.labels.some((l) => l.name === label.name)) { - // ECMA-262, 12.12: An ECMAScript program is considered - // syntactically incorrect if it contains a - // LabelledStatement that is enclosed by a - // LabelledStatement with the same Identifier as label. - croak("Label " + label.name + " defined twice"); - } - expect(":"); - S.labels.push(label); - var stat = statement(); - S.labels.pop(); - if (!(stat instanceof AST_IterationStatement)) { - // check for `continue` that refers to this label. - // those should be reported as syntax errors. - // https://github.com/mishoo/UglifyJS2/issues/287 - label.references.forEach(function(ref) { - if (ref instanceof AST_Continue) { - ref = ref.label.start; - croak("Continue label `" + label.name + "` refers to non-IterationStatement.", - ref.line, ref.col, ref.pos); - } - }); - } - return new AST_LabeledStatement({ body: stat, label: label }); - } - - function simple_statement(tmp) { - return new AST_SimpleStatement({ body: (tmp = expression(true), semicolon(), tmp) }); - } - - function break_cont(type) { - var label = null, ldef; - if (!can_insert_semicolon()) { - label = as_symbol(AST_LabelRef, true); - } - if (label != null) { - ldef = S.labels.find((l) => l.name === label.name); - if (!ldef) - croak("Undefined label " + label.name); - label.thedef = ldef; - } else if (S.in_loop == 0) - croak(type.TYPE + " not inside a loop or switch"); - semicolon(); - var stat = new type({ label: label }); - if (ldef) ldef.references.push(stat); - return stat; - } - - function for_() { - var for_await_error = "`for await` invalid in this context"; - var await_tok = S.token; - if (await_tok.type == "name" && await_tok.value == "await") { - if (!is_in_async()) { - token_error(await_tok, for_await_error); - } - next(); - } else { - await_tok = false; - } - expect("("); - var init = null; - if (!is("punc", ";")) { - init = - is("keyword", "var") ? (next(), var_(true)) : - is("keyword", "let") ? (next(), let_(true)) : - is("keyword", "const") ? (next(), const_(true)) : - expression(true, true); - var is_in = is("operator", "in"); - var is_of = is("name", "of"); - if (await_tok && !is_of) { - token_error(await_tok, for_await_error); - } - if (is_in || is_of) { - if (init instanceof AST_Definitions) { - if (init.definitions.length > 1) - token_error(init.start, "Only one variable declaration allowed in for..in loop"); - } else if (!(is_assignable(init) || (init = to_destructuring(init)) instanceof AST_Destructuring)) { - token_error(init.start, "Invalid left-hand side in for..in loop"); - } - next(); - if (is_in) { - return for_in(init); - } else { - return for_of(init, !!await_tok); - } - } - } else if (await_tok) { - token_error(await_tok, for_await_error); - } - return regular_for(init); - } - - function regular_for(init) { - expect(";"); - var test = is("punc", ";") ? null : expression(true); - expect(";"); - var step = is("punc", ")") ? null : expression(true); - expect(")"); - return new AST_For({ - init : init, - condition : test, - step : step, - body : in_loop(function() { return statement(false, true); }) - }); - } - - function for_of(init, is_await) { - var lhs = init instanceof AST_Definitions ? init.definitions[0].name : null; - var obj = expression(true); - expect(")"); - return new AST_ForOf({ - await : is_await, - init : init, - name : lhs, - object : obj, - body : in_loop(function() { return statement(false, true); }) - }); - } - - function for_in(init) { - var obj = expression(true); - expect(")"); - return new AST_ForIn({ - init : init, - object : obj, - body : in_loop(function() { return statement(false, true); }) - }); - } + names.push(to_destructuring(node.elements[i])); + } - var arrow_function = function(start, argnames, is_async) { - if (has_newline_before(S.token)) { - croak("Unexpected newline before arrow (=>)"); - } + node = new AST_Destructuring({ + start: node.start, + names: names, + is_array: true, + end: node.end + }); + } else if (node instanceof AST_ObjectProperty) { + node.value = to_destructuring(node.value); + } else if (node instanceof AST_Assign) { + node = new AST_DefaultAssign({ + start: node.start, + left: node.left, + operator: "=", + right: node.right, + end: node.end + }); + } + return node; + } + + // In ES6, AssignmentExpression can also be an ArrowFunction + var maybe_assign = function(no_in) { + handle_regexp(); + var start = S.token; + + if (start.type == "name" && start.value == "yield") { + if (is_in_generator()) { + next(); + return _yield_expression(); + } else if (S.input.has_directive("use strict")) { + token_error(S.token, "Unexpected yield identifier inside strict mode"); + } + } + + var left = maybe_conditional(no_in); + var val = S.token.value; + + if (is("operator") && ASSIGNMENT.has(val)) { + if (is_assignable(left) || (left = to_destructuring(left)) instanceof AST_Destructuring) { + next(); + + return new AST_Assign({ + start : start, + left : left, + operator : val, + right : maybe_assign(no_in), + logical : LOGICAL_ASSIGNMENT.has(val), + end : prev() + }); + } + croak("Invalid assignment"); + } + return left; + }; + + var expression = function(commas, no_in) { + var start = S.token; + var exprs = []; + while (true) { + exprs.push(maybe_assign(no_in)); + if (!commas || !is("punc", ",")) break; + next(); + commas = true; + } + return exprs.length == 1 ? exprs[0] : new AST_Sequence({ + start : start, + expressions : exprs, + end : peek() + }); + }; + + function in_loop(cont) { + ++S.in_loop; + var ret = cont(); + --S.in_loop; + return ret; + } + + if (options.expression) { + return expression(true); + } + + return (function parse_toplevel() { + var start = S.token; + var body = []; + S.input.push_directives_stack(); + if (options.module) S.input.add_directive("use strict"); + while (!is("eof")) { + body.push(statement()); + } + S.input.pop_directives_stack(); + var end = prev(); + var toplevel = options.toplevel; + if (toplevel) { + toplevel.body = toplevel.body.concat(body); + toplevel.end = end; + } else { + toplevel = new AST_Toplevel({ start: start, body: body, end: end }); + } + TEMPLATE_RAWS = new Map(); + return toplevel; + })(); + +} + +/*********************************************************************** + + A JavaScript tokenizer / parser / beautifier / compressor. + https://github.com/mishoo/UglifyJS2 + + -------------------------------- (C) --------------------------------- + + Author: Mihai Bazon + + http://mihai.bazon.net/blog + + Distributed under the BSD license: + + Copyright 2012 (c) Mihai Bazon + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + ***********************************************************************/ + +function DEFNODE(type, props, ctor, methods, base = AST_Node) { + if (!props) props = []; + else props = props.split(/\s+/); + var self_props = props; + if (base && base.PROPS) + props = props.concat(base.PROPS); + const proto = base && Object.create(base.prototype); + if (proto) { + ctor.prototype = proto; + ctor.BASE = base; + } + if (base) base.SUBCLASSES.push(ctor); + ctor.prototype.CTOR = ctor; + ctor.prototype.constructor = ctor; + ctor.PROPS = props || null; + ctor.SELF_PROPS = self_props; + ctor.SUBCLASSES = []; + if (type) { + ctor.prototype.TYPE = ctor.TYPE = type; + } + if (methods) for (let i in methods) if (HOP(methods, i)) { + if (i[0] === "$") { + ctor[i.substr(1)] = methods[i]; + } else { + ctor.prototype[i] = methods[i]; + } + } + ctor.DEFMETHOD = function(name, method) { + this.prototype[name] = method; + }; + return ctor; +} + +const has_tok_flag = (tok, flag) => Boolean(tok.flags & flag); +const set_tok_flag = (tok, flag, truth) => { + if (truth) { + tok.flags |= flag; + } else { + tok.flags &= ~flag; + } +}; + +const TOK_FLAG_NLB = 0b0001; +const TOK_FLAG_QUOTE_SINGLE = 0b0010; +const TOK_FLAG_QUOTE_EXISTS = 0b0100; +const TOK_FLAG_TEMPLATE_END = 0b1000; + +class AST_Token { + constructor(type, value, line, col, pos, nlb, comments_before, comments_after, file) { + this.flags = (nlb ? 1 : 0); + + this.type = type; + this.value = value; + this.line = line; + this.col = col; + this.pos = pos; + this.comments_before = comments_before; + this.comments_after = comments_after; + this.file = file; + + Object.seal(this); + } + + // Return a string summary of the token for node.js console.log + [Symbol.for("nodejs.util.inspect.custom")](_depth, options) { + const special = str => options.stylize(str, "special"); + const quote = typeof this.value === "string" && this.value.includes("`") ? "'" : "`"; + const value = `${quote}${this.value}${quote}`; + return `${special("[AST_Token")} ${value} at ${this.line}:${this.col}${special("]")}`; + } + + get nlb() { + return has_tok_flag(this, TOK_FLAG_NLB); + } + + set nlb(new_nlb) { + set_tok_flag(this, TOK_FLAG_NLB, new_nlb); + } + + get quote() { + return !has_tok_flag(this, TOK_FLAG_QUOTE_EXISTS) + ? "" + : (has_tok_flag(this, TOK_FLAG_QUOTE_SINGLE) ? "'" : '"'); + } + + set quote(quote_type) { + set_tok_flag(this, TOK_FLAG_QUOTE_SINGLE, quote_type === "'"); + set_tok_flag(this, TOK_FLAG_QUOTE_EXISTS, !!quote_type); + } + + get template_end() { + return has_tok_flag(this, TOK_FLAG_TEMPLATE_END); + } + + set template_end(new_template_end) { + set_tok_flag(this, TOK_FLAG_TEMPLATE_END, new_template_end); + } +} + +var AST_Node = DEFNODE("Node", "start end", function AST_Node(props) { + if (props) { + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + _clone: function(deep) { + if (deep) { + var self = this.clone(); + return self.transform(new TreeTransformer(function(node) { + if (node !== self) { + return node.clone(true); + } + })); + } + return new this.CTOR(this); + }, + clone: function(deep) { + return this._clone(deep); + }, + $documentation: "Base class of all AST nodes", + $propdoc: { + start: "[AST_Token] The first token of this node", + end: "[AST_Token] The last token of this node" + }, + _walk: function(visitor) { + return visitor._visit(this); + }, + walk: function(visitor) { + return this._walk(visitor); // not sure the indirection will be any help + }, + _children_backwards: () => {} +}, null); + +/* -----[ statements ]----- */ + +var AST_Statement = DEFNODE("Statement", null, function AST_Statement(props) { + if (props) { + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "Base class of all statements", +}); + +var AST_Debugger = DEFNODE("Debugger", null, function AST_Debugger(props) { + if (props) { + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "Represents a debugger statement", +}, AST_Statement); + +var AST_Directive = DEFNODE("Directive", "value quote", function AST_Directive(props) { + if (props) { + this.value = props.value; + this.quote = props.quote; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "Represents a directive, like \"use strict\";", + $propdoc: { + value: "[string] The value of this directive as a plain string (it's not an AST_String!)", + quote: "[string] the original quote character" + }, +}, AST_Statement); + +var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", function AST_SimpleStatement(props) { + if (props) { + this.body = props.body; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A statement consisting of an expression, i.e. a = 1 + 2", + $propdoc: { + body: "[AST_Node] an expression node (should not be instanceof AST_Statement)" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + this.body._walk(visitor); + }); + }, + _children_backwards(push) { + push(this.body); + } +}, AST_Statement); + +// XXX Emscripten localmod: Add a node type for a parenthesized expression so that we can retain +// Closure annotations that need a form "/**annotation*/(expression)" +var AST_ParenthesizedExpression = DEFNODE("ParenthesizedExpression", "body", function AST_ParenthesizedExpression(props) { + if (props) { + this.body = props.body; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "An explicitly parenthesized expression, i.e. a = (1 + 2)", + $propdoc: { + body: "[AST_Node] an expression node (should not be instanceof AST_Statement)" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + this.body._walk(visitor); + }); + } +}, AST_Statement); +// XXX End of Emscripten localmod + +function walk_body(node, visitor) { + const body = node.body; + for (var i = 0, len = body.length; i < len; i++) { + body[i]._walk(visitor); + } +} + +function clone_block_scope(deep) { + var clone = this._clone(deep); + if (this.block_scope) { + clone.block_scope = this.block_scope.clone(); + } + return clone; +} + +var AST_Block = DEFNODE("Block", "body block_scope", function AST_Block(props) { + if (props) { + this.body = props.body; + this.block_scope = props.block_scope; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A body of statements (usually braced)", + $propdoc: { + body: "[AST_Statement*] an array of statements", + block_scope: "[AST_Scope] the block scope" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + walk_body(this, visitor); + }); + }, + _children_backwards(push) { + let i = this.body.length; + while (i--) push(this.body[i]); + }, + clone: clone_block_scope +}, AST_Statement); + +var AST_BlockStatement = DEFNODE("BlockStatement", null, function AST_BlockStatement(props) { + if (props) { + this.body = props.body; + this.block_scope = props.block_scope; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A block statement", +}, AST_Block); + +var AST_EmptyStatement = DEFNODE("EmptyStatement", null, function AST_EmptyStatement(props) { + if (props) { + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "The empty statement (empty block or simply a semicolon)" +}, AST_Statement); + +var AST_StatementWithBody = DEFNODE("StatementWithBody", "body", function AST_StatementWithBody(props) { + if (props) { + this.body = props.body; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "Base class for all statements that contain one nested body: `For`, `ForIn`, `Do`, `While`, `With`", + $propdoc: { + body: "[AST_Statement] the body; this should always be present, even if it's an AST_EmptyStatement" + } +}, AST_Statement); + +var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", function AST_LabeledStatement(props) { + if (props) { + this.label = props.label; + this.body = props.body; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "Statement with a label", + $propdoc: { + label: "[AST_Label] a label definition" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + this.label._walk(visitor); + this.body._walk(visitor); + }); + }, + _children_backwards(push) { + push(this.body); + push(this.label); + }, + clone: function(deep) { + var node = this._clone(deep); + if (deep) { + var label = node.label; + var def = this.label; + node.walk(new TreeWalker(function(node) { + if (node instanceof AST_LoopControl + && node.label && node.label.thedef === def) { + node.label.thedef = label; + label.references.push(node); + } + })); + } + return node; + } +}, AST_StatementWithBody); + +var AST_IterationStatement = DEFNODE( + "IterationStatement", + "block_scope", + function AST_IterationStatement(props) { + if (props) { + this.block_scope = props.block_scope; + this.body = props.body; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; + }, + { + $documentation: "Internal class. All loops inherit from it.", + $propdoc: { + block_scope: "[AST_Scope] the block scope for this iteration statement." + }, + clone: clone_block_scope + }, + AST_StatementWithBody +); + +var AST_DWLoop = DEFNODE("DWLoop", "condition", function AST_DWLoop(props) { + if (props) { + this.condition = props.condition; + this.block_scope = props.block_scope; + this.body = props.body; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "Base class for do/while statements", + $propdoc: { + condition: "[AST_Node] the loop condition. Should not be instanceof AST_Statement" + } +}, AST_IterationStatement); + +var AST_Do = DEFNODE("Do", null, function AST_Do(props) { + if (props) { + this.condition = props.condition; + this.block_scope = props.block_scope; + this.body = props.body; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A `do` statement", + _walk: function(visitor) { + return visitor._visit(this, function() { + this.body._walk(visitor); + this.condition._walk(visitor); + }); + }, + _children_backwards(push) { + push(this.condition); + push(this.body); + } +}, AST_DWLoop); + +var AST_While = DEFNODE("While", null, function AST_While(props) { + if (props) { + this.condition = props.condition; + this.block_scope = props.block_scope; + this.body = props.body; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A `while` statement", + _walk: function(visitor) { + return visitor._visit(this, function() { + this.condition._walk(visitor); + this.body._walk(visitor); + }); + }, + _children_backwards(push) { + push(this.body); + push(this.condition); + }, +}, AST_DWLoop); + +var AST_For = DEFNODE("For", "init condition step", function AST_For(props) { + if (props) { + this.init = props.init; + this.condition = props.condition; + this.step = props.step; + this.block_scope = props.block_scope; + this.body = props.body; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A `for` statement", + $propdoc: { + init: "[AST_Node?] the `for` initialization code, or null if empty", + condition: "[AST_Node?] the `for` termination clause, or null if empty", + step: "[AST_Node?] the `for` update clause, or null if empty" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + if (this.init) this.init._walk(visitor); + if (this.condition) this.condition._walk(visitor); + if (this.step) this.step._walk(visitor); + this.body._walk(visitor); + }); + }, + _children_backwards(push) { + push(this.body); + if (this.step) push(this.step); + if (this.condition) push(this.condition); + if (this.init) push(this.init); + }, +}, AST_IterationStatement); + +var AST_ForIn = DEFNODE("ForIn", "init object", function AST_ForIn(props) { + if (props) { + this.init = props.init; + this.object = props.object; + this.block_scope = props.block_scope; + this.body = props.body; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A `for ... in` statement", + $propdoc: { + init: "[AST_Node] the `for/in` initialization code", + object: "[AST_Node] the object that we're looping through" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + this.init._walk(visitor); + this.object._walk(visitor); + this.body._walk(visitor); + }); + }, + _children_backwards(push) { + push(this.body); + if (this.object) push(this.object); + if (this.init) push(this.init); + }, +}, AST_IterationStatement); + +var AST_ForOf = DEFNODE("ForOf", "await", function AST_ForOf(props) { + if (props) { + this.await = props.await; + this.init = props.init; + this.object = props.object; + this.block_scope = props.block_scope; + this.body = props.body; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A `for ... of` statement", +}, AST_ForIn); + +var AST_With = DEFNODE("With", "expression", function AST_With(props) { + if (props) { + this.expression = props.expression; + this.body = props.body; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A `with` statement", + $propdoc: { + expression: "[AST_Node] the `with` expression" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + this.expression._walk(visitor); + this.body._walk(visitor); + }); + }, + _children_backwards(push) { + push(this.body); + push(this.expression); + }, +}, AST_StatementWithBody); + +/* -----[ scope and functions ]----- */ + +var AST_Scope = DEFNODE( + "Scope", + "variables uses_with uses_eval parent_scope enclosed cname", + function AST_Scope(props) { + if (props) { + this.variables = props.variables; + this.uses_with = props.uses_with; + this.uses_eval = props.uses_eval; + this.parent_scope = props.parent_scope; + this.enclosed = props.enclosed; + this.cname = props.cname; + this.body = props.body; + this.block_scope = props.block_scope; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; + }, + { + $documentation: "Base class for all statements introducing a lexical scope", + $propdoc: { + variables: "[Map/S] a map of name -> SymbolDef for all variables/functions defined in this scope", + uses_with: "[boolean/S] tells whether this scope uses the `with` statement", + uses_eval: "[boolean/S] tells whether this scope contains a direct call to the global `eval`", + parent_scope: "[AST_Scope?/S] link to the parent scope", + enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes", + cname: "[integer/S] current index for mangling variables (used internally by the mangler)", + }, + get_defun_scope: function() { + var self = this; + while (self.is_block_scope()) { + self = self.parent_scope; + } + return self; + }, + clone: function(deep, toplevel) { + var node = this._clone(deep); + if (deep && this.variables && toplevel && !this._block_scope) { + node.figure_out_scope({}, { + toplevel: toplevel, + parent_scope: this.parent_scope + }); + } else { + if (this.variables) node.variables = new Map(this.variables); + if (this.enclosed) node.enclosed = this.enclosed.slice(); + if (this._block_scope) node._block_scope = this._block_scope; + } + return node; + }, + pinned: function() { + return this.uses_eval || this.uses_with; + } + }, + AST_Block +); + +var AST_Toplevel = DEFNODE("Toplevel", "globals", function AST_Toplevel(props) { + if (props) { + this.globals = props.globals; + this.variables = props.variables; + this.uses_with = props.uses_with; + this.uses_eval = props.uses_eval; + this.parent_scope = props.parent_scope; + this.enclosed = props.enclosed; + this.cname = props.cname; + this.body = props.body; + this.block_scope = props.block_scope; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "The toplevel scope", + $propdoc: { + globals: "[Map/S] a map of name -> SymbolDef for all undeclared names", + }, + wrap_commonjs: function(name) { + var body = this.body; + var wrapped_tl = "(function(exports){'$ORIG';})(typeof " + name + "=='undefined'?(" + name + "={}):" + name + ");"; + wrapped_tl = parse(wrapped_tl); + wrapped_tl = wrapped_tl.transform(new TreeTransformer(function(node) { + if (node instanceof AST_Directive && node.value == "$ORIG") { + return MAP.splice(body); + } + })); + return wrapped_tl; + }, + wrap_enclose: function(args_values) { + if (typeof args_values != "string") args_values = ""; + var index = args_values.indexOf(":"); + if (index < 0) index = args_values.length; + var body = this.body; + return parse([ + "(function(", + args_values.slice(0, index), + '){"$ORIG"})(', + args_values.slice(index + 1), + ")" + ].join("")).transform(new TreeTransformer(function(node) { + if (node instanceof AST_Directive && node.value == "$ORIG") { + return MAP.splice(body); + } + })); + } +}, AST_Scope); + +var AST_Expansion = DEFNODE("Expansion", "expression", function AST_Expansion(props) { + if (props) { + this.expression = props.expression; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "An expandible argument, such as ...rest, a splat, such as [1,2,...all], or an expansion in a variable declaration, such as var [first, ...rest] = list", + $propdoc: { + expression: "[AST_Node] the thing to be expanded" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + this.expression.walk(visitor); + }); + }, + _children_backwards(push) { + push(this.expression); + }, +}); + +var AST_Lambda = DEFNODE( + "Lambda", + "name argnames uses_arguments is_generator async", + function AST_Lambda(props) { + if (props) { + this.name = props.name; + this.argnames = props.argnames; + this.uses_arguments = props.uses_arguments; + this.is_generator = props.is_generator; + this.async = props.async; + this.variables = props.variables; + this.uses_with = props.uses_with; + this.uses_eval = props.uses_eval; + this.parent_scope = props.parent_scope; + this.enclosed = props.enclosed; + this.cname = props.cname; + this.body = props.body; + this.block_scope = props.block_scope; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; + }, + { + $documentation: "Base class for functions", + $propdoc: { + name: "[AST_SymbolDeclaration?] the name of this function", + argnames: "[AST_SymbolFunarg|AST_Destructuring|AST_Expansion|AST_DefaultAssign*] array of function arguments, destructurings, or expanding arguments", + uses_arguments: "[boolean/S] tells whether this function accesses the arguments array", + is_generator: "[boolean] is this a generator method", + async: "[boolean] is this method async", + }, + args_as_names: function () { + var out = []; + for (var i = 0; i < this.argnames.length; i++) { + if (this.argnames[i] instanceof AST_Destructuring) { + out.push(...this.argnames[i].all_symbols()); + } else { + out.push(this.argnames[i]); + } + } + return out; + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + if (this.name) this.name._walk(visitor); + var argnames = this.argnames; + for (var i = 0, len = argnames.length; i < len; i++) { + argnames[i]._walk(visitor); + } + walk_body(this, visitor); + }); + }, + _children_backwards(push) { + let i = this.body.length; + while (i--) push(this.body[i]); + + i = this.argnames.length; + while (i--) push(this.argnames[i]); + + if (this.name) push(this.name); + }, + is_braceless() { + return this.body[0] instanceof AST_Return && this.body[0].value; + }, + // Default args and expansion don't count, so .argnames.length doesn't cut it + length_property() { + let length = 0; + + for (const arg of this.argnames) { + if (arg instanceof AST_SymbolFunarg || arg instanceof AST_Destructuring) { + length++; + } + } + + return length; + } + }, + AST_Scope +); + +var AST_Accessor = DEFNODE("Accessor", null, function AST_Accessor(props) { + if (props) { + this.name = props.name; + this.argnames = props.argnames; + this.uses_arguments = props.uses_arguments; + this.is_generator = props.is_generator; + this.async = props.async; + this.variables = props.variables; + this.uses_with = props.uses_with; + this.uses_eval = props.uses_eval; + this.parent_scope = props.parent_scope; + this.enclosed = props.enclosed; + this.cname = props.cname; + this.body = props.body; + this.block_scope = props.block_scope; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A setter/getter function. The `name` property is always null." +}, AST_Lambda); + +var AST_Function = DEFNODE("Function", null, function AST_Function(props) { + if (props) { + this.name = props.name; + this.argnames = props.argnames; + this.uses_arguments = props.uses_arguments; + this.is_generator = props.is_generator; + this.async = props.async; + this.variables = props.variables; + this.uses_with = props.uses_with; + this.uses_eval = props.uses_eval; + this.parent_scope = props.parent_scope; + this.enclosed = props.enclosed; + this.cname = props.cname; + this.body = props.body; + this.block_scope = props.block_scope; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A function expression" +}, AST_Lambda); + +var AST_Arrow = DEFNODE("Arrow", null, function AST_Arrow(props) { + if (props) { + this.name = props.name; + this.argnames = props.argnames; + this.uses_arguments = props.uses_arguments; + this.is_generator = props.is_generator; + this.async = props.async; + this.variables = props.variables; + this.uses_with = props.uses_with; + this.uses_eval = props.uses_eval; + this.parent_scope = props.parent_scope; + this.enclosed = props.enclosed; + this.cname = props.cname; + this.body = props.body; + this.block_scope = props.block_scope; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "An ES6 Arrow function ((a) => b)" +}, AST_Lambda); + +var AST_Defun = DEFNODE("Defun", null, function AST_Defun(props) { + if (props) { + this.name = props.name; + this.argnames = props.argnames; + this.uses_arguments = props.uses_arguments; + this.is_generator = props.is_generator; + this.async = props.async; + this.variables = props.variables; + this.uses_with = props.uses_with; + this.uses_eval = props.uses_eval; + this.parent_scope = props.parent_scope; + this.enclosed = props.enclosed; + this.cname = props.cname; + this.body = props.body; + this.block_scope = props.block_scope; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A function definition" +}, AST_Lambda); + +/* -----[ DESTRUCTURING ]----- */ +var AST_Destructuring = DEFNODE("Destructuring", "names is_array", function AST_Destructuring(props) { + if (props) { + this.names = props.names; + this.is_array = props.is_array; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A destructuring of several names. Used in destructuring assignment and with destructuring function argument names", + $propdoc: { + "names": "[AST_Node*] Array of properties or elements", + "is_array": "[Boolean] Whether the destructuring represents an object or array" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + this.names.forEach(function(name) { + name._walk(visitor); + }); + }); + }, + _children_backwards(push) { + let i = this.names.length; + while (i--) push(this.names[i]); + }, + all_symbols: function() { + var out = []; + walk(this, node => { + if (node instanceof AST_SymbolDeclaration) { + out.push(node); + } + if (node instanceof AST_Lambda) { + return true; + } + }); + return out; + } +}); + +var AST_PrefixedTemplateString = DEFNODE( + "PrefixedTemplateString", + "template_string prefix", + function AST_PrefixedTemplateString(props) { + if (props) { + this.template_string = props.template_string; + this.prefix = props.prefix; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; + }, + { + $documentation: "A templatestring with a prefix, such as String.raw`foobarbaz`", + $propdoc: { + template_string: "[AST_TemplateString] The template string", + prefix: "[AST_Node] The prefix, which will get called." + }, + _walk: function(visitor) { + return visitor._visit(this, function () { + this.prefix._walk(visitor); + this.template_string._walk(visitor); + }); + }, + _children_backwards(push) { + push(this.template_string); + push(this.prefix); + }, + } +); + +var AST_TemplateString = DEFNODE("TemplateString", "segments", function AST_TemplateString(props) { + if (props) { + this.segments = props.segments; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A template string literal", + $propdoc: { + segments: "[AST_Node*] One or more segments, starting with AST_TemplateSegment. AST_Node may follow AST_TemplateSegment, but each AST_Node must be followed by AST_TemplateSegment." + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + this.segments.forEach(function(seg) { + seg._walk(visitor); + }); + }); + }, + _children_backwards(push) { + let i = this.segments.length; + while (i--) push(this.segments[i]); + } +}); + +var AST_TemplateSegment = DEFNODE("TemplateSegment", "value raw", function AST_TemplateSegment(props) { + if (props) { + this.value = props.value; + this.raw = props.raw; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A segment of a template string literal", + $propdoc: { + value: "Content of the segment", + raw: "Raw source of the segment", + } +}); + +/* -----[ JUMPS ]----- */ + +var AST_Jump = DEFNODE("Jump", null, function AST_Jump(props) { + if (props) { + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "Base class for “jumps” (for now that's `return`, `throw`, `break` and `continue`)" +}, AST_Statement); + +/** Base class for “exits” (`return` and `throw`) */ +var AST_Exit = DEFNODE("Exit", "value", function AST_Exit(props) { + if (props) { + this.value = props.value; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "Base class for “exits” (`return` and `throw`)", + $propdoc: { + value: "[AST_Node?] the value returned or thrown by this statement; could be null for AST_Return" + }, + _walk: function(visitor) { + return visitor._visit(this, this.value && function() { + this.value._walk(visitor); + }); + }, + _children_backwards(push) { + if (this.value) push(this.value); + }, +}, AST_Jump); + +var AST_Return = DEFNODE("Return", null, function AST_Return(props) { + if (props) { + this.value = props.value; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A `return` statement" +}, AST_Exit); + +var AST_Throw = DEFNODE("Throw", null, function AST_Throw(props) { + if (props) { + this.value = props.value; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A `throw` statement" +}, AST_Exit); + +var AST_LoopControl = DEFNODE("LoopControl", "label", function AST_LoopControl(props) { + if (props) { + this.label = props.label; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "Base class for loop control statements (`break` and `continue`)", + $propdoc: { + label: "[AST_LabelRef?] the label, or null if none", + }, + _walk: function(visitor) { + return visitor._visit(this, this.label && function() { + this.label._walk(visitor); + }); + }, + _children_backwards(push) { + if (this.label) push(this.label); + }, +}, AST_Jump); + +var AST_Break = DEFNODE("Break", null, function AST_Break(props) { + if (props) { + this.label = props.label; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A `break` statement" +}, AST_LoopControl); + +var AST_Continue = DEFNODE("Continue", null, function AST_Continue(props) { + if (props) { + this.label = props.label; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A `continue` statement" +}, AST_LoopControl); + +var AST_Await = DEFNODE("Await", "expression", function AST_Await(props) { + if (props) { + this.expression = props.expression; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "An `await` statement", + $propdoc: { + expression: "[AST_Node] the mandatory expression being awaited", + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + this.expression._walk(visitor); + }); + }, + _children_backwards(push) { + push(this.expression); + }, +}); + +var AST_Yield = DEFNODE("Yield", "expression is_star", function AST_Yield(props) { + if (props) { + this.expression = props.expression; + this.is_star = props.is_star; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A `yield` statement", + $propdoc: { + expression: "[AST_Node?] the value returned or thrown by this statement; could be null (representing undefined) but only when is_star is set to false", + is_star: "[Boolean] Whether this is a yield or yield* statement" + }, + _walk: function(visitor) { + return visitor._visit(this, this.expression && function() { + this.expression._walk(visitor); + }); + }, + _children_backwards(push) { + if (this.expression) push(this.expression); + } +}); + +/* -----[ IF ]----- */ + +var AST_If = DEFNODE("If", "condition alternative", function AST_If(props) { + if (props) { + this.condition = props.condition; + this.alternative = props.alternative; + this.body = props.body; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A `if` statement", + $propdoc: { + condition: "[AST_Node] the `if` condition", + alternative: "[AST_Statement?] the `else` part, or null if not present" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + this.condition._walk(visitor); + this.body._walk(visitor); + if (this.alternative) this.alternative._walk(visitor); + }); + }, + _children_backwards(push) { + if (this.alternative) { + push(this.alternative); + } + push(this.body); + push(this.condition); + } +}, AST_StatementWithBody); + +/* -----[ SWITCH ]----- */ + +var AST_Switch = DEFNODE("Switch", "expression", function AST_Switch(props) { + if (props) { + this.expression = props.expression; + this.body = props.body; + this.block_scope = props.block_scope; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A `switch` statement", + $propdoc: { + expression: "[AST_Node] the `switch` “discriminant”" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + this.expression._walk(visitor); + walk_body(this, visitor); + }); + }, + _children_backwards(push) { + let i = this.body.length; + while (i--) push(this.body[i]); + push(this.expression); + } +}, AST_Block); + +var AST_SwitchBranch = DEFNODE("SwitchBranch", null, function AST_SwitchBranch(props) { + if (props) { + this.body = props.body; + this.block_scope = props.block_scope; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "Base class for `switch` branches", +}, AST_Block); + +var AST_Default = DEFNODE("Default", null, function AST_Default(props) { + if (props) { + this.body = props.body; + this.block_scope = props.block_scope; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A `default` switch branch", +}, AST_SwitchBranch); + +var AST_Case = DEFNODE("Case", "expression", function AST_Case(props) { + if (props) { + this.expression = props.expression; + this.body = props.body; + this.block_scope = props.block_scope; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A `case` switch branch", + $propdoc: { + expression: "[AST_Node] the `case` expression" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + this.expression._walk(visitor); + walk_body(this, visitor); + }); + }, + _children_backwards(push) { + let i = this.body.length; + while (i--) push(this.body[i]); + push(this.expression); + }, +}, AST_SwitchBranch); + +/* -----[ EXCEPTIONS ]----- */ + +var AST_Try = DEFNODE("Try", "body bcatch bfinally", function AST_Try(props) { + if (props) { + this.body = props.body; + this.bcatch = props.bcatch; + this.bfinally = props.bfinally; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A `try` statement", + $propdoc: { + body: "[AST_TryBlock] the try block", + bcatch: "[AST_Catch?] the catch block, or null if not present", + bfinally: "[AST_Finally?] the finally block, or null if not present" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + this.body._walk(visitor); + if (this.bcatch) this.bcatch._walk(visitor); + if (this.bfinally) this.bfinally._walk(visitor); + }); + }, + _children_backwards(push) { + if (this.bfinally) push(this.bfinally); + if (this.bcatch) push(this.bcatch); + push(this.body); + }, +}, AST_Statement); + +var AST_TryBlock = DEFNODE("TryBlock", null, function AST_TryBlock(props) { + if (props) { + this.body = props.body; + this.block_scope = props.block_scope; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "The `try` block of a try statement" +}, AST_Block); + +var AST_Catch = DEFNODE("Catch", "argname", function AST_Catch(props) { + if (props) { + this.argname = props.argname; + this.body = props.body; + this.block_scope = props.block_scope; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A `catch` node; only makes sense as part of a `try` statement", + $propdoc: { + argname: "[AST_SymbolCatch|AST_Destructuring|AST_Expansion|AST_DefaultAssign] symbol for the exception" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + if (this.argname) this.argname._walk(visitor); + walk_body(this, visitor); + }); + }, + _children_backwards(push) { + let i = this.body.length; + while (i--) push(this.body[i]); + if (this.argname) push(this.argname); + }, +}, AST_Block); + +var AST_Finally = DEFNODE("Finally", null, function AST_Finally(props) { + if (props) { + this.body = props.body; + this.block_scope = props.block_scope; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A `finally` node; only makes sense as part of a `try` statement" +}, AST_Block); + +/* -----[ VAR/CONST ]----- */ + +var AST_Definitions = DEFNODE("Definitions", "definitions", function AST_Definitions(props) { + if (props) { + this.definitions = props.definitions; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "Base class for `var` or `const` nodes (variable declarations/initializations)", + $propdoc: { + definitions: "[AST_VarDef*] array of variable definitions" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + var definitions = this.definitions; + for (var i = 0, len = definitions.length; i < len; i++) { + definitions[i]._walk(visitor); + } + }); + }, + _children_backwards(push) { + let i = this.definitions.length; + while (i--) push(this.definitions[i]); + }, +}, AST_Statement); + +var AST_Var = DEFNODE("Var", null, function AST_Var(props) { + if (props) { + this.definitions = props.definitions; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A `var` statement" +}, AST_Definitions); + +var AST_Let = DEFNODE("Let", null, function AST_Let(props) { + if (props) { + this.definitions = props.definitions; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A `let` statement" +}, AST_Definitions); + +var AST_Const = DEFNODE("Const", null, function AST_Const(props) { + if (props) { + this.definitions = props.definitions; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A `const` statement" +}, AST_Definitions); + +var AST_VarDef = DEFNODE("VarDef", "name value", function AST_VarDef(props) { + if (props) { + this.name = props.name; + this.value = props.value; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A variable declaration; only appears in a AST_Definitions node", + $propdoc: { + name: "[AST_Destructuring|AST_SymbolConst|AST_SymbolLet|AST_SymbolVar] name of the variable", + value: "[AST_Node?] initializer, or null of there's no initializer" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + this.name._walk(visitor); + if (this.value) this.value._walk(visitor); + }); + }, + _children_backwards(push) { + if (this.value) push(this.value); + push(this.name); + }, + declarations_as_names() { + if (this.name instanceof AST_SymbolDeclaration) { + return [this]; + } else { + return this.name.all_symbols(); + } + } +}); + +var AST_NameMapping = DEFNODE("NameMapping", "foreign_name name", function AST_NameMapping(props) { + if (props) { + this.foreign_name = props.foreign_name; + this.name = props.name; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "The part of the export/import statement that declare names from a module.", + $propdoc: { + foreign_name: "[AST_SymbolExportForeign|AST_SymbolImportForeign] The name being exported/imported (as specified in the module)", + name: "[AST_SymbolExport|AST_SymbolImport] The name as it is visible to this module." + }, + _walk: function (visitor) { + return visitor._visit(this, function() { + this.foreign_name._walk(visitor); + this.name._walk(visitor); + }); + }, + _children_backwards(push) { + push(this.name); + push(this.foreign_name); + }, +}); + +var AST_Import = DEFNODE( + "Import", + "imported_name imported_names module_name assert_clause", + function AST_Import(props) { + if (props) { + this.imported_name = props.imported_name; + this.imported_names = props.imported_names; + this.module_name = props.module_name; + this.assert_clause = props.assert_clause; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; + }, + { + $documentation: "An `import` statement", + $propdoc: { + imported_name: "[AST_SymbolImport] The name of the variable holding the module's default export.", + imported_names: "[AST_NameMapping*] The names of non-default imported variables", + module_name: "[AST_String] String literal describing where this module came from", + assert_clause: "[AST_Object?] The import assertion" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + if (this.imported_name) { + this.imported_name._walk(visitor); + } + if (this.imported_names) { + this.imported_names.forEach(function(name_import) { + name_import._walk(visitor); + }); + } + this.module_name._walk(visitor); + }); + }, + _children_backwards(push) { + push(this.module_name); + if (this.imported_names) { + let i = this.imported_names.length; + while (i--) push(this.imported_names[i]); + } + if (this.imported_name) push(this.imported_name); + }, + } +); + +var AST_ImportMeta = DEFNODE("ImportMeta", null, function AST_ImportMeta(props) { + if (props) { + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A reference to import.meta", +}); + +var AST_Export = DEFNODE( + "Export", + "exported_definition exported_value is_default exported_names module_name assert_clause", + function AST_Export(props) { + if (props) { + this.exported_definition = props.exported_definition; + this.exported_value = props.exported_value; + this.is_default = props.is_default; + this.exported_names = props.exported_names; + this.module_name = props.module_name; + this.assert_clause = props.assert_clause; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; + }, + { + $documentation: "An `export` statement", + $propdoc: { + exported_definition: "[AST_Defun|AST_Definitions|AST_DefClass?] An exported definition", + exported_value: "[AST_Node?] An exported value", + exported_names: "[AST_NameMapping*?] List of exported names", + module_name: "[AST_String?] Name of the file to load exports from", + is_default: "[Boolean] Whether this is the default exported value of this module", + assert_clause: "[AST_Object?] The import assertion" + }, + _walk: function (visitor) { + return visitor._visit(this, function () { + if (this.exported_definition) { + this.exported_definition._walk(visitor); + } + if (this.exported_value) { + this.exported_value._walk(visitor); + } + if (this.exported_names) { + this.exported_names.forEach(function(name_export) { + name_export._walk(visitor); + }); + } + if (this.module_name) { + this.module_name._walk(visitor); + } + }); + }, + _children_backwards(push) { + if (this.module_name) push(this.module_name); + if (this.exported_names) { + let i = this.exported_names.length; + while (i--) push(this.exported_names[i]); + } + if (this.exported_value) push(this.exported_value); + if (this.exported_definition) push(this.exported_definition); + } + }, + AST_Statement +); + +/* -----[ OTHER ]----- */ + +var AST_Call = DEFNODE( + "Call", + "expression args optional _annotations", + function AST_Call(props) { + if (props) { + this.expression = props.expression; + this.args = props.args; + this.optional = props.optional; + this._annotations = props._annotations; + this.start = props.start; + this.end = props.end; + this.initialize(); + } + + this.flags = 0; + }, + { + $documentation: "A function call expression", + $propdoc: { + expression: "[AST_Node] expression to invoke as function", + args: "[AST_Node*] array of arguments", + optional: "[boolean] whether this is an optional call (IE ?.() )", + _annotations: "[number] bitfield containing information about the call" + }, + initialize() { + if (this._annotations == null) this._annotations = 0; + }, + _walk(visitor) { + return visitor._visit(this, function() { + var args = this.args; + for (var i = 0, len = args.length; i < len; i++) { + args[i]._walk(visitor); + } + this.expression._walk(visitor); // TODO why do we need to crawl this last? + }); + }, + _children_backwards(push) { + let i = this.args.length; + while (i--) push(this.args[i]); + push(this.expression); + }, + } +); + +var AST_New = DEFNODE("New", null, function AST_New(props) { + if (props) { + this.expression = props.expression; + this.args = props.args; + this.optional = props.optional; + this._annotations = props._annotations; + this.start = props.start; + this.end = props.end; + this.initialize(); + } + + this.flags = 0; +}, { + $documentation: "An object instantiation. Derives from a function call since it has exactly the same properties" +}, AST_Call); + +var AST_Sequence = DEFNODE("Sequence", "expressions", function AST_Sequence(props) { + if (props) { + this.expressions = props.expressions; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A sequence expression (comma-separated expressions)", + $propdoc: { + expressions: "[AST_Node*] array of expressions (at least two)" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + this.expressions.forEach(function(node) { + node._walk(visitor); + }); + }); + }, + _children_backwards(push) { + let i = this.expressions.length; + while (i--) push(this.expressions[i]); + }, +}); + +var AST_PropAccess = DEFNODE( + "PropAccess", + "expression property optional", + function AST_PropAccess(props) { + if (props) { + this.expression = props.expression; + this.property = props.property; + this.optional = props.optional; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; + }, + { + $documentation: "Base class for property access expressions, i.e. `a.foo` or `a[\"foo\"]`", + $propdoc: { + expression: "[AST_Node] the “container” expression", + property: "[AST_Node|string] the property to access. For AST_Dot & AST_DotHash this is always a plain string, while for AST_Sub it's an arbitrary AST_Node", + + optional: "[boolean] whether this is an optional property access (IE ?.)" + } + } +); + +var AST_Dot = DEFNODE("Dot", "quote", function AST_Dot(props) { + if (props) { + this.quote = props.quote; + this.expression = props.expression; + this.property = props.property; + this.optional = props.optional; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A dotted property access expression", + $propdoc: { + quote: "[string] the original quote character when transformed from AST_Sub", + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + this.expression._walk(visitor); + }); + }, + _children_backwards(push) { + push(this.expression); + }, +}, AST_PropAccess); + +var AST_DotHash = DEFNODE("DotHash", "", function AST_DotHash(props) { + if (props) { + this.expression = props.expression; + this.property = props.property; + this.optional = props.optional; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A dotted property access to a private property", + _walk: function(visitor) { + return visitor._visit(this, function() { + this.expression._walk(visitor); + }); + }, + _children_backwards(push) { + push(this.expression); + }, +}, AST_PropAccess); + +var AST_Sub = DEFNODE("Sub", null, function AST_Sub(props) { + if (props) { + this.expression = props.expression; + this.property = props.property; + this.optional = props.optional; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "Index-style property access, i.e. `a[\"foo\"]`", + _walk: function(visitor) { + return visitor._visit(this, function() { + this.expression._walk(visitor); + this.property._walk(visitor); + }); + }, + _children_backwards(push) { + push(this.property); + push(this.expression); + }, +}, AST_PropAccess); + +var AST_Chain = DEFNODE("Chain", "expression", function AST_Chain(props) { + if (props) { + this.expression = props.expression; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A chain expression like a?.b?.(c)?.[d]", + $propdoc: { + expression: "[AST_Call|AST_Dot|AST_DotHash|AST_Sub] chain element." + }, + _walk: function (visitor) { + return visitor._visit(this, function() { + this.expression._walk(visitor); + }); + }, + _children_backwards(push) { + push(this.expression); + }, +}); + +var AST_Unary = DEFNODE("Unary", "operator expression", function AST_Unary(props) { + if (props) { + this.operator = props.operator; + this.expression = props.expression; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "Base class for unary expressions", + $propdoc: { + operator: "[string] the operator", + expression: "[AST_Node] expression that this unary operator applies to" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + this.expression._walk(visitor); + }); + }, + _children_backwards(push) { + push(this.expression); + }, +}); + +var AST_UnaryPrefix = DEFNODE("UnaryPrefix", null, function AST_UnaryPrefix(props) { + if (props) { + this.operator = props.operator; + this.expression = props.expression; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "Unary prefix expression, i.e. `typeof i` or `++i`" +}, AST_Unary); + +var AST_UnaryPostfix = DEFNODE("UnaryPostfix", null, function AST_UnaryPostfix(props) { + if (props) { + this.operator = props.operator; + this.expression = props.expression; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "Unary postfix expression, i.e. `i++`" +}, AST_Unary); + +var AST_Binary = DEFNODE("Binary", "operator left right", function AST_Binary(props) { + if (props) { + this.operator = props.operator; + this.left = props.left; + this.right = props.right; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "Binary expression, i.e. `a + b`", + $propdoc: { + left: "[AST_Node] left-hand side expression", + operator: "[string] the operator", + right: "[AST_Node] right-hand side expression" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + this.left._walk(visitor); + this.right._walk(visitor); + }); + }, + _children_backwards(push) { + push(this.right); + push(this.left); + }, +}); + +var AST_Conditional = DEFNODE( + "Conditional", + "condition consequent alternative", + function AST_Conditional(props) { + if (props) { + this.condition = props.condition; + this.consequent = props.consequent; + this.alternative = props.alternative; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; + }, + { + $documentation: "Conditional expression using the ternary operator, i.e. `a ? b : c`", + $propdoc: { + condition: "[AST_Node]", + consequent: "[AST_Node]", + alternative: "[AST_Node]" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + this.condition._walk(visitor); + this.consequent._walk(visitor); + this.alternative._walk(visitor); + }); + }, + _children_backwards(push) { + push(this.alternative); + push(this.consequent); + push(this.condition); + }, + } +); + +var AST_Assign = DEFNODE("Assign", "logical", function AST_Assign(props) { + if (props) { + this.logical = props.logical; + this.operator = props.operator; + this.left = props.left; + this.right = props.right; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "An assignment expression — `a = b + 5`", + $propdoc: { + logical: "Whether it's a logical assignment" + } +}, AST_Binary); + +var AST_DefaultAssign = DEFNODE("DefaultAssign", null, function AST_DefaultAssign(props) { + if (props) { + this.operator = props.operator; + this.left = props.left; + this.right = props.right; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A default assignment expression like in `(a = 3) => a`" +}, AST_Binary); + +/* -----[ LITERALS ]----- */ + +var AST_Array = DEFNODE("Array", "elements", function AST_Array(props) { + if (props) { + this.elements = props.elements; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "An array literal", + $propdoc: { + elements: "[AST_Node*] array of elements" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + var elements = this.elements; + for (var i = 0, len = elements.length; i < len; i++) { + elements[i]._walk(visitor); + } + }); + }, + _children_backwards(push) { + let i = this.elements.length; + while (i--) push(this.elements[i]); + }, +}); + +var AST_Object = DEFNODE("Object", "properties", function AST_Object(props) { + if (props) { + this.properties = props.properties; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "An object literal", + $propdoc: { + properties: "[AST_ObjectProperty*] array of properties" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + var properties = this.properties; + for (var i = 0, len = properties.length; i < len; i++) { + properties[i]._walk(visitor); + } + }); + }, + _children_backwards(push) { + let i = this.properties.length; + while (i--) push(this.properties[i]); + }, +}); + +var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", function AST_ObjectProperty(props) { + if (props) { + this.key = props.key; + this.value = props.value; + this.start = props.start; + this.end = props.end; + this._annotations = props._annotations; + } + + this.flags = 0; +}, { + $documentation: "Base class for literal object properties", + $propdoc: { + key: "[string|AST_Node] property name. For ObjectKeyVal this is a string. For getters, setters and computed property this is an AST_Node.", + value: "[AST_Node] property value. For getters and setters this is an AST_Accessor." + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + if (this.key instanceof AST_Node) + this.key._walk(visitor); + this.value._walk(visitor); + }); + }, + _children_backwards(push) { + push(this.value); + if (this.key instanceof AST_Node) push(this.key); + } +}); + +var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", "quote", function AST_ObjectKeyVal(props) { + if (props) { + this.quote = props.quote; + this.key = props.key; + this.value = props.value; + this.start = props.start; + this.end = props.end; + this._annotations = props._annotations; + } + + this.flags = 0; +}, { + $documentation: "A key: value object property", + $propdoc: { + quote: "[string] the original quote character" + }, + computed_key() { + return this.key instanceof AST_Node; + } +}, AST_ObjectProperty); + +var AST_PrivateSetter = DEFNODE("PrivateSetter", "static", function AST_PrivateSetter(props) { + if (props) { + this.static = props.static; + this.key = props.key; + this.value = props.value; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $propdoc: { + static: "[boolean] whether this is a static private setter" + }, + $documentation: "A private setter property", + computed_key() { + return false; + } +}, AST_ObjectProperty); + +var AST_PrivateGetter = DEFNODE("PrivateGetter", "static", function AST_PrivateGetter(props) { + if (props) { + this.static = props.static; + this.key = props.key; + this.value = props.value; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $propdoc: { + static: "[boolean] whether this is a static private getter" + }, + $documentation: "A private getter property", + computed_key() { + return false; + } +}, AST_ObjectProperty); + +var AST_ObjectSetter = DEFNODE("ObjectSetter", "quote static", function AST_ObjectSetter(props) { + if (props) { + this.quote = props.quote; + this.static = props.static; + this.key = props.key; + this.value = props.value; + this.start = props.start; + this.end = props.end; + this._annotations = props._annotations; + } + + this.flags = 0; +}, { + $propdoc: { + quote: "[string|undefined] the original quote character, if any", + static: "[boolean] whether this is a static setter (classes only)" + }, + $documentation: "An object setter property", + computed_key() { + return !(this.key instanceof AST_SymbolMethod); + } +}, AST_ObjectProperty); + +var AST_ObjectGetter = DEFNODE("ObjectGetter", "quote static", function AST_ObjectGetter(props) { + if (props) { + this.quote = props.quote; + this.static = props.static; + this.key = props.key; + this.value = props.value; + this.start = props.start; + this.end = props.end; + this._annotations = props._annotations; + } + + this.flags = 0; +}, { + $propdoc: { + quote: "[string|undefined] the original quote character, if any", + static: "[boolean] whether this is a static getter (classes only)" + }, + $documentation: "An object getter property", + computed_key() { + return !(this.key instanceof AST_SymbolMethod); + } +}, AST_ObjectProperty); + +var AST_ConciseMethod = DEFNODE( + "ConciseMethod", + "quote static is_generator async", + function AST_ConciseMethod(props) { + if (props) { + this.quote = props.quote; + this.static = props.static; + this.is_generator = props.is_generator; + this.async = props.async; + this.key = props.key; + this.value = props.value; + this.start = props.start; + this.end = props.end; + this._annotations = props._annotations; + } + + this.flags = 0; + }, + { + $propdoc: { + quote: "[string|undefined] the original quote character, if any", + static: "[boolean] is this method static (classes only)", + is_generator: "[boolean] is this a generator method", + async: "[boolean] is this method async", + }, + $documentation: "An ES6 concise method inside an object or class", + computed_key() { + return !(this.key instanceof AST_SymbolMethod); + } + }, + AST_ObjectProperty +); + +var AST_PrivateMethod = DEFNODE("PrivateMethod", "", function AST_PrivateMethod(props) { + if (props) { + this.quote = props.quote; + this.static = props.static; + this.is_generator = props.is_generator; + this.async = props.async; + this.key = props.key; + this.value = props.value; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A private class method inside a class", +}, AST_ConciseMethod); + +var AST_Class = DEFNODE("Class", "name extends properties", function AST_Class(props) { + if (props) { + this.name = props.name; + this.extends = props.extends; + this.properties = props.properties; + this.variables = props.variables; + this.uses_with = props.uses_with; + this.uses_eval = props.uses_eval; + this.parent_scope = props.parent_scope; + this.enclosed = props.enclosed; + this.cname = props.cname; + this.body = props.body; + this.block_scope = props.block_scope; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $propdoc: { + name: "[AST_SymbolClass|AST_SymbolDefClass?] optional class name.", + extends: "[AST_Node]? optional parent class", + properties: "[AST_ObjectProperty*] array of properties" + }, + $documentation: "An ES6 class", + _walk: function(visitor) { + return visitor._visit(this, function() { + if (this.name) { + this.name._walk(visitor); + } + if (this.extends) { + this.extends._walk(visitor); + } + this.properties.forEach((prop) => prop._walk(visitor)); + }); + }, + _children_backwards(push) { + let i = this.properties.length; + while (i--) push(this.properties[i]); + if (this.extends) push(this.extends); + if (this.name) push(this.name); + }, + /** go through the bits that are executed instantly, not when the class is `new`'d. Doesn't walk the name. */ + visit_nondeferred_class_parts(visitor) { + if (this.extends) { + this.extends._walk(visitor); + } + this.properties.forEach((prop) => { + if (prop instanceof AST_ClassStaticBlock) { + prop._walk(visitor); + return; + } + if (prop.computed_key()) { + visitor.push(prop); + prop.key._walk(visitor); + visitor.pop(); + } + if ((prop instanceof AST_ClassPrivateProperty || prop instanceof AST_ClassProperty) && prop.static && prop.value) { + visitor.push(prop); + prop.value._walk(visitor); + visitor.pop(); + } + }); + }, + /** go through the bits that are executed later, when the class is `new`'d or a static method is called */ + visit_deferred_class_parts(visitor) { + this.properties.forEach((prop) => { + if (prop instanceof AST_ConciseMethod) { + prop.walk(visitor); + } else if (prop instanceof AST_ClassProperty && !prop.static && prop.value) { + visitor.push(prop); + prop.value._walk(visitor); + visitor.pop(); + } + }); + }, +}, AST_Scope /* TODO a class might have a scope but it's not a scope */); + +var AST_ClassProperty = DEFNODE("ClassProperty", "static quote", function AST_ClassProperty(props) { + if (props) { + this.static = props.static; + this.quote = props.quote; + this.key = props.key; + this.value = props.value; + this.start = props.start; + this.end = props.end; + this._annotations = props._annotations; + } + + this.flags = 0; +}, { + $documentation: "A class property", + $propdoc: { + static: "[boolean] whether this is a static key", + quote: "[string] which quote is being used" + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + if (this.key instanceof AST_Node) + this.key._walk(visitor); + if (this.value instanceof AST_Node) + this.value._walk(visitor); + }); + }, + _children_backwards(push) { + if (this.value instanceof AST_Node) push(this.value); + if (this.key instanceof AST_Node) push(this.key); + }, + computed_key() { + return !(this.key instanceof AST_SymbolClassProperty); + } +}, AST_ObjectProperty); + +var AST_ClassPrivateProperty = DEFNODE("ClassPrivateProperty", "", function AST_ClassPrivateProperty(props) { + if (props) { + this.static = props.static; + this.quote = props.quote; + this.key = props.key; + this.value = props.value; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A class property for a private property", +}, AST_ClassProperty); + +var AST_PrivateIn = DEFNODE("PrivateIn", "key value", function AST_PrivateIn(props) { + if (props) { + this.key = props.key; + this.value = props.value; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "An `in` binop when the key is private, eg #x in this", + _walk: function(visitor) { + return visitor._visit(this, function() { + this.key._walk(visitor); + this.value._walk(visitor); + }); + }, + _children_backwards(push) { + push(this.value); + push(this.key); + }, +}); + +var AST_DefClass = DEFNODE("DefClass", null, function AST_DefClass(props) { + if (props) { + this.name = props.name; + this.extends = props.extends; + this.properties = props.properties; + this.variables = props.variables; + this.uses_with = props.uses_with; + this.uses_eval = props.uses_eval; + this.parent_scope = props.parent_scope; + this.enclosed = props.enclosed; + this.cname = props.cname; + this.body = props.body; + this.block_scope = props.block_scope; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A class definition", +}, AST_Class); + +var AST_ClassStaticBlock = DEFNODE("ClassStaticBlock", "body block_scope", function AST_ClassStaticBlock (props) { + this.body = props.body; + this.block_scope = props.block_scope; + this.start = props.start; + this.end = props.end; +}, { + $documentation: "A block containing statements to be executed in the context of the class", + $propdoc: { + body: "[AST_Statement*] an array of statements", + }, + _walk: function(visitor) { + return visitor._visit(this, function() { + walk_body(this, visitor); + }); + }, + _children_backwards(push) { + let i = this.body.length; + while (i--) push(this.body[i]); + }, + clone: clone_block_scope, + computed_key: () => false +}, AST_Scope); + +var AST_ClassExpression = DEFNODE("ClassExpression", null, function AST_ClassExpression(props) { + if (props) { + this.name = props.name; + this.extends = props.extends; + this.properties = props.properties; + this.variables = props.variables; + this.uses_with = props.uses_with; + this.uses_eval = props.uses_eval; + this.parent_scope = props.parent_scope; + this.enclosed = props.enclosed; + this.cname = props.cname; + this.body = props.body; + this.block_scope = props.block_scope; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A class expression." +}, AST_Class); + +var AST_Symbol = DEFNODE("Symbol", "scope name thedef", function AST_Symbol(props) { + if (props) { + this.scope = props.scope; + this.name = props.name; + this.thedef = props.thedef; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $propdoc: { + name: "[string] name of this symbol", + scope: "[AST_Scope/S] the current scope (not necessarily the definition scope)", + thedef: "[SymbolDef/S] the definition of this symbol" + }, + $documentation: "Base class for all symbols" +}); + +var AST_NewTarget = DEFNODE("NewTarget", null, function AST_NewTarget(props) { + if (props) { + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A reference to new.target" +}); + +var AST_SymbolDeclaration = DEFNODE("SymbolDeclaration", "init", function AST_SymbolDeclaration(props) { + if (props) { + this.init = props.init; + this.scope = props.scope; + this.name = props.name; + this.thedef = props.thedef; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A declaration symbol (symbol in var/const, function name or argument, symbol in catch)", +}, AST_Symbol); + +var AST_SymbolVar = DEFNODE("SymbolVar", null, function AST_SymbolVar(props) { + if (props) { + this.init = props.init; + this.scope = props.scope; + this.name = props.name; + this.thedef = props.thedef; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "Symbol defining a variable", +}, AST_SymbolDeclaration); + +var AST_SymbolBlockDeclaration = DEFNODE( + "SymbolBlockDeclaration", + null, + function AST_SymbolBlockDeclaration(props) { + if (props) { + this.init = props.init; + this.scope = props.scope; + this.name = props.name; + this.thedef = props.thedef; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; + }, + { + $documentation: "Base class for block-scoped declaration symbols" + }, + AST_SymbolDeclaration +); + +var AST_SymbolConst = DEFNODE("SymbolConst", null, function AST_SymbolConst(props) { + if (props) { + this.init = props.init; + this.scope = props.scope; + this.name = props.name; + this.thedef = props.thedef; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A constant declaration" +}, AST_SymbolBlockDeclaration); + +var AST_SymbolLet = DEFNODE("SymbolLet", null, function AST_SymbolLet(props) { + if (props) { + this.init = props.init; + this.scope = props.scope; + this.name = props.name; + this.thedef = props.thedef; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A block-scoped `let` declaration" +}, AST_SymbolBlockDeclaration); + +var AST_SymbolFunarg = DEFNODE("SymbolFunarg", null, function AST_SymbolFunarg(props) { + if (props) { + this.init = props.init; + this.scope = props.scope; + this.name = props.name; + this.thedef = props.thedef; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "Symbol naming a function argument", +}, AST_SymbolVar); + +var AST_SymbolDefun = DEFNODE("SymbolDefun", null, function AST_SymbolDefun(props) { + if (props) { + this.init = props.init; + this.scope = props.scope; + this.name = props.name; + this.thedef = props.thedef; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "Symbol defining a function", +}, AST_SymbolDeclaration); + +var AST_SymbolMethod = DEFNODE("SymbolMethod", null, function AST_SymbolMethod(props) { + if (props) { + this.scope = props.scope; + this.name = props.name; + this.thedef = props.thedef; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "Symbol in an object defining a method", +}, AST_Symbol); + +var AST_SymbolClassProperty = DEFNODE("SymbolClassProperty", null, function AST_SymbolClassProperty(props) { + if (props) { + this.scope = props.scope; + this.name = props.name; + this.thedef = props.thedef; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "Symbol for a class property", +}, AST_Symbol); + +var AST_SymbolLambda = DEFNODE("SymbolLambda", null, function AST_SymbolLambda(props) { + if (props) { + this.init = props.init; + this.scope = props.scope; + this.name = props.name; + this.thedef = props.thedef; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "Symbol naming a function expression", +}, AST_SymbolDeclaration); + +var AST_SymbolDefClass = DEFNODE("SymbolDefClass", null, function AST_SymbolDefClass(props) { + if (props) { + this.init = props.init; + this.scope = props.scope; + this.name = props.name; + this.thedef = props.thedef; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "Symbol naming a class's name in a class declaration. Lexically scoped to its containing scope, and accessible within the class." +}, AST_SymbolBlockDeclaration); + +var AST_SymbolClass = DEFNODE("SymbolClass", null, function AST_SymbolClass(props) { + if (props) { + this.init = props.init; + this.scope = props.scope; + this.name = props.name; + this.thedef = props.thedef; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "Symbol naming a class's name. Lexically scoped to the class." +}, AST_SymbolDeclaration); + +var AST_SymbolCatch = DEFNODE("SymbolCatch", null, function AST_SymbolCatch(props) { + if (props) { + this.init = props.init; + this.scope = props.scope; + this.name = props.name; + this.thedef = props.thedef; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "Symbol naming the exception in catch", +}, AST_SymbolBlockDeclaration); + +var AST_SymbolImport = DEFNODE("SymbolImport", null, function AST_SymbolImport(props) { + if (props) { + this.init = props.init; + this.scope = props.scope; + this.name = props.name; + this.thedef = props.thedef; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "Symbol referring to an imported name", +}, AST_SymbolBlockDeclaration); + +var AST_SymbolImportForeign = DEFNODE("SymbolImportForeign", null, function AST_SymbolImportForeign(props) { + if (props) { + this.scope = props.scope; + this.name = props.name; + this.thedef = props.thedef; + this.quote = props.quote; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A symbol imported from a module, but it is defined in the other module, and its real name is irrelevant for this module's purposes", +}, AST_Symbol); + +var AST_Label = DEFNODE("Label", "references", function AST_Label(props) { + if (props) { + this.references = props.references; + this.scope = props.scope; + this.name = props.name; + this.thedef = props.thedef; + this.start = props.start; + this.end = props.end; + this.initialize(); + } + + this.flags = 0; +}, { + $documentation: "Symbol naming a label (declaration)", + $propdoc: { + references: "[AST_LoopControl*] a list of nodes referring to this label" + }, + initialize: function() { + this.references = []; + this.thedef = this; + } +}, AST_Symbol); + +var AST_SymbolRef = DEFNODE("SymbolRef", null, function AST_SymbolRef(props) { + if (props) { + this.scope = props.scope; + this.name = props.name; + this.thedef = props.thedef; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "Reference to some symbol (not definition/declaration)", +}, AST_Symbol); + +var AST_SymbolExport = DEFNODE("SymbolExport", null, function AST_SymbolExport(props) { + if (props) { + this.scope = props.scope; + this.name = props.name; + this.thedef = props.thedef; + this.quote = props.quote; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "Symbol referring to a name to export", +}, AST_SymbolRef); + +var AST_SymbolExportForeign = DEFNODE("SymbolExportForeign", null, function AST_SymbolExportForeign(props) { + if (props) { + this.scope = props.scope; + this.name = props.name; + this.thedef = props.thedef; + this.quote = props.quote; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A symbol exported from this module, but it is used in the other module, and its real name is irrelevant for this module's purposes", +}, AST_Symbol); + +var AST_LabelRef = DEFNODE("LabelRef", null, function AST_LabelRef(props) { + if (props) { + this.scope = props.scope; + this.name = props.name; + this.thedef = props.thedef; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "Reference to a label symbol", +}, AST_Symbol); + +var AST_SymbolPrivateProperty = DEFNODE("SymbolPrivateProperty", null, function AST_SymbolPrivateProperty(props) { + if (props) { + this.scope = props.scope; + this.name = props.name; + this.thedef = props.thedef; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A symbol that refers to a private property", +}, AST_Symbol); + +var AST_This = DEFNODE("This", null, function AST_This(props) { + if (props) { + this.scope = props.scope; + this.name = props.name; + this.thedef = props.thedef; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "The `this` symbol", +}, AST_Symbol); + +var AST_Super = DEFNODE("Super", null, function AST_Super(props) { + if (props) { + this.scope = props.scope; + this.name = props.name; + this.thedef = props.thedef; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "The `super` symbol", +}, AST_This); + +var AST_Constant = DEFNODE("Constant", null, function AST_Constant(props) { + if (props) { + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "Base class for all constants", + getValue: function() { + return this.value; + } +}); + +var AST_String = DEFNODE("String", "value quote", function AST_String(props) { + if (props) { + this.value = props.value; + this.quote = props.quote; + this.start = props.start; + this.end = props.end; + this._annotations = props._annotations; + } + + this.flags = 0; +}, { + $documentation: "A string literal", + $propdoc: { + value: "[string] the contents of this string", + quote: "[string] the original quote character" + } +}, AST_Constant); + +var AST_Number = DEFNODE("Number", "value raw", function AST_Number(props) { + if (props) { + this.value = props.value; + this.raw = props.raw; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A number literal", + $propdoc: { + value: "[number] the numeric value", + raw: "[string] numeric value as string" + } +}, AST_Constant); + +var AST_BigInt = DEFNODE("BigInt", "value", function AST_BigInt(props) { + if (props) { + this.value = props.value; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A big int literal", + $propdoc: { + value: "[string] big int value" + } +}, AST_Constant); + +var AST_RegExp = DEFNODE("RegExp", "value", function AST_RegExp(props) { + if (props) { + this.value = props.value; + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A regexp literal", + $propdoc: { + value: "[RegExp] the actual regexp", + } +}, AST_Constant); + +var AST_Atom = DEFNODE("Atom", null, function AST_Atom(props) { + if (props) { + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "Base class for atoms", +}, AST_Constant); + +var AST_Null = DEFNODE("Null", null, function AST_Null(props) { + if (props) { + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "The `null` atom", + value: null +}, AST_Atom); + +var AST_NaN = DEFNODE("NaN", null, function AST_NaN(props) { + if (props) { + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "The impossible value", + value: 0/0 +}, AST_Atom); + +var AST_Undefined = DEFNODE("Undefined", null, function AST_Undefined(props) { + if (props) { + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "The `undefined` value", + value: (function() {}()) +}, AST_Atom); + +var AST_Hole = DEFNODE("Hole", null, function AST_Hole(props) { + if (props) { + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "A hole in an array", + value: (function() {}()) +}, AST_Atom); + +var AST_Infinity = DEFNODE("Infinity", null, function AST_Infinity(props) { + if (props) { + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "The `Infinity` value", + value: 1/0 +}, AST_Atom); + +var AST_Boolean = DEFNODE("Boolean", null, function AST_Boolean(props) { + if (props) { + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "Base class for booleans", +}, AST_Atom); + +var AST_False = DEFNODE("False", null, function AST_False(props) { + if (props) { + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "The `false` atom", + value: false +}, AST_Boolean); + +var AST_True = DEFNODE("True", null, function AST_True(props) { + if (props) { + this.start = props.start; + this.end = props.end; + } + + this.flags = 0; +}, { + $documentation: "The `true` atom", + value: true +}, AST_Boolean); + +/* -----[ Walk function ]---- */ + +/** + * Walk nodes in depth-first search fashion. + * Callback can return `walk_abort` symbol to stop iteration. + * It can also return `true` to stop iteration just for child nodes. + * Iteration can be stopped and continued by passing the `to_visit` argument, + * which is given to the callback in the second argument. + **/ +function walk(node, cb, to_visit = [node]) { + const push = to_visit.push.bind(to_visit); + while (to_visit.length) { + const node = to_visit.pop(); + const ret = cb(node, to_visit); + + if (ret) { + if (ret === walk_abort) return true; + continue; + } + + node._children_backwards(push); + } + return false; +} + +/** + * Walks an AST node and its children. + * + * {cb} can return `walk_abort` to interrupt the walk. + * + * @param node + * @param cb {(node, info: { parent: (nth) => any }) => (boolean | undefined)} + * + * @returns {boolean} whether the walk was aborted + * + * @example + * const found_some_cond = walk_parent(my_ast_node, (node, { parent }) => { + * if (some_cond(node, parent())) return walk_abort + * }); + */ +function walk_parent(node, cb, initial_stack) { + const to_visit = [node]; + const push = to_visit.push.bind(to_visit); + const stack = initial_stack ? initial_stack.slice() : []; + const parent_pop_indices = []; + + let current; + + const info = { + parent: (n = 0) => { + if (n === -1) { + return current; + } + + // [ p1 p0 ] [ 1 0 ] + if (initial_stack && n >= stack.length) { + n -= stack.length; + return initial_stack[ + initial_stack.length - (n + 1) + ]; + } + + return stack[stack.length - (1 + n)]; + }, + }; + + while (to_visit.length) { + current = to_visit.pop(); + + while ( + parent_pop_indices.length && + to_visit.length == parent_pop_indices[parent_pop_indices.length - 1] + ) { + stack.pop(); + parent_pop_indices.pop(); + } + + const ret = cb(current, info); + + if (ret) { + if (ret === walk_abort) return true; + continue; + } + + const visit_length = to_visit.length; + + current._children_backwards(push); + + // Push only if we're going to traverse the children + if (to_visit.length > visit_length) { + stack.push(current); + parent_pop_indices.push(visit_length - 1); + } + } + + return false; +} + +const walk_abort = Symbol("abort walk"); + +/* -----[ TreeWalker ]----- */ + +class TreeWalker { + constructor(callback) { + this.visit = callback; + this.stack = []; + this.directives = Object.create(null); + } + + _visit(node, descend) { + this.push(node); + var ret = this.visit(node, descend ? function() { + descend.call(node); + } : noop); + if (!ret && descend) { + descend.call(node); + } + this.pop(); + return ret; + } + + parent(n) { + return this.stack[this.stack.length - 2 - (n || 0)]; + } + + push(node) { + if (node instanceof AST_Lambda) { + this.directives = Object.create(this.directives); + } else if (node instanceof AST_Directive && !this.directives[node.value]) { + this.directives[node.value] = node; + } else if (node instanceof AST_Class) { + this.directives = Object.create(this.directives); + if (!this.directives["use strict"]) { + this.directives["use strict"] = node; + } + } + this.stack.push(node); + } + + pop() { + var node = this.stack.pop(); + if (node instanceof AST_Lambda || node instanceof AST_Class) { + this.directives = Object.getPrototypeOf(this.directives); + } + } + + self() { + return this.stack[this.stack.length - 1]; + } + + find_parent(type) { + var stack = this.stack; + for (var i = stack.length; --i >= 0;) { + var x = stack[i]; + if (x instanceof type) return x; + } + } + + find_scope() { + var stack = this.stack; + for (var i = stack.length; --i >= 0;) { + const p = stack[i]; + if (p instanceof AST_Toplevel) return p; + if (p instanceof AST_Lambda) return p; + if (p.block_scope) return p.block_scope; + } + } + + has_directive(type) { + var dir = this.directives[type]; + if (dir) return dir; + var node = this.stack[this.stack.length - 1]; + if (node instanceof AST_Scope && node.body) { + for (var i = 0; i < node.body.length; ++i) { + var st = node.body[i]; + if (!(st instanceof AST_Directive)) break; + if (st.value == type) return st; + } + } + } + + loopcontrol_target(node) { + var stack = this.stack; + if (node.label) for (var i = stack.length; --i >= 0;) { + var x = stack[i]; + if (x instanceof AST_LabeledStatement && x.label.name == node.label.name) + return x.body; + } else for (var i = stack.length; --i >= 0;) { + var x = stack[i]; + if (x instanceof AST_IterationStatement + || node instanceof AST_Break && x instanceof AST_Switch) + return x; + } + } +} + +// Tree transformer helpers. +class TreeTransformer extends TreeWalker { + constructor(before, after) { + super(); + this.before = before; + this.after = after; + } +} + +const _PURE = 0b00000001; +const _INLINE = 0b00000010; +const _NOINLINE = 0b00000100; +const _KEY = 0b00001000; +const _MANGLEPROP = 0b00010000; + +// XXX Emscripten: export TreeWalker for walking through AST in acorn-optimizer.js. +exports.TreeWalker = TreeWalker; + +/*********************************************************************** + + A JavaScript tokenizer / parser / beautifier / compressor. + https://github.com/mishoo/UglifyJS2 + + -------------------------------- (C) --------------------------------- + + Author: Mihai Bazon + + http://mihai.bazon.net/blog + + Distributed under the BSD license: + + Copyright 2012 (c) Mihai Bazon + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + ***********************************************************************/ + +function def_transform(node, descend) { + node.DEFMETHOD("transform", function(tw, in_list) { + let transformed = undefined; + tw.push(this); + if (tw.before) transformed = tw.before(this, descend, in_list); + if (transformed === undefined) { + transformed = this; + descend(transformed, tw); + if (tw.after) { + const after_ret = tw.after(transformed, in_list); + if (after_ret !== undefined) transformed = after_ret; + } + } + tw.pop(); + return transformed; + }); +} + +def_transform(AST_Node, noop); + +def_transform(AST_LabeledStatement, function(self, tw) { + self.label = self.label.transform(tw); + self.body = self.body.transform(tw); +}); + +def_transform(AST_SimpleStatement, function(self, tw) { + self.body = self.body.transform(tw); +}); + +def_transform(AST_Block, function(self, tw) { + self.body = MAP(self.body, tw); +}); + +def_transform(AST_Do, function(self, tw) { + self.body = self.body.transform(tw); + self.condition = self.condition.transform(tw); +}); + +def_transform(AST_While, function(self, tw) { + self.condition = self.condition.transform(tw); + self.body = self.body.transform(tw); +}); + +def_transform(AST_For, function(self, tw) { + if (self.init) self.init = self.init.transform(tw); + if (self.condition) self.condition = self.condition.transform(tw); + if (self.step) self.step = self.step.transform(tw); + self.body = self.body.transform(tw); +}); + +def_transform(AST_ForIn, function(self, tw) { + self.init = self.init.transform(tw); + self.object = self.object.transform(tw); + self.body = self.body.transform(tw); +}); + +def_transform(AST_With, function(self, tw) { + self.expression = self.expression.transform(tw); + self.body = self.body.transform(tw); +}); + +def_transform(AST_Exit, function(self, tw) { + if (self.value) self.value = self.value.transform(tw); +}); + +def_transform(AST_LoopControl, function(self, tw) { + if (self.label) self.label = self.label.transform(tw); +}); + +def_transform(AST_If, function(self, tw) { + self.condition = self.condition.transform(tw); + self.body = self.body.transform(tw); + if (self.alternative) self.alternative = self.alternative.transform(tw); +}); + +def_transform(AST_Switch, function(self, tw) { + self.expression = self.expression.transform(tw); + self.body = MAP(self.body, tw); +}); + +def_transform(AST_Case, function(self, tw) { + self.expression = self.expression.transform(tw); + self.body = MAP(self.body, tw); +}); + +def_transform(AST_Try, function(self, tw) { + self.body = self.body.transform(tw); + if (self.bcatch) self.bcatch = self.bcatch.transform(tw); + if (self.bfinally) self.bfinally = self.bfinally.transform(tw); +}); + +def_transform(AST_Catch, function(self, tw) { + if (self.argname) self.argname = self.argname.transform(tw); + self.body = MAP(self.body, tw); +}); + +def_transform(AST_Definitions, function(self, tw) { + self.definitions = MAP(self.definitions, tw); +}); + +def_transform(AST_VarDef, function(self, tw) { + self.name = self.name.transform(tw); + if (self.value) self.value = self.value.transform(tw); +}); + +def_transform(AST_Destructuring, function(self, tw) { + self.names = MAP(self.names, tw); +}); + +def_transform(AST_Lambda, function(self, tw) { + if (self.name) self.name = self.name.transform(tw); + self.argnames = MAP(self.argnames, tw, /* allow_splicing */ false); + if (self.body instanceof AST_Node) { + self.body = self.body.transform(tw); + } else { + self.body = MAP(self.body, tw); + } +}); + +def_transform(AST_Call, function(self, tw) { + self.expression = self.expression.transform(tw); + self.args = MAP(self.args, tw, /* allow_splicing */ false); +}); + +def_transform(AST_Sequence, function(self, tw) { + const result = MAP(self.expressions, tw); + self.expressions = result.length + ? result + : [new AST_Number({ value: 0 })]; +}); + +def_transform(AST_PropAccess, function(self, tw) { + self.expression = self.expression.transform(tw); +}); + +def_transform(AST_Sub, function(self, tw) { + self.expression = self.expression.transform(tw); + self.property = self.property.transform(tw); +}); + +def_transform(AST_Chain, function(self, tw) { + self.expression = self.expression.transform(tw); +}); + +def_transform(AST_Yield, function(self, tw) { + if (self.expression) self.expression = self.expression.transform(tw); +}); + +def_transform(AST_Await, function(self, tw) { + self.expression = self.expression.transform(tw); +}); + +def_transform(AST_Unary, function(self, tw) { + self.expression = self.expression.transform(tw); +}); + +def_transform(AST_Binary, function(self, tw) { + self.left = self.left.transform(tw); + self.right = self.right.transform(tw); +}); + +def_transform(AST_PrivateIn, function(self, tw) { + self.key = self.key.transform(tw); + self.value = self.value.transform(tw); +}); + +def_transform(AST_Conditional, function(self, tw) { + self.condition = self.condition.transform(tw); + self.consequent = self.consequent.transform(tw); + self.alternative = self.alternative.transform(tw); +}); + +def_transform(AST_Array, function(self, tw) { + self.elements = MAP(self.elements, tw); +}); + +def_transform(AST_Object, function(self, tw) { + self.properties = MAP(self.properties, tw); +}); + +def_transform(AST_ObjectProperty, function(self, tw) { + if (self.key instanceof AST_Node) { + self.key = self.key.transform(tw); + } + if (self.value) self.value = self.value.transform(tw); +}); + +def_transform(AST_Class, function(self, tw) { + if (self.name) self.name = self.name.transform(tw); + if (self.extends) self.extends = self.extends.transform(tw); + self.properties = MAP(self.properties, tw); +}); + +def_transform(AST_ClassStaticBlock, function(self, tw) { + self.body = MAP(self.body, tw); +}); + +def_transform(AST_Expansion, function(self, tw) { + self.expression = self.expression.transform(tw); +}); + +def_transform(AST_NameMapping, function(self, tw) { + self.foreign_name = self.foreign_name.transform(tw); + self.name = self.name.transform(tw); +}); + +def_transform(AST_Import, function(self, tw) { + if (self.imported_name) self.imported_name = self.imported_name.transform(tw); + if (self.imported_names) MAP(self.imported_names, tw); + self.module_name = self.module_name.transform(tw); +}); + +def_transform(AST_Export, function(self, tw) { + if (self.exported_definition) self.exported_definition = self.exported_definition.transform(tw); + if (self.exported_value) self.exported_value = self.exported_value.transform(tw); + if (self.exported_names) MAP(self.exported_names, tw); + if (self.module_name) self.module_name = self.module_name.transform(tw); +}); + +def_transform(AST_TemplateString, function(self, tw) { + self.segments = MAP(self.segments, tw); +}); + +def_transform(AST_PrefixedTemplateString, function(self, tw) { + self.prefix = self.prefix.transform(tw); + self.template_string = self.template_string.transform(tw); +}); + +/*********************************************************************** + + A JavaScript tokenizer / parser / beautifier / compressor. + https://github.com/mishoo/UglifyJS2 + + -------------------------------- (C) --------------------------------- + + Author: Mihai Bazon + + http://mihai.bazon.net/blog + + Distributed under the BSD license: + + Copyright 2012 (c) Mihai Bazon + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + ***********************************************************************/ + +(function() { + + var normalize_directives = function(body) { + var in_directive = true; + + for (var i = 0; i < body.length; i++) { + if (in_directive && body[i] instanceof AST_Statement && body[i].body instanceof AST_String) { + body[i] = new AST_Directive({ + start: body[i].start, + end: body[i].end, + value: body[i].body.value + }); + } else if (in_directive && !(body[i] instanceof AST_Statement && body[i].body instanceof AST_String)) { + in_directive = false; + } + } + + return body; + }; + + const assert_clause_from_moz = (assertions) => { + if (assertions && assertions.length > 0) { + return new AST_Object({ + start: my_start_token(assertions), + end: my_end_token(assertions), + properties: assertions.map((assertion_kv) => + new AST_ObjectKeyVal({ + start: my_start_token(assertion_kv), + end: my_end_token(assertion_kv), + key: assertion_kv.key.name || assertion_kv.key.value, + value: from_moz(assertion_kv.value) + }) + ) + }); + } + return null; + }; + + var MOZ_TO_ME = { + Program: function(M) { + return new AST_Toplevel({ + start: my_start_token(M), + end: my_end_token(M), + body: normalize_directives(M.body.map(from_moz)) + }); + }, + + ArrayPattern: function(M) { + return new AST_Destructuring({ + start: my_start_token(M), + end: my_end_token(M), + names: M.elements.map(function(elm) { + if (elm === null) { + return new AST_Hole(); + } + return from_moz(elm); + }), + is_array: true + }); + }, + + ObjectPattern: function(M) { + return new AST_Destructuring({ + start: my_start_token(M), + end: my_end_token(M), + names: M.properties.map(from_moz), + is_array: false + }); + }, + + AssignmentPattern: function(M) { + return new AST_DefaultAssign({ + start: my_start_token(M), + end: my_end_token(M), + left: from_moz(M.left), + operator: "=", + right: from_moz(M.right) + }); + }, - expect_token("arrow", "=>"); + SpreadElement: function(M) { + return new AST_Expansion({ + start: my_start_token(M), + end: my_end_token(M), + expression: from_moz(M.argument) + }); + }, - var body = _function_body(is("punc", "{"), false, is_async); + RestElement: function(M) { + return new AST_Expansion({ + start: my_start_token(M), + end: my_end_token(M), + expression: from_moz(M.argument) + }); + }, + + TemplateElement: function(M) { + return new AST_TemplateSegment({ + start: my_start_token(M), + end: my_end_token(M), + value: M.value.cooked, + raw: M.value.raw + }); + }, + + TemplateLiteral: function(M) { + var segments = []; + for (var i = 0; i < M.quasis.length; i++) { + segments.push(from_moz(M.quasis[i])); + if (M.expressions[i]) { + segments.push(from_moz(M.expressions[i])); + } + } + return new AST_TemplateString({ + start: my_start_token(M), + end: my_end_token(M), + segments: segments + }); + }, + + TaggedTemplateExpression: function(M) { + return new AST_PrefixedTemplateString({ + start: my_start_token(M), + end: my_end_token(M), + template_string: from_moz(M.quasi), + prefix: from_moz(M.tag) + }); + }, + + FunctionDeclaration: function(M) { + return new AST_Defun({ + start: my_start_token(M), + end: my_end_token(M), + name: from_moz(M.id), + argnames: M.params.map(from_moz), + is_generator: M.generator, + async: M.async, + body: normalize_directives(from_moz(M.body).body) + }); + }, + + FunctionExpression: function(M) { + return new AST_Function({ + start: my_start_token(M), + end: my_end_token(M), + name: from_moz(M.id), + argnames: M.params.map(from_moz), + is_generator: M.generator, + async: M.async, + body: normalize_directives(from_moz(M.body).body) + }); + }, + + ArrowFunctionExpression: function(M) { + const body = M.body.type === "BlockStatement" + ? from_moz(M.body).body + : [make_node(AST_Return, {}, { value: from_moz(M.body) })]; + return new AST_Arrow({ + start: my_start_token(M), + end: my_end_token(M), + argnames: M.params.map(from_moz), + body, + async: M.async, + }); + }, - var end = - body instanceof Array && body.length ? body[body.length - 1].end : - body instanceof Array ? start : - body.end; + ExpressionStatement: function(M) { + return new AST_SimpleStatement({ + start: my_start_token(M), + end: my_end_token(M), + body: from_moz(M.expression) + }); + }, + +// XXX Emscripten localmod: Add a node type for a parenthesized expression so that we can retain +// Closure annotations that need a form "/**annotation*/(expression)" + ParenthesizedExpression: function(M) { + return new AST_ParenthesizedExpression({ + start: my_start_token(M), + end: my_end_token(M), + body: from_moz(M.expression) + }); + }, +// XXX End Emscripten localmod + + TryStatement: function(M) { + var handlers = M.handlers || [M.handler]; + if (handlers.length > 1 || M.guardedHandlers && M.guardedHandlers.length) { + throw new Error("Multiple catch clauses are not supported."); + } + return new AST_Try({ + start : my_start_token(M), + end : my_end_token(M), + body : new AST_TryBlock(from_moz(M.block)), + bcatch : from_moz(handlers[0]), + bfinally : M.finalizer ? new AST_Finally(from_moz(M.finalizer)) : null + }); + }, + + Property: function(M) { + var key = M.key; + var args = { + start : my_start_token(key || M.value), + end : my_end_token(M.value), + key : key.type == "Identifier" ? key.name : key.value, + value : from_moz(M.value) + }; + if (M.computed) { + args.key = from_moz(M.key); + } + if (M.method) { + args.is_generator = M.value.generator; + args.async = M.value.async; + if (!M.computed) { + args.key = new AST_SymbolMethod({ name: args.key }); + } else { + args.key = from_moz(M.key); + } + return new AST_ConciseMethod(args); + } + if (M.kind == "init") { + if (key.type != "Identifier" && key.type != "Literal") { + args.key = from_moz(key); + } + return new AST_ObjectKeyVal(args); + } + if (typeof args.key === "string" || typeof args.key === "number") { + args.key = new AST_SymbolMethod({ + name: args.key + }); + } + args.value = new AST_Accessor(args.value); + if (M.kind == "get") return new AST_ObjectGetter(args); + if (M.kind == "set") return new AST_ObjectSetter(args); + if (M.kind == "method") { + args.async = M.value.async; + args.is_generator = M.value.generator; + args.quote = M.computed ? "\"" : null; + return new AST_ConciseMethod(args); + } + }, + + MethodDefinition: function(M) { + const is_private = M.key.type === "PrivateIdentifier"; + const key = M.computed ? from_moz(M.key) : new AST_SymbolMethod({ name: M.key.name || M.key.value }); + + var args = { + start : my_start_token(M), + end : my_end_token(M), + key, + value : from_moz(M.value), + static : M.static, + }; + if (M.kind == "get") { + return new (is_private ? AST_PrivateGetter : AST_ObjectGetter)(args); + } + if (M.kind == "set") { + return new (is_private ? AST_PrivateSetter : AST_ObjectSetter)(args); + } + args.is_generator = M.value.generator; + args.async = M.value.async; + return new (is_private ? AST_PrivateMethod : AST_ConciseMethod)(args); + }, + + FieldDefinition: function(M) { + let key; + if (M.computed) { + key = from_moz(M.key); + } else { + if (M.key.type !== "Identifier") throw new Error("Non-Identifier key in FieldDefinition"); + key = from_moz(M.key); + } + return new AST_ClassProperty({ + start : my_start_token(M), + end : my_end_token(M), + key, + value : from_moz(M.value), + static : M.static, + }); + }, + + PropertyDefinition: function(M) { + let key; + if (M.computed) { + key = from_moz(M.key); + } else if (M.key.type === "PrivateIdentifier") { + return new AST_ClassPrivateProperty({ + start : my_start_token(M), + end : my_end_token(M), + key : from_moz(M.key), + value : from_moz(M.value), + static : M.static, + }); + } else { + if (M.key.type !== "Identifier") { + throw new Error("Non-Identifier key in PropertyDefinition"); + } + key = from_moz(M.key); + } + + return new AST_ClassProperty({ + start : my_start_token(M), + end : my_end_token(M), + key, + value : from_moz(M.value), + static : M.static, + }); + }, - return new AST_Arrow({ - start : start, - end : end, - async : is_async, - argnames : argnames, - body : body - }); - }; - - var function_ = function(ctor, is_generator_property, is_async, is_export_default) { - - var in_statement = ctor === AST_Defun; - var is_generator = is("operator", "*"); - if (is_generator) { - next(); - } - - var name = is("name") ? as_symbol(in_statement ? AST_SymbolDefun : AST_SymbolLambda) : null; - if (in_statement && !name) { - if (is_export_default) { - ctor = AST_Function; - } else { - unexpected(); - } - } - - if (name && ctor !== AST_Accessor && !(name instanceof AST_SymbolDeclaration)) - unexpected(prev()); - - var args = []; - var body = _function_body(true, is_generator || is_generator_property, is_async, name, args); - return new ctor({ - start : args.start, - end : body.end, - is_generator: is_generator, - async : is_async, - name : name, - argnames: args, - body : body - }); - }; - - function track_used_binding_identifiers(is_parameter, strict) { - var parameters = new Set(); - var duplicate = false; - var default_assignment = false; - var spread = false; - var strict_mode = !!strict; - var tracker = { - add_parameter: function(token) { - if (parameters.has(token.value)) { - if (duplicate === false) { - duplicate = token; - } - tracker.check_strict(); - } else { - parameters.add(token.value); - if (is_parameter) { - switch (token.value) { - case "arguments": - case "eval": - case "yield": - if (strict_mode) { - token_error(token, "Unexpected " + token.value + " identifier as parameter inside strict mode"); - } - break; - default: - if (RESERVED_WORDS.has(token.value)) { - unexpected(); - } - } - } - } - }, - mark_default_assignment: function(token) { - if (default_assignment === false) { - default_assignment = token; - } - }, - mark_spread: function(token) { - if (spread === false) { - spread = token; - } - }, - mark_strict_mode: function() { - strict_mode = true; - }, - is_strict: function() { - return default_assignment !== false || spread !== false || strict_mode; - }, - check_strict: function() { - if (tracker.is_strict() && duplicate !== false) { - token_error(duplicate, "Parameter " + duplicate.value + " was used already"); - } - } - }; + PrivateIdentifier: function (M) { + return new AST_SymbolPrivateProperty({ + start: my_start_token(M), + end: my_end_token(M), + name: M.name + }); + }, - return tracker; - } + StaticBlock: function(M) { + return new AST_ClassStaticBlock({ + start : my_start_token(M), + end : my_end_token(M), + body : M.body.map(from_moz), + }); + }, + + ArrayExpression: function(M) { + return new AST_Array({ + start : my_start_token(M), + end : my_end_token(M), + elements : M.elements.map(function(elem) { + return elem === null ? new AST_Hole() : from_moz(elem); + }) + }); + }, + + ObjectExpression: function(M) { + return new AST_Object({ + start : my_start_token(M), + end : my_end_token(M), + properties : M.properties.map(function(prop) { + if (prop.type === "SpreadElement") { + return from_moz(prop); + } + prop.type = "Property"; + // XXX EMSCRIPTEN preserve quoted properties + // https://github.com/mishoo/UglifyJS2/pull/3323 + var ret = from_moz(prop); + if (prop.key.type === "Literal" && + (prop.key.raw[0] === '"' || prop.key.raw[0] === "'")) { + ret.quote = true; + } + return ret; + }) + }); + }, - function parameters(params) { - var used_parameters = track_used_binding_identifiers(true, S.input.has_directive("use strict")); + SequenceExpression: function(M) { + return new AST_Sequence({ + start : my_start_token(M), + end : my_end_token(M), + expressions: M.expressions.map(from_moz) + }); + }, + + MemberExpression: function(M) { + if (M.property.type === "PrivateIdentifier") { + return new AST_DotHash({ + start : my_start_token(M), + end : my_end_token(M), + property : M.property.name, + expression : from_moz(M.object), + optional : M.optional || false + }); + } + return new (M.computed ? AST_Sub : AST_Dot)({ + start : my_start_token(M), + end : my_end_token(M), + property : M.computed ? from_moz(M.property) : M.property.name, + expression : from_moz(M.object), + optional : M.optional || false + }); + }, - expect("("); + ChainExpression: function(M) { + return new AST_Chain({ + start : my_start_token(M), + end : my_end_token(M), + expression : from_moz(M.expression) + }); + }, + + SwitchCase: function(M) { + return new (M.test ? AST_Case : AST_Default)({ + start : my_start_token(M), + end : my_end_token(M), + expression : from_moz(M.test), + body : M.consequent.map(from_moz) + }); + }, + + VariableDeclaration: function(M) { + return new (M.kind === "const" ? AST_Const : + M.kind === "let" ? AST_Let : AST_Var)({ + start : my_start_token(M), + end : my_end_token(M), + definitions : M.declarations.map(from_moz) + }); + }, + + ImportDeclaration: function(M) { + var imported_name = null; + var imported_names = null; + M.specifiers.forEach(function (specifier) { + if (specifier.type === "ImportSpecifier" || specifier.type === "ImportNamespaceSpecifier") { + if (!imported_names) { imported_names = []; } + imported_names.push(from_moz(specifier)); + } else if (specifier.type === "ImportDefaultSpecifier") { + imported_name = from_moz(specifier); + } + }); + return new AST_Import({ + start : my_start_token(M), + end : my_end_token(M), + imported_name: imported_name, + imported_names : imported_names, + module_name : from_moz(M.source), + assert_clause: assert_clause_from_moz(M.assertions) + }); + }, + + ImportSpecifier: function(M) { + return new AST_NameMapping({ + start: my_start_token(M), + end: my_end_token(M), + foreign_name: from_moz(M.imported), + name: from_moz(M.local) + }); + }, + + ImportDefaultSpecifier: function(M) { + return from_moz(M.local); + }, + + ImportNamespaceSpecifier: function(M) { + return new AST_NameMapping({ + start: my_start_token(M), + end: my_end_token(M), + foreign_name: new AST_SymbolImportForeign({ name: "*" }), + name: from_moz(M.local) + }); + }, + + ExportAllDeclaration: function(M) { + var foreign_name = M.exported == null ? + new AST_SymbolExportForeign({ name: "*" }) : + from_moz(M.exported); + return new AST_Export({ + start: my_start_token(M), + end: my_end_token(M), + exported_names: [ + new AST_NameMapping({ + name: new AST_SymbolExportForeign({ name: "*" }), + foreign_name: foreign_name + }) + ], + module_name: from_moz(M.source), + assert_clause: assert_clause_from_moz(M.assertions) + }); + }, + + ExportNamedDeclaration: function(M) { + return new AST_Export({ + start: my_start_token(M), + end: my_end_token(M), + exported_definition: from_moz(M.declaration), + exported_names: M.specifiers && M.specifiers.length ? M.specifiers.map(function (specifier) { + return from_moz(specifier); + }) : null, + module_name: from_moz(M.source), + assert_clause: assert_clause_from_moz(M.assertions) + }); + }, + + ExportDefaultDeclaration: function(M) { + return new AST_Export({ + start: my_start_token(M), + end: my_end_token(M), + exported_value: from_moz(M.declaration), + is_default: true + }); + }, - while (!is("punc", ")")) { - var param = parameter(used_parameters); - params.push(param); + ExportSpecifier: function(M) { + return new AST_NameMapping({ + foreign_name: from_moz(M.exported), + name: from_moz(M.local) + }); + }, + + Literal: function(M) { + var val = M.value, args = { + start : my_start_token(M), + end : my_end_token(M) + }; + var rx = M.regex; + if (rx && rx.pattern) { + // RegExpLiteral as per ESTree AST spec + args.value = { + source: rx.pattern, + flags: rx.flags + }; + return new AST_RegExp(args); + } else if (rx) { + // support legacy RegExp + const rx_source = M.raw || val; + const match = rx_source.match(/^\/(.*)\/(\w*)$/); + if (!match) throw new Error("Invalid regex source " + rx_source); + const [_, source, flags] = match; + args.value = { source, flags }; + return new AST_RegExp(args); + } + if (val === null) return new AST_Null(args); + switch (typeof val) { + case "string": + args.quote = "\""; + var p = FROM_MOZ_STACK[FROM_MOZ_STACK.length - 2]; + if (p.type == "ImportSpecifier") { + args.name = val; + return new AST_SymbolImportForeign(args); + } else if (p.type == "ExportSpecifier") { + args.name = val; + if (M == p.exported) { + return new AST_SymbolExportForeign(args); + } else { + return new AST_SymbolExport(args); + } + } else if (p.type == "ExportAllDeclaration" && M == p.exported) { + args.name = val; + return new AST_SymbolExportForeign(args); + } + args.value = val; + return new AST_String(args); + case "number": + args.value = val; + args.raw = M.raw || val.toString(); + return new AST_Number(args); + case "boolean": + return new (val ? AST_True : AST_False)(args); + case "bigint": + args.value = val; + return new AST_BigInt(args); + case "undefined": + return undefined; + default: + throw new Error("Unhandled value type: " + typeof val); + } + }, + + MetaProperty: function(M) { + if (M.meta.name === "new" && M.property.name === "target") { + return new AST_NewTarget({ + start: my_start_token(M), + end: my_end_token(M) + }); + } else if (M.meta.name === "import" && M.property.name === "meta") { + return new AST_ImportMeta({ + start: my_start_token(M), + end: my_end_token(M) + }); + } + }, + + Identifier: function(M) { + var p = FROM_MOZ_STACK[FROM_MOZ_STACK.length - 2]; + return new ( p.type == "LabeledStatement" ? AST_Label + : p.type == "VariableDeclarator" && p.id === M ? (p.kind == "const" ? AST_SymbolConst : p.kind == "let" ? AST_SymbolLet : AST_SymbolVar) + : /Import.*Specifier/.test(p.type) ? (p.local === M ? AST_SymbolImport : AST_SymbolImportForeign) + : p.type == "ExportSpecifier" ? (p.local === M ? AST_SymbolExport : AST_SymbolExportForeign) + : p.type == "FunctionExpression" ? (p.id === M ? AST_SymbolLambda : AST_SymbolFunarg) + : p.type == "FunctionDeclaration" ? (p.id === M ? AST_SymbolDefun : AST_SymbolFunarg) + : p.type == "ArrowFunctionExpression" ? (p.params.includes(M)) ? AST_SymbolFunarg : AST_SymbolRef + : p.type == "ClassExpression" ? (p.id === M ? AST_SymbolClass : AST_SymbolRef) + : p.type == "Property" ? (p.key === M && p.computed || p.value === M ? AST_SymbolRef : AST_SymbolMethod) + : p.type == "PropertyDefinition" || p.type === "FieldDefinition" ? (p.key === M && p.computed || p.value === M ? AST_SymbolRef : AST_SymbolClassProperty) + : p.type == "ClassDeclaration" ? (p.id === M ? AST_SymbolDefClass : AST_SymbolRef) + : p.type == "MethodDefinition" ? (p.computed ? AST_SymbolRef : AST_SymbolMethod) + : p.type == "CatchClause" ? AST_SymbolCatch + : p.type == "BreakStatement" || p.type == "ContinueStatement" ? AST_LabelRef + : AST_SymbolRef)({ + start : my_start_token(M), + end : my_end_token(M), + name : M.name + }); + }, + + BigIntLiteral(M) { + return new AST_BigInt({ + start : my_start_token(M), + end : my_end_token(M), + value : M.value + }); + }, - if (!is("punc", ")")) { - expect(","); - if (is("punc", ")") && options.ecma < 8) unexpected(); - } + EmptyStatement: function(M) { + return new AST_EmptyStatement({ + start: my_start_token(M), + end: my_end_token(M) + }); + }, - if (param instanceof AST_Expansion) { - break; - } - } - - next(); - } - - function parameter(used_parameters, symbol_type) { - var param; - var expand = false; - if (used_parameters === undefined) { - used_parameters = track_used_binding_identifiers(true, S.input.has_directive("use strict")); - } - if (is("expand", "...")) { - expand = S.token; - used_parameters.mark_spread(S.token); - next(); - } - param = binding_element(used_parameters, symbol_type); - - if (is("operator", "=") && expand === false) { - used_parameters.mark_default_assignment(S.token); - next(); - param = new AST_DefaultAssign({ - start: param.start, - left: param, - operator: "=", - right: expression(false), - end: S.token - }); - } - - if (expand !== false) { - if (!is("punc", ")")) { - unexpected(); - } - param = new AST_Expansion({ - start: expand, - expression: param, - end: expand - }); - } - used_parameters.check_strict(); - - return param; - } - - function binding_element(used_parameters, symbol_type) { - var elements = []; - var first = true; - var is_expand = false; - var expand_token; - var first_token = S.token; - if (used_parameters === undefined) { - used_parameters = track_used_binding_identifiers(false, S.input.has_directive("use strict")); - } - symbol_type = symbol_type === undefined ? AST_SymbolFunarg : symbol_type; - if (is("punc", "[")) { - next(); - while (!is("punc", "]")) { - if (first) { - first = false; - } else { - expect(","); - } - - if (is("expand", "...")) { - is_expand = true; - expand_token = S.token; - used_parameters.mark_spread(S.token); - next(); - } - if (is("punc")) { - switch (S.token.value) { - case ",": - elements.push(new AST_Hole({ - start: S.token, - end: S.token - })); - continue; - case "]": // Trailing comma after last element - break; - case "[": - case "{": - elements.push(binding_element(used_parameters, symbol_type)); - break; - default: - unexpected(); - } - } else if (is("name")) { - used_parameters.add_parameter(S.token); - elements.push(as_symbol(symbol_type)); - } else { - croak("Invalid function parameter"); - } - if (is("operator", "=") && is_expand === false) { - used_parameters.mark_default_assignment(S.token); - next(); - elements[elements.length - 1] = new AST_DefaultAssign({ - start: elements[elements.length - 1].start, - left: elements[elements.length - 1], - operator: "=", - right: expression(false), - end: S.token - }); - } - if (is_expand) { - if (!is("punc", "]")) { - croak("Rest element must be last element"); - } - elements[elements.length - 1] = new AST_Expansion({ - start: expand_token, - expression: elements[elements.length - 1], - end: expand_token - }); - } - } - expect("]"); - used_parameters.check_strict(); - return new AST_Destructuring({ - start: first_token, - names: elements, - is_array: true, - end: prev() - }); - } else if (is("punc", "{")) { - next(); - while (!is("punc", "}")) { - if (first) { - first = false; - } else { - expect(","); - } - if (is("expand", "...")) { - is_expand = true; - expand_token = S.token; - used_parameters.mark_spread(S.token); - next(); - } - if (is("name") && (is_token(peek(), "punc") || is_token(peek(), "operator")) && [",", "}", "="].includes(peek().value)) { - used_parameters.add_parameter(S.token); - var start = prev(); - var value = as_symbol(symbol_type); - if (is_expand) { - elements.push(new AST_Expansion({ - start: expand_token, - expression: value, - end: value.end, - })); - } else { - elements.push(new AST_ObjectKeyVal({ - start: start, - key: value.name, - value: value, - end: value.end, - })); - } - } else if (is("punc", "}")) { - continue; // Allow trailing hole - } else { - var property_token = S.token; - var property = as_property_name(); - if (property === null) { - unexpected(prev()); - } else if (prev().type === "name" && !is("punc", ":")) { - elements.push(new AST_ObjectKeyVal({ - start: prev(), - key: property, - value: new symbol_type({ - start: prev(), - name: property, - end: prev() - }), - end: prev() - })); - } else { - expect(":"); - elements.push(new AST_ObjectKeyVal({ - start: property_token, - quote: property_token.quote, - key: property, - value: binding_element(used_parameters, symbol_type), - end: prev() - })); - } - } - if (is_expand) { - if (!is("punc", "}")) { - croak("Rest element must be last element"); - } - } else if (is("operator", "=")) { - used_parameters.mark_default_assignment(S.token); - next(); - elements[elements.length - 1].value = new AST_DefaultAssign({ - start: elements[elements.length - 1].value.start, - left: elements[elements.length - 1].value, - operator: "=", - right: expression(false), - end: S.token - }); - } - } - expect("}"); - used_parameters.check_strict(); - return new AST_Destructuring({ - start: first_token, - names: elements, - is_array: false, - end: prev() - }); - } else if (is("name")) { - used_parameters.add_parameter(S.token); - return as_symbol(symbol_type); - } else { - croak("Invalid function parameter"); - } - } - - function params_or_seq_(allow_arrows, maybe_sequence) { - var spread_token; - var invalid_sequence; - var trailing_comma; - var a = []; - expect("("); - while (!is("punc", ")")) { - if (spread_token) unexpected(spread_token); - if (is("expand", "...")) { - spread_token = S.token; - if (maybe_sequence) invalid_sequence = S.token; - next(); - a.push(new AST_Expansion({ - start: prev(), - expression: expression(), - end: S.token, - })); - } else { - a.push(expression()); - } - if (!is("punc", ")")) { - expect(","); - if (is("punc", ")")) { - if (options.ecma < 8) unexpected(); - trailing_comma = prev(); - if (maybe_sequence) invalid_sequence = trailing_comma; - } - } - } - expect(")"); - if (allow_arrows && is("arrow", "=>")) { - if (spread_token && trailing_comma) unexpected(trailing_comma); - } else if (invalid_sequence) { - unexpected(invalid_sequence); - } - return a; - } - - function _function_body(block, generator, is_async, name, args) { - var loop = S.in_loop; - var labels = S.labels; - var current_generator = S.in_generator; - var current_async = S.in_async; - ++S.in_function; - if (generator) - S.in_generator = S.in_function; - if (is_async) - S.in_async = S.in_function; - if (args) parameters(args); - if (block) - S.in_directives = true; - S.in_loop = 0; - S.labels = []; - if (block) { - S.input.push_directives_stack(); - var a = block_(); - if (name) _verify_symbol(name); - if (args) args.forEach(_verify_symbol); - S.input.pop_directives_stack(); - } else { - var a = expression(false); - } - --S.in_function; - S.in_loop = loop; - S.labels = labels; - S.in_generator = current_generator; - S.in_async = current_async; - return a; - } - - function _await_expression() { - // Previous token must be "await" and not be interpreted as an identifier - if (!is_in_async()) { - croak("Unexpected await expression outside async function", - S.prev.line, S.prev.col, S.prev.pos); - } - // the await expression is parsed as a unary expression in Babel - return new AST_Await({ - start: prev(), - end: S.token, - expression : maybe_unary(true), - }); - } - - function _yield_expression() { - // Previous token must be keyword yield and not be interpret as an identifier - if (!is_in_generator()) { - croak("Unexpected yield expression outside generator function", - S.prev.line, S.prev.col, S.prev.pos); - } - var start = S.token; - var star = false; - var has_expression = true; - - // Attempt to get expression or star (and then the mandatory expression) - // behind yield on the same line. - // - // If nothing follows on the same line of the yieldExpression, - // it should default to the value `undefined` for yield to return. - // In that case, the `undefined` stored as `null` in ast. - // - // Note 1: It isn't allowed for yield* to close without an expression - // Note 2: If there is a nlb between yield and star, it is interpret as - // yield * - if (can_insert_semicolon() || - (is("punc") && PUNC_AFTER_EXPRESSION.has(S.token.value))) { - has_expression = false; - - } else if (is("operator", "*")) { - star = true; - next(); - } - - return new AST_Yield({ - start : start, - is_star : star, - expression : has_expression ? expression() : null, - end : prev() - }); - } - - function if_() { - var cond = parenthesised(), body = statement(false, false, true), belse = null; - if (is("keyword", "else")) { - next(); - belse = statement(false, false, true); - } - return new AST_If({ - condition : cond, - body : body, - alternative : belse - }); - } - - function block_() { - expect("{"); - var a = []; - while (!is("punc", "}")) { - if (is("eof")) unexpected(); - a.push(statement()); - } - next(); - return a; - } - - function switch_body_() { - expect("{"); - var a = [], cur = null, branch = null, tmp; - while (!is("punc", "}")) { - if (is("eof")) unexpected(); - if (is("keyword", "case")) { - if (branch) branch.end = prev(); - cur = []; - branch = new AST_Case({ - start : (tmp = S.token, next(), tmp), - expression : expression(true), - body : cur - }); - a.push(branch); - expect(":"); - } else if (is("keyword", "default")) { - if (branch) branch.end = prev(); - cur = []; - branch = new AST_Default({ - start : (tmp = S.token, next(), expect(":"), tmp), - body : cur - }); - a.push(branch); - } else { - if (!cur) unexpected(); - cur.push(statement()); - } - } - if (branch) branch.end = prev(); - next(); - return a; - } - - function try_() { - var body = block_(), bcatch = null, bfinally = null; - if (is("keyword", "catch")) { - var start = S.token; - next(); - if (is("punc", "{")) { - var name = null; - } else { - expect("("); - var name = parameter(undefined, AST_SymbolCatch); - expect(")"); - } - bcatch = new AST_Catch({ - start : start, - argname : name, - body : block_(), - end : prev() - }); - } - if (is("keyword", "finally")) { - var start = S.token; - next(); - bfinally = new AST_Finally({ - start : start, - body : block_(), - end : prev() - }); - } - if (!bcatch && !bfinally) - croak("Missing catch/finally blocks"); - return new AST_Try({ - body : body, - bcatch : bcatch, - bfinally : bfinally - }); - } - - function vardefs(no_in, kind) { - var a = []; - var def; - for (;;) { - var sym_type = - kind === "var" ? AST_SymbolVar : - kind === "const" ? AST_SymbolConst : - kind === "let" ? AST_SymbolLet : null; - if (is("punc", "{") || is("punc", "[")) { - def = new AST_VarDef({ - start: S.token, - name: binding_element(undefined ,sym_type), - value: is("operator", "=") ? (expect_token("operator", "="), expression(false, no_in)) : null, - end: prev() - }); - } else { - def = new AST_VarDef({ - start : S.token, - name : as_symbol(sym_type), - value : is("operator", "=") - ? (next(), expression(false, no_in)) - : !no_in && kind === "const" - ? croak("Missing initializer in const declaration") : null, - end : prev() - }); - if (def.name.name == "import") croak("Unexpected token: import"); - } - a.push(def); - if (!is("punc", ",")) - break; - next(); - } - return a; - } - - var var_ = function(no_in) { - return new AST_Var({ - start : prev(), - definitions : vardefs(no_in, "var"), - end : prev() - }); - }; + BlockStatement: function(M) { + return new AST_BlockStatement({ + start: my_start_token(M), + end: my_end_token(M), + body: M.body.map(from_moz) + }); + }, + + IfStatement: function(M) { + return new AST_If({ + start: my_start_token(M), + end: my_end_token(M), + condition: from_moz(M.test), + body: from_moz(M.consequent), + alternative: from_moz(M.alternate) + }); + }, + + LabeledStatement: function(M) { + return new AST_LabeledStatement({ + start: my_start_token(M), + end: my_end_token(M), + label: from_moz(M.label), + body: from_moz(M.body) + }); + }, - var let_ = function(no_in) { - return new AST_Let({ - start : prev(), - definitions : vardefs(no_in, "let"), - end : prev() - }); - }; + BreakStatement: function(M) { + return new AST_Break({ + start: my_start_token(M), + end: my_end_token(M), + label: from_moz(M.label) + }); + }, - var const_ = function(no_in) { - return new AST_Const({ - start : prev(), - definitions : vardefs(no_in, "const"), - end : prev() - }); - }; - - var new_ = function(allow_calls) { - var start = S.token; - expect_token("operator", "new"); - if (is("punc", ".")) { - next(); - expect_token("name", "target"); - return subscripts(new AST_NewTarget({ - start : start, - end : prev() - }), allow_calls); - } - var newexp = expr_atom(false), args; - if (is("punc", "(")) { - next(); - args = expr_list(")", options.ecma >= 8); - } else { - args = []; - } - var call = new AST_New({ - start : start, - expression : newexp, - args : args, - end : prev() - }); - mark_pure(call); - return subscripts(call, allow_calls); - }; - - function as_atom_node() { - var tok = S.token, ret; - switch (tok.type) { - case "name": - ret = _make_symbol(AST_SymbolRef); - break; - case "num": - ret = new AST_Number({ start: tok, end: tok, value: tok.value }); - break; - case "big_int": - ret = new AST_BigInt({ start: tok, end: tok, value: tok.value }); - break; - case "string": - ret = new AST_String({ - start : tok, - end : tok, - value : tok.value, - quote : tok.quote - }); - break; - case "regexp": - ret = new AST_RegExp({ start: tok, end: tok, value: tok.value }); - break; - case "atom": - switch (tok.value) { - case "false": - ret = new AST_False({ start: tok, end: tok }); - break; - case "true": - ret = new AST_True({ start: tok, end: tok }); - break; - case "null": - ret = new AST_Null({ start: tok, end: tok }); - break; - } - break; - } - next(); - return ret; - } - - function to_fun_args(ex, _, __, default_seen_above) { - var insert_default = function(ex, default_value) { - if (default_value) { - return new AST_DefaultAssign({ - start: ex.start, - left: ex, - operator: "=", - right: default_value, - end: default_value.end - }); - } - return ex; - }; - if (ex instanceof AST_Object) { - return insert_default(new AST_Destructuring({ - start: ex.start, - end: ex.end, - is_array: false, - names: ex.properties.map(to_fun_args) - }), default_seen_above); - } else if (ex instanceof AST_ObjectKeyVal) { - ex.value = to_fun_args(ex.value, 0, [ex.key]); - return insert_default(ex, default_seen_above); - } else if (ex instanceof AST_Hole) { - return ex; - } else if (ex instanceof AST_Destructuring) { - ex.names = ex.names.map(to_fun_args); - return insert_default(ex, default_seen_above); - } else if (ex instanceof AST_SymbolRef) { - return insert_default(new AST_SymbolFunarg({ - name: ex.name, - start: ex.start, - end: ex.end - }), default_seen_above); - } else if (ex instanceof AST_Expansion) { - ex.expression = to_fun_args(ex.expression); - return insert_default(ex, default_seen_above); - } else if (ex instanceof AST_Array) { - return insert_default(new AST_Destructuring({ - start: ex.start, - end: ex.end, - is_array: true, - names: ex.elements.map(to_fun_args) - }), default_seen_above); - } else if (ex instanceof AST_Assign) { - return insert_default(to_fun_args(ex.left, undefined, undefined, ex.right), default_seen_above); - } else if (ex instanceof AST_DefaultAssign) { - ex.left = to_fun_args(ex.left, 0, [ex.left]); - return ex; - } else { - croak("Invalid function parameter", ex.start.line, ex.start.col); - } - } - - var expr_atom = function(allow_calls, allow_arrows) { - if (is("operator", "new")) { - return new_(allow_calls); - } - var start = S.token; - var peeked; - var async = is("name", "async") - && (peeked = peek()).value != "[" - && peeked.type != "arrow" - && as_atom_node(); - if (is("punc")) { - switch (S.token.value) { - case "(": - if (async && !allow_calls) break; - var exprs = params_or_seq_(allow_arrows, !async); - if (allow_arrows && is("arrow", "=>")) { - return arrow_function(start, exprs.map(to_fun_args), !!async); - } - var ex = async ? new AST_Call({ - expression: async, - args: exprs - }) : exprs.length == 1 ? exprs[0] : new AST_Sequence({ - expressions: exprs - }); - if (ex.start) { - var len = start.comments_before.length; - [].unshift.apply(ex.start.comments_before, start.comments_before); - start.comments_before = ex.start.comments_before; - start.comments_before_length = len; - if (len == 0 && start.comments_before.length > 0) { - var comment = start.comments_before[0]; - if (!comment.nlb) { - comment.nlb = start.nlb; - start.nlb = false; - } - } - start.comments_after = ex.start.comments_after; - } - ex.start = start; - var end = prev(); - if (ex.end) { - end.comments_before = ex.end.comments_before; - [].push.apply(ex.end.comments_after, end.comments_after); - end.comments_after = ex.end.comments_after; - } - ex.end = end; - if (ex instanceof AST_Call) mark_pure(ex); - return subscripts(ex, allow_calls); - case "[": - return subscripts(array_(), allow_calls); - case "{": - return subscripts(object_or_destructuring_(), allow_calls); - } - if (!async) unexpected(); - } - if (allow_arrows && is("name") && is_token(peek(), "arrow")) { - var param = new AST_SymbolFunarg({ - name: S.token.value, - start: start, - end: start, - }); - next(); - return arrow_function(start, [param], !!async); - } - if (is("keyword", "function")) { - next(); - var func = function_(AST_Function, false, !!async); - func.start = start; - func.end = prev(); - return subscripts(func, allow_calls); - } - if (async) return subscripts(async, allow_calls); - if (is("keyword", "class")) { - next(); - var cls = class_(AST_ClassExpression); - cls.start = start; - cls.end = prev(); - return subscripts(cls, allow_calls); - } - if (is("template_head")) { - return subscripts(template_string(), allow_calls); - } - if (ATOMIC_START_TOKEN.has(S.token.type)) { - return subscripts(as_atom_node(), allow_calls); - } - unexpected(); - }; - - function template_string(tagged) { - var segments = [], start = S.token; - - segments.push(new AST_TemplateSegment({ - start: S.token, - raw: S.token.raw, - value: S.token.value, - end: S.token - })); - while (S.token.end === false) { - next(); - handle_regexp(); - segments.push(expression(true)); - - if (!is_token("template_substitution")) { - unexpected(); - } + ContinueStatement: function(M) { + return new AST_Continue({ + start: my_start_token(M), + end: my_end_token(M), + label: from_moz(M.label) + }); + }, + + WithStatement: function(M) { + return new AST_With({ + start: my_start_token(M), + end: my_end_token(M), + expression: from_moz(M.object), + body: from_moz(M.body) + }); + }, + + SwitchStatement: function(M) { + return new AST_Switch({ + start: my_start_token(M), + end: my_end_token(M), + expression: from_moz(M.discriminant), + body: M.cases.map(from_moz) + }); + }, - segments.push(new AST_TemplateSegment({ - start: S.token, - raw: S.token.raw, - value: S.token.value, - end: S.token - })); - } - next(); - - return new AST_TemplateString({ - start: start, - segments: segments, - end: S.token - }); - } - - function expr_list(closing, allow_trailing_comma, allow_empty) { - var first = true, a = []; - while (!is("punc", closing)) { - if (first) first = false; else expect(","); - if (allow_trailing_comma && is("punc", closing)) break; - if (is("punc", ",") && allow_empty) { - a.push(new AST_Hole({ start: S.token, end: S.token })); - } else if (is("expand", "...")) { - next(); - a.push(new AST_Expansion({start: prev(), expression: expression(),end: S.token})); - } else { - a.push(expression(false)); - } - } - next(); - return a; - } - - var array_ = embed_tokens(function() { - expect("["); - return new AST_Array({ - elements: expr_list("]", !options.strict, true) - }); - }); - - var create_accessor = embed_tokens(function(is_generator, is_async) { - return function_(AST_Accessor, is_generator, is_async); - }); - - var object_or_destructuring_ = embed_tokens(function object_or_destructuring_() { - var start = S.token, first = true, a = []; - expect("{"); - while (!is("punc", "}")) { - if (first) first = false; else expect(","); - if (!options.strict && is("punc", "}")) - // allow trailing comma - break; - - start = S.token; - if (start.type == "expand") { - next(); - a.push(new AST_Expansion({ - start: start, - expression: expression(false), - end: prev(), - })); - continue; - } + ReturnStatement: function(M) { + return new AST_Return({ + start: my_start_token(M), + end: my_end_token(M), + value: from_moz(M.argument) + }); + }, - var name = as_property_name(); - var value; - - // Check property and fetch value - if (!is("punc", ":")) { - var concise = concise_method_or_getset(name, start); - if (concise) { - a.push(concise); - continue; - } - - value = new AST_SymbolRef({ - start: prev(), - name: name, - end: prev() - }); - } else if (name === null) { - unexpected(prev()); - } else { - next(); // `:` - see first condition - value = expression(false); - } + ThrowStatement: function(M) { + return new AST_Throw({ + start: my_start_token(M), + end: my_end_token(M), + value: from_moz(M.argument) + }); + }, + + WhileStatement: function(M) { + return new AST_While({ + start: my_start_token(M), + end: my_end_token(M), + condition: from_moz(M.test), + body: from_moz(M.body) + }); + }, + + DoWhileStatement: function(M) { + return new AST_Do({ + start: my_start_token(M), + end: my_end_token(M), + condition: from_moz(M.test), + body: from_moz(M.body) + }); + }, + + ForStatement: function(M) { + return new AST_For({ + start: my_start_token(M), + end: my_end_token(M), + init: from_moz(M.init), + condition: from_moz(M.test), + step: from_moz(M.update), + body: from_moz(M.body) + }); + }, + + ForInStatement: function(M) { + return new AST_ForIn({ + start: my_start_token(M), + end: my_end_token(M), + init: from_moz(M.left), + object: from_moz(M.right), + body: from_moz(M.body) + }); + }, + + ForOfStatement: function(M) { + return new AST_ForOf({ + start: my_start_token(M), + end: my_end_token(M), + init: from_moz(M.left), + object: from_moz(M.right), + body: from_moz(M.body), + await: M.await + }); + }, - // Check for default value and alter value accordingly if necessary - if (is("operator", "=")) { - next(); - value = new AST_Assign({ - start: start, - left: value, - operator: "=", - right: expression(false), - end: prev() - }); - } + AwaitExpression: function(M) { + return new AST_Await({ + start: my_start_token(M), + end: my_end_token(M), + expression: from_moz(M.argument) + }); + }, + + YieldExpression: function(M) { + return new AST_Yield({ + start: my_start_token(M), + end: my_end_token(M), + expression: from_moz(M.argument), + is_star: M.delegate + }); + }, - // Create property - a.push(new AST_ObjectKeyVal({ - start: start, - quote: start.quote, - key: name instanceof AST_Node ? name : "" + name, - value: value, - end: prev() - })); - } - next(); - return new AST_Object({ properties: a }); - }); - - function class_(KindOfClass) { - var start, method, class_name, extends_, a = []; - - S.input.push_directives_stack(); // Push directive stack, but not scope stack - S.input.add_directive("use strict"); - - if (S.token.type == "name" && S.token.value != "extends") { - class_name = as_symbol(KindOfClass === AST_DefClass ? AST_SymbolDefClass : AST_SymbolClass); - } - - if (KindOfClass === AST_DefClass && !class_name) { - unexpected(); - } - - if (S.token.value == "extends") { - next(); - extends_ = expression(true); - } - - expect("{"); - - if (is("punc", ";")) { next(); } // Leading semicolons are okay in class bodies. - while (!is("punc", "}")) { - start = S.token; - method = concise_method_or_getset(as_property_name(), start, true); - if (!method) { unexpected(); } - a.push(method); - if (is("punc", ";")) { next(); } - } - - S.input.pop_directives_stack(); - - next(); - - return new KindOfClass({ - start: start, - name: class_name, - extends: extends_, - properties: a, - end: prev(), - }); - } - - function concise_method_or_getset(name, start, is_class) { - var get_ast = function(name, token) { - if (typeof name === "string" || typeof name === "number") { - return new AST_SymbolMethod({ - start: token, - name: "" + name, - end: prev() - }); - } else if (name === null) { - unexpected(); - } - return name; - }; - var is_async = false; - var is_static = false; - var is_generator = false; - var property_token = start; - if (is_class && name === "static" && !is("punc", "(")) { - is_static = true; - property_token = S.token; - name = as_property_name(); - } - if (name === "async" && !is("punc", "(") && !is("punc", ",") && !is("punc", "}")) { - is_async = true; - property_token = S.token; - name = as_property_name(); - } - if (name === null) { - is_generator = true; - property_token = S.token; - name = as_property_name(); - if (name === null) { - unexpected(); - } - } - if (is("punc", "(")) { - name = get_ast(name, start); - var node = new AST_ConciseMethod({ - start : start, - static : is_static, - is_generator: is_generator, - async : is_async, - key : name, - quote : name instanceof AST_SymbolMethod ? - property_token.quote : undefined, - value : create_accessor(is_generator, is_async), - end : prev() - }); - return node; - } - property_token = S.token; - if (name == "get") { - if (!is("punc") || is("punc", "[")) { - name = get_ast(as_property_name(), start); - return new AST_ObjectGetter({ - start : start, - static: is_static, - key : name, - quote : name instanceof AST_SymbolMethod ? - property_token.quote : undefined, - value : create_accessor(), - end : prev() - }); - } - } else if (name == "set") { - if (!is("punc") || is("punc", "[")) { - name = get_ast(as_property_name(), start); - return new AST_ObjectSetter({ - start : start, - static: is_static, - key : name, - quote : name instanceof AST_SymbolMethod ? - property_token.quote : undefined, - value : create_accessor(), - end : prev() - }); - } - } - } - - function import_() { - var start = prev(); - var imported_name; - var imported_names; - if (is("name")) { - imported_name = as_symbol(AST_SymbolImport); - } - - if (is("punc", ",")) { - next(); - } - - imported_names = map_names(true); - - if (imported_names || imported_name) { - expect_token("name", "from"); - } - var mod_str = S.token; - if (mod_str.type !== "string") { - unexpected(); - } - next(); - return new AST_Import({ - start: start, - imported_name: imported_name, - imported_names: imported_names, - module_name: new AST_String({ - start: mod_str, - value: mod_str.value, - quote: mod_str.quote, - end: mod_str, - }), - end: S.token, - }); - } - - function map_name(is_import) { - function make_symbol(type) { - return new type({ - name: as_property_name(), - start: prev(), - end: prev() - }); - } - - var foreign_type = is_import ? AST_SymbolImportForeign : AST_SymbolExportForeign; - var type = is_import ? AST_SymbolImport : AST_SymbolExport; - var start = S.token; - var foreign_name; - var name; - - if (is_import) { - foreign_name = make_symbol(foreign_type); - } else { - name = make_symbol(type); - } - if (is("name", "as")) { - next(); // The "as" word - if (is_import) { - name = make_symbol(type); - } else { - foreign_name = make_symbol(foreign_type); - } - } else if (is_import) { - name = new type(foreign_name); - } else { - foreign_name = new foreign_type(name); - } - - return new AST_NameMapping({ - start: start, - foreign_name: foreign_name, - name: name, - end: prev(), - }); - } - - function map_nameAsterisk(is_import, name) { - var foreign_type = is_import ? AST_SymbolImportForeign : AST_SymbolExportForeign; - var type = is_import ? AST_SymbolImport : AST_SymbolExport; - var start = S.token; - var foreign_name; - var end = prev(); - - name = name || new type({ - name: "*", - start: start, - end: end, - }); + DebuggerStatement: function(M) { + return new AST_Debugger({ + start: my_start_token(M), + end: my_end_token(M) + }); + }, + + VariableDeclarator: function(M) { + return new AST_VarDef({ + start: my_start_token(M), + end: my_end_token(M), + name: from_moz(M.id), + value: from_moz(M.init) + }); + }, + + CatchClause: function(M) { + return new AST_Catch({ + start: my_start_token(M), + end: my_end_token(M), + argname: from_moz(M.param), + body: from_moz(M.body).body + }); + }, - foreign_name = new foreign_type({ - name: "*", - start: start, - end: end, - }); + ThisExpression: function(M) { + return new AST_This({ + start: my_start_token(M), + end: my_end_token(M) + }); + }, - return new AST_NameMapping({ - start: start, - foreign_name: foreign_name, - name: name, - end: end, - }); - } - - function map_names(is_import) { - var names; - if (is("punc", "{")) { - next(); - names = []; - while (!is("punc", "}")) { - names.push(map_name(is_import)); - if (is("punc", ",")) { - next(); - } - } - next(); - } else if (is("operator", "*")) { - var name; - next(); - if (is_import && is("name", "as")) { - next(); // The "as" word - name = as_symbol(is_import ? AST_SymbolImport : AST_SymbolExportForeign); - } - names = [map_nameAsterisk(is_import, name)]; - } - return names; - } - - function export_() { - var start = S.token; - var is_default; - var exported_names; - - if (is("keyword", "default")) { - is_default = true; - next(); - } else if (exported_names = map_names(false)) { - if (is("name", "from")) { - next(); - - var mod_str = S.token; - if (mod_str.type !== "string") { - unexpected(); - } - next(); - - return new AST_Export({ - start: start, - is_default: is_default, - exported_names: exported_names, - module_name: new AST_String({ - start: mod_str, - value: mod_str.value, - quote: mod_str.quote, - end: mod_str, - }), - end: prev(), - }); - } else { - return new AST_Export({ - start: start, - is_default: is_default, - exported_names: exported_names, - end: prev(), - }); - } - } - - var node; - var exported_value; - var exported_definition; - if (is("punc", "{") - || is_default - && (is("keyword", "class") || is("keyword", "function")) - && is_token(peek(), "punc")) { - exported_value = expression(false); - semicolon(); - } else if ((node = statement(is_default)) instanceof AST_Definitions && is_default) { - unexpected(node.start); - } else if (node instanceof AST_Definitions || node instanceof AST_Lambda || node instanceof AST_DefClass) { - exported_definition = node; - } else if (node instanceof AST_SimpleStatement) { - exported_value = node.body; - } else { - unexpected(node.start); - } - - return new AST_Export({ - start: start, - is_default: is_default, - exported_value: exported_value, - exported_definition: exported_definition, - end: prev(), - }); - } - - function as_property_name() { - var tmp = S.token; - switch (tmp.type) { - case "punc": - if (tmp.value === "[") { - next(); - var ex = expression(false); - expect("]"); - return ex; - } else unexpected(tmp); - case "operator": - if (tmp.value === "*") { - next(); - return null; - } - if (!["delete", "in", "instanceof", "new", "typeof", "void"].includes(tmp.value)) { - unexpected(tmp); - } - case "name": - if (tmp.value == "yield") { - if (is_in_generator()) { - token_error(tmp, "Yield cannot be used as identifier inside generators"); - } else if (!is_token(peek(), "punc", ":") - && !is_token(peek(), "punc", "(") - && S.input.has_directive("use strict")) { - token_error(tmp, "Unexpected yield identifier inside strict mode"); - } - } - case "string": - case "num": - case "big_int": - case "keyword": - case "atom": - next(); - return tmp.value; - default: - unexpected(tmp); - } - } - - function as_name() { - var tmp = S.token; - if (tmp.type != "name") unexpected(); - next(); - return tmp.value; - } - - function _make_symbol(type) { - var name = S.token.value; - return new (name == "this" ? AST_This : - name == "super" ? AST_Super : - type)({ - name : String(name), - start : S.token, - end : S.token - }); - } - - function _verify_symbol(sym) { - var name = sym.name; - if (is_in_generator() && name == "yield") { - token_error(sym.start, "Yield cannot be used as identifier inside generators"); - } - if (S.input.has_directive("use strict")) { - if (name == "yield") { - token_error(sym.start, "Unexpected yield identifier inside strict mode"); - } - if (sym instanceof AST_SymbolDeclaration && (name == "arguments" || name == "eval")) { - token_error(sym.start, "Unexpected " + name + " in strict mode"); - } - } - } - - function as_symbol(type, noerror) { - if (!is("name")) { - if (!noerror) croak("Name expected"); - return null; - } - var sym = _make_symbol(type); - _verify_symbol(sym); - next(); - return sym; - } - - function mark_pure(call) { - var start = call.start; - var comments = start.comments_before; - var i = HOP(start, "comments_before_length") ? start.comments_before_length : comments.length; - while (--i >= 0) { - var comment = comments[i]; - if (/[@#]__PURE__/.test(comment.value)) { - call.pure = comment; - break; - } - } - } - - var subscripts = function(expr, allow_calls) { - var start = expr.start; - if (is("punc", ".")) { - next(); - return subscripts(new AST_Dot({ - start : start, - expression : expr, - property : as_name(), - end : prev() - }), allow_calls); - } - if (is("punc", "[")) { - next(); - var prop = expression(true); - expect("]"); - return subscripts(new AST_Sub({ - start : start, - expression : expr, - property : prop, - end : prev() - }), allow_calls); - } - if (allow_calls && is("punc", "(")) { - next(); - var call = new AST_Call({ - start : start, - expression : expr, - args : call_args(), - end : prev() - }); - mark_pure(call); - return subscripts(call, true); - } - if (is("template_head")) { - return subscripts(new AST_PrefixedTemplateString({ - start: start, - prefix: expr, - template_string: template_string(), - end: prev() - }), allow_calls); - } - return expr; - }; - - var call_args = embed_tokens(function _call_args() { - var args = []; - while (!is("punc", ")")) { - if (is("expand", "...")) { - next(); - args.push(new AST_Expansion({ - start: prev(), - expression: expression(false), - end: prev() - })); - } else { - args.push(expression(false)); - } - if (!is("punc", ")")) { - expect(","); - if (is("punc", ")") && options.ecma < 8) unexpected(); - } - } - next(); - return args; - }); - - var maybe_unary = function(allow_calls, allow_arrows) { - var start = S.token; - if (start.type == "name" && start.value == "await") { - if (is_in_async()) { - next(); - return _await_expression(); - } else if (S.input.has_directive("use strict")) { - token_error(S.token, "Unexpected await identifier inside strict mode"); - } - } - if (is("operator") && UNARY_PREFIX.has(start.value)) { - next(); - handle_regexp(); - var ex = make_unary(AST_UnaryPrefix, start, maybe_unary(allow_calls)); - ex.start = start; - ex.end = prev(); - return ex; - } - var val = expr_atom(allow_calls, allow_arrows); - while (is("operator") && UNARY_POSTFIX.has(S.token.value) && !has_newline_before(S.token)) { - if (val instanceof AST_Arrow) unexpected(); - val = make_unary(AST_UnaryPostfix, S.token, val); - val.start = start; - val.end = S.token; - next(); - } - return val; - }; - - function make_unary(ctor, token, expr) { - var op = token.value; - switch (op) { - case "++": - case "--": - if (!is_assignable(expr)) - croak("Invalid use of " + op + " operator", token.line, token.col, token.pos); - break; - case "delete": - if (expr instanceof AST_SymbolRef && S.input.has_directive("use strict")) - croak("Calling delete on expression not allowed in strict mode", expr.start.line, expr.start.col, expr.start.pos); - break; - } - return new ctor({ operator: op, expression: expr }); - } - - var expr_op = function(left, min_prec, no_in) { - var op = is("operator") ? S.token.value : null; - if (op == "in" && no_in) op = null; - if (op == "**" && left instanceof AST_UnaryPrefix - /* unary token in front not allowed - parenthesis required */ - && !is_token(left.start, "punc", "(") - && left.operator !== "--" && left.operator !== "++") - unexpected(left.start); - var prec = op != null ? PRECEDENCE[op] : null; - if (prec != null && (prec > min_prec || (op === "**" && min_prec === prec))) { - next(); - var right = expr_op(maybe_unary(true), prec, no_in); - return expr_op(new AST_Binary({ - start : left.start, - left : left, - operator : op, - right : right, - end : right.end - }), min_prec, no_in); - } - return left; - }; - - function expr_ops(no_in) { - return expr_op(maybe_unary(true, true), 0, no_in); - } - - var maybe_conditional = function(no_in) { - var start = S.token; - var expr = expr_ops(no_in); - if (is("operator", "?")) { - next(); - var yes = expression(false); - expect(":"); - return new AST_Conditional({ - start : start, - condition : expr, - consequent : yes, - alternative : expression(false, no_in), - end : prev() - }); - } - return expr; - }; - - function is_assignable(expr) { - return expr instanceof AST_PropAccess || expr instanceof AST_SymbolRef; - } - - function to_destructuring(node) { - if (node instanceof AST_Object) { - node = new AST_Destructuring({ - start: node.start, - names: node.properties.map(to_destructuring), - is_array: false, - end: node.end - }); - } else if (node instanceof AST_Array) { - var names = []; - - for (var i = 0; i < node.elements.length; i++) { - // Only allow expansion as last element - if (node.elements[i] instanceof AST_Expansion) { - if (i + 1 !== node.elements.length) { - token_error(node.elements[i].start, "Spread must the be last element in destructuring array"); - } - node.elements[i].expression = to_destructuring(node.elements[i].expression); - } - - names.push(to_destructuring(node.elements[i])); - } + Super: function(M) { + return new AST_Super({ + start: my_start_token(M), + end: my_end_token(M) + }); + }, + + BinaryExpression: function(M) { + if (M.left.type === "PrivateIdentifier") { + return new AST_PrivateIn({ + start: my_start_token(M), + end: my_end_token(M), + key: new AST_SymbolPrivateProperty({ + start: my_start_token(M.left), + end: my_end_token(M.left), + name: M.left.name + }), + value: from_moz(M.right), + }); + } + return new AST_Binary({ + start: my_start_token(M), + end: my_end_token(M), + operator: M.operator, + left: from_moz(M.left), + right: from_moz(M.right) + }); + }, + + LogicalExpression: function(M) { + return new AST_Binary({ + start: my_start_token(M), + end: my_end_token(M), + operator: M.operator, + left: from_moz(M.left), + right: from_moz(M.right) + }); + }, + + AssignmentExpression: function(M) { + return new AST_Assign({ + start: my_start_token(M), + end: my_end_token(M), + operator: M.operator, + left: from_moz(M.left), + right: from_moz(M.right) + }); + }, + + ConditionalExpression: function(M) { + return new AST_Conditional({ + start: my_start_token(M), + end: my_end_token(M), + condition: from_moz(M.test), + consequent: from_moz(M.consequent), + alternative: from_moz(M.alternate) + }); + }, + + NewExpression: function(M) { + return new AST_New({ + start: my_start_token(M), + end: my_end_token(M), + expression: from_moz(M.callee), + args: M.arguments.map(from_moz) + }); + }, - node = new AST_Destructuring({ - start: node.start, - names: names, - is_array: true, - end: node.end - }); - } else if (node instanceof AST_ObjectProperty) { - node.value = to_destructuring(node.value); - } else if (node instanceof AST_Assign) { - node = new AST_DefaultAssign({ - start: node.start, - left: node.left, - operator: "=", - right: node.right, - end: node.end - }); - } - return node; - } - - // In ES6, AssignmentExpression can also be an ArrowFunction - var maybe_assign = function(no_in) { - handle_regexp(); - var start = S.token; - - if (start.type == "name" && start.value == "yield") { - if (is_in_generator()) { - next(); - return _yield_expression(); - } else if (S.input.has_directive("use strict")) { - token_error(S.token, "Unexpected yield identifier inside strict mode"); - } - } - - var left = maybe_conditional(no_in); - var val = S.token.value; - - if (is("operator") && ASSIGNMENT.has(val)) { - if (is_assignable(left) || (left = to_destructuring(left)) instanceof AST_Destructuring) { - next(); - return new AST_Assign({ - start : start, - left : left, - operator : val, - right : maybe_assign(no_in), - end : prev() - }); - } - croak("Invalid assignment"); - } - return left; - }; - - var expression = function(commas, no_in) { - var start = S.token; - var exprs = []; - while (true) { - exprs.push(maybe_assign(no_in)); - if (!commas || !is("punc", ",")) break; - next(); - commas = true; - } - return exprs.length == 1 ? exprs[0] : new AST_Sequence({ - start : start, - expressions : exprs, - end : peek() - }); - }; - - function in_loop(cont) { - ++S.in_loop; - var ret = cont(); - --S.in_loop; - return ret; - } - - if (options.expression) { - return expression(true); - } - - return (function() { - var start = S.token; - var body = []; - S.input.push_directives_stack(); - if (options.module) S.input.add_directive("use strict"); - while (!is("eof")) - body.push(statement()); - S.input.pop_directives_stack(); - var end = prev(); - var toplevel = options.toplevel; - if (toplevel) { - toplevel.body = toplevel.body.concat(body); - toplevel.end = end; - } else { - toplevel = new AST_Toplevel({ start: start, body: body, end: end }); - } - return toplevel; - })(); - - } - - /*********************************************************************** - - A JavaScript tokenizer / parser / beautifier / compressor. - https://github.com/mishoo/UglifyJS2 - - -------------------------------- (C) --------------------------------- - - Author: Mihai Bazon - - http://mihai.bazon.net/blog - - Distributed under the BSD license: - - Copyright 2012 (c) Mihai Bazon - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - * Redistributions of source code must retain the above - copyright notice, this list of conditions and the following - disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials - provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY - EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - SUCH DAMAGE. - - ***********************************************************************/ - - function DEFNODE(type, props, methods, base = AST_Node) { - if (!props) props = []; - else props = props.split(/\s+/); - var self_props = props; - if (base && base.PROPS) - props = props.concat(base.PROPS); - var code = "return function AST_" + type + "(props){ if (props) { "; - for (var i = props.length; --i >= 0;) { - code += "this." + props[i] + " = props." + props[i] + ";"; - } - var proto = base && new base; - if (proto && proto.initialize || (methods && methods.initialize)) - code += "this.initialize();"; - code += "}}"; - var ctor = new Function(code)(); - if (proto) { - ctor.prototype = proto; - ctor.BASE = base; - } - if (base) base.SUBCLASSES.push(ctor); - ctor.prototype.CTOR = ctor; - ctor.PROPS = props || null; - ctor.SELF_PROPS = self_props; - ctor.SUBCLASSES = []; - if (type) { - ctor.prototype.TYPE = ctor.TYPE = type; - } - if (methods) for (i in methods) if (HOP(methods, i)) { - if (i[0] === "$") { - ctor[i.substr(1)] = methods[i]; - } else { - ctor.prototype[i] = methods[i]; - } - } - ctor.DEFMETHOD = function(name, method) { - this.prototype[name] = method; - }; - return ctor; - } - - var AST_Token = DEFNODE("Token", "type value line col pos endline endcol endpos nlb comments_before comments_after file raw", { - }, null); - - var AST_Node = DEFNODE("Node", "start end", { - _clone: function(deep) { - if (deep) { - var self = this.clone(); - return self.transform(new TreeTransformer(function(node) { - if (node !== self) { - return node.clone(true); - } - })); - } - return new this.CTOR(this); - }, - clone: function(deep) { - return this._clone(deep); - }, - $documentation: "Base class of all AST nodes", - $propdoc: { - start: "[AST_Token] The first token of this node", - end: "[AST_Token] The last token of this node" - }, - _walk: function(visitor) { - return visitor._visit(this); - }, - walk: function(visitor) { - return this._walk(visitor); // not sure the indirection will be any help - } - }, null); - - AST_Node.warn_function = null; - AST_Node.warn = function(txt, props) { - if (AST_Node.warn_function) - AST_Node.warn_function(string_template(txt, props)); - }; - - /* -----[ statements ]----- */ - - var AST_Statement = DEFNODE("Statement", null, { - $documentation: "Base class of all statements", - }); - - var AST_Debugger = DEFNODE("Debugger", null, { - $documentation: "Represents a debugger statement", - }, AST_Statement); - - var AST_Directive = DEFNODE("Directive", "value quote", { - $documentation: "Represents a directive, like \"use strict\";", - $propdoc: { - value: "[string] The value of this directive as a plain string (it's not an AST_String!)", - quote: "[string] the original quote character" - }, - }, AST_Statement); - - var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", { - $documentation: "A statement consisting of an expression, i.e. a = 1 + 2", - $propdoc: { - body: "[AST_Node] an expression node (should not be instanceof AST_Statement)" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.body._walk(visitor); - }); - } - }, AST_Statement); - - // XXX Emscripten localmod: Add a node type for a parenthesized expression so that we can retain - // Closure annotations that need a form "/**annotation*/(expression)" - var AST_ParenthesizedExpression = DEFNODE("ParenthesizedExpression", "body", { - $documentation: "An explicitly parenthesized expression, i.e. a = (1 + 2)", - $propdoc: { - body: "[AST_Node] an expression node (should not be instanceof AST_Statement)" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.body._walk(visitor); - }); - } - }, AST_Statement); - // XXX End of Emscripten localmod - - function walk_body(node, visitor) { - var body = node.body; - if (body instanceof AST_Node) { - body._walk(visitor); - } else for (var i = 0, len = body.length; i < len; i++) { - body[i]._walk(visitor); - } - } - - function clone_block_scope(deep) { - var clone = this._clone(deep); - if (this.block_scope) { - // TODO this is sometimes undefined during compression. - // But it should always have a value! - clone.block_scope = this.block_scope.clone(); - } - return clone; - } - - var AST_Block = DEFNODE("Block", "body block_scope", { - $documentation: "A body of statements (usually braced)", - $propdoc: { - body: "[AST_Statement*] an array of statements", - block_scope: "[AST_Scope] the block scope" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - walk_body(this, visitor); - }); - }, - clone: clone_block_scope - }, AST_Statement); - - var AST_BlockStatement = DEFNODE("BlockStatement", null, { - $documentation: "A block statement", - }, AST_Block); - - var AST_EmptyStatement = DEFNODE("EmptyStatement", null, { - $documentation: "The empty statement (empty block or simply a semicolon)" - }, AST_Statement); - - var AST_StatementWithBody = DEFNODE("StatementWithBody", "body", { - $documentation: "Base class for all statements that contain one nested body: `For`, `ForIn`, `Do`, `While`, `With`", - $propdoc: { - body: "[AST_Statement] the body; this should always be present, even if it's an AST_EmptyStatement" - } - }, AST_Statement); - - var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", { - $documentation: "Statement with a label", - $propdoc: { - label: "[AST_Label] a label definition" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.label._walk(visitor); - this.body._walk(visitor); - }); - }, - clone: function(deep) { - var node = this._clone(deep); - if (deep) { - var label = node.label; - var def = this.label; - node.walk(new TreeWalker(function(node) { - if (node instanceof AST_LoopControl - && node.label && node.label.thedef === def) { - node.label.thedef = label; - label.references.push(node); - } - })); - } - return node; - } - }, AST_StatementWithBody); - - var AST_IterationStatement = DEFNODE("IterationStatement", "block_scope", { - $documentation: "Internal class. All loops inherit from it.", - $propdoc: { - block_scope: "[AST_Scope] the block scope for this iteration statement." - }, - clone: clone_block_scope - }, AST_StatementWithBody); - - var AST_DWLoop = DEFNODE("DWLoop", "condition", { - $documentation: "Base class for do/while statements", - $propdoc: { - condition: "[AST_Node] the loop condition. Should not be instanceof AST_Statement" - } - }, AST_IterationStatement); - - var AST_Do = DEFNODE("Do", null, { - $documentation: "A `do` statement", - _walk: function(visitor) { - return visitor._visit(this, function() { - this.body._walk(visitor); - this.condition._walk(visitor); + CallExpression: function(M) { + return new AST_Call({ + start: my_start_token(M), + end: my_end_token(M), + expression: from_moz(M.callee), + optional: M.optional, + args: M.arguments.map(from_moz) + }); + }, + + ImportExpression: function(M) { + let import_token = my_start_token(M); + return new AST_Call({ + start : import_token, + end : my_end_token(M), + expression : new AST_SymbolRef({ + start : import_token, + end : import_token, + name : "import" + }), + args : [from_moz(M.source)] }); - } - }, AST_DWLoop); - - var AST_While = DEFNODE("While", null, { - $documentation: "A `while` statement", - _walk: function(visitor) { - return visitor._visit(this, function() { - this.condition._walk(visitor); - this.body._walk(visitor); - }); - } - }, AST_DWLoop); - - var AST_For = DEFNODE("For", "init condition step", { - $documentation: "A `for` statement", - $propdoc: { - init: "[AST_Node?] the `for` initialization code, or null if empty", - condition: "[AST_Node?] the `for` termination clause, or null if empty", - step: "[AST_Node?] the `for` update clause, or null if empty" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - if (this.init) this.init._walk(visitor); - if (this.condition) this.condition._walk(visitor); - if (this.step) this.step._walk(visitor); - this.body._walk(visitor); - }); - } - }, AST_IterationStatement); - - var AST_ForIn = DEFNODE("ForIn", "init object", { - $documentation: "A `for ... in` statement", - $propdoc: { - init: "[AST_Node] the `for/in` initialization code", - object: "[AST_Node] the object that we're looping through" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.init._walk(visitor); - this.object._walk(visitor); - this.body._walk(visitor); - }); - } - }, AST_IterationStatement); - - var AST_ForOf = DEFNODE("ForOf", "await", { - $documentation: "A `for ... of` statement", - }, AST_ForIn); - - var AST_With = DEFNODE("With", "expression", { - $documentation: "A `with` statement", - $propdoc: { - expression: "[AST_Node] the `with` expression" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.expression._walk(visitor); - this.body._walk(visitor); - }); - } - }, AST_StatementWithBody); - - /* -----[ scope and functions ]----- */ - - var AST_Scope = DEFNODE("Scope", "variables functions uses_with uses_eval parent_scope enclosed cname", { - $documentation: "Base class for all statements introducing a lexical scope", - $propdoc: { - variables: "[Map/S] a map of name -> SymbolDef for all variables/functions defined in this scope", - functions: "[Map/S] like `variables`, but only lists function declarations", - uses_with: "[boolean/S] tells whether this scope uses the `with` statement", - uses_eval: "[boolean/S] tells whether this scope contains a direct call to the global `eval`", - parent_scope: "[AST_Scope?/S] link to the parent scope", - enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes", - cname: "[integer/S] current index for mangling variables (used internally by the mangler)", - }, - get_defun_scope: function() { - var self = this; - while (self.is_block_scope()) { - self = self.parent_scope; - } - return self; - }, - clone: function(deep) { - var node = this._clone(deep); - if (this.variables) node.variables = new Map(this.variables); - if (this.functions) node.functions = new Map(this.functions); - if (this.enclosed) node.enclosed = this.enclosed.slice(); - return node; - }, - pinned: function() { - return this.uses_eval || this.uses_with; - } - }, AST_Block); - - var AST_Toplevel = DEFNODE("Toplevel", "globals", { - $documentation: "The toplevel scope", - $propdoc: { - globals: "[Map/S] a map of name -> SymbolDef for all undeclared names", - }, - wrap_commonjs: function(name) { - var body = this.body; - var wrapped_tl = "(function(exports){'$ORIG';})(typeof " + name + "=='undefined'?(" + name + "={}):" + name + ");"; - wrapped_tl = parse(wrapped_tl); - wrapped_tl = wrapped_tl.transform(new TreeTransformer(function(node) { - if (node instanceof AST_Directive && node.value == "$ORIG") { - return MAP.splice(body); - } - })); - return wrapped_tl; - }, - wrap_enclose: function(args_values) { - if (typeof args_values != "string") args_values = ""; - var index = args_values.indexOf(":"); - if (index < 0) index = args_values.length; - var body = this.body; - return parse([ - "(function(", - args_values.slice(0, index), - '){"$ORIG"})(', - args_values.slice(index + 1), - ")" - ].join("")).transform(new TreeTransformer(function(node) { - if (node instanceof AST_Directive && node.value == "$ORIG") { - return MAP.splice(body); - } - })); - } - }, AST_Scope); - - var AST_Expansion = DEFNODE("Expansion", "expression", { - $documentation: "An expandible argument, such as ...rest, a splat, such as [1,2,...all], or an expansion in a variable declaration, such as var [first, ...rest] = list", - $propdoc: { - expression: "[AST_Node] the thing to be expanded" - }, - _walk: function(visitor) { - var self = this; - return visitor._visit(this, function() { - self.expression.walk(visitor); - }); - } - }); - - var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments is_generator async", { - $documentation: "Base class for functions", - $propdoc: { - name: "[AST_SymbolDeclaration?] the name of this function", - argnames: "[AST_SymbolFunarg|AST_Destructuring|AST_Expansion|AST_DefaultAssign*] array of function arguments, destructurings, or expanding arguments", - uses_arguments: "[boolean/S] tells whether this function accesses the arguments array", - is_generator: "[boolean] is this a generator method", - async: "[boolean] is this method async", - }, - args_as_names: function () { - var out = []; - for (var i = 0; i < this.argnames.length; i++) { - if (this.argnames[i] instanceof AST_Destructuring) { - out = out.concat(this.argnames[i].all_symbols()); - } else { - out.push(this.argnames[i]); - } - } - return out; - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - if (this.name) this.name._walk(visitor); - var argnames = this.argnames; - for (var i = 0, len = argnames.length; i < len; i++) { - argnames[i]._walk(visitor); - } - walk_body(this, visitor); - }); - } - }, AST_Scope); - - var AST_Accessor = DEFNODE("Accessor", null, { - $documentation: "A setter/getter function. The `name` property is always null." - }, AST_Lambda); - - var AST_Function = DEFNODE("Function", "inlined", { - $documentation: "A function expression" - }, AST_Lambda); - - var AST_Arrow = DEFNODE("Arrow", "inlined", { - $documentation: "An ES6 Arrow function ((a) => b)" - }, AST_Lambda); - - var AST_Defun = DEFNODE("Defun", "inlined", { - $documentation: "A function definition" - }, AST_Lambda); - - /* -----[ DESTRUCTURING ]----- */ - var AST_Destructuring = DEFNODE("Destructuring", "names is_array", { - $documentation: "A destructuring of several names. Used in destructuring assignment and with destructuring function argument names", - $propdoc: { - "names": "[AST_Node*] Array of properties or elements", - "is_array": "[Boolean] Whether the destructuring represents an object or array" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.names.forEach(function(name) { - name._walk(visitor); - }); - }); - }, - all_symbols: function() { - var out = []; - this.walk(new TreeWalker(function (node) { - if (node instanceof AST_Symbol) { - out.push(node); - } - if (node instanceof AST_Expansion) { - out.push(node.expression); - } - })); - return out; - } - }); - - var AST_PrefixedTemplateString = DEFNODE("PrefixedTemplateString", "template_string prefix", { - $documentation: "A templatestring with a prefix, such as String.raw`foobarbaz`", - $propdoc: { - template_string: "[AST_TemplateString] The template string", - prefix: "[AST_SymbolRef|AST_PropAccess] The prefix, which can be a symbol such as `foo` or a dotted expression such as `String.raw`." - }, - _walk: function(visitor) { - this.prefix._walk(visitor); - this.template_string._walk(visitor); - } - }); - - var AST_TemplateString = DEFNODE("TemplateString", "segments", { - $documentation: "A template string literal", - $propdoc: { - segments: "[AST_Node*] One or more segments, starting with AST_TemplateSegment. AST_Node may follow AST_TemplateSegment, but each AST_Node must be followed by AST_TemplateSegment." - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.segments.forEach(function(seg) { - seg._walk(visitor); - }); - }); - } - }); - - var AST_TemplateSegment = DEFNODE("TemplateSegment", "value raw", { - $documentation: "A segment of a template string literal", - $propdoc: { - value: "Content of the segment", - raw: "Raw content of the segment" - } - }); - - /* -----[ JUMPS ]----- */ - - var AST_Jump = DEFNODE("Jump", null, { - $documentation: "Base class for “jumps” (for now that's `return`, `throw`, `break` and `continue`)" - }, AST_Statement); - - var AST_Exit = DEFNODE("Exit", "value", { - $documentation: "Base class for “exits” (`return` and `throw`)", - $propdoc: { - value: "[AST_Node?] the value returned or thrown by this statement; could be null for AST_Return" - }, - _walk: function(visitor) { - return visitor._visit(this, this.value && function() { - this.value._walk(visitor); - }); - } - }, AST_Jump); - - var AST_Return = DEFNODE("Return", null, { - $documentation: "A `return` statement" - }, AST_Exit); - - var AST_Throw = DEFNODE("Throw", null, { - $documentation: "A `throw` statement" - }, AST_Exit); - - var AST_LoopControl = DEFNODE("LoopControl", "label", { - $documentation: "Base class for loop control statements (`break` and `continue`)", - $propdoc: { - label: "[AST_LabelRef?] the label, or null if none", - }, - _walk: function(visitor) { - return visitor._visit(this, this.label && function() { - this.label._walk(visitor); - }); - } - }, AST_Jump); - - var AST_Break = DEFNODE("Break", null, { - $documentation: "A `break` statement" - }, AST_LoopControl); - - var AST_Continue = DEFNODE("Continue", null, { - $documentation: "A `continue` statement" - }, AST_LoopControl); - - /* -----[ IF ]----- */ - - var AST_If = DEFNODE("If", "condition alternative", { - $documentation: "A `if` statement", - $propdoc: { - condition: "[AST_Node] the `if` condition", - alternative: "[AST_Statement?] the `else` part, or null if not present" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.condition._walk(visitor); - this.body._walk(visitor); - if (this.alternative) this.alternative._walk(visitor); - }); - } - }, AST_StatementWithBody); - - /* -----[ SWITCH ]----- */ - - var AST_Switch = DEFNODE("Switch", "expression", { - $documentation: "A `switch` statement", - $propdoc: { - expression: "[AST_Node] the `switch` “discriminant”" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.expression._walk(visitor); - walk_body(this, visitor); - }); - } - }, AST_Block); - - var AST_SwitchBranch = DEFNODE("SwitchBranch", null, { - $documentation: "Base class for `switch` branches", - }, AST_Block); - - var AST_Default = DEFNODE("Default", null, { - $documentation: "A `default` switch branch", - }, AST_SwitchBranch); - - var AST_Case = DEFNODE("Case", "expression", { - $documentation: "A `case` switch branch", - $propdoc: { - expression: "[AST_Node] the `case` expression" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.expression._walk(visitor); - walk_body(this, visitor); - }); - } - }, AST_SwitchBranch); - - /* -----[ EXCEPTIONS ]----- */ - - var AST_Try = DEFNODE("Try", "bcatch bfinally", { - $documentation: "A `try` statement", - $propdoc: { - bcatch: "[AST_Catch?] the catch block, or null if not present", - bfinally: "[AST_Finally?] the finally block, or null if not present" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - walk_body(this, visitor); - if (this.bcatch) this.bcatch._walk(visitor); - if (this.bfinally) this.bfinally._walk(visitor); - }); - } - }, AST_Block); - - var AST_Catch = DEFNODE("Catch", "argname", { - $documentation: "A `catch` node; only makes sense as part of a `try` statement", - $propdoc: { - argname: "[AST_SymbolCatch|AST_Destructuring|AST_Expansion|AST_DefaultAssign] symbol for the exception" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - if (this.argname) this.argname._walk(visitor); - walk_body(this, visitor); - }); - } - }, AST_Block); - - var AST_Finally = DEFNODE("Finally", null, { - $documentation: "A `finally` node; only makes sense as part of a `try` statement" - }, AST_Block); - - /* -----[ VAR/CONST ]----- */ - - var AST_Definitions = DEFNODE("Definitions", "definitions", { - $documentation: "Base class for `var` or `const` nodes (variable declarations/initializations)", - $propdoc: { - definitions: "[AST_VarDef*] array of variable definitions" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - var definitions = this.definitions; - for (var i = 0, len = definitions.length; i < len; i++) { - definitions[i]._walk(visitor); - } - }); - } - }, AST_Statement); - - var AST_Var = DEFNODE("Var", null, { - $documentation: "A `var` statement" - }, AST_Definitions); - - var AST_Let = DEFNODE("Let", null, { - $documentation: "A `let` statement" - }, AST_Definitions); - - var AST_Const = DEFNODE("Const", null, { - $documentation: "A `const` statement" - }, AST_Definitions); - - var AST_NameMapping = DEFNODE("NameMapping", "foreign_name name", { - $documentation: "The part of the export/import statement that declare names from a module.", - $propdoc: { - foreign_name: "[AST_SymbolExportForeign|AST_SymbolImportForeign] The name being exported/imported (as specified in the module)", - name: "[AST_SymbolExport|AST_SymbolImport] The name as it is visible to this module." - }, - _walk: function (visitor) { - return visitor._visit(this, function() { - this.foreign_name._walk(visitor); - this.name._walk(visitor); - }); - } - }); - - var AST_Import = DEFNODE("Import", "imported_name imported_names module_name", { - $documentation: "An `import` statement", - $propdoc: { - imported_name: "[AST_SymbolImport] The name of the variable holding the module's default export.", - imported_names: "[AST_NameMapping*] The names of non-default imported variables", - module_name: "[AST_String] String literal describing where this module came from", - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - if (this.imported_name) { - this.imported_name._walk(visitor); - } - if (this.imported_names) { - this.imported_names.forEach(function(name_import) { - name_import._walk(visitor); - }); - } - this.module_name._walk(visitor); - }); - } - }); - - var AST_Export = DEFNODE("Export", "exported_definition exported_value is_default exported_names module_name", { - $documentation: "An `export` statement", - $propdoc: { - exported_definition: "[AST_Defun|AST_Definitions|AST_DefClass?] An exported definition", - exported_value: "[AST_Node?] An exported value", - exported_names: "[AST_NameMapping*?] List of exported names", - module_name: "[AST_String?] Name of the file to load exports from", - is_default: "[Boolean] Whether this is the default exported value of this module" - }, - _walk: function (visitor) { - visitor._visit(this, function () { - if (this.exported_definition) { - this.exported_definition._walk(visitor); - } - if (this.exported_value) { - this.exported_value._walk(visitor); - } - if (this.exported_names) { - this.exported_names.forEach(function(name_export) { - name_export._walk(visitor); - }); - } - if (this.module_name) { - this.module_name._walk(visitor); - } - }); - } - }, AST_Statement); - - var AST_VarDef = DEFNODE("VarDef", "name value", { - $documentation: "A variable declaration; only appears in a AST_Definitions node", - $propdoc: { - name: "[AST_Destructuring|AST_SymbolConst|AST_SymbolLet|AST_SymbolVar] name of the variable", - value: "[AST_Node?] initializer, or null of there's no initializer" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.name._walk(visitor); - if (this.value) this.value._walk(visitor); - }); - } - }); - - /* -----[ OTHER ]----- */ - - var AST_Call = DEFNODE("Call", "expression args", { - $documentation: "A function call expression", - $propdoc: { - expression: "[AST_Node] expression to invoke as function", - args: "[AST_Node*] array of arguments" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - var args = this.args; - for (var i = 0, len = args.length; i < len; i++) { - args[i]._walk(visitor); - } - this.expression._walk(visitor); - }); - } - }); - - var AST_New = DEFNODE("New", null, { - $documentation: "An object instantiation. Derives from a function call since it has exactly the same properties" - }, AST_Call); - - var AST_Sequence = DEFNODE("Sequence", "expressions", { - $documentation: "A sequence expression (comma-separated expressions)", - $propdoc: { - expressions: "[AST_Node*] array of expressions (at least two)" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.expressions.forEach(function(node) { - node._walk(visitor); - }); - }); - } - }); - - var AST_PropAccess = DEFNODE("PropAccess", "expression property", { - $documentation: "Base class for property access expressions, i.e. `a.foo` or `a[\"foo\"]`", - $propdoc: { - expression: "[AST_Node] the “container” expression", - property: "[AST_Node|string] the property to access. For AST_Dot this is always a plain string, while for AST_Sub it's an arbitrary AST_Node" - } - }); - - var AST_Dot = DEFNODE("Dot", "quote", { - $documentation: "A dotted property access expression", - $propdoc: { - quote: "[string] the original quote character when transformed from AST_Sub", - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.expression._walk(visitor); - }); - } - }, AST_PropAccess); - - var AST_Sub = DEFNODE("Sub", null, { - $documentation: "Index-style property access, i.e. `a[\"foo\"]`", - _walk: function(visitor) { - return visitor._visit(this, function() { - this.expression._walk(visitor); - this.property._walk(visitor); - }); - } - }, AST_PropAccess); - - var AST_Unary = DEFNODE("Unary", "operator expression", { - $documentation: "Base class for unary expressions", - $propdoc: { - operator: "[string] the operator", - expression: "[AST_Node] expression that this unary operator applies to" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.expression._walk(visitor); - }); - } - }); - - var AST_UnaryPrefix = DEFNODE("UnaryPrefix", null, { - $documentation: "Unary prefix expression, i.e. `typeof i` or `++i`" - }, AST_Unary); - - var AST_UnaryPostfix = DEFNODE("UnaryPostfix", null, { - $documentation: "Unary postfix expression, i.e. `i++`" - }, AST_Unary); - - var AST_Binary = DEFNODE("Binary", "operator left right", { - $documentation: "Binary expression, i.e. `a + b`", - $propdoc: { - left: "[AST_Node] left-hand side expression", - operator: "[string] the operator", - right: "[AST_Node] right-hand side expression" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.left._walk(visitor); - this.right._walk(visitor); - }); - } - }); - - var AST_Conditional = DEFNODE("Conditional", "condition consequent alternative", { - $documentation: "Conditional expression using the ternary operator, i.e. `a ? b : c`", - $propdoc: { - condition: "[AST_Node]", - consequent: "[AST_Node]", - alternative: "[AST_Node]" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.condition._walk(visitor); - this.consequent._walk(visitor); - this.alternative._walk(visitor); - }); - } - }); - - var AST_Assign = DEFNODE("Assign", null, { - $documentation: "An assignment expression — `a = b + 5`", - }, AST_Binary); - - var AST_DefaultAssign = DEFNODE("DefaultAssign", null, { - $documentation: "A default assignment expression like in `(a = 3) => a`" - }, AST_Binary); - - /* -----[ LITERALS ]----- */ - - var AST_Array = DEFNODE("Array", "elements", { - $documentation: "An array literal", - $propdoc: { - elements: "[AST_Node*] array of elements" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - var elements = this.elements; - for (var i = 0, len = elements.length; i < len; i++) { - elements[i]._walk(visitor); - } - }); - } - }); - - var AST_Object = DEFNODE("Object", "properties", { - $documentation: "An object literal", - $propdoc: { - properties: "[AST_ObjectProperty*] array of properties" - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - var properties = this.properties; - for (var i = 0, len = properties.length; i < len; i++) { - properties[i]._walk(visitor); - } - }); - } - }); - - var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", { - $documentation: "Base class for literal object properties", - $propdoc: { - key: "[string|AST_Node] property name. For ObjectKeyVal this is a string. For getters, setters and computed property this is an AST_Node.", - value: "[AST_Node] property value. For getters and setters this is an AST_Accessor." - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - if (this.key instanceof AST_Node) - this.key._walk(visitor); - this.value._walk(visitor); - }); - } - }); - - var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", "quote", { - $documentation: "A key: value object property", - $propdoc: { - quote: "[string] the original quote character" - } - }, AST_ObjectProperty); - - var AST_ObjectSetter = DEFNODE("ObjectSetter", "quote static", { - $propdoc: { - quote: "[string|undefined] the original quote character, if any", - static: "[boolean] whether this is a static setter (classes only)" - }, - $documentation: "An object setter property", - }, AST_ObjectProperty); - - var AST_ObjectGetter = DEFNODE("ObjectGetter", "quote static", { - $propdoc: { - quote: "[string|undefined] the original quote character, if any", - static: "[boolean] whether this is a static getter (classes only)" - }, - $documentation: "An object getter property", - }, AST_ObjectProperty); - - var AST_ConciseMethod = DEFNODE("ConciseMethod", "quote static is_generator async", { - $propdoc: { - quote: "[string|undefined] the original quote character, if any", - static: "[boolean] is this method static (classes only)", - is_generator: "[boolean] is this a generator method", - async: "[boolean] is this method async", - }, - $documentation: "An ES6 concise method inside an object or class" - }, AST_ObjectProperty); - - var AST_Class = DEFNODE("Class", "name extends properties inlined", { - $propdoc: { - name: "[AST_SymbolClass|AST_SymbolDefClass?] optional class name.", - extends: "[AST_Node]? optional parent class", - properties: "[AST_ObjectProperty*] array of properties" - }, - $documentation: "An ES6 class", - _walk: function(visitor) { - return visitor._visit(this, function() { - if (this.name) { - this.name._walk(visitor); - } - if (this.extends) { - this.extends._walk(visitor); - } - this.properties.forEach(function(prop) { - prop._walk(visitor); - }); - }); - }, - }, AST_Scope); - - var AST_DefClass = DEFNODE("DefClass", null, { - $documentation: "A class definition", - }, AST_Class); - - var AST_ClassExpression = DEFNODE("ClassExpression", null, { - $documentation: "A class expression." - }, AST_Class); - - var AST_Symbol = DEFNODE("Symbol", "scope name thedef", { - $propdoc: { - name: "[string] name of this symbol", - scope: "[AST_Scope/S] the current scope (not necessarily the definition scope)", - thedef: "[SymbolDef/S] the definition of this symbol" - }, - $documentation: "Base class for all symbols" - }); - - var AST_NewTarget = DEFNODE("NewTarget", null, { - $documentation: "A reference to new.target" - }); - - var AST_SymbolDeclaration = DEFNODE("SymbolDeclaration", "init", { - $documentation: "A declaration symbol (symbol in var/const, function name or argument, symbol in catch)", - }, AST_Symbol); - - var AST_SymbolVar = DEFNODE("SymbolVar", null, { - $documentation: "Symbol defining a variable", - }, AST_SymbolDeclaration); - - var AST_SymbolBlockDeclaration = DEFNODE("SymbolBlockDeclaration", null, { - $documentation: "Base class for block-scoped declaration symbols" - }, AST_SymbolDeclaration); - - var AST_SymbolConst = DEFNODE("SymbolConst", null, { - $documentation: "A constant declaration" - }, AST_SymbolBlockDeclaration); - - var AST_SymbolLet = DEFNODE("SymbolLet", null, { - $documentation: "A block-scoped `let` declaration" - }, AST_SymbolBlockDeclaration); - - var AST_SymbolFunarg = DEFNODE("SymbolFunarg", null, { - $documentation: "Symbol naming a function argument", - }, AST_SymbolVar); - - var AST_SymbolDefun = DEFNODE("SymbolDefun", null, { - $documentation: "Symbol defining a function", - }, AST_SymbolDeclaration); - - var AST_SymbolMethod = DEFNODE("SymbolMethod", null, { - $documentation: "Symbol in an object defining a method", - }, AST_Symbol); - - var AST_SymbolLambda = DEFNODE("SymbolLambda", null, { - $documentation: "Symbol naming a function expression", - }, AST_SymbolDeclaration); - - var AST_SymbolDefClass = DEFNODE("SymbolDefClass", null, { - $documentation: "Symbol naming a class's name in a class declaration. Lexically scoped to its containing scope, and accessible within the class." - }, AST_SymbolBlockDeclaration); - - var AST_SymbolClass = DEFNODE("SymbolClass", null, { - $documentation: "Symbol naming a class's name. Lexically scoped to the class." - }, AST_SymbolDeclaration); - - var AST_SymbolCatch = DEFNODE("SymbolCatch", null, { - $documentation: "Symbol naming the exception in catch", - }, AST_SymbolBlockDeclaration); - - var AST_SymbolImport = DEFNODE("SymbolImport", null, { - $documentation: "Symbol referring to an imported name", - }, AST_SymbolBlockDeclaration); - - var AST_SymbolImportForeign = DEFNODE("SymbolImportForeign", null, { - $documentation: "A symbol imported from a module, but it is defined in the other module, and its real name is irrelevant for this module's purposes", - }, AST_Symbol); - - var AST_Label = DEFNODE("Label", "references", { - $documentation: "Symbol naming a label (declaration)", - $propdoc: { - references: "[AST_LoopControl*] a list of nodes referring to this label" - }, - initialize: function() { - this.references = []; - this.thedef = this; - } - }, AST_Symbol); - - var AST_SymbolRef = DEFNODE("SymbolRef", null, { - $documentation: "Reference to some symbol (not definition/declaration)", - }, AST_Symbol); - - var AST_SymbolExport = DEFNODE("SymbolExport", null, { - $documentation: "Symbol referring to a name to export", - }, AST_SymbolRef); - - var AST_SymbolExportForeign = DEFNODE("SymbolExportForeign", null, { - $documentation: "A symbol exported from this module, but it is used in the other module, and its real name is irrelevant for this module's purposes", - }, AST_Symbol); - - var AST_LabelRef = DEFNODE("LabelRef", null, { - $documentation: "Reference to a label symbol", - }, AST_Symbol); - - var AST_This = DEFNODE("This", null, { - $documentation: "The `this` symbol", - }, AST_Symbol); - - var AST_Super = DEFNODE("Super", null, { - $documentation: "The `super` symbol", - }, AST_This); - - var AST_Constant = DEFNODE("Constant", null, { - $documentation: "Base class for all constants", - getValue: function() { - return this.value; - } - }); - - var AST_String = DEFNODE("String", "value quote", { - $documentation: "A string literal", - $propdoc: { - value: "[string] the contents of this string", - quote: "[string] the original quote character" - } - }, AST_Constant); - - var AST_Number = DEFNODE("Number", "value literal", { - $documentation: "A number literal", - $propdoc: { - value: "[number] the numeric value", - literal: "[string] numeric value as string (optional)" - } - }, AST_Constant); - - var AST_BigInt = DEFNODE("BigInt", "value", { - $documentation: "A big int literal", - $propdoc: { - value: "[string] big int value" - } - }, AST_Constant); - - var AST_RegExp = DEFNODE("RegExp", "value", { - $documentation: "A regexp literal", - $propdoc: { - value: "[RegExp] the actual regexp", - } - }, AST_Constant); - - var AST_Atom = DEFNODE("Atom", null, { - $documentation: "Base class for atoms", - }, AST_Constant); - - var AST_Null = DEFNODE("Null", null, { - $documentation: "The `null` atom", - value: null - }, AST_Atom); - - var AST_NaN = DEFNODE("NaN", null, { - $documentation: "The impossible value", - value: 0/0 - }, AST_Atom); - - var AST_Undefined = DEFNODE("Undefined", null, { - $documentation: "The `undefined` value", - value: (function() {}()) - }, AST_Atom); - - var AST_Hole = DEFNODE("Hole", null, { - $documentation: "A hole in an array", - value: (function() {}()) - }, AST_Atom); - - var AST_Infinity = DEFNODE("Infinity", null, { - $documentation: "The `Infinity` value", - value: 1/0 - }, AST_Atom); - - var AST_Boolean = DEFNODE("Boolean", null, { - $documentation: "Base class for booleans", - }, AST_Atom); - - var AST_False = DEFNODE("False", null, { - $documentation: "The `false` atom", - value: false - }, AST_Boolean); - - var AST_True = DEFNODE("True", null, { - $documentation: "The `true` atom", - value: true - }, AST_Boolean); - - var AST_Await = DEFNODE("Await", "expression", { - $documentation: "An `await` statement", - $propdoc: { - expression: "[AST_Node] the mandatory expression being awaited", - }, - _walk: function(visitor) { - return visitor._visit(this, function() { - this.expression._walk(visitor); - }); - } - }); - - var AST_Yield = DEFNODE("Yield", "expression is_star", { - $documentation: "A `yield` statement", - $propdoc: { - expression: "[AST_Node?] the value returned or thrown by this statement; could be null (representing undefined) but only when is_star is set to false", - is_star: "[Boolean] Whether this is a yield or yield* statement" - }, - _walk: function(visitor) { - return visitor._visit(this, this.expression && function() { - this.expression._walk(visitor); - }); - } - }); - - /* -----[ TreeWalker ]----- */ - - function TreeWalker(callback) { - this.visit = callback; - this.stack = []; - this.directives = Object.create(null); - } - TreeWalker.prototype = { - _visit: function(node, descend) { - this.push(node); - var ret = this.visit(node, descend ? function() { - descend.call(node); - } : noop); - if (!ret && descend) { - descend.call(node); - } - this.pop(); - return ret; - }, - parent: function(n) { - return this.stack[this.stack.length - 2 - (n || 0)]; - }, - push: function(node) { - if (node instanceof AST_Lambda) { - this.directives = Object.create(this.directives); - } else if (node instanceof AST_Directive && !this.directives[node.value]) { - this.directives[node.value] = node; - } else if (node instanceof AST_Class) { - this.directives = Object.create(this.directives); - if (!this.directives["use strict"]) { - this.directives["use strict"] = node; - } - } - this.stack.push(node); - }, - pop: function() { - var node = this.stack.pop(); - if (node instanceof AST_Lambda || node instanceof AST_Class) { - this.directives = Object.getPrototypeOf(this.directives); - } - }, - self: function() { - return this.stack[this.stack.length - 1]; - }, - find_parent: function(type) { - var stack = this.stack; - for (var i = stack.length; --i >= 0;) { - var x = stack[i]; - if (x instanceof type) return x; - } - }, - has_directive: function(type) { - var dir = this.directives[type]; - if (dir) return dir; - var node = this.stack[this.stack.length - 1]; - if (node instanceof AST_Scope && node.body) { - for (var i = 0; i < node.body.length; ++i) { - var st = node.body[i]; - if (!(st instanceof AST_Directive)) break; - if (st.value == type) return st; - } - } - }, - loopcontrol_target: function(node) { - var stack = this.stack; - if (node.label) for (var i = stack.length; --i >= 0;) { - var x = stack[i]; - if (x instanceof AST_LabeledStatement && x.label.name == node.label.name) - return x.body; - } else for (var i = stack.length; --i >= 0;) { - var x = stack[i]; - if (x instanceof AST_IterationStatement - || node instanceof AST_Break && x instanceof AST_Switch) - return x; - } - } - }; - - // Tree transformer helpers. - class TreeTransformer extends TreeWalker { - constructor(before, after) { - super(); - this.before = before; - this.after = after; - } - } - - // XXX Emscripten: export TreeWalker for walking through AST in acorn-optimizer.js. - exports.TreeWalker = TreeWalker; - - var ast = /*#__PURE__*/Object.freeze({ - __proto__: null, - AST_Accessor: AST_Accessor, - AST_Array: AST_Array, - AST_Arrow: AST_Arrow, - AST_Assign: AST_Assign, - AST_Atom: AST_Atom, - AST_Await: AST_Await, - AST_BigInt: AST_BigInt, - AST_Binary: AST_Binary, - AST_Block: AST_Block, - AST_BlockStatement: AST_BlockStatement, - AST_Boolean: AST_Boolean, - AST_Break: AST_Break, - AST_Call: AST_Call, - AST_Case: AST_Case, - AST_Catch: AST_Catch, - AST_Class: AST_Class, - AST_ClassExpression: AST_ClassExpression, - AST_ConciseMethod: AST_ConciseMethod, - AST_Conditional: AST_Conditional, - AST_Const: AST_Const, - AST_Constant: AST_Constant, - AST_Continue: AST_Continue, - AST_Debugger: AST_Debugger, - AST_Default: AST_Default, - AST_DefaultAssign: AST_DefaultAssign, - AST_DefClass: AST_DefClass, - AST_Definitions: AST_Definitions, - AST_Defun: AST_Defun, - AST_Destructuring: AST_Destructuring, - AST_Directive: AST_Directive, - AST_Do: AST_Do, - AST_Dot: AST_Dot, - AST_DWLoop: AST_DWLoop, - AST_EmptyStatement: AST_EmptyStatement, - AST_Exit: AST_Exit, - AST_Expansion: AST_Expansion, - AST_Export: AST_Export, - AST_False: AST_False, - AST_Finally: AST_Finally, - AST_For: AST_For, - AST_ForIn: AST_ForIn, - AST_ForOf: AST_ForOf, - AST_Function: AST_Function, - AST_Hole: AST_Hole, - AST_If: AST_If, - AST_Import: AST_Import, - AST_Infinity: AST_Infinity, - AST_IterationStatement: AST_IterationStatement, - AST_Jump: AST_Jump, - AST_Label: AST_Label, - AST_LabeledStatement: AST_LabeledStatement, - AST_LabelRef: AST_LabelRef, - AST_Lambda: AST_Lambda, - AST_Let: AST_Let, - AST_LoopControl: AST_LoopControl, - AST_NameMapping: AST_NameMapping, - AST_NaN: AST_NaN, - AST_New: AST_New, - AST_NewTarget: AST_NewTarget, - AST_Node: AST_Node, - AST_Null: AST_Null, - AST_Number: AST_Number, - AST_Object: AST_Object, - AST_ObjectGetter: AST_ObjectGetter, - AST_ObjectKeyVal: AST_ObjectKeyVal, - AST_ObjectProperty: AST_ObjectProperty, - AST_ObjectSetter: AST_ObjectSetter, - AST_ParenthesizedExpression: AST_ParenthesizedExpression, - AST_PrefixedTemplateString: AST_PrefixedTemplateString, - AST_PropAccess: AST_PropAccess, - AST_RegExp: AST_RegExp, - AST_Return: AST_Return, - AST_Scope: AST_Scope, - AST_Sequence: AST_Sequence, - AST_SimpleStatement: AST_SimpleStatement, - AST_Statement: AST_Statement, - AST_StatementWithBody: AST_StatementWithBody, - AST_String: AST_String, - AST_Sub: AST_Sub, - AST_Super: AST_Super, - AST_Switch: AST_Switch, - AST_SwitchBranch: AST_SwitchBranch, - AST_Symbol: AST_Symbol, - AST_SymbolBlockDeclaration: AST_SymbolBlockDeclaration, - AST_SymbolCatch: AST_SymbolCatch, - AST_SymbolClass: AST_SymbolClass, - AST_SymbolConst: AST_SymbolConst, - AST_SymbolDeclaration: AST_SymbolDeclaration, - AST_SymbolDefClass: AST_SymbolDefClass, - AST_SymbolDefun: AST_SymbolDefun, - AST_SymbolExport: AST_SymbolExport, - AST_SymbolExportForeign: AST_SymbolExportForeign, - AST_SymbolFunarg: AST_SymbolFunarg, - AST_SymbolImport: AST_SymbolImport, - AST_SymbolImportForeign: AST_SymbolImportForeign, - AST_SymbolLambda: AST_SymbolLambda, - AST_SymbolLet: AST_SymbolLet, - AST_SymbolMethod: AST_SymbolMethod, - AST_SymbolRef: AST_SymbolRef, - AST_SymbolVar: AST_SymbolVar, - AST_TemplateSegment: AST_TemplateSegment, - AST_TemplateString: AST_TemplateString, - AST_This: AST_This, - AST_Throw: AST_Throw, - AST_Token: AST_Token, - AST_Toplevel: AST_Toplevel, - AST_True: AST_True, - AST_Try: AST_Try, - AST_Unary: AST_Unary, - AST_UnaryPostfix: AST_UnaryPostfix, - AST_UnaryPrefix: AST_UnaryPrefix, - AST_Undefined: AST_Undefined, - AST_Var: AST_Var, - AST_VarDef: AST_VarDef, - AST_While: AST_While, - AST_With: AST_With, - AST_Yield: AST_Yield, - TreeTransformer: TreeTransformer, - TreeWalker: TreeWalker, - walk_body: walk_body - }); - - /*********************************************************************** - - A JavaScript tokenizer / parser / beautifier / compressor. - https://github.com/mishoo/UglifyJS2 - - -------------------------------- (C) --------------------------------- - - Author: Mihai Bazon - - http://mihai.bazon.net/blog - - Distributed under the BSD license: - - Copyright 2012 (c) Mihai Bazon - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - * Redistributions of source code must retain the above - copyright notice, this list of conditions and the following - disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials - provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY - EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - SUCH DAMAGE. - - ***********************************************************************/ - - (function() { - - function _(node, descend) { - node.DEFMETHOD("transform", function(tw, in_list) { - var x, y; - tw.push(this); - if (tw.before) x = tw.before(this, descend, in_list); - if (x === undefined) { - x = this; - descend(x, tw); - if (tw.after) { - y = tw.after(x, in_list); - if (y !== undefined) x = y; - } - } - tw.pop(); - return x; - }); - } + } + }; + + MOZ_TO_ME.UpdateExpression = + MOZ_TO_ME.UnaryExpression = function To_Moz_Unary(M) { + var prefix = "prefix" in M ? M.prefix + : M.type == "UnaryExpression" ? true : false; + return new (prefix ? AST_UnaryPrefix : AST_UnaryPostfix)({ + start : my_start_token(M), + end : my_end_token(M), + operator : M.operator, + expression : from_moz(M.argument) + }); + }; + + MOZ_TO_ME.ClassDeclaration = + MOZ_TO_ME.ClassExpression = function From_Moz_Class(M) { + return new (M.type === "ClassDeclaration" ? AST_DefClass : AST_ClassExpression)({ + start : my_start_token(M), + end : my_end_token(M), + name : from_moz(M.id), + extends : from_moz(M.superClass), + properties: M.body.body.map(from_moz) + }); + }; + + def_to_moz(AST_EmptyStatement, function To_Moz_EmptyStatement() { + return { + type: "EmptyStatement" + }; + }); + def_to_moz(AST_BlockStatement, function To_Moz_BlockStatement(M) { + return { + type: "BlockStatement", + body: M.body.map(to_moz) + }; + }); + def_to_moz(AST_If, function To_Moz_IfStatement(M) { + return { + type: "IfStatement", + test: to_moz(M.condition), + consequent: to_moz(M.body), + alternate: to_moz(M.alternative) + }; + }); + def_to_moz(AST_LabeledStatement, function To_Moz_LabeledStatement(M) { + return { + type: "LabeledStatement", + label: to_moz(M.label), + body: to_moz(M.body) + }; + }); + def_to_moz(AST_Break, function To_Moz_BreakStatement(M) { + return { + type: "BreakStatement", + label: to_moz(M.label) + }; + }); + def_to_moz(AST_Continue, function To_Moz_ContinueStatement(M) { + return { + type: "ContinueStatement", + label: to_moz(M.label) + }; + }); + def_to_moz(AST_With, function To_Moz_WithStatement(M) { + return { + type: "WithStatement", + object: to_moz(M.expression), + body: to_moz(M.body) + }; + }); + def_to_moz(AST_Switch, function To_Moz_SwitchStatement(M) { + return { + type: "SwitchStatement", + discriminant: to_moz(M.expression), + cases: M.body.map(to_moz) + }; + }); + def_to_moz(AST_Return, function To_Moz_ReturnStatement(M) { + return { + type: "ReturnStatement", + argument: to_moz(M.value) + }; + }); + def_to_moz(AST_Throw, function To_Moz_ThrowStatement(M) { + return { + type: "ThrowStatement", + argument: to_moz(M.value) + }; + }); + def_to_moz(AST_While, function To_Moz_WhileStatement(M) { + return { + type: "WhileStatement", + test: to_moz(M.condition), + body: to_moz(M.body) + }; + }); + def_to_moz(AST_Do, function To_Moz_DoWhileStatement(M) { + return { + type: "DoWhileStatement", + test: to_moz(M.condition), + body: to_moz(M.body) + }; + }); + def_to_moz(AST_For, function To_Moz_ForStatement(M) { + return { + type: "ForStatement", + init: to_moz(M.init), + test: to_moz(M.condition), + update: to_moz(M.step), + body: to_moz(M.body) + }; + }); + def_to_moz(AST_ForIn, function To_Moz_ForInStatement(M) { + return { + type: "ForInStatement", + left: to_moz(M.init), + right: to_moz(M.object), + body: to_moz(M.body) + }; + }); + def_to_moz(AST_ForOf, function To_Moz_ForOfStatement(M) { + return { + type: "ForOfStatement", + left: to_moz(M.init), + right: to_moz(M.object), + body: to_moz(M.body), + await: M.await + }; + }); + def_to_moz(AST_Await, function To_Moz_AwaitExpression(M) { + return { + type: "AwaitExpression", + argument: to_moz(M.expression) + }; + }); + def_to_moz(AST_Yield, function To_Moz_YieldExpression(M) { + return { + type: "YieldExpression", + argument: to_moz(M.expression), + delegate: M.is_star + }; + }); + def_to_moz(AST_Debugger, function To_Moz_DebuggerStatement() { + return { + type: "DebuggerStatement" + }; + }); + def_to_moz(AST_VarDef, function To_Moz_VariableDeclarator(M) { + return { + type: "VariableDeclarator", + id: to_moz(M.name), + init: to_moz(M.value) + }; + }); + def_to_moz(AST_Catch, function To_Moz_CatchClause(M) { + return { + type: "CatchClause", + param: to_moz(M.argname), + body: to_moz_block(M) + }; + }); + + def_to_moz(AST_This, function To_Moz_ThisExpression() { + return { + type: "ThisExpression" + }; + }); + def_to_moz(AST_Super, function To_Moz_Super() { + return { + type: "Super" + }; + }); + def_to_moz(AST_Binary, function To_Moz_BinaryExpression(M) { + return { + type: "BinaryExpression", + operator: M.operator, + left: to_moz(M.left), + right: to_moz(M.right) + }; + }); + def_to_moz(AST_Binary, function To_Moz_LogicalExpression(M) { + return { + type: "LogicalExpression", + operator: M.operator, + left: to_moz(M.left), + right: to_moz(M.right) + }; + }); + def_to_moz(AST_Assign, function To_Moz_AssignmentExpression(M) { + return { + type: "AssignmentExpression", + operator: M.operator, + left: to_moz(M.left), + right: to_moz(M.right) + }; + }); + def_to_moz(AST_Conditional, function To_Moz_ConditionalExpression(M) { + return { + type: "ConditionalExpression", + test: to_moz(M.condition), + consequent: to_moz(M.consequent), + alternate: to_moz(M.alternative) + }; + }); + def_to_moz(AST_New, function To_Moz_NewExpression(M) { + return { + type: "NewExpression", + callee: to_moz(M.expression), + arguments: M.args.map(to_moz) + }; + }); + def_to_moz(AST_Call, function To_Moz_CallExpression(M) { + return { + type: "CallExpression", + callee: to_moz(M.expression), + optional: M.optional, + arguments: M.args.map(to_moz) + }; + }); + + def_to_moz(AST_Toplevel, function To_Moz_Program(M) { + return to_moz_scope("Program", M); + }); + + def_to_moz(AST_Expansion, function To_Moz_Spread(M) { + return { + type: to_moz_in_destructuring() ? "RestElement" : "SpreadElement", + argument: to_moz(M.expression) + }; + }); + + def_to_moz(AST_PrefixedTemplateString, function To_Moz_TaggedTemplateExpression(M) { + return { + type: "TaggedTemplateExpression", + tag: to_moz(M.prefix), + quasi: to_moz(M.template_string) + }; + }); + + def_to_moz(AST_TemplateString, function To_Moz_TemplateLiteral(M) { + var quasis = []; + var expressions = []; + for (var i = 0; i < M.segments.length; i++) { + if (i % 2 !== 0) { + expressions.push(to_moz(M.segments[i])); + } else { + quasis.push({ + type: "TemplateElement", + value: { + raw: M.segments[i].raw, + cooked: M.segments[i].value + }, + tail: i === M.segments.length - 1 + }); + } + } + return { + type: "TemplateLiteral", + quasis: quasis, + expressions: expressions + }; + }); + + def_to_moz(AST_Defun, function To_Moz_FunctionDeclaration(M) { + return { + type: "FunctionDeclaration", + id: to_moz(M.name), + params: M.argnames.map(to_moz), + generator: M.is_generator, + async: M.async, + body: to_moz_scope("BlockStatement", M) + }; + }); + + def_to_moz(AST_Function, function To_Moz_FunctionExpression(M, parent) { + var is_generator = parent.is_generator !== undefined ? + parent.is_generator : M.is_generator; + return { + type: "FunctionExpression", + id: to_moz(M.name), + params: M.argnames.map(to_moz), + generator: is_generator, + async: M.async, + body: to_moz_scope("BlockStatement", M) + }; + }); + + def_to_moz(AST_Arrow, function To_Moz_ArrowFunctionExpression(M) { + var body = { + type: "BlockStatement", + body: M.body.map(to_moz) + }; + return { + type: "ArrowFunctionExpression", + params: M.argnames.map(to_moz), + async: M.async, + body: body + }; + }); + + def_to_moz(AST_Destructuring, function To_Moz_ObjectPattern(M) { + if (M.is_array) { + return { + type: "ArrayPattern", + elements: M.names.map(to_moz) + }; + } + return { + type: "ObjectPattern", + properties: M.names.map(to_moz) + }; + }); + + def_to_moz(AST_Directive, function To_Moz_Directive(M) { + return { + type: "ExpressionStatement", + expression: { + type: "Literal", + value: M.value, + raw: M.print_to_string() + }, + directive: M.value + }; + }); + + def_to_moz(AST_SimpleStatement, function To_Moz_ExpressionStatement(M) { + return { + type: "ExpressionStatement", + expression: to_moz(M.body) + }; + }); + + def_to_moz(AST_SwitchBranch, function To_Moz_SwitchCase(M) { + return { + type: "SwitchCase", + test: to_moz(M.expression), + consequent: M.body.map(to_moz) + }; + }); + + def_to_moz(AST_Try, function To_Moz_TryStatement(M) { + return { + type: "TryStatement", + block: to_moz_block(M.body), + handler: to_moz(M.bcatch), + guardedHandlers: [], + finalizer: to_moz(M.bfinally) + }; + }); + + def_to_moz(AST_Catch, function To_Moz_CatchClause(M) { + return { + type: "CatchClause", + param: to_moz(M.argname), + guard: null, + body: to_moz_block(M) + }; + }); + + def_to_moz(AST_Definitions, function To_Moz_VariableDeclaration(M) { + return { + type: "VariableDeclaration", + kind: + M instanceof AST_Const ? "const" : + M instanceof AST_Let ? "let" : "var", + declarations: M.definitions.map(to_moz) + }; + }); + + const assert_clause_to_moz = assert_clause => { + const assertions = []; + if (assert_clause) { + for (const { key, value } of assert_clause.properties) { + const key_moz = is_basic_identifier_string(key) + ? { type: "Identifier", name: key } + : { type: "Literal", value: key, raw: JSON.stringify(key) }; + assertions.push({ + type: "ImportAttribute", + key: key_moz, + value: to_moz(value) + }); + } + } + return assertions; + }; + + def_to_moz(AST_Export, function To_Moz_ExportDeclaration(M) { + if (M.exported_names) { + var first_exported = M.exported_names[0]; + var first_exported_name = first_exported.name; + if (first_exported_name.name === "*" && !first_exported_name.quote) { + var foreign_name = first_exported.foreign_name; + var exported = foreign_name.name === "*" && !foreign_name.quote + ? null + : to_moz(foreign_name); + return { + type: "ExportAllDeclaration", + source: to_moz(M.module_name), + exported: exported, + assertions: assert_clause_to_moz(M.assert_clause) + }; + } + return { + type: "ExportNamedDeclaration", + specifiers: M.exported_names.map(function (name_mapping) { + return { + type: "ExportSpecifier", + exported: to_moz(name_mapping.foreign_name), + local: to_moz(name_mapping.name) + }; + }), + declaration: to_moz(M.exported_definition), + source: to_moz(M.module_name), + assertions: assert_clause_to_moz(M.assert_clause) + }; + } + return { + type: M.is_default ? "ExportDefaultDeclaration" : "ExportNamedDeclaration", + declaration: to_moz(M.exported_value || M.exported_definition) + }; + }); + + def_to_moz(AST_Import, function To_Moz_ImportDeclaration(M) { + var specifiers = []; + if (M.imported_name) { + specifiers.push({ + type: "ImportDefaultSpecifier", + local: to_moz(M.imported_name) + }); + } + if (M.imported_names) { + var first_imported_foreign_name = M.imported_names[0].foreign_name; + if (first_imported_foreign_name.name === "*" && !first_imported_foreign_name.quote) { + specifiers.push({ + type: "ImportNamespaceSpecifier", + local: to_moz(M.imported_names[0].name) + }); + } else { + M.imported_names.forEach(function(name_mapping) { + specifiers.push({ + type: "ImportSpecifier", + local: to_moz(name_mapping.name), + imported: to_moz(name_mapping.foreign_name) + }); + }); + } + } + return { + type: "ImportDeclaration", + specifiers: specifiers, + source: to_moz(M.module_name), + assertions: assert_clause_to_moz(M.assert_clause) + }; + }); + + def_to_moz(AST_ImportMeta, function To_Moz_MetaProperty() { + return { + type: "MetaProperty", + meta: { + type: "Identifier", + name: "import" + }, + property: { + type: "Identifier", + name: "meta" + } + }; + }); + + def_to_moz(AST_Sequence, function To_Moz_SequenceExpression(M) { + return { + type: "SequenceExpression", + expressions: M.expressions.map(to_moz) + }; + }); + + def_to_moz(AST_DotHash, function To_Moz_PrivateMemberExpression(M) { + return { + type: "MemberExpression", + object: to_moz(M.expression), + computed: false, + property: { + type: "PrivateIdentifier", + name: M.property + }, + optional: M.optional + }; + }); + + def_to_moz(AST_PropAccess, function To_Moz_MemberExpression(M) { + var isComputed = M instanceof AST_Sub; + return { + type: "MemberExpression", + object: to_moz(M.expression), + computed: isComputed, + property: isComputed ? to_moz(M.property) : {type: "Identifier", name: M.property}, + optional: M.optional + }; + }); + + def_to_moz(AST_Chain, function To_Moz_ChainExpression(M) { + return { + type: "ChainExpression", + expression: to_moz(M.expression) + }; + }); + + def_to_moz(AST_Unary, function To_Moz_Unary(M) { + return { + type: M.operator == "++" || M.operator == "--" ? "UpdateExpression" : "UnaryExpression", + operator: M.operator, + prefix: M instanceof AST_UnaryPrefix, + argument: to_moz(M.expression) + }; + }); + + def_to_moz(AST_Binary, function To_Moz_BinaryExpression(M) { + if (M.operator == "=" && to_moz_in_destructuring()) { + return { + type: "AssignmentPattern", + left: to_moz(M.left), + right: to_moz(M.right) + }; + } + + const type = M.operator == "&&" || M.operator == "||" || M.operator === "??" + ? "LogicalExpression" + : "BinaryExpression"; + + return { + type, + left: to_moz(M.left), + operator: M.operator, + right: to_moz(M.right) + }; + }); + + def_to_moz(AST_PrivateIn, function To_Moz_BinaryExpression_PrivateIn(M) { + return { + type: "BinaryExpression", + left: { type: "PrivateIdentifier", name: M.key.name }, + operator: "in", + right: to_moz(M.value), + }; + }); + + def_to_moz(AST_Array, function To_Moz_ArrayExpression(M) { + return { + type: "ArrayExpression", + elements: M.elements.map(to_moz) + }; + }); + + def_to_moz(AST_Object, function To_Moz_ObjectExpression(M) { + return { + type: "ObjectExpression", + properties: M.properties.map(to_moz) + }; + }); + + def_to_moz(AST_ObjectProperty, function To_Moz_Property(M, parent) { + var key = M.key instanceof AST_Node ? to_moz(M.key) : { + type: "Identifier", + value: M.key + }; + if (typeof M.key === "number") { + key = { + type: "Literal", + value: Number(M.key) + }; + } + if (typeof M.key === "string") { + key = { + type: "Identifier", + name: M.key + }; + } + var kind; + var string_or_num = typeof M.key === "string" || typeof M.key === "number"; + var computed = string_or_num ? false : !(M.key instanceof AST_Symbol) || M.key instanceof AST_SymbolRef; + if (M instanceof AST_ObjectKeyVal) { + kind = "init"; + computed = !string_or_num; + } else + if (M instanceof AST_ObjectGetter) { + kind = "get"; + } else + if (M instanceof AST_ObjectSetter) { + kind = "set"; + } + if (M instanceof AST_PrivateGetter || M instanceof AST_PrivateSetter) { + const kind = M instanceof AST_PrivateGetter ? "get" : "set"; + return { + type: "MethodDefinition", + computed: false, + kind: kind, + static: M.static, + key: { + type: "PrivateIdentifier", + name: M.key.name + }, + value: to_moz(M.value) + }; + } + if (M instanceof AST_ClassPrivateProperty) { + return { + type: "PropertyDefinition", + key: { + type: "PrivateIdentifier", + name: M.key.name + }, + value: to_moz(M.value), + computed: false, + static: M.static + }; + } + if (M instanceof AST_ClassProperty) { + return { + type: "PropertyDefinition", + key, + value: to_moz(M.value), + computed, + static: M.static + }; + } + if (parent instanceof AST_Class) { + return { + type: "MethodDefinition", + computed: computed, + kind: kind, + static: M.static, + key: to_moz(M.key), + value: to_moz(M.value) + }; + } + return { + type: "Property", + computed: computed, + kind: kind, + key: key, + value: to_moz(M.value) + }; + }); + + def_to_moz(AST_ConciseMethod, function To_Moz_MethodDefinition(M, parent) { + if (parent instanceof AST_Object) { + return { + type: "Property", + computed: !(M.key instanceof AST_Symbol) || M.key instanceof AST_SymbolRef, + kind: "init", + method: true, + shorthand: false, + key: to_moz(M.key), + value: to_moz(M.value) + }; + } + + const key = M instanceof AST_PrivateMethod + ? { + type: "PrivateIdentifier", + name: M.key.name + } + : to_moz(M.key); + + return { + type: "MethodDefinition", + kind: M.key === "constructor" ? "constructor" : "method", + key, + value: to_moz(M.value), + computed: !(M.key instanceof AST_Symbol) || M.key instanceof AST_SymbolRef, + static: M.static, + }; + }); + + def_to_moz(AST_Class, function To_Moz_Class(M) { + var type = M instanceof AST_ClassExpression ? "ClassExpression" : "ClassDeclaration"; + return { + type: type, + superClass: to_moz(M.extends), + id: M.name ? to_moz(M.name) : null, + body: { + type: "ClassBody", + body: M.properties.map(to_moz) + } + }; + }); + + def_to_moz(AST_ClassStaticBlock, function To_Moz_StaticBlock(M) { + return { + type: "StaticBlock", + body: M.body.map(to_moz), + }; + }); + + def_to_moz(AST_NewTarget, function To_Moz_MetaProperty() { + return { + type: "MetaProperty", + meta: { + type: "Identifier", + name: "new" + }, + property: { + type: "Identifier", + name: "target" + } + }; + }); + + def_to_moz(AST_Symbol, function To_Moz_Identifier(M, parent) { + if ( + (M instanceof AST_SymbolMethod && parent.quote) || + (( + M instanceof AST_SymbolImportForeign || + M instanceof AST_SymbolExportForeign || + M instanceof AST_SymbolExport + ) && M.quote) + ) { + return { + type: "Literal", + value: M.name + }; + } + var def = M.definition(); + return { + type: "Identifier", + name: def ? def.mangled_name || def.name : M.name + }; + }); + + def_to_moz(AST_RegExp, function To_Moz_RegExpLiteral(M) { + const pattern = M.value.source; + const flags = M.value.flags; + return { + type: "Literal", + value: null, + raw: M.print_to_string(), + regex: { pattern, flags } + }; + }); + + def_to_moz(AST_Constant, function To_Moz_Literal(M) { + var value = M.value; + return { + type: "Literal", + value: value, + raw: M.raw || M.print_to_string() + }; + }); + + def_to_moz(AST_Atom, function To_Moz_Atom(M) { + return { + type: "Identifier", + name: String(M.value) + }; + }); + + def_to_moz(AST_BigInt, M => ({ + type: "BigIntLiteral", + value: M.value + })); + + AST_Boolean.DEFMETHOD("to_mozilla_ast", AST_Constant.prototype.to_mozilla_ast); + AST_Null.DEFMETHOD("to_mozilla_ast", AST_Constant.prototype.to_mozilla_ast); + AST_Hole.DEFMETHOD("to_mozilla_ast", function To_Moz_ArrayHole() { return null; }); + + AST_Block.DEFMETHOD("to_mozilla_ast", AST_BlockStatement.prototype.to_mozilla_ast); + AST_Lambda.DEFMETHOD("to_mozilla_ast", AST_Function.prototype.to_mozilla_ast); + + /* -----[ tools ]----- */ + + function my_start_token(moznode) { + var loc = moznode.loc, start = loc && loc.start; + var range = moznode.range; + return new AST_Token( + "", + "", + start && start.line || 0, + start && start.column || 0, + range ? range [0] : moznode.start, + false, + [], + [], + loc && loc.source, + ); + } + + function my_end_token(moznode) { + var loc = moznode.loc, end = loc && loc.end; + var range = moznode.range; + return new AST_Token( + "", + "", + end && end.line || 0, + end && end.column || 0, + range ? range [0] : moznode.end, + false, + [], + [], + loc && loc.source, + ); + } + + var FROM_MOZ_STACK = null; + + function from_moz(node) { + FROM_MOZ_STACK.push(node); + var ret = node != null ? MOZ_TO_ME[node.type](node) : null; + FROM_MOZ_STACK.pop(); + return ret; + } + + AST_Node.from_mozilla_ast = function(node) { + var save_stack = FROM_MOZ_STACK; + FROM_MOZ_STACK = []; + var ast = from_moz(node); + FROM_MOZ_STACK = save_stack; + return ast; + }; + + function set_moz_loc(mynode, moznode) { + var start = mynode.start; + var end = mynode.end; + if (!(start && end)) { + return moznode; + } + if (start.pos != null && end.endpos != null) { + moznode.range = [start.pos, end.endpos]; + } + if (start.line) { + moznode.loc = { + start: {line: start.line, column: start.col}, + end: end.endline ? {line: end.endline, column: end.endcol} : null + }; + if (start.file) { + moznode.loc.source = start.file; + } + } + return moznode; + } + + function def_to_moz(mytype, handler) { + mytype.DEFMETHOD("to_mozilla_ast", function(parent) { + return set_moz_loc(this, handler(this, parent)); + }); + } + + var TO_MOZ_STACK = null; + + function to_moz(node) { + if (TO_MOZ_STACK === null) { TO_MOZ_STACK = []; } + TO_MOZ_STACK.push(node); + var ast = node != null ? node.to_mozilla_ast(TO_MOZ_STACK[TO_MOZ_STACK.length - 2]) : null; + TO_MOZ_STACK.pop(); + if (TO_MOZ_STACK.length === 0) { TO_MOZ_STACK = null; } + return ast; + } + + function to_moz_in_destructuring() { + var i = TO_MOZ_STACK.length; + while (i--) { + if (TO_MOZ_STACK[i] instanceof AST_Destructuring) { + return true; + } + } + return false; + } + + function to_moz_block(node) { + return { + type: "BlockStatement", + body: node.body.map(to_moz) + }; + } + + function to_moz_scope(type, node) { + var body = node.body.map(to_moz); + if (node.body[0] instanceof AST_SimpleStatement && node.body[0].body instanceof AST_String) { + body.unshift(to_moz(new AST_EmptyStatement(node.body[0]))); + } + return { + type: type, + body: body + }; + } +})(); + +// return true if the node at the top of the stack (that means the +// innermost node in the current output) is lexically the first in +// a statement. +function first_in_statement(stack) { + let node = stack.parent(-1); + for (let i = 0, p; p = stack.parent(i); i++) { + if (p instanceof AST_Statement && p.body === node) + return true; + if ((p instanceof AST_Sequence && p.expressions[0] === node) || + (p.TYPE === "Call" && p.expression === node) || + (p instanceof AST_PrefixedTemplateString && p.prefix === node) || + (p instanceof AST_Dot && p.expression === node) || + (p instanceof AST_Sub && p.expression === node) || + (p instanceof AST_Chain && p.expression === node) || + (p instanceof AST_Conditional && p.condition === node) || + (p instanceof AST_Binary && p.left === node) || + (p instanceof AST_UnaryPostfix && p.expression === node) + ) { + node = p; + } else { + return false; + } + } +} + +// Returns whether the leftmost item in the expression is an object +function left_is_object(node) { + if (node instanceof AST_Object) return true; + if (node instanceof AST_Sequence) return left_is_object(node.expressions[0]); + if (node.TYPE === "Call") return left_is_object(node.expression); + if (node instanceof AST_PrefixedTemplateString) return left_is_object(node.prefix); + if (node instanceof AST_Dot || node instanceof AST_Sub) return left_is_object(node.expression); + if (node instanceof AST_Chain) return left_is_object(node.expression); + if (node instanceof AST_Conditional) return left_is_object(node.condition); + if (node instanceof AST_Binary) return left_is_object(node.left); + if (node instanceof AST_UnaryPostfix) return left_is_object(node.expression); + return false; +} + +/*********************************************************************** + + A JavaScript tokenizer / parser / beautifier / compressor. + https://github.com/mishoo/UglifyJS2 + + -------------------------------- (C) --------------------------------- + + Author: Mihai Bazon + + http://mihai.bazon.net/blog + + Distributed under the BSD license: + + Copyright 2012 (c) Mihai Bazon + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + ***********************************************************************/ + +const EXPECT_DIRECTIVE = /^$|[;{][\s\n]*$/; +const CODE_LINE_BREAK = 10; +const CODE_SPACE = 32; + +const r_annotation = /[@#]__(PURE|INLINE|NOINLINE)__/g; + +function is_some_comments(comment) { + // multiline comment + return ( + (comment.type === "comment2" || comment.type === "comment1") + && /@preserve|@copyright|@lic|@cc_on|^\**!/i.test(comment.value) + ); +} + +class Rope { + constructor() { + this.committed = ""; + this.current = ""; + } + + append(str) { + this.current += str; + } + + insertAt(char, index) { + const { committed, current } = this; + if (index < committed.length) { + this.committed = committed.slice(0, index) + char + committed.slice(index); + } else if (index === committed.length) { + this.committed += char; + } else { + index -= committed.length; + this.committed += current.slice(0, index) + char; + this.current = current.slice(index); + } + } + + charAt(index) { + const { committed } = this; + if (index < committed.length) return committed[index]; + return this.current[index - committed.length]; + } + + curLength() { + return this.current.length; + } + + length() { + return this.committed.length + this.current.length; + } + + toString() { + return this.committed + this.current; + } +} + +function OutputStream(options) { + + var readonly = !options; + options = defaults(options, { + ascii_only : false, + beautify : false, + braces : false, + comments : "some", + ecma : 5, + ie8 : false, + indent_level : 4, + indent_start : 0, + inline_script : true, + keep_numbers : false, + keep_quoted_props : false, + max_line_len : false, + preamble : null, + preserve_annotations : false, + quote_keys : false, + quote_style : 0, + safari10 : false, + semicolons : true, + shebang : true, + shorthand : undefined, + source_map : null, + webkit : false, + width : 80, + wrap_iife : false, + wrap_func_args : true, + + _destroy_ast : false + }, true); + + if (options.shorthand === undefined) + options.shorthand = options.ecma > 5; + + // Convert comment option to RegExp if necessary and set up comments filter + var comment_filter = return_false; // Default case, throw all comments away + if (options.comments) { + let comments = options.comments; + if (typeof options.comments === "string" && /^\/.*\/[a-zA-Z]*$/.test(options.comments)) { + var regex_pos = options.comments.lastIndexOf("/"); + comments = new RegExp( + options.comments.substr(1, regex_pos - 1), + options.comments.substr(regex_pos + 1) + ); + } + if (comments instanceof RegExp) { + comment_filter = function(comment) { + return comment.type != "comment5" && comments.test(comment.value); + }; + } else if (typeof comments === "function") { + comment_filter = function(comment) { + return comment.type != "comment5" && comments(this, comment); + }; + } else if (comments === "some") { + comment_filter = is_some_comments; + } else { // NOTE includes "all" option + comment_filter = return_true; + } + } + + var indentation = 0; + var current_col = 0; + var current_line = 1; + var current_pos = 0; + var OUTPUT = new Rope(); + let printed_comments = new Set(); + + var to_utf8 = options.ascii_only ? function(str, identifier = false, regexp = false) { + if (options.ecma >= 2015 && !options.safari10 && !regexp) { + str = str.replace(/[\ud800-\udbff][\udc00-\udfff]/g, function(ch) { + var code = get_full_char_code(ch, 0).toString(16); + return "\\u{" + code + "}"; + }); + } + return str.replace(/[\u0000-\u001f\u007f-\uffff]/g, function(ch) { + var code = ch.charCodeAt(0).toString(16); + if (code.length <= 2 && !identifier) { + while (code.length < 2) code = "0" + code; + return "\\x" + code; + } else { + while (code.length < 4) code = "0" + code; + return "\\u" + code; + } + }); + } : function(str) { + return str.replace(/[\ud800-\udbff][\udc00-\udfff]|([\ud800-\udbff]|[\udc00-\udfff])/g, function(match, lone) { + if (lone) { + return "\\u" + lone.charCodeAt(0).toString(16); + } + return match; + }); + }; + + function make_string(str, quote) { + var dq = 0, sq = 0; + str = str.replace(/[\\\b\f\n\r\v\t\x22\x27\u2028\u2029\0\ufeff]/g, + function(s, i) { + switch (s) { + case '"': ++dq; return '"'; + case "'": ++sq; return "'"; + case "\\": return "\\\\"; + case "\n": return "\\n"; + case "\r": return "\\r"; + case "\t": return "\\t"; + case "\b": return "\\b"; + case "\f": return "\\f"; + case "\x0B": return options.ie8 ? "\\x0B" : "\\v"; + case "\u2028": return "\\u2028"; + case "\u2029": return "\\u2029"; + case "\ufeff": return "\\ufeff"; + case "\0": + return /[0-9]/.test(get_full_char(str, i+1)) ? "\\x00" : "\\0"; + } + return s; + }); + function quote_single() { + return "'" + str.replace(/\x27/g, "\\'") + "'"; + } + function quote_double() { + return '"' + str.replace(/\x22/g, '\\"') + '"'; + } + function quote_template() { + return "`" + str.replace(/`/g, "\\`") + "`"; + } + str = to_utf8(str); + if (quote === "`") return quote_template(); + switch (options.quote_style) { + case 1: + return quote_single(); + case 2: + return quote_double(); + case 3: + return quote == "'" ? quote_single() : quote_double(); + default: + return dq > sq ? quote_single() : quote_double(); + } + } + + function encode_string(str, quote) { + var ret = make_string(str, quote); + if (options.inline_script) { + ret = ret.replace(/<\x2f(script)([>\/\t\n\f\r ])/gi, "<\\/$1$2"); + ret = ret.replace(/\x3c!--/g, "\\x3c!--"); + ret = ret.replace(/--\x3e/g, "--\\x3e"); + } + return ret; + } + + function make_name(name) { + name = name.toString(); + name = to_utf8(name, true); + return name; + } + + function make_indent(back) { + return " ".repeat(options.indent_start + indentation - back * options.indent_level); + } + + /* -----[ beautification/minification ]----- */ + + var has_parens = false; + var might_need_space = false; + var might_need_semicolon = false; + var might_add_newline = 0; + var need_newline_indented = false; + var need_space = false; + var newline_insert = -1; + var last = ""; + var mapping_token, mapping_name, mappings = options.source_map && []; + + var do_add_mapping = mappings ? function() { + mappings.forEach(function(mapping) { + try { + let { name, token } = mapping; + if (token.type == "name" || token.type === "privatename") { + name = token.value; + } else if (name instanceof AST_Symbol) { + name = token.type === "string" ? token.value : name.name; + } + options.source_map.add( + mapping.token.file, + mapping.line, mapping.col, + mapping.token.line, mapping.token.col, + is_basic_identifier_string(name) ? name : undefined + ); + } catch(ex) { + // Ignore bad mapping + } + }); + mappings = []; + } : noop; + + var ensure_line_len = options.max_line_len ? function() { + if (current_col > options.max_line_len) { + if (might_add_newline) { + OUTPUT.insertAt("\n", might_add_newline); + const curLength = OUTPUT.curLength(); + if (mappings) { + var delta = curLength - current_col; + mappings.forEach(function(mapping) { + mapping.line++; + mapping.col += delta; + }); + } + current_line++; + current_pos++; + current_col = curLength; + } + } + if (might_add_newline) { + might_add_newline = 0; + do_add_mapping(); + } + } : noop; + + var requireSemicolonChars = makePredicate("( [ + * / - , . `"); + + function print(str) { + str = String(str); + var ch = get_full_char(str, 0); + if (need_newline_indented && ch) { + need_newline_indented = false; + if (ch !== "\n") { + print("\n"); + indent(); + } + } + if (need_space && ch) { + need_space = false; + if (!/[\s;})]/.test(ch)) { + space(); + } + } + newline_insert = -1; + var prev = last.charAt(last.length - 1); + if (might_need_semicolon) { + might_need_semicolon = false; + + if (prev === ":" && ch === "}" || (!ch || !";}".includes(ch)) && prev !== ";") { + if (options.semicolons || requireSemicolonChars.has(ch)) { + OUTPUT.append(";"); + current_col++; + current_pos++; + } else { + ensure_line_len(); + if (current_col > 0) { + OUTPUT.append("\n"); + current_pos++; + current_line++; + current_col = 0; + } + + if (/^\s+$/.test(str)) { + // reset the semicolon flag, since we didn't print one + // now and might still have to later + might_need_semicolon = true; + } + } - function do_list(list, tw) { - return MAP(list, function(node) { - return node.transform(tw, true); - }); - } - - _(AST_Node, noop); - - _(AST_LabeledStatement, function(self, tw) { - self.label = self.label.transform(tw); - self.body = self.body.transform(tw); - }); - - _(AST_SimpleStatement, function(self, tw) { - self.body = self.body.transform(tw); - }); - - _(AST_Block, function(self, tw) { - self.body = do_list(self.body, tw); - }); - - _(AST_Do, function(self, tw) { - self.body = self.body.transform(tw); - self.condition = self.condition.transform(tw); - }); - - _(AST_While, function(self, tw) { - self.condition = self.condition.transform(tw); - self.body = self.body.transform(tw); - }); - - _(AST_For, function(self, tw) { - if (self.init) self.init = self.init.transform(tw); - if (self.condition) self.condition = self.condition.transform(tw); - if (self.step) self.step = self.step.transform(tw); - self.body = self.body.transform(tw); - }); - - _(AST_ForIn, function(self, tw) { - self.init = self.init.transform(tw); - self.object = self.object.transform(tw); - self.body = self.body.transform(tw); - }); - - _(AST_With, function(self, tw) { - self.expression = self.expression.transform(tw); - self.body = self.body.transform(tw); - }); - - _(AST_Exit, function(self, tw) { - if (self.value) self.value = self.value.transform(tw); - }); - - _(AST_LoopControl, function(self, tw) { - if (self.label) self.label = self.label.transform(tw); - }); - - _(AST_If, function(self, tw) { - self.condition = self.condition.transform(tw); - self.body = self.body.transform(tw); - if (self.alternative) self.alternative = self.alternative.transform(tw); - }); - - _(AST_Switch, function(self, tw) { - self.expression = self.expression.transform(tw); - self.body = do_list(self.body, tw); - }); - - _(AST_Case, function(self, tw) { - self.expression = self.expression.transform(tw); - self.body = do_list(self.body, tw); - }); - - _(AST_Try, function(self, tw) { - self.body = do_list(self.body, tw); - if (self.bcatch) self.bcatch = self.bcatch.transform(tw); - if (self.bfinally) self.bfinally = self.bfinally.transform(tw); - }); - - _(AST_Catch, function(self, tw) { - if (self.argname) self.argname = self.argname.transform(tw); - self.body = do_list(self.body, tw); - }); - - _(AST_Definitions, function(self, tw) { - self.definitions = do_list(self.definitions, tw); - }); - - _(AST_VarDef, function(self, tw) { - self.name = self.name.transform(tw); - if (self.value) self.value = self.value.transform(tw); - }); - - _(AST_Destructuring, function(self, tw) { - self.names = do_list(self.names, tw); - }); - - _(AST_Lambda, function(self, tw) { - if (self.name) self.name = self.name.transform(tw); - self.argnames = do_list(self.argnames, tw); - if (self.body instanceof AST_Node) { - self.body = self.body.transform(tw); - } else { - self.body = do_list(self.body, tw); - } - }); - - _(AST_Call, function(self, tw) { - self.expression = self.expression.transform(tw); - self.args = do_list(self.args, tw); - }); - - _(AST_Sequence, function(self, tw) { - self.expressions = do_list(self.expressions, tw); - }); - - _(AST_Dot, function(self, tw) { - self.expression = self.expression.transform(tw); - }); - - _(AST_Sub, function(self, tw) { - self.expression = self.expression.transform(tw); - self.property = self.property.transform(tw); - }); - - _(AST_Yield, function(self, tw) { - if (self.expression) self.expression = self.expression.transform(tw); - }); - - _(AST_Await, function(self, tw) { - self.expression = self.expression.transform(tw); - }); - - _(AST_Unary, function(self, tw) { - self.expression = self.expression.transform(tw); - }); - - _(AST_Binary, function(self, tw) { - self.left = self.left.transform(tw); - self.right = self.right.transform(tw); - }); - - _(AST_Conditional, function(self, tw) { - self.condition = self.condition.transform(tw); - self.consequent = self.consequent.transform(tw); - self.alternative = self.alternative.transform(tw); - }); - - _(AST_Array, function(self, tw) { - self.elements = do_list(self.elements, tw); - }); - - _(AST_Object, function(self, tw) { - self.properties = do_list(self.properties, tw); - }); - - _(AST_ObjectProperty, function(self, tw) { - if (self.key instanceof AST_Node) { - self.key = self.key.transform(tw); - } - self.value = self.value.transform(tw); - }); - - _(AST_Class, function(self, tw) { - if (self.name) self.name = self.name.transform(tw); - if (self.extends) self.extends = self.extends.transform(tw); - self.properties = do_list(self.properties, tw); - }); - - _(AST_Expansion, function(self, tw) { - self.expression = self.expression.transform(tw); - }); - - _(AST_NameMapping, function(self, tw) { - self.foreign_name = self.foreign_name.transform(tw); - self.name = self.name.transform(tw); - }); - - _(AST_Import, function(self, tw) { - if (self.imported_name) self.imported_name = self.imported_name.transform(tw); - if (self.imported_names) do_list(self.imported_names, tw); - self.module_name = self.module_name.transform(tw); - }); - - _(AST_Export, function(self, tw) { - if (self.exported_definition) self.exported_definition = self.exported_definition.transform(tw); - if (self.exported_value) self.exported_value = self.exported_value.transform(tw); - if (self.exported_names) do_list(self.exported_names, tw); - if (self.module_name) self.module_name = self.module_name.transform(tw); - }); - - _(AST_TemplateString, function(self, tw) { - self.segments = do_list(self.segments, tw); - }); - - _(AST_PrefixedTemplateString, function(self, tw) { - self.prefix = self.prefix.transform(tw); - self.template_string = self.template_string.transform(tw); - }); - - })(); - - /*********************************************************************** - - A JavaScript tokenizer / parser / beautifier / compressor. - https://github.com/mishoo/UglifyJS2 - - -------------------------------- (C) --------------------------------- - - Author: Mihai Bazon - - http://mihai.bazon.net/blog - - Distributed under the BSD license: - - Copyright 2012 (c) Mihai Bazon - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - * Redistributions of source code must retain the above - copyright notice, this list of conditions and the following - disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials - provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY - EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - SUCH DAMAGE. - - ***********************************************************************/ - - function SymbolDef(scope, orig, init) { - this.name = orig.name; - this.orig = [ orig ]; - this.init = init; - this.eliminated = 0; - this.scope = scope; - this.references = []; - this.replaced = 0; - this.global = false; - this.export = false; - this.mangled_name = null; - this.undeclared = false; - this.id = SymbolDef.next_id++; - } - - SymbolDef.next_id = 1; - - var MASK_EXPORT_DONT_MANGLE = 1 << 0; - var MASK_EXPORT_WANT_MANGLE = 1 << 1; - - SymbolDef.prototype = { - unmangleable: function(options) { - if (!options) options = {}; - - return this.global && !options.toplevel - || (this.export & MASK_EXPORT_DONT_MANGLE) - || this.undeclared - || !options.eval && this.scope.pinned() - || (this.orig[0] instanceof AST_SymbolLambda - || this.orig[0] instanceof AST_SymbolDefun) && keep_name(options.keep_fnames, this.orig[0].name) - || this.orig[0] instanceof AST_SymbolMethod - || (this.orig[0] instanceof AST_SymbolClass - || this.orig[0] instanceof AST_SymbolDefClass) && keep_name(options.keep_classnames, this.orig[0].name); - }, - mangle: function(options) { - var cache = options.cache && options.cache.props; - if (this.global && cache && cache.has(this.name)) { - this.mangled_name = cache.get(this.name); - } else if (!this.mangled_name && !this.unmangleable(options)) { - var s = this.scope; - var sym = this.orig[0]; - if (options.ie8 && sym instanceof AST_SymbolLambda) - s = s.parent_scope; - var def; - if (def = this.redefined()) { - this.mangled_name = def.mangled_name || def.name; - } else - this.mangled_name = s.next_mangled(options, this); - if (this.global && cache) { - cache.set(this.name, this.mangled_name); - } - } - }, - redefined: function() { - return this.defun && this.defun.variables.get(this.name); - } - }; - - AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) { - options = defaults(options, { - cache: null, - ie8: false, - safari10: false, - }); - - // pass 1: setup scope chaining and handle definitions - var self = this; - var scope = self.parent_scope = null; - var labels = new Map(); - var defun = null; - var in_destructuring = null; - var for_scopes = []; - var tw = new TreeWalker(function(node, descend) { - if (node.is_block_scope()) { - var save_scope = scope; - node.block_scope = scope = new AST_Scope(node); - scope.init_scope_vars(save_scope); - if (!(node instanceof AST_Scope)) { - scope.uses_with = save_scope.uses_with; - scope.uses_eval = save_scope.uses_eval; - scope.directives = save_scope.directives; - } - if (options.safari10) { - if (node instanceof AST_For || node instanceof AST_ForIn) { - for_scopes.push(scope); - } - } - descend(); - scope = save_scope; - return true; - } - if (node instanceof AST_Destructuring) { - in_destructuring = node; // These don't nest - descend(); - in_destructuring = null; - return true; - } - if (node instanceof AST_Scope) { - node.init_scope_vars(scope); - var save_scope = scope; - var save_defun = defun; - var save_labels = labels; - defun = scope = node; - labels = new Map(); - descend(); - scope = save_scope; - defun = save_defun; - labels = save_labels; - return true; // don't descend again in TreeWalker - } - if (node instanceof AST_LabeledStatement) { - var l = node.label; - if (labels.has(l.name)) { - throw new Error(string_template("Label {name} defined twice", l)); - } - labels.set(l.name, l); - descend(); - labels.delete(l.name); - return true; // no descend again - } - if (node instanceof AST_With) { - for (var s = scope; s; s = s.parent_scope) - s.uses_with = true; - return; - } - if (node instanceof AST_Symbol) { - node.scope = scope; - } - if (node instanceof AST_Label) { - node.thedef = node; - node.references = []; - } - if (node instanceof AST_SymbolLambda) { - defun.def_function(node, node.name == "arguments" ? undefined : defun); - } else if (node instanceof AST_SymbolDefun) { - // Careful here, the scope where this should be defined is - // the parent scope. The reason is that we enter a new - // scope when we encounter the AST_Defun node (which is - // instanceof AST_Scope) but we get to the symbol a bit - // later. - mark_export((node.scope = defun.parent_scope.get_defun_scope()).def_function(node, defun), 1); - } else if (node instanceof AST_SymbolClass) { - mark_export(defun.def_variable(node, defun), 1); - } else if (node instanceof AST_SymbolImport) { - scope.def_variable(node); - } else if (node instanceof AST_SymbolDefClass) { - // This deals with the name of the class being available - // inside the class. - mark_export((node.scope = defun.parent_scope).def_function(node, defun), 1); - } else if (node instanceof AST_SymbolVar - || node instanceof AST_SymbolLet - || node instanceof AST_SymbolConst) { - var def; - if (node instanceof AST_SymbolBlockDeclaration) { - def = scope.def_variable(node, null); - } else { - def = defun.def_variable(node, node.TYPE == "SymbolVar" ? null : undefined); - } - if (!def.orig.every((sym) => { - if (sym === node) return true; - if (node instanceof AST_SymbolBlockDeclaration) { - return sym instanceof AST_SymbolLambda; - } - return !(sym instanceof AST_SymbolLet || sym instanceof AST_SymbolConst); - })) { - js_error( - node.name + " redeclared", - node.start.file, - node.start.line, - node.start.col, - node.start.pos - ); - } - if (!(node instanceof AST_SymbolFunarg)) mark_export(def, 2); - def.destructuring = in_destructuring; - if (defun !== scope) { - node.mark_enclosed(options); - var def = scope.find_variable(node); - if (node.thedef !== def) { - node.thedef = def; - node.reference(options); - } - } - } else if (node instanceof AST_SymbolCatch) { - scope.def_variable(node).defun = defun; - } else if (node instanceof AST_LabelRef) { - var sym = labels.get(node.name); - if (!sym) throw new Error(string_template("Undefined label {name} [{line},{col}]", { - name: node.name, - line: node.start.line, - col: node.start.col - })); - node.thedef = sym; - } - if (!(scope instanceof AST_Toplevel) && (node instanceof AST_Export || node instanceof AST_Import)) { - js_error( - node.TYPE + " statement may only appear at top level", - node.start.file, - node.start.line, - node.start.col, - node.start.pos - ); - } - - function mark_export(def, level) { - if (in_destructuring) { - var i = 0; - do { - level++; - } while (tw.parent(i++) !== in_destructuring); - } - var node = tw.parent(level); - if (def.export = node instanceof AST_Export && MASK_EXPORT_DONT_MANGLE) { - var exported = node.exported_definition; - if ((exported instanceof AST_Defun || exported instanceof AST_DefClass) && node.is_default) { - def.export = MASK_EXPORT_WANT_MANGLE; - } - } - } - }); - self.walk(tw); - - // pass 2: find back references and eval - self.globals = new Map(); - var tw = new TreeWalker(function(node, descend) { - if (node instanceof AST_LoopControl && node.label) { - node.label.thedef.references.push(node); - return true; - } - if (node instanceof AST_SymbolRef) { - var name = node.name; - if (name == "eval" && tw.parent() instanceof AST_Call) { - for (var s = node.scope; s && !s.uses_eval; s = s.parent_scope) { - s.uses_eval = true; - } - } - var sym; - if (tw.parent() instanceof AST_NameMapping && tw.parent(1).module_name - || !(sym = node.scope.find_variable(name))) { - sym = self.def_global(node); - if (node instanceof AST_SymbolExport) sym.export = MASK_EXPORT_DONT_MANGLE; - } else if (sym.scope instanceof AST_Lambda && name == "arguments") { - sym.scope.uses_arguments = true; - } - node.thedef = sym; - node.reference(options); - if (node.scope.is_block_scope() - && !(sym.orig[0] instanceof AST_SymbolBlockDeclaration)) { - node.scope = node.scope.get_defun_scope(); - } - return true; - } - // ensure mangling works if catch reuses a scope variable - var def; - if (node instanceof AST_SymbolCatch && (def = node.definition().redefined())) { - var s = node.scope; - while (s) { - push_uniq(s.enclosed, def); - if (s === def.scope) break; - s = s.parent_scope; - } - } - }); - self.walk(tw); - - // pass 3: work around IE8 and Safari catch scope bugs - if (options.ie8 || options.safari10) { - self.walk(new TreeWalker(function(node, descend) { - if (node instanceof AST_SymbolCatch) { - var name = node.name; - var refs = node.thedef.references; - var scope = node.thedef.defun; - var def = scope.find_variable(name) || self.globals.get(name) || scope.def_variable(node); - refs.forEach(function(ref) { - ref.thedef = def; - ref.reference(options); - }); - node.thedef = def; - node.reference(options); - return true; - } - })); - } - - // pass 4: add symbol definitions to loop scopes - // Safari/Webkit bug workaround - loop init let variable shadowing argument. - // https://github.com/mishoo/UglifyJS2/issues/1753 - // https://bugs.webkit.org/show_bug.cgi?id=171041 - if (options.safari10) { - for (var i = 0; i < for_scopes.length; i++) { - var scope = for_scopes[i]; - scope.parent_scope.variables.forEach(function(def) { - push_uniq(scope.enclosed, def); - }); - } - } - }); - - AST_Toplevel.DEFMETHOD("def_global", function(node) { - var globals = this.globals, name = node.name; - if (globals.has(name)) { - return globals.get(name); - } else { - var g = new SymbolDef(this, node); - g.undeclared = true; - g.global = true; - globals.set(name, g); - return g; - } - }); - - AST_Scope.DEFMETHOD("init_scope_vars", function(parent_scope) { - this.variables = new Map(); // map name to AST_SymbolVar (variables defined in this scope; includes functions) - this.functions = new Map(); // map name to AST_SymbolDefun (functions defined in this scope) - this.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement - this.uses_eval = false; // will be set to true if this or nested scope uses the global `eval` - this.parent_scope = parent_scope; // the parent scope - this.enclosed = []; // a list of variables from this or outer scope(s) that are referenced from this or inner scopes - this.cname = -1; // the current index for mangling functions/variables - }); - - AST_Node.DEFMETHOD("is_block_scope", return_false); - AST_Class.DEFMETHOD("is_block_scope", return_false); - AST_Lambda.DEFMETHOD("is_block_scope", return_false); - AST_Toplevel.DEFMETHOD("is_block_scope", return_false); - AST_SwitchBranch.DEFMETHOD("is_block_scope", return_false); - AST_Block.DEFMETHOD("is_block_scope", return_true); - AST_IterationStatement.DEFMETHOD("is_block_scope", return_true); - - AST_Lambda.DEFMETHOD("init_scope_vars", function() { - AST_Scope.prototype.init_scope_vars.apply(this, arguments); - this.uses_arguments = false; - this.def_variable(new AST_SymbolFunarg({ - name: "arguments", - start: this.start, - end: this.end - })); - }); - - AST_Arrow.DEFMETHOD("init_scope_vars", function() { - AST_Scope.prototype.init_scope_vars.apply(this, arguments); - this.uses_arguments = false; - }); - - AST_Symbol.DEFMETHOD("mark_enclosed", function(options) { - var def = this.definition(); - var s = this.scope; - while (s) { - push_uniq(s.enclosed, def); - if (options.keep_fnames) { - s.functions.forEach(function(d) { - if (keep_name(options.keep_fnames, d.name)) { - push_uniq(def.scope.enclosed, d); - } - }); - } - if (s === def.scope) break; - s = s.parent_scope; - } - }); - - AST_Symbol.DEFMETHOD("reference", function(options) { - this.definition().references.push(this); - this.mark_enclosed(options); - }); - - AST_Scope.DEFMETHOD("find_variable", function(name) { - if (name instanceof AST_Symbol) name = name.name; - return this.variables.get(name) - || (this.parent_scope && this.parent_scope.find_variable(name)); - }); - - AST_Scope.DEFMETHOD("def_function", function(symbol, init) { - var def = this.def_variable(symbol, init); - if (!def.init || def.init instanceof AST_Defun) def.init = init; - this.functions.set(symbol.name, def); - return def; - }); - - AST_Scope.DEFMETHOD("def_variable", function(symbol, init) { - var def = this.variables.get(symbol.name); - if (def) { - def.orig.push(symbol); - if (def.init && (def.scope !== symbol.scope || def.init instanceof AST_Function)) { - def.init = init; - } - } else { - def = new SymbolDef(this, symbol, init); - this.variables.set(symbol.name, def); - def.global = !this.parent_scope; - } - return symbol.thedef = def; - }); - - function next_mangled(scope, options) { - var ext = scope.enclosed; - out: while (true) { - var m = base54(++scope.cname); - if (RESERVED_WORDS.has(m)) continue; // skip over "do" - - // https://github.com/mishoo/UglifyJS2/issues/242 -- do not - // shadow a name reserved from mangling. - if (member(m, options.reserved)) continue; - - // we must ensure that the mangled name does not shadow a name - // from some parent scope that is referenced in this or in - // inner scopes. - for (var i = ext.length; --i >= 0;) { - var sym = ext[i]; - var name = sym.mangled_name || (sym.unmangleable(options) && sym.name); - if (m == name) continue out; - } - return m; - } - } - - AST_Scope.DEFMETHOD("next_mangled", function(options) { - return next_mangled(this, options); - }); - - AST_Toplevel.DEFMETHOD("next_mangled", function(options) { - var name; - do { - name = next_mangled(this, options); - } while (this.mangled_names.has(name)); - return name; - }); - - AST_Function.DEFMETHOD("next_mangled", function(options, def) { - // #179, #326 - // in Safari strict mode, something like (function x(x){...}) is a syntax error; - // a function expression's argument cannot shadow the function expression's name - - var tricky_def = def.orig[0] instanceof AST_SymbolFunarg && this.name && this.name.definition(); - - // the function's mangled_name is null when keep_fnames is true - var tricky_name = tricky_def ? tricky_def.mangled_name || tricky_def.name : null; - - while (true) { - var name = next_mangled(this, options); - if (!tricky_name || tricky_name != name) - return name; - } - }); - - AST_Symbol.DEFMETHOD("unmangleable", function(options) { - var def = this.definition(); - return !def || def.unmangleable(options); - }); - - // labels are always mangleable - AST_Label.DEFMETHOD("unmangleable", return_false); - - AST_Symbol.DEFMETHOD("unreferenced", function() { - return !this.definition().references.length && !this.scope.pinned(); - }); - - AST_Symbol.DEFMETHOD("definition", function() { - return this.thedef; - }); - - AST_Symbol.DEFMETHOD("global", function() { - return this.definition().global; - }); - - AST_Toplevel.DEFMETHOD("_default_mangler_options", function(options) { - options = defaults(options, { - eval : false, - ie8 : false, - keep_classnames: false, - keep_fnames : false, - module : false, - reserved : [], - toplevel : false, - }); - if (options["module"]) { - options.toplevel = true; - } - if (!Array.isArray(options.reserved)) options.reserved = []; - // Never mangle arguments - push_uniq(options.reserved, "arguments"); - return options; - }); - - AST_Toplevel.DEFMETHOD("mangle_names", function(options) { - options = this._default_mangler_options(options); - - // We only need to mangle declaration nodes. Special logic wired - // into the code generator will display the mangled name if it's - // present (and for AST_SymbolRef-s it'll use the mangled name of - // the AST_SymbolDeclaration that it points to). - var lname = -1; - var to_mangle = []; - - var mangled_names = this.mangled_names = new Set(); - if (options.cache) { - this.globals.forEach(collect); - if (options.cache.props) { - options.cache.props.forEach(function(mangled_name) { - mangled_names.add(mangled_name); - }); - } - } - - var tw = new TreeWalker(function(node, descend) { - if (node instanceof AST_LabeledStatement) { - // lname is incremented when we get to the AST_Label - var save_nesting = lname; - descend(); - lname = save_nesting; - return true; // don't descend again in TreeWalker - } - if (node instanceof AST_Scope) { - node.variables.forEach(collect); - return; - } - if (node.is_block_scope()) { - node.block_scope.variables.forEach(collect); - return; - } - if (node instanceof AST_Label) { - var name; - do name = base54(++lname); while (RESERVED_WORDS.has(name)); - node.mangled_name = name; - return true; - } - if (!(options.ie8 || options.safari10) && node instanceof AST_SymbolCatch) { - to_mangle.push(node.definition()); - return; - } - }); - this.walk(tw); - to_mangle.forEach(function(def) { def.mangle(options); }); - - function collect(symbol) { - if (!member(symbol.name, options.reserved)) { - if (!(symbol.export & MASK_EXPORT_DONT_MANGLE)) { - to_mangle.push(symbol); - } - } - } - }); - - AST_Toplevel.DEFMETHOD("find_colliding_names", function(options) { - var cache = options.cache && options.cache.props; - var avoid = new Set(); - options.reserved.forEach(to_avoid); - this.globals.forEach(add_def); - this.walk(new TreeWalker(function(node) { - if (node instanceof AST_Scope) node.variables.forEach(add_def); - if (node instanceof AST_SymbolCatch) add_def(node.definition()); - })); - return avoid; - - function to_avoid(name) { - avoid.add(name); - } - - function add_def(def) { - var name = def.name; - if (def.global && cache && cache.has(name)) name = cache.get(name); - else if (!def.unmangleable(options)) return; - to_avoid(name); - } - }); - - AST_Toplevel.DEFMETHOD("expand_names", function(options) { - base54.reset(); - base54.sort(); - options = this._default_mangler_options(options); - var avoid = this.find_colliding_names(options); - var cname = 0; - this.globals.forEach(rename); - this.walk(new TreeWalker(function(node) { - if (node instanceof AST_Scope) node.variables.forEach(rename); - if (node instanceof AST_SymbolCatch) rename(node.definition()); - })); - - function next_name() { - var name; - do { - name = base54(cname++); - } while (avoid.has(name) || RESERVED_WORDS.has(name)); - return name; - } - - function rename(def) { - if (def.global && options.cache) return; - if (def.unmangleable(options)) return; - if (member(def.name, options.reserved)) return; - var d = def.redefined(); - def.name = d ? d.name : next_name(); - def.orig.forEach(function(sym) { - sym.name = def.name; - }); - def.references.forEach(function(sym) { - sym.name = def.name; - }); - } - }); - - AST_Node.DEFMETHOD("tail_node", return_this); - AST_Sequence.DEFMETHOD("tail_node", function() { - return this.expressions[this.expressions.length - 1]; - }); - - AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options) { - options = this._default_mangler_options(options); - try { - AST_Node.prototype.print = function(stream, force_parens) { - this._print(stream, force_parens); - if (this instanceof AST_Symbol && !this.unmangleable(options)) { - base54.consider(this.name, -1); - } else if (options.properties) { - if (this instanceof AST_Dot) { - base54.consider(this.property, -1); - } else if (this instanceof AST_Sub) { - skip_string(this.property); - } - } - }; - base54.consider(this.print_to_string(), 1); - } finally { - AST_Node.prototype.print = AST_Node.prototype._print; - } - base54.sort(); - - function skip_string(node) { - if (node instanceof AST_String) { - base54.consider(node.value, -1); - } else if (node instanceof AST_Conditional) { - skip_string(node.consequent); - skip_string(node.alternative); - } else if (node instanceof AST_Sequence) { - skip_string(node.tail_node()); - } - } - }); - - var base54 = (function() { - var leading = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_".split(""); - var digits = "0123456789".split(""); - var chars, frequency; - function reset() { - frequency = new Map(); - leading.forEach(function(ch) { - frequency.set(ch, 0); - }); - digits.forEach(function(ch) { - frequency.set(ch, 0); - }); - } - base54.consider = function(str, delta) { - for (var i = str.length; --i >= 0;) { - frequency.set(str[i], frequency.get(str[i]) + delta); - } - }; - function compare(a, b) { - return frequency.get(b) - frequency.get(a); - } - base54.sort = function() { - chars = mergeSort(leading, compare).concat(mergeSort(digits, compare)); - }; - base54.reset = reset; - reset(); - function base54(num) { - var ret = "", base = 54; - num++; - do { - num--; - ret += chars[num % base]; - num = Math.floor(num / base); - base = 64; - } while (num > 0); - return ret; - } - return base54; - })(); - - // return true if the node at the top of the stack (that means the - // innermost node in the current output) is lexically the first in - // a statement. - function first_in_statement(stack) { - let node = stack.parent(-1); - for (let i = 0, p; p = stack.parent(i); i++) { - if (p instanceof AST_Statement && p.body === node) - return true; - if ((p instanceof AST_Sequence && p.expressions[0] === node) || - (p.TYPE === "Call" && p.expression === node) || - (p instanceof AST_Dot && p.expression === node) || - (p instanceof AST_Sub && p.expression === node) || - (p instanceof AST_Conditional && p.condition === node) || - (p instanceof AST_Binary && p.left === node) || - (p instanceof AST_UnaryPostfix && p.expression === node) - ) { - node = p; - } else { - return false; - } - } - } - - /*********************************************************************** - - A JavaScript tokenizer / parser / beautifier / compressor. - https://github.com/mishoo/UglifyJS2 - - -------------------------------- (C) --------------------------------- - - Author: Mihai Bazon - - http://mihai.bazon.net/blog - - Distributed under the BSD license: - - Copyright 2012 (c) Mihai Bazon - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - * Redistributions of source code must retain the above - copyright notice, this list of conditions and the following - disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials - provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY - EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - SUCH DAMAGE. - - ***********************************************************************/ - - var EXPECT_DIRECTIVE = /^$|[;{][\s\n]*$/; - const CODE_LINE_BREAK = 10; - const CODE_SPACE = 32; - - function is_some_comments(comment) { - // multiline comment - return comment.type == "comment2" && /@preserve|@license|@cc_on/i.test(comment.value); - } - - function OutputStream(options) { - - var readonly = !options; - options = defaults(options, { - ascii_only : false, - beautify : false, - braces : false, - comments : false, - ecma : 5, - ie8 : false, - indent_level : 4, - indent_start : 0, - inline_script : true, - keep_quoted_props: false, - max_line_len : false, - preamble : null, - quote_keys : false, - quote_style : 0, - safari10 : false, - semicolons : true, - shebang : true, - shorthand : undefined, - source_map : null, - webkit : false, - width : 80, - wrap_iife : false, - }, true); - - if (options.shorthand === undefined) - options.shorthand = options.ecma > 5; - - // Convert comment option to RegExp if neccessary and set up comments filter - var comment_filter = return_false; // Default case, throw all comments away - if (options.comments) { - var comments = options.comments; - if (typeof options.comments === "string" && /^\/.*\/[a-zA-Z]*$/.test(options.comments)) { - var regex_pos = options.comments.lastIndexOf("/"); - comments = new RegExp( - options.comments.substr(1, regex_pos - 1), - options.comments.substr(regex_pos + 1) - ); - } - if (comments instanceof RegExp) { - comment_filter = function(comment) { - return comment.type != "comment5" && comments.test(comment.value); - }; - } else if (typeof comments === "function") { - comment_filter = function(comment) { - return comment.type != "comment5" && comments(this, comment); - }; - } else if (comments === "some") { - comment_filter = is_some_comments; - } else { // NOTE includes "all" option - comment_filter = return_true; - } - } - - var indentation = 0; - var current_col = 0; - var current_line = 1; - var current_pos = 0; - var OUTPUT = ""; - - var to_utf8 = options.ascii_only ? function(str, identifier) { - if (options.ecma >= 6) { - str = str.replace(/[\ud800-\udbff][\udc00-\udfff]/g, function(ch) { - var code = get_full_char_code(ch, 0).toString(16); - return "\\u{" + code + "}"; - }); - } - return str.replace(/[\u0000-\u001f\u007f-\uffff]/g, function(ch) { - var code = ch.charCodeAt(0).toString(16); - if (code.length <= 2 && !identifier) { - while (code.length < 2) code = "0" + code; - return "\\x" + code; - } else { - while (code.length < 4) code = "0" + code; - return "\\u" + code; - } - }); - } : function(str) { - var s = ""; - for (var i = 0, len = str.length; i < len; i++) { - if (is_surrogate_pair_head(str[i]) && !is_surrogate_pair_tail(str[i + 1]) - || is_surrogate_pair_tail(str[i]) && !is_surrogate_pair_head(str[i - 1])) { - s += "\\u" + str.charCodeAt(i).toString(16); - } else { - s += str[i]; - } - } - return s; - }; - - function make_string(str, quote) { - var dq = 0, sq = 0; - str = str.replace(/[\\\b\f\n\r\v\t\x22\x27\u2028\u2029\0\ufeff]/g, - function(s, i) { - switch (s) { - case '"': ++dq; return '"'; - case "'": ++sq; return "'"; - case "\\": return "\\\\"; - case "\n": return "\\n"; - case "\r": return "\\r"; - case "\t": return "\\t"; - case "\b": return "\\b"; - case "\f": return "\\f"; - case "\x0B": return options.ie8 ? "\\x0B" : "\\v"; - case "\u2028": return "\\u2028"; - case "\u2029": return "\\u2029"; - case "\ufeff": return "\\ufeff"; - case "\0": - return /[0-9]/.test(get_full_char(str, i+1)) ? "\\x00" : "\\0"; - } - return s; - }); - function quote_single() { - return "'" + str.replace(/\x27/g, "\\'") + "'"; - } - function quote_double() { - return '"' + str.replace(/\x22/g, '\\"') + '"'; - } - function quote_template() { - return "`" + str.replace(/`/g, "\\`") + "`"; - } - str = to_utf8(str); - if (quote === "`") return quote_template(); - switch (options.quote_style) { - case 1: - return quote_single(); - case 2: - return quote_double(); - case 3: - return quote == "'" ? quote_single() : quote_double(); - default: - return dq > sq ? quote_single() : quote_double(); - } - } - - function encode_string(str, quote) { - var ret = make_string(str, quote); - if (options.inline_script) { - ret = ret.replace(/<\x2f(script)([>\/\t\n\f\r ])/gi, "<\\/$1$2"); - ret = ret.replace(/\x3c!--/g, "\\x3c!--"); - ret = ret.replace(/--\x3e/g, "--\\x3e"); - } - return ret; - } - - function make_name(name) { - name = name.toString(); - name = to_utf8(name, true); - return name; - } - - function make_indent(back) { - return " ".repeat(options.indent_start + indentation - back * options.indent_level); - } - - /* -----[ beautification/minification ]----- */ - - var has_parens = false; - var might_need_space = false; - var might_need_semicolon = false; - var might_add_newline = 0; - var need_newline_indented = false; - var need_space = false; - var newline_insert = -1; - var last = ""; - var mapping_token, mapping_name, mappings = options.source_map && []; - - var do_add_mapping = mappings ? function() { - mappings.forEach(function(mapping) { - try { - options.source_map.add( - mapping.token.file, - mapping.line, mapping.col, - mapping.token.line, mapping.token.col, - !mapping.name && mapping.token.type == "name" ? mapping.token.value : mapping.name - ); - } catch(ex) { - mapping.token.file != null && AST_Node.warn("Couldn't figure out mapping for {file}:{line},{col} → {cline},{ccol} [{name}]", { - file: mapping.token.file, - line: mapping.token.line, - col: mapping.token.col, - cline: mapping.line, - ccol: mapping.col, - name: mapping.name || "" - }); - } - }); - mappings = []; - } : noop; - - var ensure_line_len = options.max_line_len ? function() { - if (current_col > options.max_line_len) { - if (might_add_newline) { - var left = OUTPUT.slice(0, might_add_newline); - var right = OUTPUT.slice(might_add_newline); - if (mappings) { - var delta = right.length - current_col; - mappings.forEach(function(mapping) { - mapping.line++; - mapping.col += delta; - }); - } - OUTPUT = left + "\n" + right; - current_line++; - current_pos++; - current_col = right.length; - } - if (current_col > options.max_line_len) { - AST_Node.warn("Output exceeds {max_line_len} characters", options); - } - } - if (might_add_newline) { - might_add_newline = 0; - do_add_mapping(); - } - } : noop; - - var requireSemicolonChars = makePredicate("( [ + * / - , . `"); - - function print(str) { - str = String(str); - var ch = get_full_char(str, 0); - if (need_newline_indented && ch) { - need_newline_indented = false; - if (ch !== "\n") { - print("\n"); - indent(); - } - } - if (need_space && ch) { - need_space = false; - if (!/[\s;})]/.test(ch)) { - space(); - } - } - newline_insert = -1; - var prev = last.charAt(last.length - 1); - if (might_need_semicolon) { - might_need_semicolon = false; - - if (prev === ":" && ch === "}" || (!ch || !";}".includes(ch)) && prev !== ";") { - if (options.semicolons || requireSemicolonChars.has(ch)) { - OUTPUT += ";"; - current_col++; - current_pos++; - } else { - ensure_line_len(); - if (current_col > 0) { - OUTPUT += "\n"; - current_pos++; - current_line++; - current_col = 0; - } - - if (/^\s+$/.test(str)) { - // reset the semicolon flag, since we didn't print one - // now and might still have to later - might_need_semicolon = true; - } - } - - if (!options.beautify) - might_need_space = false; - } - } - - if (might_need_space) { - if ((is_identifier_char(prev) - && (is_identifier_char(ch) || ch == "\\")) - || (ch == "/" && ch == prev) - || ((ch == "+" || ch == "-") && ch == last) - ) { - OUTPUT += " "; - current_col++; - current_pos++; - } - might_need_space = false; - } - - if (mapping_token) { - mappings.push({ - token: mapping_token, - name: mapping_name, - line: current_line, - col: current_col - }); - mapping_token = false; - if (!might_add_newline) do_add_mapping(); - } - - OUTPUT += str; - has_parens = str[str.length - 1] == "("; - current_pos += str.length; - var a = str.split(/\r?\n/), n = a.length - 1; - current_line += n; - current_col += a[0].length; - if (n > 0) { - ensure_line_len(); - current_col = a[n].length; - } - last = str; - } - - var star = function() { - print("*"); - }; - - var space = options.beautify ? function() { - print(" "); - } : function() { - might_need_space = true; - }; - - var indent = options.beautify ? function(half) { - if (options.beautify) { - print(make_indent(half ? 0.5 : 0)); - } - } : noop; - - var with_indent = options.beautify ? function(col, cont) { - if (col === true) col = next_indent(); - var save_indentation = indentation; - indentation = col; - var ret = cont(); - indentation = save_indentation; - return ret; - } : function(col, cont) { return cont(); }; - - var newline = options.beautify ? function() { - if (newline_insert < 0) return print("\n"); - if (OUTPUT[newline_insert] != "\n") { - OUTPUT = OUTPUT.slice(0, newline_insert) + "\n" + OUTPUT.slice(newline_insert); - current_pos++; - current_line++; - } - newline_insert++; - } : options.max_line_len ? function() { - ensure_line_len(); - might_add_newline = OUTPUT.length; - } : noop; - - var semicolon = options.beautify ? function() { - print(";"); - } : function() { - might_need_semicolon = true; - }; - - function force_semicolon() { - might_need_semicolon = false; - print(";"); - } - - function next_indent() { - return indentation + options.indent_level; - } - - function with_block(cont) { - var ret; - print("{"); - newline(); - with_indent(next_indent(), function() { - ret = cont(); - }); - indent(); - print("}"); - return ret; - } - - function with_parens(cont) { - print("("); - //XXX: still nice to have that for argument lists - //var ret = with_indent(current_col, cont); - var ret = cont(); - print(")"); - return ret; - } - - function with_square(cont) { - print("["); - //var ret = with_indent(current_col, cont); - var ret = cont(); - print("]"); - return ret; - } - - function comma() { - print(","); - space(); - } - - function colon() { - print(":"); - space(); - } - - var add_mapping = mappings ? function(token, name) { - mapping_token = token; - mapping_name = name; - } : noop; - - function get() { - if (might_add_newline) { - ensure_line_len(); - } - return OUTPUT; - } - - function has_nlb() { - let n = OUTPUT.length - 1; - while (n >= 0) { - const code = OUTPUT.charCodeAt(n); - if (code === CODE_LINE_BREAK) { - return true; - } + if (!options.beautify) + might_need_space = false; + } + } + + if (might_need_space) { + if ((is_identifier_char(prev) + && (is_identifier_char(ch) || ch == "\\")) + || (ch == "/" && ch == prev) + || ((ch == "+" || ch == "-") && ch == last) + ) { + OUTPUT.append(" "); + current_col++; + current_pos++; + } + might_need_space = false; + } + + if (mapping_token) { + mappings.push({ + token: mapping_token, + name: mapping_name, + line: current_line, + col: current_col + }); + mapping_token = false; + if (!might_add_newline) do_add_mapping(); + } + + OUTPUT.append(str); + has_parens = str[str.length - 1] == "("; + current_pos += str.length; + var a = str.split(/\r?\n/), n = a.length - 1; + current_line += n; + current_col += a[0].length; + if (n > 0) { + ensure_line_len(); + current_col = a[n].length; + } + last = str; + } + + var star = function() { + print("*"); + }; + + var space = options.beautify ? function() { + print(" "); + } : function() { + might_need_space = true; + }; + + var indent = options.beautify ? function(half) { + if (options.beautify) { + print(make_indent(half ? 0.5 : 0)); + } + } : noop; + + var with_indent = options.beautify ? function(col, cont) { + if (col === true) col = next_indent(); + var save_indentation = indentation; + indentation = col; + var ret = cont(); + indentation = save_indentation; + return ret; + } : function(col, cont) { return cont(); }; + + var newline = options.beautify ? function() { + if (newline_insert < 0) return print("\n"); + if (OUTPUT.charAt(newline_insert) != "\n") { + OUTPUT.insertAt("\n", newline_insert); + current_pos++; + current_line++; + } + newline_insert++; + } : options.max_line_len ? function() { + ensure_line_len(); + might_add_newline = OUTPUT.length(); + } : noop; + + var semicolon = options.beautify ? function() { + print(";"); + } : function() { + might_need_semicolon = true; + }; + + function force_semicolon() { + might_need_semicolon = false; + print(";"); + } + + function next_indent() { + return indentation + options.indent_level; + } + + function with_block(cont) { + var ret; + print("{"); + newline(); + with_indent(next_indent(), function() { + ret = cont(); + }); + indent(); + print("}"); + return ret; + } + + function with_parens(cont) { + print("("); + //XXX: still nice to have that for argument lists + //var ret = with_indent(current_col, cont); + var ret = cont(); + print(")"); + return ret; + } + + function with_square(cont) { + print("["); + //var ret = with_indent(current_col, cont); + var ret = cont(); + print("]"); + return ret; + } + + function comma() { + print(","); + space(); + } + + function colon() { + print(":"); + space(); + } + + var add_mapping = mappings ? function(token, name) { + mapping_token = token; + mapping_name = name; + } : noop; + + function get() { + if (might_add_newline) { + ensure_line_len(); + } + return OUTPUT.toString(); + } + + function has_nlb() { + const output = OUTPUT.toString(); + let n = output.length - 1; + while (n >= 0) { + const code = output.charCodeAt(n); + if (code === CODE_LINE_BREAK) { + return true; + } + + if (code !== CODE_SPACE) { + return false; + } + n--; + } + return true; + } + + function filter_comment(comment) { + if (!options.preserve_annotations) { + comment = comment.replace(r_annotation, " "); + } + if (/^\s*$/.test(comment)) { + return ""; + } + return comment.replace(/(<\s*\/\s*)(script)/i, "<\\/$2"); + } + + function prepend_comments(node) { + var self = this; + var start = node.start; + if (!start) return; + var printed_comments = self.printed_comments; + + // There cannot be a newline between return/yield and its value. + const keyword_with_value = + node instanceof AST_Exit && node.value + || (node instanceof AST_Await || node instanceof AST_Yield) + && node.expression; + + if ( + start.comments_before + && printed_comments.has(start.comments_before) + ) { + if (keyword_with_value) { + start.comments_before = []; + } else { + return; + } + } + + var comments = start.comments_before; + if (!comments) { + comments = start.comments_before = []; + } + printed_comments.add(comments); + + if (keyword_with_value) { + var tw = new TreeWalker(function(node) { + var parent = tw.parent(); + if (parent instanceof AST_Exit + || parent instanceof AST_Await + || parent instanceof AST_Yield + || parent instanceof AST_Binary && parent.left === node + || parent.TYPE == "Call" && parent.expression === node + || parent instanceof AST_Conditional && parent.condition === node + || parent instanceof AST_Dot && parent.expression === node + || parent instanceof AST_Sequence && parent.expressions[0] === node + || parent instanceof AST_Sub && parent.expression === node + || parent instanceof AST_UnaryPostfix) { + if (!node.start) return; + var text = node.start.comments_before; + if (text && !printed_comments.has(text)) { + printed_comments.add(text); + comments = comments.concat(text); + } + } else { + return true; + } + }); + tw.push(node); + keyword_with_value.walk(tw); + } + + if (current_pos == 0) { + if (comments.length > 0 && options.shebang && comments[0].type === "comment5" + && !printed_comments.has(comments[0])) { + print("#!" + comments.shift().value + "\n"); + indent(); + } + var preamble = options.preamble; + if (preamble) { + print(preamble.replace(/\r\n?|[\n\u2028\u2029]|\s*$/g, "\n")); + } + } + + comments = comments.filter(comment_filter, node).filter(c => !printed_comments.has(c)); + if (comments.length == 0) return; + var last_nlb = has_nlb(); + comments.forEach(function(c, i) { + printed_comments.add(c); + if (!last_nlb) { + if (c.nlb) { + print("\n"); + indent(); + last_nlb = true; + } else if (i > 0) { + space(); + } + } - if (code !== CODE_SPACE) { - return false; - } - n--; - } - return true; - } - - function prepend_comments(node) { - var self = this; - var start = node.start; - if (!start) return; - if (start.comments_before && start.comments_before._dumped === self) return; - var comments = start.comments_before; - if (!comments) { - comments = start.comments_before = []; - } - comments._dumped = self; - - if (node instanceof AST_Exit && node.value) { - var tw = new TreeWalker(function(node) { - var parent = tw.parent(); - if (parent instanceof AST_Exit - || parent instanceof AST_Binary && parent.left === node - || parent.TYPE == "Call" && parent.expression === node - || parent instanceof AST_Conditional && parent.condition === node - || parent instanceof AST_Dot && parent.expression === node - || parent instanceof AST_Sequence && parent.expressions[0] === node - || parent instanceof AST_Sub && parent.expression === node - || parent instanceof AST_UnaryPostfix) { - if (!node.start) return; - var text = node.start.comments_before; - if (text && text._dumped !== self) { - text._dumped = self; - comments = comments.concat(text); - } - } else { - return true; - } - }); - tw.push(node); - node.value.walk(tw); - } - - if (current_pos == 0) { - if (comments.length > 0 && options.shebang && comments[0].type == "comment5") { - print("#!" + comments.shift().value + "\n"); - indent(); - } - var preamble = options.preamble; - if (preamble) { - print(preamble.replace(/\r\n?|[\n\u2028\u2029]|\s*$/g, "\n")); - } - } - - comments = comments.filter(comment_filter, node); - if (comments.length == 0) return; - var last_nlb = has_nlb(); - comments.forEach(function(c, i) { - if (!last_nlb) { - if (c.nlb) { - print("\n"); - indent(); - last_nlb = true; - } else if (i > 0) { - space(); - } - } - if (/comment[134]/.test(c.type)) { - print("//" + c.value.replace(/[@#]__PURE__/g, " ") + "\n"); - indent(); - last_nlb = true; - } else if (c.type == "comment2") { - print("/*" + c.value.replace(/[@#]__PURE__/g, " ") + "*/"); - last_nlb = false; - } - }); - if (!last_nlb) { - if (start.nlb) { - print("\n"); - indent(); - } else { - space(); - } - } - } - - function append_comments(node, tail) { - var self = this; - var token = node.end; - if (!token) return; - var comments = token[tail ? "comments_before" : "comments_after"]; - if (!comments || comments._dumped === self) return; - if (!(node instanceof AST_Statement || comments.every((c) => - !/comment[134]/.test(c.type) - ))) return; - comments._dumped = self; - var insert = OUTPUT.length; - comments.filter(comment_filter, node).forEach(function(c, i) { - need_space = false; - if (need_newline_indented) { - print("\n"); - indent(); - need_newline_indented = false; - } else if (c.nlb && (i > 0 || !has_nlb())) { - print("\n"); - indent(); - } else if (i > 0 || !tail) { - space(); - } - if (/comment[134]/.test(c.type)) { - print("//" + c.value.replace(/[@#]__PURE__/g, " ")); - need_newline_indented = true; - } else if (c.type == "comment2") { - print("/*" + c.value.replace(/[@#]__PURE__/g, " ") + "*/"); - need_space = true; - } - }); - if (OUTPUT.length > insert) newline_insert = insert; - } - - var stack = []; - return { - get : get, - toString : get, - indent : indent, - indentation : function() { return indentation; }, - current_width : function() { return current_col - indentation; }, - should_break : function() { return options.width && this.current_width() >= options.width; }, - has_parens : function() { return has_parens; }, - newline : newline, - print : print, - star : star, - space : space, - comma : comma, - colon : colon, - last : function() { return last; }, - semicolon : semicolon, - force_semicolon : force_semicolon, - to_utf8 : to_utf8, - print_name : function(name) { print(make_name(name)); }, - print_string : function(str, quote, escape_directive) { - var encoded = encode_string(str, quote); - if (escape_directive === true && !encoded.includes("\\")) { - // Insert semicolons to break directive prologue - if (!EXPECT_DIRECTIVE.test(OUTPUT)) { - force_semicolon(); - } - force_semicolon(); - } - print(encoded); - }, - print_template_string_chars: function(str) { - var encoded = encode_string(str, "`").replace(/\${/g, "\\${"); - return print(encoded.substr(1, encoded.length - 2)); - }, - encode_string : encode_string, - next_indent : next_indent, - with_indent : with_indent, - with_block : with_block, - with_parens : with_parens, - with_square : with_square, - add_mapping : add_mapping, - option : function(opt) { return options[opt]; }, - prepend_comments: readonly ? noop : prepend_comments, - append_comments : readonly || comment_filter === return_false ? noop : append_comments, - line : function() { return current_line; }, - col : function() { return current_col; }, - pos : function() { return current_pos; }, - push_node : function(node) { stack.push(node); }, - pop_node : function() { return stack.pop(); }, - parent : function(n) { - return stack[stack.length - 2 - (n || 0)]; - } - }; - - } - - /* -----[ code generators ]----- */ - - (function() { - - /* -----[ utils ]----- */ - - function DEFPRINT(nodetype, generator) { - nodetype.DEFMETHOD("_codegen", generator); - } - - var in_directive = false; - var active_scope = null; - var use_asm = null; - - AST_Node.DEFMETHOD("print", function(stream, force_parens) { - var self = this, generator = self._codegen; - if (self instanceof AST_Scope) { - active_scope = self; - } else if (!use_asm && self instanceof AST_Directive && self.value == "use asm") { - use_asm = active_scope; - } - function doit() { - stream.prepend_comments(self); - self.add_source_map(stream); - generator(self, stream); - stream.append_comments(self); - } - stream.push_node(self); - if (force_parens || self.needs_parens(stream)) { - stream.with_parens(doit); - } else { - doit(); - } - stream.pop_node(); - if (self === use_asm) { - use_asm = null; - } - }); - AST_Node.DEFMETHOD("_print", AST_Node.prototype.print); - - AST_Node.DEFMETHOD("print_to_string", function(options) { - var s = OutputStream(options); - this.print(s); - return s.get(); - }); - - /* -----[ PARENTHESES ]----- */ - - function PARENS(nodetype, func) { - if (Array.isArray(nodetype)) { - nodetype.forEach(function(nodetype) { - PARENS(nodetype, func); - }); - } else { - nodetype.DEFMETHOD("needs_parens", func); - } - } - - PARENS(AST_Node, return_false); - - // a function expression needs parens around it when it's provably - // the first token to appear in a statement. - PARENS(AST_Function, function(output) { - if (!output.has_parens() && first_in_statement(output)) { - return true; - } - - if (output.option("webkit")) { - var p = output.parent(); - if (p instanceof AST_PropAccess && p.expression === this) { - return true; - } - } - - if (output.option("wrap_iife")) { - var p = output.parent(); - return p instanceof AST_Call && p.expression === this; - } - - return false; - }); - - PARENS(AST_Arrow, function(output) { - var p = output.parent(); - return p instanceof AST_PropAccess && p.expression === this; - }); - - // same goes for an object literal, because otherwise it would be - // interpreted as a block of code. - PARENS(AST_Object, function(output) { - return !output.has_parens() && first_in_statement(output); - }); - - PARENS(AST_ClassExpression, first_in_statement); - - PARENS(AST_Unary, function(output) { - var p = output.parent(); - return p instanceof AST_PropAccess && p.expression === this - || p instanceof AST_Call && p.expression === this - || p instanceof AST_Binary - && p.operator === "**" - && this instanceof AST_UnaryPrefix - && p.left === this - && this.operator !== "++" - && this.operator !== "--"; - }); - - PARENS(AST_Await, function(output) { - var p = output.parent(); - return p instanceof AST_PropAccess && p.expression === this - || p instanceof AST_Call && p.expression === this - || output.option("safari10") && p instanceof AST_UnaryPrefix; - }); - - PARENS(AST_Sequence, function(output) { - var p = output.parent(); - return p instanceof AST_Call // (foo, bar)() or foo(1, (2, 3), 4) - || p instanceof AST_Unary // !(foo, bar, baz) - || p instanceof AST_Binary // 1 + (2, 3) + 4 ==> 8 - || p instanceof AST_VarDef // var a = (1, 2), b = a + a; ==> b == 4 - || p instanceof AST_PropAccess // (1, {foo:2}).foo or (1, {foo:2})["foo"] ==> 2 - || p instanceof AST_Array // [ 1, (2, 3), 4 ] ==> [ 1, 3, 4 ] - || p instanceof AST_ObjectProperty // { foo: (1, 2) }.foo ==> 2 - || p instanceof AST_Conditional /* (false, true) ? (a = 10, b = 20) : (c = 30) - * ==> 20 (side effect, set a := 10 and b := 20) */ - || p instanceof AST_Arrow // x => (x, x) - || p instanceof AST_DefaultAssign // x => (x = (0, function(){})) - || p instanceof AST_Expansion // [...(a, b)] - || p instanceof AST_ForOf && this === p.object // for (e of (foo, bar)) {} - || p instanceof AST_Yield // yield (foo, bar) - || p instanceof AST_Export // export default (foo, bar) - ; - }); - - PARENS(AST_Binary, function(output) { - var p = output.parent(); - // (foo && bar)() - if (p instanceof AST_Call && p.expression === this) - return true; - // typeof (foo && bar) - if (p instanceof AST_Unary) - return true; - // (foo && bar)["prop"], (foo && bar).prop - if (p instanceof AST_PropAccess && p.expression === this) - return true; - // this deals with precedence: 3 * (2 + 1) - if (p instanceof AST_Binary) { - var po = p.operator, pp = PRECEDENCE[po]; - var so = this.operator, sp = PRECEDENCE[so]; - if (pp > sp - || (pp == sp - && (this === p.right || po == "**"))) { - return true; - } - } - }); - - PARENS(AST_Yield, function(output) { - var p = output.parent(); - // (yield 1) + (yield 2) - // a = yield 3 - if (p instanceof AST_Binary && p.operator !== "=") - return true; - // (yield 1)() - // new (yield 1)() - if (p instanceof AST_Call && p.expression === this) - return true; - // (yield 1) ? yield 2 : yield 3 - if (p instanceof AST_Conditional && p.condition === this) - return true; - // -(yield 4) - if (p instanceof AST_Unary) - return true; - // (yield x).foo - // (yield x)['foo'] - if (p instanceof AST_PropAccess && p.expression === this) - return true; - }); - - PARENS(AST_PropAccess, function(output) { - var p = output.parent(); - if (p instanceof AST_New && p.expression === this) { - // i.e. new (foo.bar().baz) - // - // if there's one call into this subtree, then we need - // parens around it too, otherwise the call will be - // interpreted as passing the arguments to the upper New - // expression. - var parens = false; - this.walk(new TreeWalker(function(node) { - if (parens || node instanceof AST_Scope) return true; - if (node instanceof AST_Call) { - parens = true; - return true; - } - })); - return parens; - } - }); - - PARENS(AST_Call, function(output) { - var p = output.parent(), p1; - if (p instanceof AST_New && p.expression === this - || p instanceof AST_Export && p.is_default && this.expression instanceof AST_Function) - return true; - - // workaround for Safari bug. - // https://bugs.webkit.org/show_bug.cgi?id=123506 - return this.expression instanceof AST_Function - && p instanceof AST_PropAccess - && p.expression === this - && (p1 = output.parent(1)) instanceof AST_Assign - && p1.left === p; - }); - - PARENS(AST_New, function(output) { - var p = output.parent(); - if (!need_constructor_parens(this, output) - && (p instanceof AST_PropAccess // (new Date).getTime(), (new Date)["getTime"]() - || p instanceof AST_Call && p.expression === this)) // (new foo)(bar) - return true; - }); - - PARENS(AST_Number, function(output) { - var p = output.parent(); - if (p instanceof AST_PropAccess && p.expression === this) { - var value = this.getValue(); - if (value < 0 || /^0/.test(make_num(value))) { - return true; - } - } - }); - - PARENS(AST_BigInt, function(output) { - var p = output.parent(); - if (p instanceof AST_PropAccess && p.expression === this) { - var value = this.getValue(); - if (value.startsWith("-")) { - return true; - } - } - }); - - PARENS([ AST_Assign, AST_Conditional ], function(output) { - var p = output.parent(); - // !(a = false) → true - if (p instanceof AST_Unary) - return true; - // 1 + (a = 2) + 3 → 6, side effect setting a = 2 - if (p instanceof AST_Binary && !(p instanceof AST_Assign)) - return true; - // (a = func)() —or— new (a = Object)() - if (p instanceof AST_Call && p.expression === this) - return true; - // (a = foo) ? bar : baz - if (p instanceof AST_Conditional && p.condition === this) - return true; - // (a = foo)["prop"] —or— (a = foo).prop - if (p instanceof AST_PropAccess && p.expression === this) - return true; - // ({a, b} = {a: 1, b: 2}), a destructuring assignment - if (this instanceof AST_Assign && this.left instanceof AST_Destructuring && this.left.is_array === false) - return true; - }); - - /* -----[ PRINTERS ]----- */ - - DEFPRINT(AST_Directive, function(self, output) { - output.print_string(self.value, self.quote); - output.semicolon(); - }); - - DEFPRINT(AST_Expansion, function (self, output) { - output.print("..."); - self.expression.print(output); - }); - - DEFPRINT(AST_Destructuring, function (self, output) { - output.print(self.is_array ? "[" : "{"); - var len = self.names.length; - self.names.forEach(function (name, i) { - if (i > 0) output.comma(); - name.print(output); - // If the final element is a hole, we need to make sure it - // doesn't look like a trailing comma, by inserting an actual - // trailing comma. - if (i == len - 1 && name instanceof AST_Hole) output.comma(); - }); - output.print(self.is_array ? "]" : "}"); - }); - - DEFPRINT(AST_Debugger, function(self, output) { - output.print("debugger"); - output.semicolon(); - }); - - /* -----[ statements ]----- */ - - function display_body(body, is_toplevel, output, allow_directives) { - var last = body.length - 1; - in_directive = allow_directives; - body.forEach(function(stmt, i) { - if (in_directive === true && !(stmt instanceof AST_Directive || - stmt instanceof AST_EmptyStatement || - (stmt instanceof AST_SimpleStatement && stmt.body instanceof AST_String) - )) { - in_directive = false; - } - if (!(stmt instanceof AST_EmptyStatement)) { - output.indent(); - stmt.print(output); - if (!(i == last && is_toplevel)) { - output.newline(); - if (is_toplevel) output.newline(); - } - } - if (in_directive === true && - stmt instanceof AST_SimpleStatement && - stmt.body instanceof AST_String - ) { - in_directive = false; - } - }); - in_directive = false; - } - - AST_StatementWithBody.DEFMETHOD("_do_print_body", function(output) { - force_statement(this.body, output); - }); - - DEFPRINT(AST_Statement, function(self, output) { - self.body.print(output); - output.semicolon(); - }); - DEFPRINT(AST_Toplevel, function(self, output) { - display_body(self.body, true, output, true); - output.print(""); - }); - DEFPRINT(AST_LabeledStatement, function(self, output) { - self.label.print(output); - output.colon(); - self.body.print(output); - }); - DEFPRINT(AST_SimpleStatement, function(self, output) { - self.body.print(output); - output.semicolon(); - }); - // XXX Emscripten localmod: Add a node type for a parenthesized expression so that we can retain - // Closure annotations that need a form "/**annotation*/(expression)" - DEFPRINT(AST_ParenthesizedExpression, function(self, output) { - output.print('('); - self.body.print(output); - output.print(')'); - }); - // XXX End Emscripten localmod - function print_braced_empty(self, output) { - output.print("{"); - output.with_indent(output.next_indent(), function() { - output.append_comments(self, true); - }); - output.print("}"); - } - function print_braced(self, output, allow_directives) { - if (self.body.length > 0) { - output.with_block(function() { - display_body(self.body, false, output, allow_directives); - }); - } else print_braced_empty(self, output); - } - DEFPRINT(AST_BlockStatement, function(self, output) { - print_braced(self, output); - }); - DEFPRINT(AST_EmptyStatement, function(self, output) { - output.semicolon(); - }); - DEFPRINT(AST_Do, function(self, output) { - output.print("do"); - output.space(); - make_block(self.body, output); - output.space(); - output.print("while"); - output.space(); - output.with_parens(function() { - self.condition.print(output); - }); - output.semicolon(); - }); - DEFPRINT(AST_While, function(self, output) { - output.print("while"); - output.space(); - output.with_parens(function() { - self.condition.print(output); - }); - output.space(); - self._do_print_body(output); - }); - DEFPRINT(AST_For, function(self, output) { - output.print("for"); - output.space(); - output.with_parens(function() { - if (self.init) { - if (self.init instanceof AST_Definitions) { - self.init.print(output); - } else { - parenthesize_for_noin(self.init, output, true); - } - output.print(";"); - output.space(); - } else { - output.print(";"); - } - if (self.condition) { - self.condition.print(output); - output.print(";"); - output.space(); - } else { - output.print(";"); - } - if (self.step) { - self.step.print(output); - } - }); - output.space(); - self._do_print_body(output); - }); - DEFPRINT(AST_ForIn, function(self, output) { - output.print("for"); - if (self.await) { - output.space(); - output.print("await"); - } - output.space(); - output.with_parens(function() { - self.init.print(output); - output.space(); - output.print(self instanceof AST_ForOf ? "of" : "in"); - output.space(); - self.object.print(output); - }); - output.space(); - self._do_print_body(output); - }); - DEFPRINT(AST_With, function(self, output) { - output.print("with"); - output.space(); - output.with_parens(function() { - self.expression.print(output); - }); - output.space(); - self._do_print_body(output); - }); - - /* -----[ functions ]----- */ - AST_Lambda.DEFMETHOD("_do_print", function(output, nokeyword) { - var self = this; - if (!nokeyword) { - if (self.async) { - output.print("async"); - output.space(); - } - output.print("function"); - if (self.is_generator) { - output.star(); - } - if (self.name) { - output.space(); - } - } - if (self.name instanceof AST_Symbol) { - self.name.print(output); - } else if (nokeyword && self.name instanceof AST_Node) { - output.with_square(function() { - self.name.print(output); // Computed method name - }); - } - output.with_parens(function() { - self.argnames.forEach(function(arg, i) { - if (i) output.comma(); - arg.print(output); - }); - }); - output.space(); - print_braced(self, output, true); - }); - DEFPRINT(AST_Lambda, function(self, output) { - self._do_print(output); - }); - - DEFPRINT(AST_PrefixedTemplateString, function(self, output) { - var tag = self.prefix; - var parenthesize_tag = tag instanceof AST_Arrow - || tag instanceof AST_Binary - || tag instanceof AST_Conditional - || tag instanceof AST_Sequence - || tag instanceof AST_Unary; - if (parenthesize_tag) output.print("("); - self.prefix.print(output); - if (parenthesize_tag) output.print(")"); - self.template_string.print(output); - }); - DEFPRINT(AST_TemplateString, function(self, output) { - var is_tagged = output.parent() instanceof AST_PrefixedTemplateString; - - output.print("`"); - for (var i = 0; i < self.segments.length; i++) { - if (!(self.segments[i] instanceof AST_TemplateSegment)) { - output.print("${"); - self.segments[i].print(output); - output.print("}"); - } else if (is_tagged) { - output.print(self.segments[i].raw); - } else { - output.print_template_string_chars(self.segments[i].value); - } - } - output.print("`"); - }); - - AST_Arrow.DEFMETHOD("_do_print", function(output) { - var self = this; - var parent = output.parent(); - var needs_parens = (parent instanceof AST_Binary && !(parent instanceof AST_Assign)) || - parent instanceof AST_Unary || - (parent instanceof AST_Call && self === parent.expression); - if (needs_parens) { output.print("("); } - if (self.async) { - output.print("async"); - output.space(); - } - if (self.argnames.length === 1 && self.argnames[0] instanceof AST_Symbol) { - self.argnames[0].print(output); - } else { - output.with_parens(function() { - self.argnames.forEach(function(arg, i) { - if (i) output.comma(); - arg.print(output); - }); - }); - } - output.space(); - output.print("=>"); - output.space(); - if (self.body instanceof AST_Node) { - self.body.print(output); - } else { - print_braced(self, output); - } - if (needs_parens) { output.print(")"); } - }); - - /* -----[ exits ]----- */ - AST_Exit.DEFMETHOD("_do_print", function(output, kind) { - output.print(kind); - if (this.value) { - output.space(); - this.value.print(output); - } - output.semicolon(); - }); - DEFPRINT(AST_Return, function(self, output) { - self._do_print(output, "return"); - }); - DEFPRINT(AST_Throw, function(self, output) { - self._do_print(output, "throw"); - }); - - /* -----[ yield ]----- */ - - DEFPRINT(AST_Yield, function(self, output) { - var star = self.is_star ? "*" : ""; - output.print("yield" + star); - if (self.expression) { - output.space(); - self.expression.print(output); - } - }); - - DEFPRINT(AST_Await, function(self, output) { - output.print("await"); - output.space(); - var e = self.expression; - var parens = !( - e instanceof AST_Call - || e instanceof AST_SymbolRef - || e instanceof AST_PropAccess - || e instanceof AST_Unary - || e instanceof AST_Constant - ); - if (parens) output.print("("); - self.expression.print(output); - if (parens) output.print(")"); - }); - - /* -----[ loop control ]----- */ - AST_LoopControl.DEFMETHOD("_do_print", function(output, kind) { - output.print(kind); - if (this.label) { - output.space(); - this.label.print(output); - } - output.semicolon(); - }); - DEFPRINT(AST_Break, function(self, output) { - self._do_print(output, "break"); - }); - DEFPRINT(AST_Continue, function(self, output) { - self._do_print(output, "continue"); - }); - - /* -----[ if ]----- */ - function make_then(self, output) { - var b = self.body; - if (output.option("braces") - || output.option("ie8") && b instanceof AST_Do) - return make_block(b, output); - // The squeezer replaces "block"-s that contain only a single - // statement with the statement itself; technically, the AST - // is correct, but this can create problems when we output an - // IF having an ELSE clause where the THEN clause ends in an - // IF *without* an ELSE block (then the outer ELSE would refer - // to the inner IF). This function checks for this case and - // adds the block braces if needed. - if (!b) return output.force_semicolon(); - while (true) { - if (b instanceof AST_If) { - if (!b.alternative) { - make_block(self.body, output); - return; - } - b = b.alternative; - } else if (b instanceof AST_StatementWithBody) { - b = b.body; - } else break; - } - force_statement(self.body, output); - } - DEFPRINT(AST_If, function(self, output) { - output.print("if"); - output.space(); - output.with_parens(function() { - self.condition.print(output); - }); - output.space(); - if (self.alternative) { - make_then(self, output); - output.space(); - output.print("else"); - output.space(); - if (self.alternative instanceof AST_If) - self.alternative.print(output); - else - force_statement(self.alternative, output); - } else { - self._do_print_body(output); - } - }); - - /* -----[ switch ]----- */ - DEFPRINT(AST_Switch, function(self, output) { - output.print("switch"); - output.space(); - output.with_parens(function() { - self.expression.print(output); - }); - output.space(); - var last = self.body.length - 1; - if (last < 0) print_braced_empty(self, output); - else output.with_block(function() { - self.body.forEach(function(branch, i) { - output.indent(true); - branch.print(output); - if (i < last && branch.body.length > 0) - output.newline(); - }); - }); - }); - AST_SwitchBranch.DEFMETHOD("_do_print_body", function(output) { - output.newline(); - this.body.forEach(function(stmt) { - output.indent(); - stmt.print(output); - output.newline(); - }); - }); - DEFPRINT(AST_Default, function(self, output) { - output.print("default:"); - self._do_print_body(output); - }); - DEFPRINT(AST_Case, function(self, output) { - output.print("case"); - output.space(); - self.expression.print(output); - output.print(":"); - self._do_print_body(output); - }); - - /* -----[ exceptions ]----- */ - DEFPRINT(AST_Try, function(self, output) { - output.print("try"); - output.space(); - print_braced(self, output); - if (self.bcatch) { - output.space(); - self.bcatch.print(output); - } - if (self.bfinally) { - output.space(); - self.bfinally.print(output); - } - }); - DEFPRINT(AST_Catch, function(self, output) { - output.print("catch"); - if (self.argname) { - output.space(); - output.with_parens(function() { - self.argname.print(output); - }); - } - output.space(); - print_braced(self, output); - }); - DEFPRINT(AST_Finally, function(self, output) { - output.print("finally"); - output.space(); - print_braced(self, output); - }); - - /* -----[ var/const ]----- */ - AST_Definitions.DEFMETHOD("_do_print", function(output, kind) { - output.print(kind); - output.space(); - this.definitions.forEach(function(def, i) { - if (i) output.comma(); - def.print(output); - }); - var p = output.parent(); - var in_for = p instanceof AST_For || p instanceof AST_ForIn; - var output_semicolon = !in_for || p && p.init !== this; - if (output_semicolon) - output.semicolon(); - }); - DEFPRINT(AST_Let, function(self, output) { - self._do_print(output, "let"); - }); - DEFPRINT(AST_Var, function(self, output) { - self._do_print(output, "var"); - }); - DEFPRINT(AST_Const, function(self, output) { - self._do_print(output, "const"); - }); - DEFPRINT(AST_Import, function(self, output) { - output.print("import"); - output.space(); - if (self.imported_name) { - self.imported_name.print(output); - } - if (self.imported_name && self.imported_names) { - output.print(","); - output.space(); - } - if (self.imported_names) { - if (self.imported_names.length === 1 && self.imported_names[0].foreign_name.name === "*") { - self.imported_names[0].print(output); - } else { - output.print("{"); - self.imported_names.forEach(function (name_import, i) { - output.space(); - name_import.print(output); - if (i < self.imported_names.length - 1) { - output.print(","); - } - }); - output.space(); - output.print("}"); - } - } - if (self.imported_name || self.imported_names) { - output.space(); - output.print("from"); - output.space(); - } - self.module_name.print(output); - output.semicolon(); - }); - - DEFPRINT(AST_NameMapping, function(self, output) { - var is_import = output.parent() instanceof AST_Import; - var definition = self.name.definition(); - var names_are_different = - (definition && definition.mangled_name || self.name.name) !== - self.foreign_name.name; - if (names_are_different) { - if (is_import) { - output.print(self.foreign_name.name); - } else { - self.name.print(output); - } - output.space(); - output.print("as"); - output.space(); - if (is_import) { - self.name.print(output); - } else { - output.print(self.foreign_name.name); - } - } else { - self.name.print(output); - } - }); - - DEFPRINT(AST_Export, function(self, output) { - output.print("export"); - output.space(); - if (self.is_default) { - output.print("default"); - output.space(); - } - if (self.exported_names) { - if (self.exported_names.length === 1 && self.exported_names[0].name.name === "*") { - self.exported_names[0].print(output); - } else { - output.print("{"); - self.exported_names.forEach(function(name_export, i) { - output.space(); - name_export.print(output); - if (i < self.exported_names.length - 1) { - output.print(","); - } - }); - output.space(); - output.print("}"); - } - } else if (self.exported_value) { - self.exported_value.print(output); - } else if (self.exported_definition) { - self.exported_definition.print(output); - if (self.exported_definition instanceof AST_Definitions) return; - } - if (self.module_name) { - output.space(); - output.print("from"); - output.space(); - self.module_name.print(output); - } - if (self.exported_value - && !(self.exported_value instanceof AST_Defun || - self.exported_value instanceof AST_Function || - self.exported_value instanceof AST_Class) - || self.module_name - || self.exported_names - ) { - output.semicolon(); - } - }); - - function parenthesize_for_noin(node, output, noin) { - var parens = false; - // need to take some precautions here: - // https://github.com/mishoo/UglifyJS2/issues/60 - if (noin) node.walk(new TreeWalker(function(node) { - if (parens || node instanceof AST_Scope) return true; - if (node instanceof AST_Binary && node.operator == "in") { - parens = true; - return true; - } - })); - node.print(output, parens); - } - - DEFPRINT(AST_VarDef, function(self, output) { - self.name.print(output); - if (self.value) { - output.space(); - output.print("="); - output.space(); - var p = output.parent(1); - var noin = p instanceof AST_For || p instanceof AST_ForIn; - parenthesize_for_noin(self.value, output, noin); - } - }); - - /* -----[ other expressions ]----- */ - DEFPRINT(AST_Call, function(self, output) { - self.expression.print(output); - if (self instanceof AST_New && !need_constructor_parens(self, output)) - return; - if (self.expression instanceof AST_Call || self.expression instanceof AST_Lambda) { - output.add_mapping(self.start); - } - output.with_parens(function() { - self.args.forEach(function(expr, i) { - if (i) output.comma(); - expr.print(output); - }); - }); - }); - DEFPRINT(AST_New, function(self, output) { - output.print("new"); - output.space(); - AST_Call.prototype._codegen(self, output); - }); - - AST_Sequence.DEFMETHOD("_do_print", function(output) { - this.expressions.forEach(function(node, index) { - if (index > 0) { + if (/comment[134]/.test(c.type)) { + var value = filter_comment(c.value); + if (value) { + print("//" + value + "\n"); + indent(); + } + last_nlb = true; + } else if (c.type == "comment2") { + var value = filter_comment(c.value); + if (value) { + print("/*" + value + "*/"); + } + last_nlb = false; + } + }); + if (!last_nlb) { + if (start.nlb) { + print("\n"); + indent(); + } else { + space(); + } + } + } + + function append_comments(node, tail) { + var self = this; + var token = node.end; + if (!token) return; + var printed_comments = self.printed_comments; + var comments = token[tail ? "comments_before" : "comments_after"]; + if (!comments || printed_comments.has(comments)) return; + if (!(node instanceof AST_Statement || comments.every((c) => + !/comment[134]/.test(c.type) + ))) return; + printed_comments.add(comments); + var insert = OUTPUT.length(); + comments.filter(comment_filter, node).forEach(function(c, i) { + if (printed_comments.has(c)) return; + printed_comments.add(c); + need_space = false; + if (need_newline_indented) { + print("\n"); + indent(); + need_newline_indented = false; + } else if (c.nlb && (i > 0 || !has_nlb())) { + print("\n"); + indent(); + } else if (i > 0 || !tail) { + space(); + } + if (/comment[134]/.test(c.type)) { + const value = filter_comment(c.value); + if (value) { + print("//" + value); + } + need_newline_indented = true; + } else if (c.type == "comment2") { + const value = filter_comment(c.value); + if (value) { + print("/*" + value + "*/"); + } + need_space = true; + } + }); + if (OUTPUT.length() > insert) newline_insert = insert; + } + + /** + * When output.option("_destroy_ast") is enabled, destroy the function. + * Call this after printing it. + */ + const gc_scope = + options["_destroy_ast"] + ? function gc_scope(scope) { + scope.body.length = 0; + scope.argnames.length = 0; + } + : noop; + + var stack = []; + return { + get : get, + toString : get, + indent : indent, + in_directive : false, + use_asm : null, + active_scope : null, + indentation : function() { return indentation; }, + current_width : function() { return current_col - indentation; }, + should_break : function() { return options.width && this.current_width() >= options.width; }, + has_parens : function() { return has_parens; }, + newline : newline, + print : print, + star : star, + space : space, + comma : comma, + colon : colon, + last : function() { return last; }, + semicolon : semicolon, + force_semicolon : force_semicolon, + to_utf8 : to_utf8, + print_name : function(name) { print(make_name(name)); }, + print_string : function(str, quote, escape_directive) { + var encoded = encode_string(str, quote); + if (escape_directive === true && !encoded.includes("\\")) { + // Insert semicolons to break directive prologue + if (!EXPECT_DIRECTIVE.test(OUTPUT.toString())) { + force_semicolon(); + } + force_semicolon(); + } + print(encoded); + }, + print_template_string_chars: function(str) { + var encoded = encode_string(str, "`").replace(/\${/g, "\\${"); + return print(encoded.substr(1, encoded.length - 2)); + }, + encode_string : encode_string, + next_indent : next_indent, + with_indent : with_indent, + with_block : with_block, + with_parens : with_parens, + with_square : with_square, + add_mapping : add_mapping, + option : function(opt) { return options[opt]; }, + gc_scope, + printed_comments: printed_comments, + prepend_comments: readonly ? noop : prepend_comments, + append_comments : readonly || comment_filter === return_false ? noop : append_comments, + line : function() { return current_line; }, + col : function() { return current_col; }, + pos : function() { return current_pos; }, + push_node : function(node) { stack.push(node); }, + pop_node : function() { return stack.pop(); }, + parent : function(n) { + return stack[stack.length - 2 - (n || 0)]; + } + }; + +} + +/* -----[ code generators ]----- */ + +(function() { + + /* -----[ utils ]----- */ + + function DEFPRINT(nodetype, generator) { + nodetype.DEFMETHOD("_codegen", generator); + } + + AST_Node.DEFMETHOD("print", function(output, force_parens) { + var self = this, generator = self._codegen; + if (self instanceof AST_Scope) { + output.active_scope = self; + } else if (!output.use_asm && self instanceof AST_Directive && self.value == "use asm") { + output.use_asm = output.active_scope; + } + function doit() { + output.prepend_comments(self); + self.add_source_map(output); + generator(self, output); + output.append_comments(self); + } + output.push_node(self); + if (force_parens || self.needs_parens(output)) { + output.with_parens(doit); + } else { + doit(); + } + output.pop_node(); + if (self === output.use_asm) { + output.use_asm = null; + } + }); + AST_Node.DEFMETHOD("_print", AST_Node.prototype.print); + + AST_Node.DEFMETHOD("print_to_string", function(options) { + var output = OutputStream(options); + this.print(output); + return output.get(); + }); + + /* -----[ PARENTHESES ]----- */ + + function PARENS(nodetype, func) { + if (Array.isArray(nodetype)) { + nodetype.forEach(function(nodetype) { + PARENS(nodetype, func); + }); + } else { + nodetype.DEFMETHOD("needs_parens", func); + } + } + + PARENS(AST_Node, return_false); + + // a function expression needs parens around it when it's provably + // the first token to appear in a statement. + PARENS(AST_Function, function(output) { + if (!output.has_parens() && first_in_statement(output)) { + return true; + } + + if (output.option("webkit")) { + var p = output.parent(); + if (p instanceof AST_PropAccess && p.expression === this) { + return true; + } + } + + if (output.option("wrap_iife")) { + var p = output.parent(); + if (p instanceof AST_Call && p.expression === this) { + return true; + } + } + + if (output.option("wrap_func_args")) { + var p = output.parent(); + if (p instanceof AST_Call && p.args.includes(this)) { + return true; + } + } + + return false; + }); + + PARENS(AST_Arrow, function(output) { + var p = output.parent(); + + if ( + output.option("wrap_func_args") + && p instanceof AST_Call + && p.args.includes(this) + ) { + return true; + } + return p instanceof AST_PropAccess && p.expression === this; + }); + + // same goes for an object literal (as in AST_Function), because + // otherwise {...} would be interpreted as a block of code. + PARENS(AST_Object, function(output) { + return !output.has_parens() && first_in_statement(output); + }); + + PARENS(AST_ClassExpression, first_in_statement); + + PARENS(AST_Unary, function(output) { + var p = output.parent(); + return p instanceof AST_PropAccess && p.expression === this + || p instanceof AST_Call && p.expression === this + || p instanceof AST_Binary + && p.operator === "**" + && this instanceof AST_UnaryPrefix + && p.left === this + && this.operator !== "++" + && this.operator !== "--"; + }); + + PARENS(AST_Await, function(output) { + var p = output.parent(); + return p instanceof AST_PropAccess && p.expression === this + || p instanceof AST_Call && p.expression === this + || p instanceof AST_Binary && p.operator === "**" && p.left === this + || output.option("safari10") && p instanceof AST_UnaryPrefix; + }); + + PARENS(AST_Sequence, function(output) { + var p = output.parent(); + return p instanceof AST_Call // (foo, bar)() or foo(1, (2, 3), 4) + || p instanceof AST_Unary // !(foo, bar, baz) + || p instanceof AST_Binary // 1 + (2, 3) + 4 ==> 8 + || p instanceof AST_VarDef // var a = (1, 2), b = a + a; ==> b == 4 + || p instanceof AST_PropAccess // (1, {foo:2}).foo or (1, {foo:2})["foo"] ==> 2 + || p instanceof AST_Array // [ 1, (2, 3), 4 ] ==> [ 1, 3, 4 ] + || p instanceof AST_ObjectProperty // { foo: (1, 2) }.foo ==> 2 + || p instanceof AST_Conditional /* (false, true) ? (a = 10, b = 20) : (c = 30) + * ==> 20 (side effect, set a := 10 and b := 20) */ + || p instanceof AST_Arrow // x => (x, x) + || p instanceof AST_DefaultAssign // x => (x = (0, function(){})) + || p instanceof AST_Expansion // [...(a, b)] + || p instanceof AST_ForOf && this === p.object // for (e of (foo, bar)) {} + || p instanceof AST_Yield // yield (foo, bar) + || p instanceof AST_Export // export default (foo, bar) + ; + }); + + PARENS(AST_Binary, function(output) { + var p = output.parent(); + // (foo && bar)() + if (p instanceof AST_Call && p.expression === this) + return true; + // typeof (foo && bar) + if (p instanceof AST_Unary) + return true; + // (foo && bar)["prop"], (foo && bar).prop + if (p instanceof AST_PropAccess && p.expression === this) + return true; + // this deals with precedence: 3 * (2 + 1) + if (p instanceof AST_Binary) { + const po = p.operator; + const so = this.operator; + + if (so === "??" && (po === "||" || po === "&&")) { + return true; + } + + if (po === "??" && (so === "||" || so === "&&")) { + return true; + } + + const pp = PRECEDENCE[po]; + const sp = PRECEDENCE[so]; + if (pp > sp + || (pp == sp + && (this === p.right || po == "**"))) { + return true; + } + } + }); + + PARENS(AST_Yield, function(output) { + var p = output.parent(); + // (yield 1) + (yield 2) + // a = yield 3 + if (p instanceof AST_Binary && p.operator !== "=") + return true; + // (yield 1)() + // new (yield 1)() + if (p instanceof AST_Call && p.expression === this) + return true; + // (yield 1) ? yield 2 : yield 3 + if (p instanceof AST_Conditional && p.condition === this) + return true; + // -(yield 4) + if (p instanceof AST_Unary) + return true; + // (yield x).foo + // (yield x)['foo'] + if (p instanceof AST_PropAccess && p.expression === this) + return true; + }); + + PARENS(AST_Chain, function(output) { + var p = output.parent(); + if (!(p instanceof AST_Call || p instanceof AST_PropAccess)) return false; + return p.expression === this; + }); + + PARENS(AST_PropAccess, function(output) { + var p = output.parent(); + if (p instanceof AST_New && p.expression === this) { + // i.e. new (foo.bar().baz) + // + // if there's one call into this subtree, then we need + // parens around it too, otherwise the call will be + // interpreted as passing the arguments to the upper New + // expression. + return walk(this, node => { + if (node instanceof AST_Scope) return true; + if (node instanceof AST_Call) { + return walk_abort; // makes walk() return true. + } + }); + } + }); + + PARENS(AST_Call, function(output) { + var p = output.parent(), p1; + if (p instanceof AST_New && p.expression === this + || p instanceof AST_Export && p.is_default && this.expression instanceof AST_Function) + return true; + + // workaround for Safari bug. + // https://bugs.webkit.org/show_bug.cgi?id=123506 + return this.expression instanceof AST_Function + && p instanceof AST_PropAccess + && p.expression === this + && (p1 = output.parent(1)) instanceof AST_Assign + && p1.left === p; + }); + + PARENS(AST_New, function(output) { + var p = output.parent(); + if (this.args.length === 0 + && (p instanceof AST_PropAccess // (new Date).getTime(), (new Date)["getTime"]() + || p instanceof AST_Call && p.expression === this + || p instanceof AST_PrefixedTemplateString && p.prefix === this)) // (new foo)(bar) + return true; + }); + + PARENS(AST_Number, function(output) { + var p = output.parent(); + if (p instanceof AST_PropAccess && p.expression === this) { + var value = this.getValue(); + if (value < 0 || /^0/.test(make_num(value))) { + return true; + } + } + }); + + PARENS(AST_BigInt, function(output) { + var p = output.parent(); + if (p instanceof AST_PropAccess && p.expression === this) { + var value = this.getValue(); + if (value.startsWith("-")) { + return true; + } + } + }); + + PARENS([ AST_Assign, AST_Conditional ], function(output) { + var p = output.parent(); + // !(a = false) → true + if (p instanceof AST_Unary) + return true; + // 1 + (a = 2) + 3 → 6, side effect setting a = 2 + if (p instanceof AST_Binary && !(p instanceof AST_Assign)) + return true; + // (a = func)() —or— new (a = Object)() + if (p instanceof AST_Call && p.expression === this) + return true; + // (a = foo) ? bar : baz + if (p instanceof AST_Conditional && p.condition === this) + return true; + // (a = foo)["prop"] —or— (a = foo).prop + if (p instanceof AST_PropAccess && p.expression === this) + return true; + // ({a, b} = {a: 1, b: 2}), a destructuring assignment + if (this instanceof AST_Assign && this.left instanceof AST_Destructuring && this.left.is_array === false) + return true; + }); + + /* -----[ PRINTERS ]----- */ + + DEFPRINT(AST_Directive, function(self, output) { + output.print_string(self.value, self.quote); + output.semicolon(); + }); + + DEFPRINT(AST_Expansion, function (self, output) { + output.print("..."); + self.expression.print(output); + }); + + DEFPRINT(AST_Destructuring, function (self, output) { + output.print(self.is_array ? "[" : "{"); + var len = self.names.length; + self.names.forEach(function (name, i) { + if (i > 0) output.comma(); + name.print(output); + // If the final element is a hole, we need to make sure it + // doesn't look like a trailing comma, by inserting an actual + // trailing comma. + if (i == len - 1 && name instanceof AST_Hole) output.comma(); + }); + output.print(self.is_array ? "]" : "}"); + }); + + DEFPRINT(AST_Debugger, function(self, output) { + output.print("debugger"); + output.semicolon(); + }); + + /* -----[ statements ]----- */ + + function display_body(body, is_toplevel, output, allow_directives) { + var last = body.length - 1; + output.in_directive = allow_directives; + body.forEach(function(stmt, i) { + if (output.in_directive === true && !(stmt instanceof AST_Directive || + stmt instanceof AST_EmptyStatement || + (stmt instanceof AST_SimpleStatement && stmt.body instanceof AST_String) + )) { + output.in_directive = false; + } + if (!(stmt instanceof AST_EmptyStatement)) { + output.indent(); + stmt.print(output); + if (!(i == last && is_toplevel)) { + output.newline(); + if (is_toplevel) output.newline(); + } + } + if (output.in_directive === true && + stmt instanceof AST_SimpleStatement && + stmt.body instanceof AST_String + ) { + output.in_directive = false; + } + }); + output.in_directive = false; + } + + AST_StatementWithBody.DEFMETHOD("_do_print_body", function(output) { + print_maybe_braced_body(this.body, output); + }); + + DEFPRINT(AST_Statement, function(self, output) { + self.body.print(output); + output.semicolon(); + }); + DEFPRINT(AST_Toplevel, function(self, output) { + display_body(self.body, true, output, true); + output.print(""); + }); + DEFPRINT(AST_LabeledStatement, function(self, output) { + self.label.print(output); + output.colon(); + self.body.print(output); + }); + DEFPRINT(AST_SimpleStatement, function(self, output) { + self.body.print(output); + output.semicolon(); + }); +// XXX Emscripten localmod: Add a node type for a parenthesized expression so that we can retain +// Closure annotations that need a form "/**annotation*/(expression)" + DEFPRINT(AST_ParenthesizedExpression, function(self, output) { + output.print('('); + self.body.print(output); + output.print(')'); + }); +// XXX End Emscripten localmod + function print_braced_empty(self, output) { + output.print("{"); + output.with_indent(output.next_indent(), function() { + output.append_comments(self, true); + }); + output.add_mapping(self.end); + output.print("}"); + } + function print_braced(self, output, allow_directives) { + if (self.body.length > 0) { + output.with_block(function() { + display_body(self.body, false, output, allow_directives); + output.add_mapping(self.end); + }); + } else print_braced_empty(self, output); + } + DEFPRINT(AST_BlockStatement, function(self, output) { + print_braced(self, output); + }); + DEFPRINT(AST_EmptyStatement, function(self, output) { + output.semicolon(); + }); + DEFPRINT(AST_Do, function(self, output) { + output.print("do"); + output.space(); + make_block(self.body, output); + output.space(); + output.print("while"); + output.space(); + output.with_parens(function() { + self.condition.print(output); + }); + output.semicolon(); + }); + DEFPRINT(AST_While, function(self, output) { + output.print("while"); + output.space(); + output.with_parens(function() { + self.condition.print(output); + }); + output.space(); + self._do_print_body(output); + }); + DEFPRINT(AST_For, function(self, output) { + output.print("for"); + output.space(); + output.with_parens(function() { + if (self.init) { + if (self.init instanceof AST_Definitions) { + self.init.print(output); + } else { + parenthesize_for_noin(self.init, output, true); + } + output.print(";"); + output.space(); + } else { + output.print(";"); + } + if (self.condition) { + self.condition.print(output); + output.print(";"); + output.space(); + } else { + output.print(";"); + } + if (self.step) { + self.step.print(output); + } + }); + output.space(); + self._do_print_body(output); + }); + DEFPRINT(AST_ForIn, function(self, output) { + output.print("for"); + if (self.await) { + output.space(); + output.print("await"); + } + output.space(); + output.with_parens(function() { + self.init.print(output); + output.space(); + output.print(self instanceof AST_ForOf ? "of" : "in"); + output.space(); + self.object.print(output); + }); + output.space(); + self._do_print_body(output); + }); + DEFPRINT(AST_With, function(self, output) { + output.print("with"); + output.space(); + output.with_parens(function() { + self.expression.print(output); + }); + output.space(); + self._do_print_body(output); + }); + + /* -----[ functions ]----- */ + AST_Lambda.DEFMETHOD("_do_print", function(output, nokeyword) { + var self = this; + if (!nokeyword) { + if (self.async) { + output.print("async"); + output.space(); + } + output.print("function"); + if (self.is_generator) { + output.star(); + } + if (self.name) { + output.space(); + } + } + if (self.name instanceof AST_Symbol) { + self.name.print(output); + } else if (nokeyword && self.name instanceof AST_Node) { + output.with_square(function() { + self.name.print(output); // Computed method name + }); + } + output.with_parens(function() { + self.argnames.forEach(function(arg, i) { + if (i) output.comma(); + arg.print(output); + }); + }); + output.space(); + print_braced(self, output, true); + }); + DEFPRINT(AST_Lambda, function(self, output) { + self._do_print(output); + output.gc_scope(self); + }); + + DEFPRINT(AST_PrefixedTemplateString, function(self, output) { + var tag = self.prefix; + var parenthesize_tag = tag instanceof AST_Lambda + || tag instanceof AST_Binary + || tag instanceof AST_Conditional + || tag instanceof AST_Sequence + || tag instanceof AST_Unary + || tag instanceof AST_Dot && tag.expression instanceof AST_Object; + if (parenthesize_tag) output.print("("); + self.prefix.print(output); + if (parenthesize_tag) output.print(")"); + self.template_string.print(output); + }); + DEFPRINT(AST_TemplateString, function(self, output) { + var is_tagged = output.parent() instanceof AST_PrefixedTemplateString; + + output.print("`"); + for (var i = 0; i < self.segments.length; i++) { + if (!(self.segments[i] instanceof AST_TemplateSegment)) { + output.print("${"); + self.segments[i].print(output); + output.print("}"); + } else if (is_tagged) { + output.print(self.segments[i].raw); + } else { + output.print_template_string_chars(self.segments[i].value); + } + } + output.print("`"); + }); + DEFPRINT(AST_TemplateSegment, function(self, output) { + output.print_template_string_chars(self.value); + }); + + AST_Arrow.DEFMETHOD("_do_print", function(output) { + var self = this; + var parent = output.parent(); + var needs_parens = (parent instanceof AST_Binary && !(parent instanceof AST_Assign)) || + parent instanceof AST_Unary || + (parent instanceof AST_Call && self === parent.expression); + if (needs_parens) { output.print("("); } + if (self.async) { + output.print("async"); + output.space(); + } + if (self.argnames.length === 1 && self.argnames[0] instanceof AST_Symbol) { + self.argnames[0].print(output); + } else { + output.with_parens(function() { + self.argnames.forEach(function(arg, i) { + if (i) output.comma(); + arg.print(output); + }); + }); + } + output.space(); + output.print("=>"); + output.space(); + const first_statement = self.body[0]; + if ( + self.body.length === 1 + && first_statement instanceof AST_Return + ) { + const returned = first_statement.value; + if (!returned) { + output.print("{}"); + } else if (left_is_object(returned)) { + output.print("("); + returned.print(output); + output.print(")"); + } else { + returned.print(output); + } + } else { + print_braced(self, output); + } + if (needs_parens) { output.print(")"); } + output.gc_scope(self); + }); + + /* -----[ exits ]----- */ + AST_Exit.DEFMETHOD("_do_print", function(output, kind) { + output.print(kind); + if (this.value) { + output.space(); + const comments = this.value.start.comments_before; + if (comments && comments.length && !output.printed_comments.has(comments)) { + output.print("("); + this.value.print(output); + output.print(")"); + } else { + this.value.print(output); + } + } + output.semicolon(); + }); + DEFPRINT(AST_Return, function(self, output) { + self._do_print(output, "return"); + }); + DEFPRINT(AST_Throw, function(self, output) { + self._do_print(output, "throw"); + }); + + /* -----[ yield ]----- */ + + DEFPRINT(AST_Yield, function(self, output) { + var star = self.is_star ? "*" : ""; + output.print("yield" + star); + if (self.expression) { + output.space(); + self.expression.print(output); + } + }); + + DEFPRINT(AST_Await, function(self, output) { + output.print("await"); + output.space(); + var e = self.expression; + var parens = !( + e instanceof AST_Call + || e instanceof AST_SymbolRef + || e instanceof AST_PropAccess + || e instanceof AST_Unary + || e instanceof AST_Constant + || e instanceof AST_Await + || e instanceof AST_Object + ); + if (parens) output.print("("); + self.expression.print(output); + if (parens) output.print(")"); + }); + + /* -----[ loop control ]----- */ + AST_LoopControl.DEFMETHOD("_do_print", function(output, kind) { + output.print(kind); + if (this.label) { + output.space(); + this.label.print(output); + } + output.semicolon(); + }); + DEFPRINT(AST_Break, function(self, output) { + self._do_print(output, "break"); + }); + DEFPRINT(AST_Continue, function(self, output) { + self._do_print(output, "continue"); + }); + + /* -----[ if ]----- */ + function make_then(self, output) { + var b = self.body; + if (output.option("braces") + || output.option("ie8") && b instanceof AST_Do) + return make_block(b, output); + // The squeezer replaces "block"-s that contain only a single + // statement with the statement itself; technically, the AST + // is correct, but this can create problems when we output an + // IF having an ELSE clause where the THEN clause ends in an + // IF *without* an ELSE block (then the outer ELSE would refer + // to the inner IF). This function checks for this case and + // adds the block braces if needed. + if (!b) return output.force_semicolon(); + while (true) { + if (b instanceof AST_If) { + if (!b.alternative) { + make_block(self.body, output); + return; + } + b = b.alternative; + } else if (b instanceof AST_StatementWithBody) { + b = b.body; + } else break; + } + print_maybe_braced_body(self.body, output); + } + DEFPRINT(AST_If, function(self, output) { + output.print("if"); + output.space(); + output.with_parens(function() { + self.condition.print(output); + }); + output.space(); + if (self.alternative) { + make_then(self, output); + output.space(); + output.print("else"); + output.space(); + if (self.alternative instanceof AST_If) + self.alternative.print(output); + else + print_maybe_braced_body(self.alternative, output); + } else { + self._do_print_body(output); + } + }); + + /* -----[ switch ]----- */ + DEFPRINT(AST_Switch, function(self, output) { + output.print("switch"); + output.space(); + output.with_parens(function() { + self.expression.print(output); + }); + output.space(); + var last = self.body.length - 1; + if (last < 0) print_braced_empty(self, output); + else output.with_block(function() { + self.body.forEach(function(branch, i) { + output.indent(true); + branch.print(output); + if (i < last && branch.body.length > 0) + output.newline(); + }); + }); + }); + AST_SwitchBranch.DEFMETHOD("_do_print_body", function(output) { + output.newline(); + this.body.forEach(function(stmt) { + output.indent(); + stmt.print(output); + output.newline(); + }); + }); + DEFPRINT(AST_Default, function(self, output) { + output.print("default:"); + self._do_print_body(output); + }); + DEFPRINT(AST_Case, function(self, output) { + output.print("case"); + output.space(); + self.expression.print(output); + output.print(":"); + self._do_print_body(output); + }); + + /* -----[ exceptions ]----- */ + DEFPRINT(AST_Try, function(self, output) { + output.print("try"); + output.space(); + self.body.print(output); + if (self.bcatch) { + output.space(); + self.bcatch.print(output); + } + if (self.bfinally) { + output.space(); + self.bfinally.print(output); + } + }); + DEFPRINT(AST_TryBlock, function(self, output) { + print_braced(self, output); + }); + DEFPRINT(AST_Catch, function(self, output) { + output.print("catch"); + if (self.argname) { + output.space(); + output.with_parens(function() { + self.argname.print(output); + }); + } + output.space(); + print_braced(self, output); + }); + DEFPRINT(AST_Finally, function(self, output) { + output.print("finally"); + output.space(); + print_braced(self, output); + }); + + /* -----[ var/const ]----- */ + AST_Definitions.DEFMETHOD("_do_print", function(output, kind) { + output.print(kind); + output.space(); + this.definitions.forEach(function(def, i) { + if (i) output.comma(); + def.print(output); + }); + var p = output.parent(); + var in_for = p instanceof AST_For || p instanceof AST_ForIn; + var output_semicolon = !in_for || p && p.init !== this; + if (output_semicolon) + output.semicolon(); + }); + DEFPRINT(AST_Let, function(self, output) { + self._do_print(output, "let"); + }); + DEFPRINT(AST_Var, function(self, output) { + self._do_print(output, "var"); + }); + DEFPRINT(AST_Const, function(self, output) { + self._do_print(output, "const"); + }); + DEFPRINT(AST_Import, function(self, output) { + output.print("import"); + output.space(); + if (self.imported_name) { + self.imported_name.print(output); + } + if (self.imported_name && self.imported_names) { + output.print(","); + output.space(); + } + if (self.imported_names) { + if (self.imported_names.length === 1 && + self.imported_names[0].foreign_name.name === "*" && + !self.imported_names[0].foreign_name.quote) { + self.imported_names[0].print(output); + } else { + output.print("{"); + self.imported_names.forEach(function (name_import, i) { + output.space(); + name_import.print(output); + if (i < self.imported_names.length - 1) { + output.print(","); + } + }); + output.space(); + output.print("}"); + } + } + if (self.imported_name || self.imported_names) { + output.space(); + output.print("from"); + output.space(); + } + self.module_name.print(output); + if (self.assert_clause) { + output.print("assert"); + self.assert_clause.print(output); + } + output.semicolon(); + }); + DEFPRINT(AST_ImportMeta, function(self, output) { + output.print("import.meta"); + }); + + DEFPRINT(AST_NameMapping, function(self, output) { + var is_import = output.parent() instanceof AST_Import; + var definition = self.name.definition(); + var foreign_name = self.foreign_name; + var names_are_different = + (definition && definition.mangled_name || self.name.name) !== + foreign_name.name; + if (!names_are_different && + foreign_name.name === "*" && + foreign_name.quote != self.name.quote) { + // export * as "*" + names_are_different = true; + } + var foreign_name_is_name = foreign_name.quote == null; + if (names_are_different) { + if (is_import) { + if (foreign_name_is_name) { + output.print(foreign_name.name); + } else { + output.print_string(foreign_name.name, foreign_name.quote); + } + } else { + if (self.name.quote == null) { + self.name.print(output); + } else { + output.print_string(self.name.name, self.name.quote); + } + + } + output.space(); + output.print("as"); + output.space(); + if (is_import) { + self.name.print(output); + } else { + if (foreign_name_is_name) { + output.print(foreign_name.name); + } else { + output.print_string(foreign_name.name, foreign_name.quote); + } + } + } else { + if (self.name.quote == null) { + self.name.print(output); + } else { + output.print_string(self.name.name, self.name.quote); + } + } + }); + + DEFPRINT(AST_Export, function(self, output) { + output.print("export"); + output.space(); + if (self.is_default) { + output.print("default"); + output.space(); + } + if (self.exported_names) { + if (self.exported_names.length === 1 && + self.exported_names[0].name.name === "*" && + !self.exported_names[0].name.quote) { + self.exported_names[0].print(output); + } else { + output.print("{"); + self.exported_names.forEach(function(name_export, i) { + output.space(); + name_export.print(output); + if (i < self.exported_names.length - 1) { + output.print(","); + } + }); + output.space(); + output.print("}"); + } + } else if (self.exported_value) { + self.exported_value.print(output); + } else if (self.exported_definition) { + self.exported_definition.print(output); + if (self.exported_definition instanceof AST_Definitions) return; + } + if (self.module_name) { + output.space(); + output.print("from"); + output.space(); + self.module_name.print(output); + } + if (self.assert_clause) { + output.print("assert"); + self.assert_clause.print(output); + } + if (self.exported_value + && !(self.exported_value instanceof AST_Defun || + self.exported_value instanceof AST_Function || + self.exported_value instanceof AST_Class) + || self.module_name + || self.exported_names + ) { + output.semicolon(); + } + }); + + function parenthesize_for_noin(node, output, noin) { + var parens = false; + // need to take some precautions here: + // https://github.com/mishoo/UglifyJS2/issues/60 + if (noin) { + parens = walk(node, node => { + // Don't go into scopes -- except arrow functions: + // https://github.com/terser/terser/issues/1019#issuecomment-877642607 + if (node instanceof AST_Scope && !(node instanceof AST_Arrow)) { + return true; + } + if ( + node instanceof AST_Binary && node.operator == "in" + || node instanceof AST_PrivateIn + ) { + return walk_abort; // makes walk() return true + } + }); + } + node.print(output, parens); + } + + DEFPRINT(AST_VarDef, function(self, output) { + self.name.print(output); + if (self.value) { + output.space(); + output.print("="); + output.space(); + var p = output.parent(1); + var noin = p instanceof AST_For || p instanceof AST_ForIn; + parenthesize_for_noin(self.value, output, noin); + } + }); + + /* -----[ other expressions ]----- */ + DEFPRINT(AST_Call, function(self, output) { + self.expression.print(output); + if (self instanceof AST_New && self.args.length === 0) + return; + if (self.expression instanceof AST_Call || self.expression instanceof AST_Lambda) { + output.add_mapping(self.start); + } + if (self.optional) output.print("?."); + output.with_parens(function() { + self.args.forEach(function(expr, i) { + if (i) output.comma(); + expr.print(output); + }); + }); + }); + DEFPRINT(AST_New, function(self, output) { + output.print("new"); + output.space(); + AST_Call.prototype._codegen(self, output); + }); + + AST_Sequence.DEFMETHOD("_do_print", function(output) { + this.expressions.forEach(function(node, index) { + if (index > 0) { + output.comma(); + if (output.should_break()) { + output.newline(); + output.indent(); + } + } + node.print(output); + }); + }); + DEFPRINT(AST_Sequence, function(self, output) { + self._do_print(output); + // var p = output.parent(); + // if (p instanceof AST_Statement) { + // output.with_indent(output.next_indent(), function(){ + // self._do_print(output); + // }); + // } else { + // self._do_print(output); + // } + }); + DEFPRINT(AST_Dot, function(self, output) { + var expr = self.expression; + expr.print(output); + var prop = self.property; + var print_computed = ALL_RESERVED_WORDS.has(prop) + ? output.option("ie8") + : !is_identifier_string( + prop, + output.option("ecma") >= 2015 && !output.option("safari10") + ); + + if (self.optional) output.print("?."); + + if (print_computed) { + output.print("["); + output.add_mapping(self.end); + output.print_string(prop); + output.print("]"); + } else { + if (expr instanceof AST_Number && expr.getValue() >= 0) { + if (!/[xa-f.)]/i.test(output.last())) { + output.print("."); + } + } + if (!self.optional) output.print("."); + // the name after dot would be mapped about here. + output.add_mapping(self.end); + output.print_name(prop); + } + }); + DEFPRINT(AST_DotHash, function(self, output) { + var expr = self.expression; + expr.print(output); + var prop = self.property; + + if (self.optional) output.print("?"); + output.print(".#"); + output.add_mapping(self.end); + output.print_name(prop); + }); + DEFPRINT(AST_Sub, function(self, output) { + self.expression.print(output); + if (self.optional) output.print("?."); + output.print("["); + self.property.print(output); + output.print("]"); + }); + DEFPRINT(AST_Chain, function(self, output) { + self.expression.print(output); + }); + DEFPRINT(AST_UnaryPrefix, function(self, output) { + var op = self.operator; + output.print(op); + if (/^[a-z]/i.test(op) + || (/[+-]$/.test(op) + && self.expression instanceof AST_UnaryPrefix + && /^[+-]/.test(self.expression.operator))) { + output.space(); + } + self.expression.print(output); + }); + DEFPRINT(AST_UnaryPostfix, function(self, output) { + self.expression.print(output); + output.print(self.operator); + }); + DEFPRINT(AST_Binary, function(self, output) { + var op = self.operator; + self.left.print(output); + if (op[0] == ">" /* ">>" ">>>" ">" ">=" */ + && self.left instanceof AST_UnaryPostfix + && self.left.operator == "--") { + // space is mandatory to avoid outputting --> + output.print(" "); + } else { + // the space is optional depending on "beautify" + output.space(); + } + output.print(op); + if ((op == "<" || op == "<<") + && self.right instanceof AST_UnaryPrefix + && self.right.operator == "!" + && self.right.expression instanceof AST_UnaryPrefix + && self.right.expression.operator == "--") { + // space is mandatory to avoid outputting - output.print(" "); - } else { - // the space is optional depending on "beautify" - output.space(); - } - output.print(op); - if ((op == "<" || op == "<<") - && self.right instanceof AST_UnaryPrefix - && self.right.operator == "!" - && self.right.expression instanceof AST_UnaryPrefix - && self.right.expression.operator == "--") { - // space is mandatory to avoid outputting x ? y : false - if (self.left.operator == "||") { - var lr = self.left.right.evaluate(compressor); - if (!lr) return make_node(AST_Conditional, self, { - condition: self.left.left, - consequent: self.right, - alternative: self.left.right - }).optimize(compressor); - } - break; - case "||": - var ll = self.left.truthy ? true : self.left.falsy ? false : self.left.evaluate(compressor); - if (!ll) { - compressor.warn("Condition left of || always false [{file}:{line},{col}]", self.start); - return make_sequence(self, [ self.left, self.right ]).optimize(compressor); - } else if (!(ll instanceof AST_Node)) { - compressor.warn("Condition left of || always true [{file}:{line},{col}]", self.start); - return maintain_this_binding(compressor.parent(), compressor.self(), self.left).optimize(compressor); - } - var rr = self.right.evaluate(compressor); - if (!rr) { - var parent = compressor.parent(); - if (parent.operator == "||" && parent.left === compressor.self() || compressor.in_boolean_context()) { - compressor.warn("Dropping side-effect-free || [{file}:{line},{col}]", self.start); - return self.left.optimize(compressor); - } - } else if (!(rr instanceof AST_Node)) { - if (compressor.in_boolean_context()) { - compressor.warn("Boolean || always true [{file}:{line},{col}]", self.start); - return make_sequence(self, [ - self.left, - make_node(AST_True, self) - ]).optimize(compressor); - } else self.truthy = true; - } - if (self.left.operator == "&&") { - var lr = self.left.right.evaluate(compressor); - if (lr && !(lr instanceof AST_Node)) return make_node(AST_Conditional, self, { - condition: self.left.left, - consequent: self.left.right, - alternative: self.right - }).optimize(compressor); - } - break; - } - var associative = true; - switch (self.operator) { - case "+": - // "foo" + ("bar" + x) => "foobar" + x - if (self.left instanceof AST_Constant - && self.right instanceof AST_Binary - && self.right.operator == "+" - && self.right.left instanceof AST_Constant - && self.right.is_string(compressor)) { - self = make_node(AST_Binary, self, { - operator: "+", - left: make_node(AST_String, self.left, { - value: "" + self.left.getValue() + self.right.left.getValue(), - start: self.left.start, - end: self.right.left.end - }), - right: self.right.right - }); - } - // (x + "foo") + "bar" => x + "foobar" - if (self.right instanceof AST_Constant - && self.left instanceof AST_Binary - && self.left.operator == "+" - && self.left.right instanceof AST_Constant - && self.left.is_string(compressor)) { - self = make_node(AST_Binary, self, { - operator: "+", - left: self.left.left, - right: make_node(AST_String, self.right, { - value: "" + self.left.right.getValue() + self.right.getValue(), - start: self.left.right.start, - end: self.right.end - }) - }); - } - // (x + "foo") + ("bar" + y) => (x + "foobar") + y - if (self.left instanceof AST_Binary - && self.left.operator == "+" - && self.left.is_string(compressor) - && self.left.right instanceof AST_Constant - && self.right instanceof AST_Binary - && self.right.operator == "+" - && self.right.left instanceof AST_Constant - && self.right.is_string(compressor)) { - self = make_node(AST_Binary, self, { - operator: "+", - left: make_node(AST_Binary, self.left, { - operator: "+", - left: self.left.left, - right: make_node(AST_String, self.left.right, { - value: "" + self.left.right.getValue() + self.right.left.getValue(), - start: self.left.right.start, - end: self.right.left.end - }) - }), - right: self.right.right - }); - } - // a + -b => a - b - if (self.right instanceof AST_UnaryPrefix - && self.right.operator == "-" - && self.left.is_number(compressor)) { - self = make_node(AST_Binary, self, { - operator: "-", - left: self.left, - right: self.right.expression - }); - break; - } - // -a + b => b - a - if (self.left instanceof AST_UnaryPrefix - && self.left.operator == "-" - && reversible() - && self.right.is_number(compressor)) { - self = make_node(AST_Binary, self, { - operator: "-", - left: self.right, - right: self.left.expression - }); - break; - } - case "*": - associative = compressor.option("unsafe_math"); - case "&": - case "|": - case "^": - // a + +b => +b + a - if (self.left.is_number(compressor) - && self.right.is_number(compressor) - && reversible() - && !(self.left instanceof AST_Binary - && self.left.operator != self.operator - && PRECEDENCE[self.left.operator] >= PRECEDENCE[self.operator])) { - var reversed = make_node(AST_Binary, self, { - operator: self.operator, - left: self.right, - right: self.left - }); - if (self.right instanceof AST_Constant - && !(self.left instanceof AST_Constant)) { - self = best_of(compressor, reversed, self); - } else { - self = best_of(compressor, self, reversed); - } - } - if (associative && self.is_number(compressor)) { - // a + (b + c) => (a + b) + c - if (self.right instanceof AST_Binary - && self.right.operator == self.operator) { - self = make_node(AST_Binary, self, { - operator: self.operator, - left: make_node(AST_Binary, self.left, { - operator: self.operator, - left: self.left, - right: self.right.left, - start: self.left.start, - end: self.right.left.end - }), - right: self.right.right - }); - } - // (n + 2) + 3 => 5 + n - // (2 * n) * 3 => 6 + n - if (self.right instanceof AST_Constant - && self.left instanceof AST_Binary - && self.left.operator == self.operator) { - if (self.left.left instanceof AST_Constant) { - self = make_node(AST_Binary, self, { - operator: self.operator, - left: make_node(AST_Binary, self.left, { - operator: self.operator, - left: self.left.left, - right: self.right, - start: self.left.left.start, - end: self.right.end - }), - right: self.left.right - }); - } else if (self.left.right instanceof AST_Constant) { - self = make_node(AST_Binary, self, { - operator: self.operator, - left: make_node(AST_Binary, self.left, { - operator: self.operator, - left: self.left.right, - right: self.right, - start: self.left.right.start, - end: self.right.end - }), - right: self.left.left - }); - } - } - // (a | 1) | (2 | d) => (3 | a) | b - if (self.left instanceof AST_Binary - && self.left.operator == self.operator - && self.left.right instanceof AST_Constant - && self.right instanceof AST_Binary - && self.right.operator == self.operator - && self.right.left instanceof AST_Constant) { - self = make_node(AST_Binary, self, { - operator: self.operator, - left: make_node(AST_Binary, self.left, { - operator: self.operator, - left: make_node(AST_Binary, self.left.left, { - operator: self.operator, - left: self.left.right, - right: self.right.left, - start: self.left.right.start, - end: self.right.left.end - }), - right: self.left.left - }), - right: self.right.right - }); - } - } - } - } - // x && (y && z) ==> x && y && z - // x || (y || z) ==> x || y || z - // x + ("y" + z) ==> x + "y" + z - // "x" + (y + "z")==> "x" + y + "z" - if (self.right instanceof AST_Binary - && self.right.operator == self.operator - && (lazy_op.has(self.operator) - || (self.operator == "+" - && (self.right.left.is_string(compressor) - || (self.left.is_string(compressor) - && self.right.right.is_string(compressor))))) - ) { - self.left = make_node(AST_Binary, self.left, { - operator : self.operator, - left : self.left, - right : self.right.left - }); - self.right = self.right.right; - return self.transform(compressor); - } - var ev = self.evaluate(compressor); - if (ev !== self) { - ev = make_node_from_constant(ev, self).optimize(compressor); - return best_of(compressor, ev, self); - } - return self; - }); - - def_optimize(AST_SymbolExport, function(self, compressor) { - return self; - }); - - function recursive_ref(compressor, def) { - var node; - for (var i = 0; node = compressor.parent(i); i++) { - if (node instanceof AST_Lambda) { - var name = node.name; - if (name && name.definition() === def) break; - } - } - return node; - } - - function within_array_or_object_literal(compressor) { - var node, level = 0; - while (node = compressor.parent(level++)) { - if (node instanceof AST_Statement) return false; - if (node instanceof AST_Array - || node instanceof AST_ObjectKeyVal - || node instanceof AST_Object) { - return true; - } - } - return false; - } - - def_optimize(AST_SymbolRef, function(self, compressor) { - if (!compressor.option("ie8") - && is_undeclared_ref(self) - && (!self.scope.uses_with || !compressor.find_parent(AST_With))) { - switch (self.name) { - case "undefined": - return make_node(AST_Undefined, self).optimize(compressor); - case "NaN": - return make_node(AST_NaN, self).optimize(compressor); - case "Infinity": - return make_node(AST_Infinity, self).optimize(compressor); - } - } - var parent = compressor.parent(); - if (compressor.option("reduce_vars") && is_lhs(self, parent) !== self) { - var d = self.definition(); - if (compressor.top_retain && d.global && compressor.top_retain(d)) { - d.fixed = false; - d.should_replace = false; - d.single_use = false; - return self; - } - var fixed = self.fixed_value(); - var single_use = d.single_use - && !(parent instanceof AST_Call && parent.is_expr_pure(compressor)); - if (single_use && (fixed instanceof AST_Lambda || fixed instanceof AST_Class)) { - if (retain_top_func(fixed, compressor)) { - single_use = false; - } else if (d.scope !== self.scope - && (!compressor.option("reduce_funcs") && fixed instanceof AST_Lambda - || d.escaped == 1 - || fixed.inlined - || within_array_or_object_literal(compressor))) { - single_use = false; - } else if (recursive_ref(compressor, d)) { - single_use = false; - } else if (d.scope !== self.scope || d.orig[0] instanceof AST_SymbolFunarg) { - single_use = fixed.is_constant_expression(self.scope); - if (single_use == "f") { - var scope = self.scope; - do { - if (scope instanceof AST_Defun || is_func_expr(scope)) { - scope.inlined = true; - } - } while (scope = scope.parent_scope); - } - } - } - if (single_use && fixed) { - if (fixed instanceof AST_DefClass) { - fixed = make_node(AST_ClassExpression, fixed, fixed); - } - if (fixed instanceof AST_Defun) { - fixed._squeezed = true; - fixed = make_node(AST_Function, fixed, fixed); - } - var value; - if (d.recursive_refs > 0 && fixed.name instanceof AST_SymbolDefun) { - value = fixed.clone(true); - var defun_def = value.name.definition(); - var lambda_def = value.variables.get(value.name.name); - var name = lambda_def && lambda_def.orig[0]; - if (!(name instanceof AST_SymbolLambda)) { - name = make_node(AST_SymbolLambda, value.name, value.name); - name.scope = value; - value.name = name; - lambda_def = value.def_function(name); - } - value.walk(new TreeWalker(function(node) { - if (node instanceof AST_SymbolRef && node.definition() === defun_def) { - node.thedef = lambda_def; - lambda_def.references.push(node); - } - })); - } else { - value = fixed.optimize(compressor); - if (value === fixed) value = fixed.clone(true); - } - return value; - } - if (fixed && d.should_replace === undefined) { - var init; - if (fixed instanceof AST_This) { - if (!(d.orig[0] instanceof AST_SymbolFunarg) - && d.references.every((ref) => - d.scope === ref.scope - )) { - init = fixed; - } - } else { - var ev = fixed.evaluate(compressor); - if (ev !== fixed && (compressor.option("unsafe_regexp") || !(ev instanceof RegExp))) { - init = make_node_from_constant(ev, fixed); - } - } - if (init) { - var value_length = init.optimize(compressor).print_to_string().length; - var fn; - if (has_symbol_ref(fixed)) { - fn = function() { - var result = init.optimize(compressor); - return result === init ? result.clone(true) : result; - }; - } else { - value_length = Math.min(value_length, fixed.print_to_string().length); - fn = function() { - var result = best_of_expression(init.optimize(compressor), fixed); - return result === init || result === fixed ? result.clone(true) : result; - }; - } - var name_length = d.name.length; - var overhead = 0; - if (compressor.option("unused") && !compressor.exposed(d)) { - overhead = (name_length + 2 + value_length) / (d.references.length - d.assignments); - } - d.should_replace = value_length <= name_length + overhead ? fn : false; - } else { - d.should_replace = false; - } - } - if (d.should_replace) { - return d.should_replace(); - } - } - return self; - - function has_symbol_ref(value) { - var found; - value.walk(new TreeWalker(function(node) { - if (node instanceof AST_SymbolRef) found = true; - if (found) return true; - })); - return found; - } - }); - - function is_atomic(lhs, self) { - return lhs instanceof AST_SymbolRef || lhs.TYPE === self.TYPE; - } - - def_optimize(AST_Undefined, function(self, compressor) { - if (compressor.option("unsafe_undefined")) { - var undef = find_variable(compressor, "undefined"); - if (undef) { - var ref = make_node(AST_SymbolRef, self, { - name : "undefined", - scope : undef.scope, - thedef : undef - }); - ref.is_undefined = true; - return ref; - } - } - var lhs = is_lhs(compressor.self(), compressor.parent()); - if (lhs && is_atomic(lhs, self)) return self; - return make_node(AST_UnaryPrefix, self, { - operator: "void", - expression: make_node(AST_Number, self, { - value: 0 - }) - }); - }); - - def_optimize(AST_Infinity, function(self, compressor) { - var lhs = is_lhs(compressor.self(), compressor.parent()); - if (lhs && is_atomic(lhs, self)) return self; - if (compressor.option("keep_infinity") - && !(lhs && !is_atomic(lhs, self)) - && !find_variable(compressor, "Infinity")) - return self; - return make_node(AST_Binary, self, { - operator: "/", - left: make_node(AST_Number, self, { - value: 1 - }), - right: make_node(AST_Number, self, { - value: 0 - }) - }); - }); - - def_optimize(AST_NaN, function(self, compressor) { - var lhs = is_lhs(compressor.self(), compressor.parent()); - if (lhs && !is_atomic(lhs, self) - || find_variable(compressor, "NaN")) { - return make_node(AST_Binary, self, { - operator: "/", - left: make_node(AST_Number, self, { - value: 0 - }), - right: make_node(AST_Number, self, { - value: 0 - }) - }); - } - return self; - }); - - function is_reachable(self, defs) { - var reachable = false; - var find_ref = new TreeWalker(function(node) { - if (reachable) return true; - if (node instanceof AST_SymbolRef && member(node.definition(), defs)) { - return reachable = true; - } - }); - var scan_scope = new TreeWalker(function(node) { - if (reachable) return true; - if (node instanceof AST_Scope && node !== self) { - var parent = scan_scope.parent(); - if (parent instanceof AST_Call && parent.expression === node) return; - node.walk(find_ref); - return true; - } - }); - self.walk(scan_scope); - return reachable; - } - - const ASSIGN_OPS = makePredicate("+ - / * % >> << >>> | ^ &"); - const ASSIGN_OPS_COMMUTATIVE = makePredicate("* | ^ &"); - def_optimize(AST_Assign, function(self, compressor) { - var def; - if (compressor.option("dead_code") - && self.left instanceof AST_SymbolRef - && (def = self.left.definition()).scope === compressor.find_parent(AST_Lambda)) { - var level = 0, node, parent = self; - do { - node = parent; - parent = compressor.parent(level++); - if (parent instanceof AST_Exit) { - if (in_try(level, parent)) break; - if (is_reachable(def.scope, [ def ])) break; - if (self.operator == "=") return self.right; - def.fixed = false; - return make_node(AST_Binary, self, { - operator: self.operator.slice(0, -1), - left: self.left, - right: self.right - }).optimize(compressor); - } - } while (parent instanceof AST_Binary && parent.right === node - || parent instanceof AST_Sequence && parent.tail_node() === node); - } - self = self.lift_sequences(compressor); - if (self.operator == "=" && self.left instanceof AST_SymbolRef && self.right instanceof AST_Binary) { - // x = expr1 OP expr2 - if (self.right.left instanceof AST_SymbolRef - && self.right.left.name == self.left.name - && ASSIGN_OPS.has(self.right.operator)) { - // x = x - 2 ---> x -= 2 - self.operator = self.right.operator + "="; - self.right = self.right.right; - } else if (self.right.right instanceof AST_SymbolRef - && self.right.right.name == self.left.name - && ASSIGN_OPS_COMMUTATIVE.has(self.right.operator) - && !self.right.left.has_side_effects(compressor)) { - // x = 2 & x ---> x &= 2 - self.operator = self.right.operator + "="; - self.right = self.right.left; - } - } - return self; - - function in_try(level, node) { - var right = self.right; - self.right = make_node(AST_Null, right); - var may_throw = node.may_throw(compressor); - self.right = right; - var scope = self.left.definition().scope; - var parent; - while ((parent = compressor.parent(level++)) !== scope) { - if (parent instanceof AST_Try) { - if (parent.bfinally) return true; - if (may_throw && parent.bcatch) return true; - } - } - } - }); - - def_optimize(AST_DefaultAssign, function(self, compressor) { - if (!compressor.option("evaluate")) { - return self; - } - var evaluateRight = self.right.evaluate(compressor); - - // `[x = undefined] = foo` ---> `[x] = foo` - if (evaluateRight === undefined) { - self = self.left; - } else if (evaluateRight !== self.right) { - evaluateRight = make_node_from_constant(evaluateRight, self.right); - self.right = best_of_expression(evaluateRight, self.right); - } - - return self; - }); - - def_optimize(AST_Conditional, function(self, compressor) { - if (!compressor.option("conditionals")) return self; - // This looks like lift_sequences(), should probably be under "sequences" - if (self.condition instanceof AST_Sequence) { - var expressions = self.condition.expressions.slice(); - self.condition = expressions.pop(); - expressions.push(self); - return make_sequence(self, expressions); - } - var cond = self.condition.evaluate(compressor); - if (cond !== self.condition) { - if (cond) { - compressor.warn("Condition always true [{file}:{line},{col}]", self.start); - return maintain_this_binding(compressor.parent(), compressor.self(), self.consequent); - } else { - compressor.warn("Condition always false [{file}:{line},{col}]", self.start); - return maintain_this_binding(compressor.parent(), compressor.self(), self.alternative); - } - } - var negated = cond.negate(compressor, first_in_statement(compressor)); - if (best_of(compressor, cond, negated) === negated) { - self = make_node(AST_Conditional, self, { - condition: negated, - consequent: self.alternative, - alternative: self.consequent - }); - } - var condition = self.condition; - var consequent = self.consequent; - var alternative = self.alternative; - // x?x:y --> x||y - if (condition instanceof AST_SymbolRef - && consequent instanceof AST_SymbolRef - && condition.definition() === consequent.definition()) { - return make_node(AST_Binary, self, { - operator: "||", - left: condition, - right: alternative - }); - } - // if (foo) exp = something; else exp = something_else; - // | - // v - // exp = foo ? something : something_else; - if (consequent instanceof AST_Assign - && alternative instanceof AST_Assign - && consequent.operator == alternative.operator - && consequent.left.equivalent_to(alternative.left) - && (!self.condition.has_side_effects(compressor) - || consequent.operator == "=" - && !consequent.left.has_side_effects(compressor))) { - return make_node(AST_Assign, self, { - operator: consequent.operator, - left: consequent.left, - right: make_node(AST_Conditional, self, { - condition: self.condition, - consequent: consequent.right, - alternative: alternative.right - }) - }); - } - // x ? y(a) : y(b) --> y(x ? a : b) - var arg_index; - if (consequent instanceof AST_Call - && alternative.TYPE === consequent.TYPE - && consequent.args.length > 0 - && consequent.args.length == alternative.args.length - && consequent.expression.equivalent_to(alternative.expression) - && !self.condition.has_side_effects(compressor) - && !consequent.expression.has_side_effects(compressor) - && typeof (arg_index = single_arg_diff()) == "number") { - var node = consequent.clone(); - node.args[arg_index] = make_node(AST_Conditional, self, { - condition: self.condition, - consequent: consequent.args[arg_index], - alternative: alternative.args[arg_index] - }); - return node; - } - // x?y?z:a:a --> x&&y?z:a - if (consequent instanceof AST_Conditional - && consequent.alternative.equivalent_to(alternative)) { - return make_node(AST_Conditional, self, { - condition: make_node(AST_Binary, self, { - left: self.condition, - operator: "&&", - right: consequent.condition - }), - consequent: consequent.consequent, - alternative: alternative - }); - } - // x ? y : y --> x, y - if (consequent.equivalent_to(alternative)) { - return make_sequence(self, [ - self.condition, - consequent - ]).optimize(compressor); - } - // x ? y || z : z --> x && y || z - if (consequent instanceof AST_Binary - && consequent.operator == "||" - && consequent.right.equivalent_to(alternative)) { - return make_node(AST_Binary, self, { - operator: "||", - left: make_node(AST_Binary, self, { - operator: "&&", - left: self.condition, - right: consequent.left - }), - right: alternative - }).optimize(compressor); - } - var in_bool = compressor.in_boolean_context(); - if (is_true(self.consequent)) { - if (is_false(self.alternative)) { - // c ? true : false ---> !!c - return booleanize(self.condition); - } - // c ? true : x ---> !!c || x - return make_node(AST_Binary, self, { - operator: "||", - left: booleanize(self.condition), - right: self.alternative - }); - } - if (is_false(self.consequent)) { - if (is_true(self.alternative)) { - // c ? false : true ---> !c - return booleanize(self.condition.negate(compressor)); - } - // c ? false : x ---> !c && x - return make_node(AST_Binary, self, { - operator: "&&", - left: booleanize(self.condition.negate(compressor)), - right: self.alternative - }); - } - if (is_true(self.alternative)) { - // c ? x : true ---> !c || x - return make_node(AST_Binary, self, { - operator: "||", - left: booleanize(self.condition.negate(compressor)), - right: self.consequent - }); - } - if (is_false(self.alternative)) { - // c ? x : false ---> !!c && x - return make_node(AST_Binary, self, { - operator: "&&", - left: booleanize(self.condition), - right: self.consequent - }); - } - - return self; - - function booleanize(node) { - if (node.is_boolean()) return node; - // !!expression - return make_node(AST_UnaryPrefix, node, { - operator: "!", - expression: node.negate(compressor) - }); - } - - // AST_True or !0 - function is_true(node) { - return node instanceof AST_True - || in_bool - && node instanceof AST_Constant - && node.getValue() - || (node instanceof AST_UnaryPrefix - && node.operator == "!" - && node.expression instanceof AST_Constant - && !node.expression.getValue()); - } - // AST_False or !1 - function is_false(node) { - return node instanceof AST_False - || in_bool - && node instanceof AST_Constant - && !node.getValue() - || (node instanceof AST_UnaryPrefix - && node.operator == "!" - && node.expression instanceof AST_Constant - && node.expression.getValue()); - } - - function single_arg_diff() { - var a = consequent.args; - var b = alternative.args; - for (var i = 0, len = a.length; i < len; i++) { - if (a[i] instanceof AST_Expansion) return; - if (!a[i].equivalent_to(b[i])) { - if (b[i] instanceof AST_Expansion) return; - for (var j = i + 1; j < len; j++) { - if (a[j] instanceof AST_Expansion) return; - if (!a[j].equivalent_to(b[j])) return; - } - return i; - } - } - } - }); +AST_SwitchBranch.prototype.shallow_cmp = pass_through; + +AST_Try.prototype.shallow_cmp = function(other) { + return (this.body === other.body) && (this.bcatch == null ? other.bcatch == null : this.bcatch === other.bcatch) && (this.bfinally == null ? other.bfinally == null : this.bfinally === other.bfinally); +}; + +AST_Catch.prototype.shallow_cmp = function(other) { + return this.argname == null ? other.argname == null : this.argname === other.argname; +}; + +AST_Finally.prototype.shallow_cmp = pass_through; + +AST_Definitions.prototype.shallow_cmp = pass_through; + +AST_VarDef.prototype.shallow_cmp = function(other) { + return this.value == null ? other.value == null : this.value === other.value; +}; + +AST_NameMapping.prototype.shallow_cmp = pass_through; + +AST_Import.prototype.shallow_cmp = function(other) { + return (this.imported_name == null ? other.imported_name == null : this.imported_name === other.imported_name) && (this.imported_names == null ? other.imported_names == null : this.imported_names === other.imported_names); +}; + +AST_ImportMeta.prototype.shallow_cmp = pass_through; + +AST_Export.prototype.shallow_cmp = function(other) { + return (this.exported_definition == null ? other.exported_definition == null : this.exported_definition === other.exported_definition) && (this.exported_value == null ? other.exported_value == null : this.exported_value === other.exported_value) && (this.exported_names == null ? other.exported_names == null : this.exported_names === other.exported_names) && this.module_name === other.module_name && this.is_default === other.is_default; +}; + +AST_Call.prototype.shallow_cmp = pass_through; + +AST_Sequence.prototype.shallow_cmp = pass_through; + +AST_PropAccess.prototype.shallow_cmp = pass_through; + +AST_Chain.prototype.shallow_cmp = pass_through; + +AST_Dot.prototype.shallow_cmp = function(other) { + return this.property === other.property; +}; + +AST_DotHash.prototype.shallow_cmp = function(other) { + return this.property === other.property; +}; + +AST_Unary.prototype.shallow_cmp = function(other) { + return this.operator === other.operator; +}; + +AST_Binary.prototype.shallow_cmp = function(other) { + return this.operator === other.operator; +}; + +AST_Conditional.prototype.shallow_cmp = pass_through; + +AST_Array.prototype.shallow_cmp = pass_through; + +AST_Object.prototype.shallow_cmp = pass_through; + +AST_ObjectProperty.prototype.shallow_cmp = pass_through; + +AST_ObjectKeyVal.prototype.shallow_cmp = function(other) { + return this.key === other.key; +}; + +AST_ObjectSetter.prototype.shallow_cmp = function(other) { + return this.static === other.static; +}; + +AST_ObjectGetter.prototype.shallow_cmp = function(other) { + return this.static === other.static; +}; + +AST_ConciseMethod.prototype.shallow_cmp = function(other) { + return this.static === other.static && this.is_generator === other.is_generator && this.async === other.async; +}; + +AST_Class.prototype.shallow_cmp = function(other) { + return (this.name == null ? other.name == null : this.name === other.name) && (this.extends == null ? other.extends == null : this.extends === other.extends); +}; + +AST_ClassProperty.prototype.shallow_cmp = function(other) { + return this.static === other.static; +}; + +AST_Symbol.prototype.shallow_cmp = function(other) { + return this.name === other.name; +}; + +AST_NewTarget.prototype.shallow_cmp = pass_through; + +AST_This.prototype.shallow_cmp = pass_through; + +AST_Super.prototype.shallow_cmp = pass_through; + +AST_String.prototype.shallow_cmp = function(other) { + return this.value === other.value; +}; + +AST_Number.prototype.shallow_cmp = function(other) { + return this.value === other.value; +}; + +AST_BigInt.prototype.shallow_cmp = function(other) { + return this.value === other.value; +}; + +AST_RegExp.prototype.shallow_cmp = function (other) { + return ( + this.value.flags === other.value.flags + && this.value.source === other.value.source + ); +}; + +AST_Atom.prototype.shallow_cmp = pass_through; + +/*********************************************************************** + + A JavaScript tokenizer / parser / beautifier / compressor. + https://github.com/mishoo/UglifyJS2 + + -------------------------------- (C) --------------------------------- + + Author: Mihai Bazon + + http://mihai.bazon.net/blog + + Distributed under the BSD license: + + Copyright 2012 (c) Mihai Bazon + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + ***********************************************************************/ + +const MASK_EXPORT_DONT_MANGLE = 1 << 0; +const MASK_EXPORT_WANT_MANGLE = 1 << 1; + +let function_defs = null; +let unmangleable_names = null; +/** + * When defined, there is a function declaration somewhere that's inside of a block. + * See https://tc39.es/ecma262/multipage/additional-ecmascript-features-for-web-browsers.html#sec-block-level-function-declarations-web-legacy-compatibility-semantics +*/ +let scopes_with_block_defuns = null; + +class SymbolDef { + constructor(scope, orig, init) { + this.name = orig.name; + this.orig = [ orig ]; + this.init = init; + this.eliminated = 0; + this.assignments = 0; + this.scope = scope; + this.replaced = 0; + this.global = false; + this.export = 0; + this.mangled_name = null; + this.undeclared = false; + this.id = SymbolDef.next_id++; + this.chained = false; + this.direct_access = false; + this.escaped = 0; + this.recursive_refs = 0; + this.references = []; + this.should_replace = undefined; + this.single_use = false; + this.fixed = false; + Object.seal(this); + } + fixed_value() { + if (!this.fixed || this.fixed instanceof AST_Node) return this.fixed; + return this.fixed(); + } + unmangleable(options) { + if (!options) options = {}; + + if ( + function_defs && + function_defs.has(this.id) && + keep_name(options.keep_fnames, this.orig[0].name) + ) return true; + + return this.global && !options.toplevel + || (this.export & MASK_EXPORT_DONT_MANGLE) + || this.undeclared + || !options.eval && this.scope.pinned() + || (this.orig[0] instanceof AST_SymbolLambda + || this.orig[0] instanceof AST_SymbolDefun) && keep_name(options.keep_fnames, this.orig[0].name) + || this.orig[0] instanceof AST_SymbolMethod + || (this.orig[0] instanceof AST_SymbolClass + || this.orig[0] instanceof AST_SymbolDefClass) && keep_name(options.keep_classnames, this.orig[0].name); + } + mangle(options) { + const cache = options.cache && options.cache.props; + if (this.global && cache && cache.has(this.name)) { + this.mangled_name = cache.get(this.name); + } else if (!this.mangled_name && !this.unmangleable(options)) { + var s = this.scope; + var sym = this.orig[0]; + if (options.ie8 && sym instanceof AST_SymbolLambda) + s = s.parent_scope; + const redefinition = redefined_catch_def(this); + this.mangled_name = redefinition + ? redefinition.mangled_name || redefinition.name + : s.next_mangled(options, this); + if (this.global && cache) { + cache.set(this.name, this.mangled_name); + } + } + } +} + +SymbolDef.next_id = 1; + +function redefined_catch_def(def) { + if (def.orig[0] instanceof AST_SymbolCatch + && def.scope.is_block_scope() + ) { + return def.scope.get_defun_scope().variables.get(def.name); + } +} + +AST_Scope.DEFMETHOD("figure_out_scope", function(options, { parent_scope = null, toplevel = this } = {}) { + options = defaults(options, { + cache: null, + ie8: false, + safari10: false, + }); + + if (!(toplevel instanceof AST_Toplevel)) { + throw new Error("Invalid toplevel scope"); + } + + // pass 1: setup scope chaining and handle definitions + var scope = this.parent_scope = parent_scope; + var labels = new Map(); + var defun = null; + var in_destructuring = null; + var for_scopes = []; + var tw = new TreeWalker((node, descend) => { + if (node.is_block_scope()) { + const save_scope = scope; + node.block_scope = scope = new AST_Scope(node); + scope._block_scope = true; + scope.init_scope_vars(save_scope); + scope.uses_with = save_scope.uses_with; + scope.uses_eval = save_scope.uses_eval; + + if (options.safari10) { + if (node instanceof AST_For || node instanceof AST_ForIn || node instanceof AST_ForOf) { + for_scopes.push(scope); + } + } + + if (node instanceof AST_Switch) { + // XXX: HACK! Ensure the switch expression gets the correct scope (the parent scope) and the body gets the contained scope + // AST_Switch has a scope within the body, but it itself "is a block scope" + // This means the switched expression has to belong to the outer scope + // while the body inside belongs to the switch itself. + // This is pretty nasty and warrants an AST change + const the_block_scope = scope; + scope = save_scope; + node.expression.walk(tw); + scope = the_block_scope; + for (let i = 0; i < node.body.length; i++) { + node.body[i].walk(tw); + } + } else { + descend(); + } + scope = save_scope; + return true; + } + if (node instanceof AST_Destructuring) { + const save_destructuring = in_destructuring; + in_destructuring = node; + descend(); + in_destructuring = save_destructuring; + return true; + } + if (node instanceof AST_Scope) { + node.init_scope_vars(scope); + var save_scope = scope; + var save_defun = defun; + var save_labels = labels; + defun = scope = node; + labels = new Map(); + descend(); + scope = save_scope; + defun = save_defun; + labels = save_labels; + return true; // don't descend again in TreeWalker + } + if (node instanceof AST_LabeledStatement) { + var l = node.label; + if (labels.has(l.name)) { + throw new Error(string_template("Label {name} defined twice", l)); + } + labels.set(l.name, l); + descend(); + labels.delete(l.name); + return true; // no descend again + } + if (node instanceof AST_With) { + for (var s = scope; s; s = s.parent_scope) + s.uses_with = true; + return; + } + if (node instanceof AST_Symbol) { + node.scope = scope; + } + if (node instanceof AST_Label) { + node.thedef = node; + node.references = []; + } + if (node instanceof AST_SymbolLambda) { + defun.def_function(node, node.name == "arguments" ? undefined : defun); + } else if (node instanceof AST_SymbolDefun) { + // Careful here, the scope where this should be defined is + // the parent scope. The reason is that we enter a new + // scope when we encounter the AST_Defun node (which is + // instanceof AST_Scope) but we get to the symbol a bit + // later. + const closest_scope = defun.parent_scope; + + // In strict mode, function definitions are block-scoped + node.scope = tw.directives["use strict"] + ? closest_scope + : closest_scope.get_defun_scope(); + + mark_export(node.scope.def_function(node, defun), 1); + } else if (node instanceof AST_SymbolClass) { + mark_export(defun.def_variable(node, defun), 1); + } else if (node instanceof AST_SymbolImport) { + scope.def_variable(node); + } else if (node instanceof AST_SymbolDefClass) { + // This deals with the name of the class being available + // inside the class. + mark_export((node.scope = defun.parent_scope).def_function(node, defun), 1); + } else if ( + node instanceof AST_SymbolVar + || node instanceof AST_SymbolLet + || node instanceof AST_SymbolConst + || node instanceof AST_SymbolCatch + ) { + var def; + if (node instanceof AST_SymbolBlockDeclaration) { + def = scope.def_variable(node, null); + } else { + def = defun.def_variable(node, node.TYPE == "SymbolVar" ? null : undefined); + } + if (!def.orig.every((sym) => { + if (sym === node) return true; + if (node instanceof AST_SymbolBlockDeclaration) { + return sym instanceof AST_SymbolLambda; + } + return !(sym instanceof AST_SymbolLet || sym instanceof AST_SymbolConst); + })) { + js_error( + `"${node.name}" is redeclared`, + node.start.file, + node.start.line, + node.start.col, + node.start.pos + ); + } + if (!(node instanceof AST_SymbolFunarg)) mark_export(def, 2); + if (defun !== scope) { + node.mark_enclosed(); + var def = scope.find_variable(node); + if (node.thedef !== def) { + node.thedef = def; + node.reference(); + } + } + } else if (node instanceof AST_LabelRef) { + var sym = labels.get(node.name); + if (!sym) throw new Error(string_template("Undefined label {name} [{line},{col}]", { + name: node.name, + line: node.start.line, + col: node.start.col + })); + node.thedef = sym; + } + if (!(scope instanceof AST_Toplevel) && (node instanceof AST_Export || node instanceof AST_Import)) { + js_error( + `"${node.TYPE}" statement may only appear at the top level`, + node.start.file, + node.start.line, + node.start.col, + node.start.pos + ); + } + }); + this.walk(tw); + + function mark_export(def, level) { + if (in_destructuring) { + var i = 0; + do { + level++; + } while (tw.parent(i++) !== in_destructuring); + } + var node = tw.parent(level); + if (def.export = node instanceof AST_Export ? MASK_EXPORT_DONT_MANGLE : 0) { + var exported = node.exported_definition; + if ((exported instanceof AST_Defun || exported instanceof AST_DefClass) && node.is_default) { + def.export = MASK_EXPORT_WANT_MANGLE; + } + } + } + + // pass 2: find back references and eval + const is_toplevel = this instanceof AST_Toplevel; + if (is_toplevel) { + this.globals = new Map(); + } + + var tw = new TreeWalker(node => { + if (node instanceof AST_LoopControl && node.label) { + node.label.thedef.references.push(node); + return true; + } + if (node instanceof AST_SymbolRef) { + var name = node.name; + if (name == "eval" && tw.parent() instanceof AST_Call) { + for (var s = node.scope; s && !s.uses_eval; s = s.parent_scope) { + s.uses_eval = true; + } + } + var sym; + if (tw.parent() instanceof AST_NameMapping && tw.parent(1).module_name + || !(sym = node.scope.find_variable(name))) { + + sym = toplevel.def_global(node); + if (node instanceof AST_SymbolExport) sym.export = MASK_EXPORT_DONT_MANGLE; + } else if (sym.scope instanceof AST_Lambda && name == "arguments") { + sym.scope.get_defun_scope().uses_arguments = true; + } + node.thedef = sym; + node.reference(); + if (node.scope.is_block_scope() + && !(sym.orig[0] instanceof AST_SymbolBlockDeclaration)) { + node.scope = node.scope.get_defun_scope(); + } + return true; + } + // ensure mangling works if catch reuses a scope variable + var def; + if (node instanceof AST_SymbolCatch && (def = redefined_catch_def(node.definition()))) { + var s = node.scope; + while (s) { + push_uniq(s.enclosed, def); + if (s === def.scope) break; + s = s.parent_scope; + } + } + }); + this.walk(tw); + + // pass 3: work around IE8 and Safari catch scope bugs + if (options.ie8 || options.safari10) { + walk(this, node => { + if (node instanceof AST_SymbolCatch) { + var name = node.name; + var refs = node.thedef.references; + var scope = node.scope.get_defun_scope(); + var def = scope.find_variable(name) + || toplevel.globals.get(name) + || scope.def_variable(node); + refs.forEach(function(ref) { + ref.thedef = def; + ref.reference(); + }); + node.thedef = def; + node.reference(); + return true; + } + }); + } + + // pass 4: add symbol definitions to loop scopes + // Safari/Webkit bug workaround - loop init let variable shadowing argument. + // https://github.com/mishoo/UglifyJS2/issues/1753 + // https://bugs.webkit.org/show_bug.cgi?id=171041 + if (options.safari10) { + for (const scope of for_scopes) { + scope.parent_scope.variables.forEach(function(def) { + push_uniq(scope.enclosed, def); + }); + } + } +}); + +AST_Toplevel.DEFMETHOD("def_global", function(node) { + var globals = this.globals, name = node.name; + if (globals.has(name)) { + return globals.get(name); + } else { + var g = new SymbolDef(this, node); + g.undeclared = true; + g.global = true; + globals.set(name, g); + return g; + } +}); + +AST_Scope.DEFMETHOD("init_scope_vars", function(parent_scope) { + this.variables = new Map(); // map name to AST_SymbolVar (variables defined in this scope; includes functions) + this.uses_with = false; // will be set to true if this or some nested scope uses the `with` statement + this.uses_eval = false; // will be set to true if this or nested scope uses the global `eval` + this.parent_scope = parent_scope; // the parent scope + this.enclosed = []; // a list of variables from this or outer scope(s) that are referenced from this or inner scopes + this.cname = -1; // the current index for mangling functions/variables +}); + +AST_Scope.DEFMETHOD("conflicting_def", function (name) { + return ( + this.enclosed.find(def => def.name === name) + || this.variables.has(name) + || (this.parent_scope && this.parent_scope.conflicting_def(name)) + ); +}); + +AST_Scope.DEFMETHOD("conflicting_def_shallow", function (name) { + return ( + this.enclosed.find(def => def.name === name) + || this.variables.has(name) + ); +}); + +AST_Scope.DEFMETHOD("add_child_scope", function (scope) { + // `scope` is going to be moved into `this` right now. + // Update the required scopes' information + + if (scope.parent_scope === this) return; + + scope.parent_scope = this; + + // Propagate to this.uses_arguments from arrow functions + if ((scope instanceof AST_Arrow) && !this.uses_arguments) { + this.uses_arguments = walk(scope, node => { + if ( + node instanceof AST_SymbolRef + && node.scope instanceof AST_Lambda + && node.name === "arguments" + ) { + return walk_abort; + } + + if (node instanceof AST_Lambda && !(node instanceof AST_Arrow)) { + return true; + } + }); + } + + this.uses_with = this.uses_with || scope.uses_with; + this.uses_eval = this.uses_eval || scope.uses_eval; + + const scope_ancestry = (() => { + const ancestry = []; + let cur = this; + do { + ancestry.push(cur); + } while ((cur = cur.parent_scope)); + ancestry.reverse(); + return ancestry; + })(); + + const new_scope_enclosed_set = new Set(scope.enclosed); + const to_enclose = []; + for (const scope_topdown of scope_ancestry) { + to_enclose.forEach(e => push_uniq(scope_topdown.enclosed, e)); + for (const def of scope_topdown.variables.values()) { + if (new_scope_enclosed_set.has(def)) { + push_uniq(to_enclose, def); + push_uniq(scope_topdown.enclosed, def); + } + } + } +}); + +function find_scopes_visible_from(scopes) { + const found_scopes = new Set(); + + for (const scope of new Set(scopes)) { + (function bubble_up(scope) { + if (scope == null || found_scopes.has(scope)) return; + + found_scopes.add(scope); + + bubble_up(scope.parent_scope); + })(scope); + } + + return [...found_scopes]; +} + +// Creates a symbol during compression +AST_Scope.DEFMETHOD("create_symbol", function(SymClass, { + source, + tentative_name, + scope, + conflict_scopes = [scope], + init = null +} = {}) { + let symbol_name; + + conflict_scopes = find_scopes_visible_from(conflict_scopes); + + if (tentative_name) { + // Implement hygiene (no new names are conflicting with existing names) + tentative_name = + symbol_name = + tentative_name.replace(/(?:^[^a-z_$]|[^a-z0-9_$])/ig, "_"); + + let i = 0; + while (conflict_scopes.find(s => s.conflicting_def_shallow(symbol_name))) { + symbol_name = tentative_name + "$" + i++; + } + } + + if (!symbol_name) { + throw new Error("No symbol name could be generated in create_symbol()"); + } + + const symbol = make_node(SymClass, source, { + name: symbol_name, + scope + }); + + this.def_variable(symbol, init || null); + + symbol.mark_enclosed(); + + return symbol; +}); + + +AST_Node.DEFMETHOD("is_block_scope", return_false); +AST_Class.DEFMETHOD("is_block_scope", return_false); +AST_Lambda.DEFMETHOD("is_block_scope", return_false); +AST_Toplevel.DEFMETHOD("is_block_scope", return_false); +AST_SwitchBranch.DEFMETHOD("is_block_scope", return_false); +AST_Block.DEFMETHOD("is_block_scope", return_true); +AST_Scope.DEFMETHOD("is_block_scope", function () { + return this._block_scope || false; +}); +AST_IterationStatement.DEFMETHOD("is_block_scope", return_true); + +AST_Lambda.DEFMETHOD("init_scope_vars", function() { + AST_Scope.prototype.init_scope_vars.apply(this, arguments); + this.uses_arguments = false; + this.def_variable(new AST_SymbolFunarg({ + name: "arguments", + start: this.start, + end: this.end + })); +}); + +AST_Arrow.DEFMETHOD("init_scope_vars", function() { + AST_Scope.prototype.init_scope_vars.apply(this, arguments); + this.uses_arguments = false; +}); + +AST_Symbol.DEFMETHOD("mark_enclosed", function() { + var def = this.definition(); + var s = this.scope; + while (s) { + push_uniq(s.enclosed, def); + if (s === def.scope) break; + s = s.parent_scope; + } +}); + +AST_Symbol.DEFMETHOD("reference", function() { + this.definition().references.push(this); + this.mark_enclosed(); +}); + +AST_Scope.DEFMETHOD("find_variable", function(name) { + if (name instanceof AST_Symbol) name = name.name; + return this.variables.get(name) + || (this.parent_scope && this.parent_scope.find_variable(name)); +}); + +AST_Scope.DEFMETHOD("def_function", function(symbol, init) { + var def = this.def_variable(symbol, init); + if (!def.init || def.init instanceof AST_Defun) def.init = init; + return def; +}); + +AST_Scope.DEFMETHOD("def_variable", function(symbol, init) { + var def = this.variables.get(symbol.name); + if (def) { + def.orig.push(symbol); + if (def.init && (def.scope !== symbol.scope || def.init instanceof AST_Function)) { + def.init = init; + } + } else { + def = new SymbolDef(this, symbol, init); + this.variables.set(symbol.name, def); + def.global = !this.parent_scope; + } + return symbol.thedef = def; +}); + +function next_mangled(scope, options) { + let defun_scope; + if ( + scopes_with_block_defuns + && (defun_scope = scope.get_defun_scope()) + && scopes_with_block_defuns.has(defun_scope) + ) { + scope = defun_scope; + } + + var ext = scope.enclosed; + var nth_identifier = options.nth_identifier; + out: while (true) { + var m = nth_identifier.get(++scope.cname); + if (ALL_RESERVED_WORDS.has(m)) continue; // skip over "do" + + // https://github.com/mishoo/UglifyJS2/issues/242 -- do not + // shadow a name reserved from mangling. + if (options.reserved.has(m)) continue; + + // Functions with short names might collide with base54 output + // and therefore cause collisions when keep_fnames is true. + if (unmangleable_names && unmangleable_names.has(m)) continue out; + + // we must ensure that the mangled name does not shadow a name + // from some parent scope that is referenced in this or in + // inner scopes. + for (let i = ext.length; --i >= 0;) { + const def = ext[i]; + const name = def.mangled_name || (def.unmangleable(options) && def.name); + if (m == name) continue out; + } + return m; + } +} + +AST_Scope.DEFMETHOD("next_mangled", function(options) { + return next_mangled(this, options); +}); + +AST_Toplevel.DEFMETHOD("next_mangled", function(options) { + let name; + const mangled_names = this.mangled_names; + do { + name = next_mangled(this, options); + } while (mangled_names.has(name)); + return name; +}); + +AST_Function.DEFMETHOD("next_mangled", function(options, def) { + // #179, #326 + // in Safari strict mode, something like (function x(x){...}) is a syntax error; + // a function expression's argument cannot shadow the function expression's name + + var tricky_def = def.orig[0] instanceof AST_SymbolFunarg && this.name && this.name.definition(); + + // the function's mangled_name is null when keep_fnames is true + var tricky_name = tricky_def ? tricky_def.mangled_name || tricky_def.name : null; + + while (true) { + var name = next_mangled(this, options); + if (!tricky_name || tricky_name != name) + return name; + } +}); + +AST_Symbol.DEFMETHOD("unmangleable", function(options) { + var def = this.definition(); + return !def || def.unmangleable(options); +}); + +// labels are always mangleable +AST_Label.DEFMETHOD("unmangleable", return_false); + +AST_Symbol.DEFMETHOD("unreferenced", function() { + return !this.definition().references.length && !this.scope.pinned(); +}); + +AST_Symbol.DEFMETHOD("definition", function() { + return this.thedef; +}); + +AST_Symbol.DEFMETHOD("global", function() { + return this.thedef.global; +}); + +/** + * Format the mangler options (if any) into their appropriate types + */ +function format_mangler_options(options) { + options = defaults(options, { + eval : false, + nth_identifier : base54, + ie8 : false, + keep_classnames: false, + keep_fnames : false, + module : false, + reserved : [], + toplevel : false, + }); + if (options.module) options.toplevel = true; + if (!Array.isArray(options.reserved) + && !(options.reserved instanceof Set) + ) { + options.reserved = []; + } + options.reserved = new Set(options.reserved); + // Never mangle arguments + options.reserved.add("arguments"); + return options; +} + +AST_Toplevel.DEFMETHOD("mangle_names", function(options) { + options = format_mangler_options(options); + var nth_identifier = options.nth_identifier; + + // We only need to mangle declaration nodes. Special logic wired + // into the code generator will display the mangled name if it's + // present (and for AST_SymbolRef-s it'll use the mangled name of + // the AST_SymbolDeclaration that it points to). + var lname = -1; + var to_mangle = []; + + if (options.keep_fnames) { + function_defs = new Set(); + } + + const mangled_names = this.mangled_names = new Set(); + unmangleable_names = new Set(); + + if (options.cache) { + this.globals.forEach(collect); + if (options.cache.props) { + options.cache.props.forEach(function(mangled_name) { + mangled_names.add(mangled_name); + }); + } + } + + var tw = new TreeWalker(function(node, descend) { + if (node instanceof AST_LabeledStatement) { + // lname is incremented when we get to the AST_Label + var save_nesting = lname; + descend(); + lname = save_nesting; + return true; // don't descend again in TreeWalker + } + if ( + node instanceof AST_Defun + && !(tw.parent() instanceof AST_Scope) + ) { + scopes_with_block_defuns = scopes_with_block_defuns || new Set(); + scopes_with_block_defuns.add(node.parent_scope.get_defun_scope()); + } + if (node instanceof AST_Scope) { + node.variables.forEach(collect); + return; + } + if (node.is_block_scope()) { + node.block_scope.variables.forEach(collect); + return; + } + if ( + function_defs + && node instanceof AST_VarDef + && node.value instanceof AST_Lambda + && !node.value.name + && keep_name(options.keep_fnames, node.name.name) + ) { + function_defs.add(node.name.definition().id); + return; + } + if (node instanceof AST_Label) { + let name; + do { + name = nth_identifier.get(++lname); + } while (ALL_RESERVED_WORDS.has(name)); + node.mangled_name = name; + return true; + } + if (!(options.ie8 || options.safari10) && node instanceof AST_SymbolCatch) { + to_mangle.push(node.definition()); + return; + } + }); + + this.walk(tw); + + if (options.keep_fnames || options.keep_classnames) { + // Collect a set of short names which are unmangleable, + // for use in avoiding collisions in next_mangled. + to_mangle.forEach(def => { + if (def.name.length < 6 && def.unmangleable(options)) { + unmangleable_names.add(def.name); + } + }); + } + + to_mangle.forEach(def => { def.mangle(options); }); + + function_defs = null; + unmangleable_names = null; + scopes_with_block_defuns = null; + + function collect(symbol) { + if (symbol.export & MASK_EXPORT_DONT_MANGLE) { + unmangleable_names.add(symbol.name); + } else if (!options.reserved.has(symbol.name)) { + to_mangle.push(symbol); + } + } +}); + +AST_Toplevel.DEFMETHOD("find_colliding_names", function(options) { + const cache = options.cache && options.cache.props; + const avoid = new Set(); + options.reserved.forEach(to_avoid); + this.globals.forEach(add_def); + this.walk(new TreeWalker(function(node) { + if (node instanceof AST_Scope) node.variables.forEach(add_def); + if (node instanceof AST_SymbolCatch) add_def(node.definition()); + })); + return avoid; + + function to_avoid(name) { + avoid.add(name); + } + + function add_def(def) { + var name = def.name; + if (def.global && cache && cache.has(name)) name = cache.get(name); + else if (!def.unmangleable(options)) return; + to_avoid(name); + } +}); + +AST_Toplevel.DEFMETHOD("expand_names", function(options) { + options = format_mangler_options(options); + var nth_identifier = options.nth_identifier; + if (nth_identifier.reset && nth_identifier.sort) { + nth_identifier.reset(); + nth_identifier.sort(); + } + var avoid = this.find_colliding_names(options); + var cname = 0; + this.globals.forEach(rename); + this.walk(new TreeWalker(function(node) { + if (node instanceof AST_Scope) node.variables.forEach(rename); + if (node instanceof AST_SymbolCatch) rename(node.definition()); + })); + + function next_name() { + var name; + do { + name = nth_identifier.get(cname++); + } while (avoid.has(name) || ALL_RESERVED_WORDS.has(name)); + return name; + } + + function rename(def) { + if (def.global && options.cache) return; + if (def.unmangleable(options)) return; + if (options.reserved.has(def.name)) return; + const redefinition = redefined_catch_def(def); + const name = def.name = redefinition ? redefinition.name : next_name(); + def.orig.forEach(function(sym) { + sym.name = name; + }); + def.references.forEach(function(sym) { + sym.name = name; + }); + } +}); + +AST_Node.DEFMETHOD("tail_node", return_this); +AST_Sequence.DEFMETHOD("tail_node", function() { + return this.expressions[this.expressions.length - 1]; +}); + +AST_Toplevel.DEFMETHOD("compute_char_frequency", function(options) { + options = format_mangler_options(options); + var nth_identifier = options.nth_identifier; + if (!nth_identifier.reset || !nth_identifier.consider || !nth_identifier.sort) { + // If the identifier mangler is invariant, skip computing character frequency. + return; + } + nth_identifier.reset(); + + try { + AST_Node.prototype.print = function(stream, force_parens) { + this._print(stream, force_parens); + if (this instanceof AST_Symbol && !this.unmangleable(options)) { + nth_identifier.consider(this.name, -1); + } else if (options.properties) { + if (this instanceof AST_DotHash) { + nth_identifier.consider("#" + this.property, -1); + } else if (this instanceof AST_Dot) { + nth_identifier.consider(this.property, -1); + } else if (this instanceof AST_Sub) { + skip_string(this.property); + } + } + }; + nth_identifier.consider(this.print_to_string(), 1); + } finally { + AST_Node.prototype.print = AST_Node.prototype._print; + } + nth_identifier.sort(); + + function skip_string(node) { + if (node instanceof AST_String) { + nth_identifier.consider(node.value, -1); + } else if (node instanceof AST_Conditional) { + skip_string(node.consequent); + skip_string(node.alternative); + } else if (node instanceof AST_Sequence) { + skip_string(node.tail_node()); + } + } +}); + +const base54 = (() => { + const leading = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_".split(""); + const digits = "0123456789".split(""); + let chars; + let frequency; + function reset() { + frequency = new Map(); + leading.forEach(function(ch) { + frequency.set(ch, 0); + }); + digits.forEach(function(ch) { + frequency.set(ch, 0); + }); + } + function consider(str, delta) { + for (var i = str.length; --i >= 0;) { + frequency.set(str[i], frequency.get(str[i]) + delta); + } + } + function compare(a, b) { + return frequency.get(b) - frequency.get(a); + } + function sort() { + chars = mergeSort(leading, compare).concat(mergeSort(digits, compare)); + } + // Ensure this is in a usable initial state. + reset(); + sort(); + function base54(num) { + var ret = "", base = 54; + num++; + do { + num--; + ret += chars[num % base]; + num = Math.floor(num / base); + base = 64; + } while (num > 0); + return ret; + } + + return { + get: base54, + consider, + reset, + sort + }; +})(); + +let mangle_options = undefined; +AST_Node.prototype.size = function (compressor, stack) { + mangle_options = compressor && compressor.mangle_options; + + let size = 0; + walk_parent(this, (node, info) => { + size += node._size(info); + + // Braceless arrow functions have fake "return" statements + if (node instanceof AST_Arrow && node.is_braceless()) { + size += node.body[0].value._size(info); + return true; + } + }, stack || (compressor && compressor.stack)); + + // just to save a bit of memory + mangle_options = undefined; + + return size; +}; + +AST_Node.prototype._size = () => 0; + +AST_Debugger.prototype._size = () => 8; + +AST_Directive.prototype._size = function () { + // TODO string encoding stuff + return 2 + this.value.length; +}; + +/** Count commas/semicolons necessary to show a list of expressions/statements */ +const list_overhead = (array) => array.length && array.length - 1; + +AST_Block.prototype._size = function () { + return 2 + list_overhead(this.body); +}; + +AST_Toplevel.prototype._size = function() { + return list_overhead(this.body); +}; + +AST_EmptyStatement.prototype._size = () => 1; + +AST_LabeledStatement.prototype._size = () => 2; // x: + +AST_Do.prototype._size = () => 9; + +AST_While.prototype._size = () => 7; + +AST_For.prototype._size = () => 8; + +AST_ForIn.prototype._size = () => 8; +// AST_ForOf inherits ^ + +AST_With.prototype._size = () => 6; + +AST_Expansion.prototype._size = () => 3; + +const lambda_modifiers = func => + (func.is_generator ? 1 : 0) + (func.async ? 6 : 0); + +AST_Accessor.prototype._size = function () { + return lambda_modifiers(this) + 4 + list_overhead(this.argnames) + list_overhead(this.body); +}; + +AST_Function.prototype._size = function (info) { + const first = !!first_in_statement(info); + return (first * 2) + lambda_modifiers(this) + 12 + list_overhead(this.argnames) + list_overhead(this.body); +}; + +AST_Defun.prototype._size = function () { + return lambda_modifiers(this) + 13 + list_overhead(this.argnames) + list_overhead(this.body); +}; + +AST_Arrow.prototype._size = function () { + let args_and_arrow = 2 + list_overhead(this.argnames); + + if ( + !( + this.argnames.length === 1 + && this.argnames[0] instanceof AST_Symbol + ) + ) { + args_and_arrow += 2; // parens around the args + } + + const body_overhead = this.is_braceless() ? 0 : list_overhead(this.body) + 2; + + return lambda_modifiers(this) + args_and_arrow + body_overhead; +}; + +AST_Destructuring.prototype._size = () => 2; + +AST_TemplateString.prototype._size = function () { + return 2 + (Math.floor(this.segments.length / 2) * 3); /* "${}" */ +}; + +AST_TemplateSegment.prototype._size = function () { + return this.value.length; +}; + +AST_Return.prototype._size = function () { + return this.value ? 7 : 6; +}; + +AST_Throw.prototype._size = () => 6; + +AST_Break.prototype._size = function () { + return this.label ? 6 : 5; +}; + +AST_Continue.prototype._size = function () { + return this.label ? 9 : 8; +}; + +AST_If.prototype._size = () => 4; + +AST_Switch.prototype._size = function () { + return 8 + list_overhead(this.body); +}; + +AST_Case.prototype._size = function () { + return 5 + list_overhead(this.body); +}; + +AST_Default.prototype._size = function () { + return 8 + list_overhead(this.body); +}; + +AST_Try.prototype._size = () => 3; + +AST_Catch.prototype._size = function () { + let size = 7 + list_overhead(this.body); + if (this.argname) { + size += 2; + } + return size; +}; + +AST_Finally.prototype._size = function () { + return 7 + list_overhead(this.body); +}; + +AST_Var.prototype._size = function () { + return 4 + list_overhead(this.definitions); +}; + +AST_Let.prototype._size = function () { + return 4 + list_overhead(this.definitions); +}; + +AST_Const.prototype._size = function () { + return 6 + list_overhead(this.definitions); +}; + +AST_VarDef.prototype._size = function () { + return this.value ? 1 : 0; +}; + +AST_NameMapping.prototype._size = function () { + // foreign name isn't mangled + return this.name ? 4 : 0; +}; + +AST_Import.prototype._size = function () { + // import + let size = 6; + + if (this.imported_name) size += 1; + + // from + if (this.imported_name || this.imported_names) size += 5; + + // braces, and the commas + if (this.imported_names) { + size += 2 + list_overhead(this.imported_names); + } + + return size; +}; + +AST_ImportMeta.prototype._size = () => 11; + +AST_Export.prototype._size = function () { + let size = 7 + (this.is_default ? 8 : 0); + + if (this.exported_value) { + size += this.exported_value._size(); + } + + if (this.exported_names) { + // Braces and commas + size += 2 + list_overhead(this.exported_names); + } + + if (this.module_name) { + // "from " + size += 5; + } + + return size; +}; + +AST_Call.prototype._size = function () { + if (this.optional) { + return 4 + list_overhead(this.args); + } + return 2 + list_overhead(this.args); +}; + +AST_New.prototype._size = function () { + return 6 + list_overhead(this.args); +}; + +AST_Sequence.prototype._size = function () { + return list_overhead(this.expressions); +}; + +AST_Dot.prototype._size = function () { + if (this.optional) { + return this.property.length + 2; + } + return this.property.length + 1; +}; + +AST_DotHash.prototype._size = function () { + if (this.optional) { + return this.property.length + 3; + } + return this.property.length + 2; +}; + +AST_Sub.prototype._size = function () { + return this.optional ? 4 : 2; +}; + +AST_Unary.prototype._size = function () { + if (this.operator === "typeof") return 7; + if (this.operator === "void") return 5; + return this.operator.length; +}; + +AST_Binary.prototype._size = function (info) { + if (this.operator === "in") return 4; + + let size = this.operator.length; + + if ( + (this.operator === "+" || this.operator === "-") + && this.right instanceof AST_Unary && this.right.operator === this.operator + ) { + // 1+ +a > needs space between the + + size += 1; + } + + if (this.needs_parens(info)) { + size += 2; + } + + return size; +}; + +AST_Conditional.prototype._size = () => 3; + +AST_Array.prototype._size = function () { + return 2 + list_overhead(this.elements); +}; + +AST_Object.prototype._size = function (info) { + let base = 2; + if (first_in_statement(info)) { + base += 2; // parens + } + return base + list_overhead(this.properties); +}; + +/*#__INLINE__*/ +const key_size = key => + typeof key === "string" ? key.length : 0; + +AST_ObjectKeyVal.prototype._size = function () { + return key_size(this.key) + 1; +}; + +/*#__INLINE__*/ +const static_size = is_static => is_static ? 7 : 0; + +AST_ObjectGetter.prototype._size = function () { + return 5 + static_size(this.static) + key_size(this.key); +}; + +AST_ObjectSetter.prototype._size = function () { + return 5 + static_size(this.static) + key_size(this.key); +}; + +AST_ConciseMethod.prototype._size = function () { + return static_size(this.static) + key_size(this.key) + lambda_modifiers(this); +}; + +AST_PrivateMethod.prototype._size = function () { + return AST_ConciseMethod.prototype._size.call(this) + 1; +}; + +AST_PrivateGetter.prototype._size = AST_PrivateSetter.prototype._size = function () { + return AST_ConciseMethod.prototype._size.call(this) + 4; +}; + +AST_PrivateIn.prototype._size = function () { + return 5; // "#", and " in " +}; + +AST_Class.prototype._size = function () { + return ( + (this.name ? 8 : 7) + + (this.extends ? 8 : 0) + ); +}; + +AST_ClassStaticBlock.prototype._size = function () { + // "class{}" + semicolons + return 7 + list_overhead(this.body); +}; + +AST_ClassProperty.prototype._size = function () { + return ( + static_size(this.static) + + (typeof this.key === "string" ? this.key.length + 2 : 0) + + (this.value ? 1 : 0) + ); +}; + +AST_ClassPrivateProperty.prototype._size = function () { + return AST_ClassProperty.prototype._size.call(this) + 1; +}; + +AST_Symbol.prototype._size = function () { + if (!(mangle_options && this.thedef && !this.thedef.unmangleable(mangle_options))) { + return this.name.length; + } else { + return 1; + } +}; + +// TODO take propmangle into account +AST_SymbolClassProperty.prototype._size = function () { + return this.name.length; +}; + +AST_SymbolRef.prototype._size = AST_SymbolDeclaration.prototype._size = function () { + if (this.name === "arguments") return 9; + + return AST_Symbol.prototype._size.call(this); +}; + +AST_NewTarget.prototype._size = () => 10; + +AST_SymbolImportForeign.prototype._size = function () { + return this.name.length; +}; + +AST_SymbolExportForeign.prototype._size = function () { + return this.name.length; +}; + +AST_This.prototype._size = () => 4; + +AST_Super.prototype._size = () => 5; + +AST_String.prototype._size = function () { + return this.value.length + 2; +}; + +AST_Number.prototype._size = function () { + const { value } = this; + if (value === 0) return 1; + if (value > 0 && Math.floor(value) === value) { + return Math.floor(Math.log10(value) + 1); + } + return value.toString().length; +}; + +AST_BigInt.prototype._size = function () { + return this.value.length; +}; + +AST_RegExp.prototype._size = function () { + return this.value.toString().length; +}; + +AST_Null.prototype._size = () => 4; + +AST_NaN.prototype._size = () => 3; - def_optimize(AST_Boolean, function(self, compressor) { - if (compressor.in_boolean_context()) return make_node(AST_Number, self, { - value: +self.value - }); - var p = compressor.parent(); - if (compressor.option("booleans_as_integers")) { - if (p instanceof AST_Binary && (p.operator == "===" || p.operator == "!==")) { - p.operator = p.operator.replace(/=$/, ""); - } - return make_node(AST_Number, self, { - value: +self.value - }); - } - if (compressor.option("booleans")) { - if (p instanceof AST_Binary && (p.operator == "==" - || p.operator == "!=")) { - compressor.warn("Non-strict equality against boolean: {operator} {value} [{file}:{line},{col}]", { - operator : p.operator, - value : self.value, - file : p.start.file, - line : p.start.line, - col : p.start.col, - }); - return make_node(AST_Number, self, { - value: +self.value - }); - } - return make_node(AST_UnaryPrefix, self, { - operator: "!", - expression: make_node(AST_Number, self, { - value: 1 - self.value - }) - }); - } - return self; - }); - - function safe_to_flatten(value, compressor) { - if (value instanceof AST_SymbolRef) { - value = value.fixed_value(); - } - if (!value) return false; - return !(value instanceof AST_Lambda || value instanceof AST_Class) - || compressor.parent() instanceof AST_New - || !value.contains_this(); - } - - def_optimize(AST_Sub, function(self, compressor) { - var expr = self.expression; - var prop = self.property; - if (compressor.option("properties")) { - var key = prop.evaluate(compressor); - if (key !== prop) { - if (typeof key == "string") { - if (key == "undefined") { - key = undefined; - } else { - var value = parseFloat(key); - if (value.toString() == key) { - key = value; - } - } - } - prop = self.property = best_of_expression(prop, make_node_from_constant(key, prop).transform(compressor)); - var property = "" + key; - if (is_identifier_string(property) - && property.length <= prop.print_to_string().length + 1) { - return make_node(AST_Dot, self, { - expression: expr, - property: property, - quote: prop.quote, - }).optimize(compressor); - } - } - } - var fn; - OPT_ARGUMENTS: if (compressor.option("arguments") - && expr instanceof AST_SymbolRef - && expr.name == "arguments" - && expr.definition().orig.length == 1 - && (fn = expr.scope) instanceof AST_Lambda - && fn.uses_arguments - && !(fn instanceof AST_Arrow) - && prop instanceof AST_Number) { - var index = prop.getValue(); - var params = new Set(); - var argnames = fn.argnames; - for (var n = 0; n < argnames.length; n++) { - if (!(argnames[n] instanceof AST_SymbolFunarg)) { - break OPT_ARGUMENTS; // destructuring parameter - bail - } - var param = argnames[n].name; - if (params.has(param)) { - break OPT_ARGUMENTS; // duplicate parameter - bail - } - params.add(param); - } - var argname = fn.argnames[index]; - if (argname && compressor.has_directive("use strict")) { - var def = argname.definition(); - if (!compressor.option("reduce_vars") || def.assignments || def.orig.length > 1) { - argname = null; - } - } else if (!argname && !compressor.option("keep_fargs") && index < fn.argnames.length + 5) { - while (index >= fn.argnames.length) { - argname = make_node(AST_SymbolFunarg, fn, { - name: fn.make_var_name("argument_" + fn.argnames.length), - scope: fn - }); - fn.argnames.push(argname); - fn.enclosed.push(fn.def_variable(argname)); - } - } - if (argname) { - var sym = make_node(AST_SymbolRef, self, argname); - sym.reference({}); - delete argname.__unused; - return sym; - } - } - if (is_lhs(self, compressor.parent())) return self; - if (key !== prop) { - var sub = self.flatten_object(property, compressor); - if (sub) { - expr = self.expression = sub.expression; - prop = self.property = sub.property; - } - } - if (compressor.option("properties") && compressor.option("side_effects") - && prop instanceof AST_Number && expr instanceof AST_Array) { - var index = prop.getValue(); - var elements = expr.elements; - var retValue = elements[index]; - FLATTEN: if (safe_to_flatten(retValue, compressor)) { - var flatten = true; - var values = []; - for (var i = elements.length; --i > index;) { - var value = elements[i].drop_side_effect_free(compressor); - if (value) { - values.unshift(value); - if (flatten && value.has_side_effects(compressor)) flatten = false; - } - } - if (retValue instanceof AST_Expansion) break FLATTEN; - retValue = retValue instanceof AST_Hole ? make_node(AST_Undefined, retValue) : retValue; - if (!flatten) values.unshift(retValue); - while (--i >= 0) { - var value = elements[i]; - if (value instanceof AST_Expansion) break FLATTEN; - value = value.drop_side_effect_free(compressor); - if (value) values.unshift(value); - else index--; - } - if (flatten) { - values.push(retValue); - return make_sequence(self, values).optimize(compressor); - } else return make_node(AST_Sub, self, { - expression: make_node(AST_Array, expr, { - elements: values - }), - property: make_node(AST_Number, prop, { - value: index - }) - }); - } - } - var ev = self.evaluate(compressor); - if (ev !== self) { - ev = make_node_from_constant(ev, self).optimize(compressor); - return best_of(compressor, ev, self); - } - return self; - }); - - AST_Lambda.DEFMETHOD("contains_this", function() { - var result; - var self = this; - self.walk(new TreeWalker(function(node) { - if (result) return true; - if (node instanceof AST_This) return result = true; - if (node !== self && node instanceof AST_Scope && !(node instanceof AST_Arrow)) return true; - })); - return result; - }); - - AST_PropAccess.DEFMETHOD("flatten_object", function(key, compressor) { - if (!compressor.option("properties")) return; - var arrows = compressor.option("unsafe_arrows") && compressor.option("ecma") >= 6; - var expr = this.expression; - if (expr instanceof AST_Object) { - var props = expr.properties; - for (var i = props.length; --i >= 0;) { - var prop = props[i]; - if ("" + (prop instanceof AST_ConciseMethod ? prop.key.name : prop.key) == key) { - if (!props.every((prop) => { - return prop instanceof AST_ObjectKeyVal - || arrows && prop instanceof AST_ConciseMethod && !prop.is_generator; - })) break; - if (!safe_to_flatten(prop.value, compressor)) break; - return make_node(AST_Sub, this, { - expression: make_node(AST_Array, expr, { - elements: props.map(function(prop) { - var v = prop.value; - if (v instanceof AST_Accessor) v = make_node(AST_Function, v, v); - var k = prop.key; - if (k instanceof AST_Node && !(k instanceof AST_SymbolMethod)) { - return make_sequence(prop, [ k, v ]); - } - return v; - }) - }), - property: make_node(AST_Number, this, { - value: i - }) - }); - } - } - } - }); - - def_optimize(AST_Dot, function(self, compressor) { - if (self.property == "arguments" || self.property == "caller") { - compressor.warn("Function.prototype.{prop} not supported [{file}:{line},{col}]", { - prop: self.property, - file: self.start.file, - line: self.start.line, - col: self.start.col - }); - } - if (is_lhs(self, compressor.parent())) return self; - if (compressor.option("unsafe_proto") - && self.expression instanceof AST_Dot - && self.expression.property == "prototype") { - var exp = self.expression.expression; - if (is_undeclared_ref(exp)) switch (exp.name) { - case "Array": - self.expression = make_node(AST_Array, self.expression, { - elements: [] - }); - break; - case "Function": - self.expression = make_node(AST_Function, self.expression, { - argnames: [], - body: [] - }); - break; - case "Number": - self.expression = make_node(AST_Number, self.expression, { - value: 0 - }); - break; - case "Object": - self.expression = make_node(AST_Object, self.expression, { - properties: [] - }); - break; - case "RegExp": - self.expression = make_node(AST_RegExp, self.expression, { - value: /t/ - }); - break; - case "String": - self.expression = make_node(AST_String, self.expression, { - value: "" - }); - break; - } - } - var sub = self.flatten_object(self.property, compressor); - if (sub) return sub.optimize(compressor); - var ev = self.evaluate(compressor); - if (ev !== self) { - ev = make_node_from_constant(ev, self).optimize(compressor); - return best_of(compressor, ev, self); - } - return self; - }); - - function literals_in_boolean_context(self, compressor) { - if (compressor.in_boolean_context()) { - return best_of(compressor, self, make_sequence(self, [ - self, - make_node(AST_True, self) - ]).optimize(compressor)); - } - return self; - } - - function inline_array_like_spread(self, compressor, elements) { - for (var i = 0; i < elements.length; i++) { - var el = elements[i]; - if (el instanceof AST_Expansion) { - var expr = el.expression; - if ( expr instanceof AST_Array) { - elements.splice.apply(elements, [i, 1].concat(expr.elements)); - // Step back one, as the element at i is now new. - i--; - } - // In array-like spread, spreading a non-iterable value is TypeError. - // We therefore can’t optimize anything else, unlike with object spread. - } - } - return self; - } - - def_optimize(AST_Array, function(self, compressor) { - var optimized = literals_in_boolean_context(self, compressor); - if (optimized !== self) { - return optimized; - } - return inline_array_like_spread(self, compressor, self.elements); - }); - - def_optimize(AST_Object, function(self, compressor) { - var optimized = literals_in_boolean_context(self, compressor); - if (optimized !== self) { - return optimized; - } - var props = self.properties; - for (var i = 0; i < props.length; i++) { - var prop = props[i]; - if (prop instanceof AST_Expansion) { - var expr = prop.expression; - if (expr instanceof AST_Object) { - props.splice.apply(props, [i, 1].concat(prop.expression.properties)); - // Step back one, as the property at i is now new. - i--; - } else if (expr instanceof AST_Constant - && !(expr instanceof AST_String)) { - // Unlike array-like spread, in object spread, spreading a - // non-iterable value silently does nothing; it is thus safe - // to remove. AST_String is the only iterable AST_Constant. - props.splice(i, 1); - } - } - } - return self; - }); - - def_optimize(AST_RegExp, literals_in_boolean_context); - - def_optimize(AST_Return, function(self, compressor) { - if (self.value && is_undefined(self.value, compressor)) { - self.value = null; - } - return self; - }); - - def_optimize(AST_Arrow, function(self, compressor) { - if (!(self.body instanceof AST_Node)) { - self = opt_AST_Lambda(self, compressor); - } - if (compressor.option("arrows") - && self.body.length == 1 - && self.body[0] instanceof AST_Return) { - var value = self.body[0].value; - self.body = value ? value : []; - } - return self; - }); - - def_optimize(AST_Function, function(self, compressor) { - self = opt_AST_Lambda(self, compressor); - if (compressor.option("unsafe_arrows") - && compressor.option("ecma") >= 6 - && !self.name - && !self.is_generator - && !self.uses_arguments - && !self.pinned()) { - var has_special_symbol = false; - self.walk(new TreeWalker(function(node) { - if (has_special_symbol) return true; - if (node instanceof AST_This) { - has_special_symbol = true; - return true; - } - })); - if (!has_special_symbol) return make_node(AST_Arrow, self, self).optimize(compressor); - } - return self; - }); - - def_optimize(AST_Class, function(self, compressor) { - // HACK to avoid compress failure. - // AST_Class is not really an AST_Scope/AST_Block as it lacks a body. - return self; - }); - - def_optimize(AST_Yield, function(self, compressor) { - if (self.expression && !self.is_star && is_undefined(self.expression, compressor)) { - self.expression = null; - } - return self; - }); - - def_optimize(AST_TemplateString, function(self, compressor) { - if (!compressor.option("evaluate") - || compressor.parent() instanceof AST_PrefixedTemplateString) - return self; - - var segments = []; - for (var i = 0; i < self.segments.length; i++) { - var segment = self.segments[i]; - if (segment instanceof AST_Node) { - var result = segment.evaluate(compressor); - // Evaluate to constant value - // Constant value shorter than ${segment} - if (result !== segment && (result + "").length <= segment.print_to_string().length + "${}".length) { - // There should always be a previous and next segment if segment is a node - segments[segments.length - 1].value = segments[segments.length - 1].value + result + self.segments[++i].value; - continue; - } - } - segments.push(segment); - } - self.segments = segments; - - return segments.length == 1 ? make_node(AST_String, self, segments[0]) : self; - }); - - def_optimize(AST_PrefixedTemplateString, function(self, compressor) { - return self; - }); - - // ["p"]:1 ---> p:1 - // [42]:1 ---> 42:1 - function lift_key(self, compressor) { - if (!compressor.option("computed_props")) return self; - // save a comparison in the typical case - if (!(self.key instanceof AST_Constant)) return self; - // whitelist acceptable props as not all AST_Constants are true constants - if (self.key instanceof AST_String || self.key instanceof AST_Number) { - if (self.key.value === "__proto__") return self; - if (self.key.value == "constructor" - && compressor.parent() instanceof AST_Class) return self; - if (self instanceof AST_ObjectKeyVal) { - self.key = self.key.value; - } else { - self.key = make_node(AST_SymbolMethod, self.key, { - name: self.key.value - }); - } - } - return self; - } - - def_optimize(AST_ObjectProperty, lift_key); - - def_optimize(AST_ConciseMethod, function(self, compressor) { - lift_key(self, compressor); - // p(){return x;} ---> p:()=>x - if (compressor.option("arrows") - && compressor.parent() instanceof AST_Object - && !self.is_generator - && !self.value.uses_arguments - && !self.value.pinned() - && self.value.body.length == 1 - && self.value.body[0] instanceof AST_Return - && self.value.body[0].value - && !self.value.contains_this()) { - var arrow = make_node(AST_Arrow, self.value, self.value); - arrow.async = self.async; - arrow.is_generator = self.is_generator; - return make_node(AST_ObjectKeyVal, self, { - key: self.key instanceof AST_SymbolMethod ? self.key.name : self.key, - value: arrow, - quote: self.quote, - }); - } - return self; - }); - - def_optimize(AST_ObjectKeyVal, function(self, compressor) { - lift_key(self, compressor); - // p:function(){} ---> p(){} - // p:function*(){} ---> *p(){} - // p:async function(){} ---> async p(){} - // p:()=>{} ---> p(){} - // p:async()=>{} ---> async p(){} - var unsafe_methods = compressor.option("unsafe_methods"); - if (unsafe_methods - && compressor.option("ecma") >= 6 - && (!(unsafe_methods instanceof RegExp) || unsafe_methods.test(self.key + ""))) { - var key = self.key; - var value = self.value; - var is_arrow_with_block = value instanceof AST_Arrow - && Array.isArray(value.body) - && !value.contains_this(); - if ((is_arrow_with_block || value instanceof AST_Function) && !value.name) { - return make_node(AST_ConciseMethod, self, { - async: value.async, - is_generator: value.is_generator, - key: key instanceof AST_Node ? key : make_node(AST_SymbolMethod, self, { - name: key, - }), - value: make_node(AST_Accessor, value, value), - quote: self.quote, - }); - } - } - return self; - }); - - def_optimize(AST_Destructuring, function(self, compressor) { - if (compressor.option("pure_getters") == true - && compressor.option("unused") - && !self.is_array - && Array.isArray(self.names) - && !is_destructuring_export_decl(compressor)) { - var keep = []; - for (var i = 0; i < self.names.length; i++) { - var elem = self.names[i]; - if (!(elem instanceof AST_ObjectKeyVal - && typeof elem.key == "string" - && elem.value instanceof AST_SymbolDeclaration - && !should_retain(compressor, elem.value.definition()))) { - keep.push(elem); - } - } - if (keep.length != self.names.length) { - self.names = keep; - } - } - return self; - - function is_destructuring_export_decl(compressor) { - var ancestors = [/^VarDef$/, /^(Const|Let|Var)$/, /^Export$/]; - for (var a = 0, p = 0, len = ancestors.length; a < len; p++) { - var parent = compressor.parent(p); - if (!parent) return false; - if (a === 0 && parent.TYPE == "Destructuring") continue; - if (!ancestors[a].test(parent.TYPE)) { - return false; - } - a++; - } - return true; - } - - function should_retain(compressor, def) { - if (def.references.length) return true; - if (!def.global) return false; - if (compressor.toplevel.vars) { - if (compressor.top_retain) { - return compressor.top_retain(def); - } - return false; - } - return true; - } - }); - })(); - - var domprops = [ - "$&", - "$'", - "$*", - "$+", - "$1", - "$2", - "$3", - "$4", - "$5", - "$6", - "$7", - "$8", - "$9", - "$_", - "$`", - "$input", - "@@iterator", - "ABORT_ERR", - "ACTIVE", - "ACTIVE_ATTRIBUTES", - "ACTIVE_TEXTURE", - "ACTIVE_UNIFORMS", - "ADDITION", - "ALIASED_LINE_WIDTH_RANGE", - "ALIASED_POINT_SIZE_RANGE", - "ALLOW_KEYBOARD_INPUT", - "ALLPASS", - "ALPHA", - "ALPHA_BITS", - "ALT_MASK", - "ALWAYS", - "ANY_TYPE", - "ANY_UNORDERED_NODE_TYPE", - "ARRAY_BUFFER", - "ARRAY_BUFFER_BINDING", - "ATTACHED_SHADERS", - "ATTRIBUTE_NODE", - "AT_TARGET", - "AddSearchProvider", - "AnalyserNode", - "AnimationEvent", - "AnonXMLHttpRequest", - "ApplicationCache", - "ApplicationCacheErrorEvent", - "Array", - "ArrayBuffer", - "Attr", - "Audio", - "AudioBuffer", - "AudioBufferSourceNode", - "AudioContext", - "AudioDestinationNode", - "AudioListener", - "AudioNode", - "AudioParam", - "AudioProcessingEvent", - "AudioStreamTrack", - "AutocompleteErrorEvent", - "BACK", - "BAD_BOUNDARYPOINTS_ERR", - "BANDPASS", - "BLEND", - "BLEND_COLOR", - "BLEND_DST_ALPHA", - "BLEND_DST_RGB", - "BLEND_EQUATION", - "BLEND_EQUATION_ALPHA", - "BLEND_EQUATION_RGB", - "BLEND_SRC_ALPHA", - "BLEND_SRC_RGB", - "BLUE_BITS", - "BLUR", - "BOOL", - "BOOLEAN_TYPE", - "BOOL_VEC2", - "BOOL_VEC3", - "BOOL_VEC4", - "BOTH", - "BROWSER_DEFAULT_WEBGL", - "BUBBLING_PHASE", - "BUFFER_SIZE", - "BUFFER_USAGE", - "BYTE", - "BYTES_PER_ELEMENT", - "BarProp", - "BaseHref", - "BatteryManager", - "BeforeLoadEvent", - "BeforeUnloadEvent", - "BiquadFilterNode", - "Blob", - "BlobEvent", - "Boolean", - "CAPTURING_PHASE", - "CCW", - "CDATASection", - "CDATA_SECTION_NODE", - "CHANGE", - "CHARSET_RULE", - "CHECKING", - "CLAMP_TO_EDGE", - "CLICK", - "CLOSED", - "CLOSING", - "COLOR_ATTACHMENT0", - "COLOR_BUFFER_BIT", - "COLOR_CLEAR_VALUE", - "COLOR_WRITEMASK", - "COMMENT_NODE", - "COMPILE_STATUS", - "COMPRESSED_RGBA_S3TC_DXT1_EXT", - "COMPRESSED_RGBA_S3TC_DXT3_EXT", - "COMPRESSED_RGBA_S3TC_DXT5_EXT", - "COMPRESSED_RGB_S3TC_DXT1_EXT", - "COMPRESSED_TEXTURE_FORMATS", - "CONNECTING", - "CONSTANT_ALPHA", - "CONSTANT_COLOR", - "CONSTRAINT_ERR", - "CONTEXT_LOST_WEBGL", - "CONTROL_MASK", - "COUNTER_STYLE_RULE", - "CSS", - "CSS2Properties", - "CSSCharsetRule", - "CSSConditionRule", - "CSSCounterStyleRule", - "CSSFontFaceRule", - "CSSFontFeatureValuesRule", - "CSSGroupingRule", - "CSSImportRule", - "CSSKeyframeRule", - "CSSKeyframesRule", - "CSSMediaRule", - "CSSMozDocumentRule", - "CSSNameSpaceRule", - "CSSPageRule", - "CSSPrimitiveValue", - "CSSRule", - "CSSRuleList", - "CSSStyleDeclaration", - "CSSStyleRule", - "CSSStyleSheet", - "CSSSupportsRule", - "CSSUnknownRule", - "CSSValue", - "CSSValueList", - "CSSVariablesDeclaration", - "CSSVariablesRule", - "CSSViewportRule", - "CSS_ATTR", - "CSS_CM", - "CSS_COUNTER", - "CSS_CUSTOM", - "CSS_DEG", - "CSS_DIMENSION", - "CSS_EMS", - "CSS_EXS", - "CSS_FILTER_BLUR", - "CSS_FILTER_BRIGHTNESS", - "CSS_FILTER_CONTRAST", - "CSS_FILTER_CUSTOM", - "CSS_FILTER_DROP_SHADOW", - "CSS_FILTER_GRAYSCALE", - "CSS_FILTER_HUE_ROTATE", - "CSS_FILTER_INVERT", - "CSS_FILTER_OPACITY", - "CSS_FILTER_REFERENCE", - "CSS_FILTER_SATURATE", - "CSS_FILTER_SEPIA", - "CSS_GRAD", - "CSS_HZ", - "CSS_IDENT", - "CSS_IN", - "CSS_INHERIT", - "CSS_KHZ", - "CSS_MATRIX", - "CSS_MATRIX3D", - "CSS_MM", - "CSS_MS", - "CSS_NUMBER", - "CSS_PC", - "CSS_PERCENTAGE", - "CSS_PERSPECTIVE", - "CSS_PRIMITIVE_VALUE", - "CSS_PT", - "CSS_PX", - "CSS_RAD", - "CSS_RECT", - "CSS_RGBCOLOR", - "CSS_ROTATE", - "CSS_ROTATE3D", - "CSS_ROTATEX", - "CSS_ROTATEY", - "CSS_ROTATEZ", - "CSS_S", - "CSS_SCALE", - "CSS_SCALE3D", - "CSS_SCALEX", - "CSS_SCALEY", - "CSS_SCALEZ", - "CSS_SKEW", - "CSS_SKEWX", - "CSS_SKEWY", - "CSS_STRING", - "CSS_TRANSLATE", - "CSS_TRANSLATE3D", - "CSS_TRANSLATEX", - "CSS_TRANSLATEY", - "CSS_TRANSLATEZ", - "CSS_UNKNOWN", - "CSS_URI", - "CSS_VALUE_LIST", - "CSS_VH", - "CSS_VMAX", - "CSS_VMIN", - "CSS_VW", - "CULL_FACE", - "CULL_FACE_MODE", - "CURRENT_PROGRAM", - "CURRENT_VERTEX_ATTRIB", - "CUSTOM", - "CW", - "CanvasGradient", - "CanvasPattern", - "CanvasRenderingContext2D", - "CaretPosition", - "ChannelMergerNode", - "ChannelSplitterNode", - "CharacterData", - "ClientRect", - "ClientRectList", - "Clipboard", - "ClipboardEvent", - "CloseEvent", - "Collator", - "CommandEvent", - "Comment", - "CompositionEvent", - "Console", - "Controllers", - "ConvolverNode", - "Counter", - "Crypto", - "CryptoKey", - "CustomEvent", - "DATABASE_ERR", - "DATA_CLONE_ERR", - "DATA_ERR", - "DBLCLICK", - "DECR", - "DECR_WRAP", - "DELETE_STATUS", - "DEPTH_ATTACHMENT", - "DEPTH_BITS", - "DEPTH_BUFFER_BIT", - "DEPTH_CLEAR_VALUE", - "DEPTH_COMPONENT", - "DEPTH_COMPONENT16", - "DEPTH_FUNC", - "DEPTH_RANGE", - "DEPTH_STENCIL", - "DEPTH_STENCIL_ATTACHMENT", - "DEPTH_TEST", - "DEPTH_WRITEMASK", - "DIRECTION_DOWN", - "DIRECTION_LEFT", - "DIRECTION_RIGHT", - "DIRECTION_UP", - "DISABLED", - "DISPATCH_REQUEST_ERR", - "DITHER", - "DOCUMENT_FRAGMENT_NODE", - "DOCUMENT_NODE", - "DOCUMENT_POSITION_CONTAINED_BY", - "DOCUMENT_POSITION_CONTAINS", - "DOCUMENT_POSITION_DISCONNECTED", - "DOCUMENT_POSITION_FOLLOWING", - "DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC", - "DOCUMENT_POSITION_PRECEDING", - "DOCUMENT_TYPE_NODE", - "DOMCursor", - "DOMError", - "DOMException", - "DOMImplementation", - "DOMImplementationLS", - "DOMMatrix", - "DOMMatrixReadOnly", - "DOMParser", - "DOMPoint", - "DOMPointReadOnly", - "DOMQuad", - "DOMRect", - "DOMRectList", - "DOMRectReadOnly", - "DOMRequest", - "DOMSTRING_SIZE_ERR", - "DOMSettableTokenList", - "DOMStringList", - "DOMStringMap", - "DOMTokenList", - "DOMTransactionEvent", - "DOM_DELTA_LINE", - "DOM_DELTA_PAGE", - "DOM_DELTA_PIXEL", - "DOM_INPUT_METHOD_DROP", - "DOM_INPUT_METHOD_HANDWRITING", - "DOM_INPUT_METHOD_IME", - "DOM_INPUT_METHOD_KEYBOARD", - "DOM_INPUT_METHOD_MULTIMODAL", - "DOM_INPUT_METHOD_OPTION", - "DOM_INPUT_METHOD_PASTE", - "DOM_INPUT_METHOD_SCRIPT", - "DOM_INPUT_METHOD_UNKNOWN", - "DOM_INPUT_METHOD_VOICE", - "DOM_KEY_LOCATION_JOYSTICK", - "DOM_KEY_LOCATION_LEFT", - "DOM_KEY_LOCATION_MOBILE", - "DOM_KEY_LOCATION_NUMPAD", - "DOM_KEY_LOCATION_RIGHT", - "DOM_KEY_LOCATION_STANDARD", - "DOM_VK_0", - "DOM_VK_1", - "DOM_VK_2", - "DOM_VK_3", - "DOM_VK_4", - "DOM_VK_5", - "DOM_VK_6", - "DOM_VK_7", - "DOM_VK_8", - "DOM_VK_9", - "DOM_VK_A", - "DOM_VK_ACCEPT", - "DOM_VK_ADD", - "DOM_VK_ALT", - "DOM_VK_ALTGR", - "DOM_VK_AMPERSAND", - "DOM_VK_ASTERISK", - "DOM_VK_AT", - "DOM_VK_ATTN", - "DOM_VK_B", - "DOM_VK_BACKSPACE", - "DOM_VK_BACK_QUOTE", - "DOM_VK_BACK_SLASH", - "DOM_VK_BACK_SPACE", - "DOM_VK_C", - "DOM_VK_CANCEL", - "DOM_VK_CAPS_LOCK", - "DOM_VK_CIRCUMFLEX", - "DOM_VK_CLEAR", - "DOM_VK_CLOSE_BRACKET", - "DOM_VK_CLOSE_CURLY_BRACKET", - "DOM_VK_CLOSE_PAREN", - "DOM_VK_COLON", - "DOM_VK_COMMA", - "DOM_VK_CONTEXT_MENU", - "DOM_VK_CONTROL", - "DOM_VK_CONVERT", - "DOM_VK_CRSEL", - "DOM_VK_CTRL", - "DOM_VK_D", - "DOM_VK_DECIMAL", - "DOM_VK_DELETE", - "DOM_VK_DIVIDE", - "DOM_VK_DOLLAR", - "DOM_VK_DOUBLE_QUOTE", - "DOM_VK_DOWN", - "DOM_VK_E", - "DOM_VK_EISU", - "DOM_VK_END", - "DOM_VK_ENTER", - "DOM_VK_EQUALS", - "DOM_VK_EREOF", - "DOM_VK_ESCAPE", - "DOM_VK_EXCLAMATION", - "DOM_VK_EXECUTE", - "DOM_VK_EXSEL", - "DOM_VK_F", - "DOM_VK_F1", - "DOM_VK_F10", - "DOM_VK_F11", - "DOM_VK_F12", - "DOM_VK_F13", - "DOM_VK_F14", - "DOM_VK_F15", - "DOM_VK_F16", - "DOM_VK_F17", - "DOM_VK_F18", - "DOM_VK_F19", - "DOM_VK_F2", - "DOM_VK_F20", - "DOM_VK_F21", - "DOM_VK_F22", - "DOM_VK_F23", - "DOM_VK_F24", - "DOM_VK_F25", - "DOM_VK_F26", - "DOM_VK_F27", - "DOM_VK_F28", - "DOM_VK_F29", - "DOM_VK_F3", - "DOM_VK_F30", - "DOM_VK_F31", - "DOM_VK_F32", - "DOM_VK_F33", - "DOM_VK_F34", - "DOM_VK_F35", - "DOM_VK_F36", - "DOM_VK_F4", - "DOM_VK_F5", - "DOM_VK_F6", - "DOM_VK_F7", - "DOM_VK_F8", - "DOM_VK_F9", - "DOM_VK_FINAL", - "DOM_VK_FRONT", - "DOM_VK_G", - "DOM_VK_GREATER_THAN", - "DOM_VK_H", - "DOM_VK_HANGUL", - "DOM_VK_HANJA", - "DOM_VK_HASH", - "DOM_VK_HELP", - "DOM_VK_HK_TOGGLE", - "DOM_VK_HOME", - "DOM_VK_HYPHEN_MINUS", - "DOM_VK_I", - "DOM_VK_INSERT", - "DOM_VK_J", - "DOM_VK_JUNJA", - "DOM_VK_K", - "DOM_VK_KANA", - "DOM_VK_KANJI", - "DOM_VK_L", - "DOM_VK_LEFT", - "DOM_VK_LEFT_TAB", - "DOM_VK_LESS_THAN", - "DOM_VK_M", - "DOM_VK_META", - "DOM_VK_MODECHANGE", - "DOM_VK_MULTIPLY", - "DOM_VK_N", - "DOM_VK_NONCONVERT", - "DOM_VK_NUMPAD0", - "DOM_VK_NUMPAD1", - "DOM_VK_NUMPAD2", - "DOM_VK_NUMPAD3", - "DOM_VK_NUMPAD4", - "DOM_VK_NUMPAD5", - "DOM_VK_NUMPAD6", - "DOM_VK_NUMPAD7", - "DOM_VK_NUMPAD8", - "DOM_VK_NUMPAD9", - "DOM_VK_NUM_LOCK", - "DOM_VK_O", - "DOM_VK_OEM_1", - "DOM_VK_OEM_102", - "DOM_VK_OEM_2", - "DOM_VK_OEM_3", - "DOM_VK_OEM_4", - "DOM_VK_OEM_5", - "DOM_VK_OEM_6", - "DOM_VK_OEM_7", - "DOM_VK_OEM_8", - "DOM_VK_OEM_COMMA", - "DOM_VK_OEM_MINUS", - "DOM_VK_OEM_PERIOD", - "DOM_VK_OEM_PLUS", - "DOM_VK_OPEN_BRACKET", - "DOM_VK_OPEN_CURLY_BRACKET", - "DOM_VK_OPEN_PAREN", - "DOM_VK_P", - "DOM_VK_PA1", - "DOM_VK_PAGEDOWN", - "DOM_VK_PAGEUP", - "DOM_VK_PAGE_DOWN", - "DOM_VK_PAGE_UP", - "DOM_VK_PAUSE", - "DOM_VK_PERCENT", - "DOM_VK_PERIOD", - "DOM_VK_PIPE", - "DOM_VK_PLAY", - "DOM_VK_PLUS", - "DOM_VK_PRINT", - "DOM_VK_PRINTSCREEN", - "DOM_VK_PROCESSKEY", - "DOM_VK_PROPERITES", - "DOM_VK_Q", - "DOM_VK_QUESTION_MARK", - "DOM_VK_QUOTE", - "DOM_VK_R", - "DOM_VK_REDO", - "DOM_VK_RETURN", - "DOM_VK_RIGHT", - "DOM_VK_S", - "DOM_VK_SCROLL_LOCK", - "DOM_VK_SELECT", - "DOM_VK_SEMICOLON", - "DOM_VK_SEPARATOR", - "DOM_VK_SHIFT", - "DOM_VK_SLASH", - "DOM_VK_SLEEP", - "DOM_VK_SPACE", - "DOM_VK_SUBTRACT", - "DOM_VK_T", - "DOM_VK_TAB", - "DOM_VK_TILDE", - "DOM_VK_U", - "DOM_VK_UNDERSCORE", - "DOM_VK_UNDO", - "DOM_VK_UNICODE", - "DOM_VK_UP", - "DOM_VK_V", - "DOM_VK_VOLUME_DOWN", - "DOM_VK_VOLUME_MUTE", - "DOM_VK_VOLUME_UP", - "DOM_VK_W", - "DOM_VK_WIN", - "DOM_VK_WINDOW", - "DOM_VK_WIN_ICO_00", - "DOM_VK_WIN_ICO_CLEAR", - "DOM_VK_WIN_ICO_HELP", - "DOM_VK_WIN_OEM_ATTN", - "DOM_VK_WIN_OEM_AUTO", - "DOM_VK_WIN_OEM_BACKTAB", - "DOM_VK_WIN_OEM_CLEAR", - "DOM_VK_WIN_OEM_COPY", - "DOM_VK_WIN_OEM_CUSEL", - "DOM_VK_WIN_OEM_ENLW", - "DOM_VK_WIN_OEM_FINISH", - "DOM_VK_WIN_OEM_FJ_JISHO", - "DOM_VK_WIN_OEM_FJ_LOYA", - "DOM_VK_WIN_OEM_FJ_MASSHOU", - "DOM_VK_WIN_OEM_FJ_ROYA", - "DOM_VK_WIN_OEM_FJ_TOUROKU", - "DOM_VK_WIN_OEM_JUMP", - "DOM_VK_WIN_OEM_PA1", - "DOM_VK_WIN_OEM_PA2", - "DOM_VK_WIN_OEM_PA3", - "DOM_VK_WIN_OEM_RESET", - "DOM_VK_WIN_OEM_WSCTRL", - "DOM_VK_X", - "DOM_VK_XF86XK_ADD_FAVORITE", - "DOM_VK_XF86XK_APPLICATION_LEFT", - "DOM_VK_XF86XK_APPLICATION_RIGHT", - "DOM_VK_XF86XK_AUDIO_CYCLE_TRACK", - "DOM_VK_XF86XK_AUDIO_FORWARD", - "DOM_VK_XF86XK_AUDIO_LOWER_VOLUME", - "DOM_VK_XF86XK_AUDIO_MEDIA", - "DOM_VK_XF86XK_AUDIO_MUTE", - "DOM_VK_XF86XK_AUDIO_NEXT", - "DOM_VK_XF86XK_AUDIO_PAUSE", - "DOM_VK_XF86XK_AUDIO_PLAY", - "DOM_VK_XF86XK_AUDIO_PREV", - "DOM_VK_XF86XK_AUDIO_RAISE_VOLUME", - "DOM_VK_XF86XK_AUDIO_RANDOM_PLAY", - "DOM_VK_XF86XK_AUDIO_RECORD", - "DOM_VK_XF86XK_AUDIO_REPEAT", - "DOM_VK_XF86XK_AUDIO_REWIND", - "DOM_VK_XF86XK_AUDIO_STOP", - "DOM_VK_XF86XK_AWAY", - "DOM_VK_XF86XK_BACK", - "DOM_VK_XF86XK_BACK_FORWARD", - "DOM_VK_XF86XK_BATTERY", - "DOM_VK_XF86XK_BLUE", - "DOM_VK_XF86XK_BLUETOOTH", - "DOM_VK_XF86XK_BOOK", - "DOM_VK_XF86XK_BRIGHTNESS_ADJUST", - "DOM_VK_XF86XK_CALCULATOR", - "DOM_VK_XF86XK_CALENDAR", - "DOM_VK_XF86XK_CD", - "DOM_VK_XF86XK_CLOSE", - "DOM_VK_XF86XK_COMMUNITY", - "DOM_VK_XF86XK_CONTRAST_ADJUST", - "DOM_VK_XF86XK_COPY", - "DOM_VK_XF86XK_CUT", - "DOM_VK_XF86XK_CYCLE_ANGLE", - "DOM_VK_XF86XK_DISPLAY", - "DOM_VK_XF86XK_DOCUMENTS", - "DOM_VK_XF86XK_DOS", - "DOM_VK_XF86XK_EJECT", - "DOM_VK_XF86XK_EXCEL", - "DOM_VK_XF86XK_EXPLORER", - "DOM_VK_XF86XK_FAVORITES", - "DOM_VK_XF86XK_FINANCE", - "DOM_VK_XF86XK_FORWARD", - "DOM_VK_XF86XK_FRAME_BACK", - "DOM_VK_XF86XK_FRAME_FORWARD", - "DOM_VK_XF86XK_GAME", - "DOM_VK_XF86XK_GO", - "DOM_VK_XF86XK_GREEN", - "DOM_VK_XF86XK_HIBERNATE", - "DOM_VK_XF86XK_HISTORY", - "DOM_VK_XF86XK_HOME_PAGE", - "DOM_VK_XF86XK_HOT_LINKS", - "DOM_VK_XF86XK_I_TOUCH", - "DOM_VK_XF86XK_KBD_BRIGHTNESS_DOWN", - "DOM_VK_XF86XK_KBD_BRIGHTNESS_UP", - "DOM_VK_XF86XK_KBD_LIGHT_ON_OFF", - "DOM_VK_XF86XK_LAUNCH0", - "DOM_VK_XF86XK_LAUNCH1", - "DOM_VK_XF86XK_LAUNCH2", - "DOM_VK_XF86XK_LAUNCH3", - "DOM_VK_XF86XK_LAUNCH4", - "DOM_VK_XF86XK_LAUNCH5", - "DOM_VK_XF86XK_LAUNCH6", - "DOM_VK_XF86XK_LAUNCH7", - "DOM_VK_XF86XK_LAUNCH8", - "DOM_VK_XF86XK_LAUNCH9", - "DOM_VK_XF86XK_LAUNCH_A", - "DOM_VK_XF86XK_LAUNCH_B", - "DOM_VK_XF86XK_LAUNCH_C", - "DOM_VK_XF86XK_LAUNCH_D", - "DOM_VK_XF86XK_LAUNCH_E", - "DOM_VK_XF86XK_LAUNCH_F", - "DOM_VK_XF86XK_LIGHT_BULB", - "DOM_VK_XF86XK_LOG_OFF", - "DOM_VK_XF86XK_MAIL", - "DOM_VK_XF86XK_MAIL_FORWARD", - "DOM_VK_XF86XK_MARKET", - "DOM_VK_XF86XK_MEETING", - "DOM_VK_XF86XK_MEMO", - "DOM_VK_XF86XK_MENU_KB", - "DOM_VK_XF86XK_MENU_PB", - "DOM_VK_XF86XK_MESSENGER", - "DOM_VK_XF86XK_MON_BRIGHTNESS_DOWN", - "DOM_VK_XF86XK_MON_BRIGHTNESS_UP", - "DOM_VK_XF86XK_MUSIC", - "DOM_VK_XF86XK_MY_COMPUTER", - "DOM_VK_XF86XK_MY_SITES", - "DOM_VK_XF86XK_NEW", - "DOM_VK_XF86XK_NEWS", - "DOM_VK_XF86XK_OFFICE_HOME", - "DOM_VK_XF86XK_OPEN", - "DOM_VK_XF86XK_OPEN_URL", - "DOM_VK_XF86XK_OPTION", - "DOM_VK_XF86XK_PASTE", - "DOM_VK_XF86XK_PHONE", - "DOM_VK_XF86XK_PICTURES", - "DOM_VK_XF86XK_POWER_DOWN", - "DOM_VK_XF86XK_POWER_OFF", - "DOM_VK_XF86XK_RED", - "DOM_VK_XF86XK_REFRESH", - "DOM_VK_XF86XK_RELOAD", - "DOM_VK_XF86XK_REPLY", - "DOM_VK_XF86XK_ROCKER_DOWN", - "DOM_VK_XF86XK_ROCKER_ENTER", - "DOM_VK_XF86XK_ROCKER_UP", - "DOM_VK_XF86XK_ROTATE_WINDOWS", - "DOM_VK_XF86XK_ROTATION_KB", - "DOM_VK_XF86XK_ROTATION_PB", - "DOM_VK_XF86XK_SAVE", - "DOM_VK_XF86XK_SCREEN_SAVER", - "DOM_VK_XF86XK_SCROLL_CLICK", - "DOM_VK_XF86XK_SCROLL_DOWN", - "DOM_VK_XF86XK_SCROLL_UP", - "DOM_VK_XF86XK_SEARCH", - "DOM_VK_XF86XK_SEND", - "DOM_VK_XF86XK_SHOP", - "DOM_VK_XF86XK_SPELL", - "DOM_VK_XF86XK_SPLIT_SCREEN", - "DOM_VK_XF86XK_STANDBY", - "DOM_VK_XF86XK_START", - "DOM_VK_XF86XK_STOP", - "DOM_VK_XF86XK_SUBTITLE", - "DOM_VK_XF86XK_SUPPORT", - "DOM_VK_XF86XK_SUSPEND", - "DOM_VK_XF86XK_TASK_PANE", - "DOM_VK_XF86XK_TERMINAL", - "DOM_VK_XF86XK_TIME", - "DOM_VK_XF86XK_TOOLS", - "DOM_VK_XF86XK_TOP_MENU", - "DOM_VK_XF86XK_TO_DO_LIST", - "DOM_VK_XF86XK_TRAVEL", - "DOM_VK_XF86XK_USER1KB", - "DOM_VK_XF86XK_USER2KB", - "DOM_VK_XF86XK_USER_PB", - "DOM_VK_XF86XK_UWB", - "DOM_VK_XF86XK_VENDOR_HOME", - "DOM_VK_XF86XK_VIDEO", - "DOM_VK_XF86XK_VIEW", - "DOM_VK_XF86XK_WAKE_UP", - "DOM_VK_XF86XK_WEB_CAM", - "DOM_VK_XF86XK_WHEEL_BUTTON", - "DOM_VK_XF86XK_WLAN", - "DOM_VK_XF86XK_WORD", - "DOM_VK_XF86XK_WWW", - "DOM_VK_XF86XK_XFER", - "DOM_VK_XF86XK_YELLOW", - "DOM_VK_XF86XK_ZOOM_IN", - "DOM_VK_XF86XK_ZOOM_OUT", - "DOM_VK_Y", - "DOM_VK_Z", - "DOM_VK_ZOOM", - "DONE", - "DONT_CARE", - "DOWNLOADING", - "DRAGDROP", - "DST_ALPHA", - "DST_COLOR", - "DYNAMIC_DRAW", - "DataChannel", - "DataTransfer", - "DataTransferItem", - "DataTransferItemList", - "DataView", - "Date", - "DateTimeFormat", - "DelayNode", - "DesktopNotification", - "DesktopNotificationCenter", - "DeviceLightEvent", - "DeviceMotionEvent", - "DeviceOrientationEvent", - "DeviceProximityEvent", - "DeviceStorage", - "DeviceStorageChangeEvent", - "Document", - "DocumentFragment", - "DocumentType", - "DragEvent", - "DynamicsCompressorNode", - "E", - "ELEMENT_ARRAY_BUFFER", - "ELEMENT_ARRAY_BUFFER_BINDING", - "ELEMENT_NODE", - "EMPTY", - "ENCODING_ERR", - "ENDED", - "END_TO_END", - "END_TO_START", - "ENTITY_NODE", - "ENTITY_REFERENCE_NODE", - "EPSILON", - "EQUAL", - "EQUALPOWER", - "ERROR", - "EXPONENTIAL_DISTANCE", - "Element", - "ElementQuery", - "Entity", - "EntityReference", - "Error", - "ErrorEvent", - "EvalError", - "Event", - "EventException", - "EventSource", - "EventTarget", - "External", - "FASTEST", - "FIDOSDK", - "FILTER_ACCEPT", - "FILTER_INTERRUPT", - "FILTER_REJECT", - "FILTER_SKIP", - "FINISHED_STATE", - "FIRST_ORDERED_NODE_TYPE", - "FLOAT", - "FLOAT_MAT2", - "FLOAT_MAT3", - "FLOAT_MAT4", - "FLOAT_VEC2", - "FLOAT_VEC3", - "FLOAT_VEC4", - "FOCUS", - "FONT_FACE_RULE", - "FONT_FEATURE_VALUES_RULE", - "FRAGMENT_SHADER", - "FRAGMENT_SHADER_DERIVATIVE_HINT_OES", - "FRAMEBUFFER", - "FRAMEBUFFER_ATTACHMENT_OBJECT_NAME", - "FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE", - "FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE", - "FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL", - "FRAMEBUFFER_BINDING", - "FRAMEBUFFER_COMPLETE", - "FRAMEBUFFER_INCOMPLETE_ATTACHMENT", - "FRAMEBUFFER_INCOMPLETE_DIMENSIONS", - "FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT", - "FRAMEBUFFER_UNSUPPORTED", - "FRONT", - "FRONT_AND_BACK", - "FRONT_FACE", - "FUNC_ADD", - "FUNC_REVERSE_SUBTRACT", - "FUNC_SUBTRACT", - "Feed", - "FeedEntry", - "File", - "FileError", - "FileList", - "FileReader", - "FindInPage", - "Float32Array", - "Float64Array", - "FocusEvent", - "FontFace", - "FormData", - "Function", - "GENERATE_MIPMAP_HINT", - "GEQUAL", - "GREATER", - "GREEN_BITS", - "GainNode", - "Gamepad", - "GamepadButton", - "GamepadEvent", - "GestureEvent", - "HAVE_CURRENT_DATA", - "HAVE_ENOUGH_DATA", - "HAVE_FUTURE_DATA", - "HAVE_METADATA", - "HAVE_NOTHING", - "HEADERS_RECEIVED", - "HIDDEN", - "HIERARCHY_REQUEST_ERR", - "HIGHPASS", - "HIGHSHELF", - "HIGH_FLOAT", - "HIGH_INT", - "HORIZONTAL", - "HORIZONTAL_AXIS", - "HRTF", - "HTMLAllCollection", - "HTMLAnchorElement", - "HTMLAppletElement", - "HTMLAreaElement", - "HTMLAudioElement", - "HTMLBRElement", - "HTMLBaseElement", - "HTMLBaseFontElement", - "HTMLBlockquoteElement", - "HTMLBodyElement", - "HTMLButtonElement", - "HTMLCanvasElement", - "HTMLCollection", - "HTMLCommandElement", - "HTMLContentElement", - "HTMLDListElement", - "HTMLDataElement", - "HTMLDataListElement", - "HTMLDetailsElement", - "HTMLDialogElement", - "HTMLDirectoryElement", - "HTMLDivElement", - "HTMLDocument", - "HTMLElement", - "HTMLEmbedElement", - "HTMLFieldSetElement", - "HTMLFontElement", - "HTMLFormControlsCollection", - "HTMLFormElement", - "HTMLFrameElement", - "HTMLFrameSetElement", - "HTMLHRElement", - "HTMLHeadElement", - "HTMLHeadingElement", - "HTMLHtmlElement", - "HTMLIFrameElement", - "HTMLImageElement", - "HTMLInputElement", - "HTMLIsIndexElement", - "HTMLKeygenElement", - "HTMLLIElement", - "HTMLLabelElement", - "HTMLLegendElement", - "HTMLLinkElement", - "HTMLMapElement", - "HTMLMarqueeElement", - "HTMLMediaElement", - "HTMLMenuElement", - "HTMLMenuItemElement", - "HTMLMetaElement", - "HTMLMeterElement", - "HTMLModElement", - "HTMLOListElement", - "HTMLObjectElement", - "HTMLOptGroupElement", - "HTMLOptionElement", - "HTMLOptionsCollection", - "HTMLOutputElement", - "HTMLParagraphElement", - "HTMLParamElement", - "HTMLPictureElement", - "HTMLPreElement", - "HTMLProgressElement", - "HTMLPropertiesCollection", - "HTMLQuoteElement", - "HTMLScriptElement", - "HTMLSelectElement", - "HTMLShadowElement", - "HTMLSourceElement", - "HTMLSpanElement", - "HTMLStyleElement", - "HTMLTableCaptionElement", - "HTMLTableCellElement", - "HTMLTableColElement", - "HTMLTableElement", - "HTMLTableRowElement", - "HTMLTableSectionElement", - "HTMLTemplateElement", - "HTMLTextAreaElement", - "HTMLTimeElement", - "HTMLTitleElement", - "HTMLTrackElement", - "HTMLUListElement", - "HTMLUnknownElement", - "HTMLVideoElement", - "HashChangeEvent", - "Headers", - "History", - "ICE_CHECKING", - "ICE_CLOSED", - "ICE_COMPLETED", - "ICE_CONNECTED", - "ICE_FAILED", - "ICE_GATHERING", - "ICE_WAITING", - "IDBCursor", - "IDBCursorWithValue", - "IDBDatabase", - "IDBDatabaseException", - "IDBFactory", - "IDBFileHandle", - "IDBFileRequest", - "IDBIndex", - "IDBKeyRange", - "IDBMutableFile", - "IDBObjectStore", - "IDBOpenDBRequest", - "IDBRequest", - "IDBTransaction", - "IDBVersionChangeEvent", - "IDLE", - "IMPLEMENTATION_COLOR_READ_FORMAT", - "IMPLEMENTATION_COLOR_READ_TYPE", - "IMPORT_RULE", - "INCR", - "INCR_WRAP", - "INDEX_SIZE_ERR", - "INT", - "INT_VEC2", - "INT_VEC3", - "INT_VEC4", - "INUSE_ATTRIBUTE_ERR", - "INVALID_ACCESS_ERR", - "INVALID_CHARACTER_ERR", - "INVALID_ENUM", - "INVALID_EXPRESSION_ERR", - "INVALID_FRAMEBUFFER_OPERATION", - "INVALID_MODIFICATION_ERR", - "INVALID_NODE_TYPE_ERR", - "INVALID_OPERATION", - "INVALID_STATE_ERR", - "INVALID_VALUE", - "INVERSE_DISTANCE", - "INVERT", - "IceCandidate", - "Image", - "ImageBitmap", - "ImageData", - "Infinity", - "InputEvent", - "InputMethodContext", - "InstallTrigger", - "Int16Array", - "Int32Array", - "Int8Array", - "Intent", - "InternalError", - "Intl", - "IsSearchProviderInstalled", - "Iterator", - "JSON", - "KEEP", - "KEYDOWN", - "KEYFRAMES_RULE", - "KEYFRAME_RULE", - "KEYPRESS", - "KEYUP", - "KeyEvent", - "KeyboardEvent", - "LENGTHADJUST_SPACING", - "LENGTHADJUST_SPACINGANDGLYPHS", - "LENGTHADJUST_UNKNOWN", - "LEQUAL", - "LESS", - "LINEAR", - "LINEAR_DISTANCE", - "LINEAR_MIPMAP_LINEAR", - "LINEAR_MIPMAP_NEAREST", - "LINES", - "LINE_LOOP", - "LINE_STRIP", - "LINE_WIDTH", - "LINK_STATUS", - "LIVE", - "LN10", - "LN2", - "LOADED", - "LOADING", - "LOG10E", - "LOG2E", - "LOWPASS", - "LOWSHELF", - "LOW_FLOAT", - "LOW_INT", - "LSException", - "LSParserFilter", - "LUMINANCE", - "LUMINANCE_ALPHA", - "LocalMediaStream", - "Location", - "MAX_COMBINED_TEXTURE_IMAGE_UNITS", - "MAX_CUBE_MAP_TEXTURE_SIZE", - "MAX_FRAGMENT_UNIFORM_VECTORS", - "MAX_RENDERBUFFER_SIZE", - "MAX_SAFE_INTEGER", - "MAX_TEXTURE_IMAGE_UNITS", - "MAX_TEXTURE_MAX_ANISOTROPY_EXT", - "MAX_TEXTURE_SIZE", - "MAX_VALUE", - "MAX_VARYING_VECTORS", - "MAX_VERTEX_ATTRIBS", - "MAX_VERTEX_TEXTURE_IMAGE_UNITS", - "MAX_VERTEX_UNIFORM_VECTORS", - "MAX_VIEWPORT_DIMS", - "MEDIA_ERR_ABORTED", - "MEDIA_ERR_DECODE", - "MEDIA_ERR_ENCRYPTED", - "MEDIA_ERR_NETWORK", - "MEDIA_ERR_SRC_NOT_SUPPORTED", - "MEDIA_KEYERR_CLIENT", - "MEDIA_KEYERR_DOMAIN", - "MEDIA_KEYERR_HARDWARECHANGE", - "MEDIA_KEYERR_OUTPUT", - "MEDIA_KEYERR_SERVICE", - "MEDIA_KEYERR_UNKNOWN", - "MEDIA_RULE", - "MEDIUM_FLOAT", - "MEDIUM_INT", - "META_MASK", - "MIN_SAFE_INTEGER", - "MIN_VALUE", - "MIRRORED_REPEAT", - "MODE_ASYNCHRONOUS", - "MODE_SYNCHRONOUS", - "MODIFICATION", - "MOUSEDOWN", - "MOUSEDRAG", - "MOUSEMOVE", - "MOUSEOUT", - "MOUSEOVER", - "MOUSEUP", - "MOZ_KEYFRAMES_RULE", - "MOZ_KEYFRAME_RULE", - "MOZ_SOURCE_CURSOR", - "MOZ_SOURCE_ERASER", - "MOZ_SOURCE_KEYBOARD", - "MOZ_SOURCE_MOUSE", - "MOZ_SOURCE_PEN", - "MOZ_SOURCE_TOUCH", - "MOZ_SOURCE_UNKNOWN", - "MSGESTURE_FLAG_BEGIN", - "MSGESTURE_FLAG_CANCEL", - "MSGESTURE_FLAG_END", - "MSGESTURE_FLAG_INERTIA", - "MSGESTURE_FLAG_NONE", - "MSPOINTER_TYPE_MOUSE", - "MSPOINTER_TYPE_PEN", - "MSPOINTER_TYPE_TOUCH", - "MS_ASYNC_CALLBACK_STATUS_ASSIGN_DELEGATE", - "MS_ASYNC_CALLBACK_STATUS_CANCEL", - "MS_ASYNC_CALLBACK_STATUS_CHOOSEANY", - "MS_ASYNC_CALLBACK_STATUS_ERROR", - "MS_ASYNC_CALLBACK_STATUS_JOIN", - "MS_ASYNC_OP_STATUS_CANCELED", - "MS_ASYNC_OP_STATUS_ERROR", - "MS_ASYNC_OP_STATUS_SUCCESS", - "MS_MANIPULATION_STATE_ACTIVE", - "MS_MANIPULATION_STATE_CANCELLED", - "MS_MANIPULATION_STATE_COMMITTED", - "MS_MANIPULATION_STATE_DRAGGING", - "MS_MANIPULATION_STATE_INERTIA", - "MS_MANIPULATION_STATE_PRESELECT", - "MS_MANIPULATION_STATE_SELECTING", - "MS_MANIPULATION_STATE_STOPPED", - "MS_MEDIA_ERR_ENCRYPTED", - "MS_MEDIA_KEYERR_CLIENT", - "MS_MEDIA_KEYERR_DOMAIN", - "MS_MEDIA_KEYERR_HARDWARECHANGE", - "MS_MEDIA_KEYERR_OUTPUT", - "MS_MEDIA_KEYERR_SERVICE", - "MS_MEDIA_KEYERR_UNKNOWN", - "Map", - "Math", - "MediaController", - "MediaDevices", - "MediaElementAudioSourceNode", - "MediaEncryptedEvent", - "MediaError", - "MediaKeyError", - "MediaKeyEvent", - "MediaKeyMessageEvent", - "MediaKeyNeededEvent", - "MediaKeySession", - "MediaKeyStatusMap", - "MediaKeySystemAccess", - "MediaKeys", - "MediaList", - "MediaQueryList", - "MediaQueryListEvent", - "MediaRecorder", - "MediaSource", - "MediaStream", - "MediaStreamAudioDestinationNode", - "MediaStreamAudioSourceNode", - "MediaStreamEvent", - "MediaStreamTrack", - "MediaStreamTrackEvent", - "MessageChannel", - "MessageEvent", - "MessagePort", - "Methods", - "MimeType", - "MimeTypeArray", - "MouseEvent", - "MouseScrollEvent", - "MozAnimation", - "MozAnimationDelay", - "MozAnimationDirection", - "MozAnimationDuration", - "MozAnimationFillMode", - "MozAnimationIterationCount", - "MozAnimationName", - "MozAnimationPlayState", - "MozAnimationTimingFunction", - "MozAppearance", - "MozBackfaceVisibility", - "MozBinding", - "MozBorderBottomColors", - "MozBorderEnd", - "MozBorderEndColor", - "MozBorderEndStyle", - "MozBorderEndWidth", - "MozBorderImage", - "MozBorderLeftColors", - "MozBorderRightColors", - "MozBorderStart", - "MozBorderStartColor", - "MozBorderStartStyle", - "MozBorderStartWidth", - "MozBorderTopColors", - "MozBoxAlign", - "MozBoxDirection", - "MozBoxFlex", - "MozBoxOrdinalGroup", - "MozBoxOrient", - "MozBoxPack", - "MozBoxSizing", - "MozCSSKeyframeRule", - "MozCSSKeyframesRule", - "MozColumnCount", - "MozColumnFill", - "MozColumnGap", - "MozColumnRule", - "MozColumnRuleColor", - "MozColumnRuleStyle", - "MozColumnRuleWidth", - "MozColumnWidth", - "MozColumns", - "MozContactChangeEvent", - "MozFloatEdge", - "MozFontFeatureSettings", - "MozFontLanguageOverride", - "MozForceBrokenImageIcon", - "MozHyphens", - "MozImageRegion", - "MozMarginEnd", - "MozMarginStart", - "MozMmsEvent", - "MozMmsMessage", - "MozMobileMessageThread", - "MozOSXFontSmoothing", - "MozOrient", - "MozOutlineRadius", - "MozOutlineRadiusBottomleft", - "MozOutlineRadiusBottomright", - "MozOutlineRadiusTopleft", - "MozOutlineRadiusTopright", - "MozPaddingEnd", - "MozPaddingStart", - "MozPerspective", - "MozPerspectiveOrigin", - "MozPowerManager", - "MozSettingsEvent", - "MozSmsEvent", - "MozSmsMessage", - "MozStackSizing", - "MozTabSize", - "MozTextAlignLast", - "MozTextDecorationColor", - "MozTextDecorationLine", - "MozTextDecorationStyle", - "MozTextSizeAdjust", - "MozTransform", - "MozTransformOrigin", - "MozTransformStyle", - "MozTransition", - "MozTransitionDelay", - "MozTransitionDuration", - "MozTransitionProperty", - "MozTransitionTimingFunction", - "MozUserFocus", - "MozUserInput", - "MozUserModify", - "MozUserSelect", - "MozWindowDragging", - "MozWindowShadow", - "MutationEvent", - "MutationObserver", - "MutationRecord", - "NAMESPACE_ERR", - "NAMESPACE_RULE", - "NEAREST", - "NEAREST_MIPMAP_LINEAR", - "NEAREST_MIPMAP_NEAREST", - "NEGATIVE_INFINITY", - "NETWORK_EMPTY", - "NETWORK_ERR", - "NETWORK_IDLE", - "NETWORK_LOADED", - "NETWORK_LOADING", - "NETWORK_NO_SOURCE", - "NEVER", - "NEW", - "NEXT", - "NEXT_NO_DUPLICATE", - "NICEST", - "NODE_AFTER", - "NODE_BEFORE", - "NODE_BEFORE_AND_AFTER", - "NODE_INSIDE", - "NONE", - "NON_TRANSIENT_ERR", - "NOTATION_NODE", - "NOTCH", - "NOTEQUAL", - "NOT_ALLOWED_ERR", - "NOT_FOUND_ERR", - "NOT_READABLE_ERR", - "NOT_SUPPORTED_ERR", - "NO_DATA_ALLOWED_ERR", - "NO_ERR", - "NO_ERROR", - "NO_MODIFICATION_ALLOWED_ERR", - "NUMBER_TYPE", - "NUM_COMPRESSED_TEXTURE_FORMATS", - "NaN", - "NamedNodeMap", - "Navigator", - "NearbyLinks", - "NetworkInformation", - "Node", - "NodeFilter", - "NodeIterator", - "NodeList", - "Notation", - "Notification", - "NotifyPaintEvent", - "Number", - "NumberFormat", - "OBSOLETE", - "ONE", - "ONE_MINUS_CONSTANT_ALPHA", - "ONE_MINUS_CONSTANT_COLOR", - "ONE_MINUS_DST_ALPHA", - "ONE_MINUS_DST_COLOR", - "ONE_MINUS_SRC_ALPHA", - "ONE_MINUS_SRC_COLOR", - "OPEN", - "OPENED", - "OPENING", - "ORDERED_NODE_ITERATOR_TYPE", - "ORDERED_NODE_SNAPSHOT_TYPE", - "OUT_OF_MEMORY", - "Object", - "OfflineAudioCompletionEvent", - "OfflineAudioContext", - "OfflineResourceList", - "Option", - "OscillatorNode", - "OverflowEvent", - "PACK_ALIGNMENT", - "PAGE_RULE", - "PARSE_ERR", - "PATHSEG_ARC_ABS", - "PATHSEG_ARC_REL", - "PATHSEG_CLOSEPATH", - "PATHSEG_CURVETO_CUBIC_ABS", - "PATHSEG_CURVETO_CUBIC_REL", - "PATHSEG_CURVETO_CUBIC_SMOOTH_ABS", - "PATHSEG_CURVETO_CUBIC_SMOOTH_REL", - "PATHSEG_CURVETO_QUADRATIC_ABS", - "PATHSEG_CURVETO_QUADRATIC_REL", - "PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS", - "PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL", - "PATHSEG_LINETO_ABS", - "PATHSEG_LINETO_HORIZONTAL_ABS", - "PATHSEG_LINETO_HORIZONTAL_REL", - "PATHSEG_LINETO_REL", - "PATHSEG_LINETO_VERTICAL_ABS", - "PATHSEG_LINETO_VERTICAL_REL", - "PATHSEG_MOVETO_ABS", - "PATHSEG_MOVETO_REL", - "PATHSEG_UNKNOWN", - "PATH_EXISTS_ERR", - "PEAKING", - "PERMISSION_DENIED", - "PERSISTENT", - "PI", - "PLAYING_STATE", - "POINTS", - "POLYGON_OFFSET_FACTOR", - "POLYGON_OFFSET_FILL", - "POLYGON_OFFSET_UNITS", - "POSITION_UNAVAILABLE", - "POSITIVE_INFINITY", - "PREV", - "PREV_NO_DUPLICATE", - "PROCESSING_INSTRUCTION_NODE", - "PageChangeEvent", - "PageTransitionEvent", - "PaintRequest", - "PaintRequestList", - "PannerNode", - "Path2D", - "Performance", - "PerformanceEntry", - "PerformanceMark", - "PerformanceMeasure", - "PerformanceNavigation", - "PerformanceResourceTiming", - "PerformanceTiming", - "PeriodicWave", - "Plugin", - "PluginArray", - "PopStateEvent", - "PopupBlockedEvent", - "ProcessingInstruction", - "ProgressEvent", - "Promise", - "PropertyNodeList", - "Proxy", - "PushManager", - "PushSubscription", - "Q", - "QUOTA_ERR", - "QUOTA_EXCEEDED_ERR", - "QueryInterface", - "READ_ONLY", - "READ_ONLY_ERR", - "READ_WRITE", - "RED_BITS", - "REMOVAL", - "RENDERBUFFER", - "RENDERBUFFER_ALPHA_SIZE", - "RENDERBUFFER_BINDING", - "RENDERBUFFER_BLUE_SIZE", - "RENDERBUFFER_DEPTH_SIZE", - "RENDERBUFFER_GREEN_SIZE", - "RENDERBUFFER_HEIGHT", - "RENDERBUFFER_INTERNAL_FORMAT", - "RENDERBUFFER_RED_SIZE", - "RENDERBUFFER_STENCIL_SIZE", - "RENDERBUFFER_WIDTH", - "RENDERER", - "RENDERING_INTENT_ABSOLUTE_COLORIMETRIC", - "RENDERING_INTENT_AUTO", - "RENDERING_INTENT_PERCEPTUAL", - "RENDERING_INTENT_RELATIVE_COLORIMETRIC", - "RENDERING_INTENT_SATURATION", - "RENDERING_INTENT_UNKNOWN", - "REPEAT", - "REPLACE", - "RGB", - "RGB565", - "RGB5_A1", - "RGBA", - "RGBA4", - "RGBColor", - "ROTATION_CLOCKWISE", - "ROTATION_COUNTERCLOCKWISE", - "RTCDataChannelEvent", - "RTCIceCandidate", - "RTCPeerConnectionIceEvent", - "RTCRtpReceiver", - "RTCRtpSender", - "RTCSessionDescription", - "RTCStatsReport", - "RadioNodeList", - "Range", - "RangeError", - "RangeException", - "RecordErrorEvent", - "Rect", - "ReferenceError", - "RegExp", - "Request", - "Response", - "SAMPLER_2D", - "SAMPLER_CUBE", - "SAMPLES", - "SAMPLE_ALPHA_TO_COVERAGE", - "SAMPLE_BUFFERS", - "SAMPLE_COVERAGE", - "SAMPLE_COVERAGE_INVERT", - "SAMPLE_COVERAGE_VALUE", - "SAWTOOTH", - "SCHEDULED_STATE", - "SCISSOR_BOX", - "SCISSOR_TEST", - "SCROLL_PAGE_DOWN", - "SCROLL_PAGE_UP", - "SDP_ANSWER", - "SDP_OFFER", - "SDP_PRANSWER", - "SECURITY_ERR", - "SELECT", - "SERIALIZE_ERR", - "SEVERITY_ERROR", - "SEVERITY_FATAL_ERROR", - "SEVERITY_WARNING", - "SHADER_COMPILER", - "SHADER_TYPE", - "SHADING_LANGUAGE_VERSION", - "SHIFT_MASK", - "SHORT", - "SHOWING", - "SHOW_ALL", - "SHOW_ATTRIBUTE", - "SHOW_CDATA_SECTION", - "SHOW_COMMENT", - "SHOW_DOCUMENT", - "SHOW_DOCUMENT_FRAGMENT", - "SHOW_DOCUMENT_TYPE", - "SHOW_ELEMENT", - "SHOW_ENTITY", - "SHOW_ENTITY_REFERENCE", - "SHOW_NOTATION", - "SHOW_PROCESSING_INSTRUCTION", - "SHOW_TEXT", - "SINE", - "SOUNDFIELD", - "SQLException", - "SQRT1_2", - "SQRT2", - "SQUARE", - "SRC_ALPHA", - "SRC_ALPHA_SATURATE", - "SRC_COLOR", - "START_TO_END", - "START_TO_START", - "STATIC_DRAW", - "STENCIL_ATTACHMENT", - "STENCIL_BACK_FAIL", - "STENCIL_BACK_FUNC", - "STENCIL_BACK_PASS_DEPTH_FAIL", - "STENCIL_BACK_PASS_DEPTH_PASS", - "STENCIL_BACK_REF", - "STENCIL_BACK_VALUE_MASK", - "STENCIL_BACK_WRITEMASK", - "STENCIL_BITS", - "STENCIL_BUFFER_BIT", - "STENCIL_CLEAR_VALUE", - "STENCIL_FAIL", - "STENCIL_FUNC", - "STENCIL_INDEX", - "STENCIL_INDEX8", - "STENCIL_PASS_DEPTH_FAIL", - "STENCIL_PASS_DEPTH_PASS", - "STENCIL_REF", - "STENCIL_TEST", - "STENCIL_VALUE_MASK", - "STENCIL_WRITEMASK", - "STREAM_DRAW", - "STRING_TYPE", - "STYLE_RULE", - "SUBPIXEL_BITS", - "SUPPORTS_RULE", - "SVGAElement", - "SVGAltGlyphDefElement", - "SVGAltGlyphElement", - "SVGAltGlyphItemElement", - "SVGAngle", - "SVGAnimateColorElement", - "SVGAnimateElement", - "SVGAnimateMotionElement", - "SVGAnimateTransformElement", - "SVGAnimatedAngle", - "SVGAnimatedBoolean", - "SVGAnimatedEnumeration", - "SVGAnimatedInteger", - "SVGAnimatedLength", - "SVGAnimatedLengthList", - "SVGAnimatedNumber", - "SVGAnimatedNumberList", - "SVGAnimatedPreserveAspectRatio", - "SVGAnimatedRect", - "SVGAnimatedString", - "SVGAnimatedTransformList", - "SVGAnimationElement", - "SVGCircleElement", - "SVGClipPathElement", - "SVGColor", - "SVGComponentTransferFunctionElement", - "SVGCursorElement", - "SVGDefsElement", - "SVGDescElement", - "SVGDiscardElement", - "SVGDocument", - "SVGElement", - "SVGElementInstance", - "SVGElementInstanceList", - "SVGEllipseElement", - "SVGException", - "SVGFEBlendElement", - "SVGFEColorMatrixElement", - "SVGFEComponentTransferElement", - "SVGFECompositeElement", - "SVGFEConvolveMatrixElement", - "SVGFEDiffuseLightingElement", - "SVGFEDisplacementMapElement", - "SVGFEDistantLightElement", - "SVGFEDropShadowElement", - "SVGFEFloodElement", - "SVGFEFuncAElement", - "SVGFEFuncBElement", - "SVGFEFuncGElement", - "SVGFEFuncRElement", - "SVGFEGaussianBlurElement", - "SVGFEImageElement", - "SVGFEMergeElement", - "SVGFEMergeNodeElement", - "SVGFEMorphologyElement", - "SVGFEOffsetElement", - "SVGFEPointLightElement", - "SVGFESpecularLightingElement", - "SVGFESpotLightElement", - "SVGFETileElement", - "SVGFETurbulenceElement", - "SVGFilterElement", - "SVGFontElement", - "SVGFontFaceElement", - "SVGFontFaceFormatElement", - "SVGFontFaceNameElement", - "SVGFontFaceSrcElement", - "SVGFontFaceUriElement", - "SVGForeignObjectElement", - "SVGGElement", - "SVGGeometryElement", - "SVGGlyphElement", - "SVGGlyphRefElement", - "SVGGradientElement", - "SVGGraphicsElement", - "SVGHKernElement", - "SVGImageElement", - "SVGLength", - "SVGLengthList", - "SVGLineElement", - "SVGLinearGradientElement", - "SVGMPathElement", - "SVGMarkerElement", - "SVGMaskElement", - "SVGMatrix", - "SVGMetadataElement", - "SVGMissingGlyphElement", - "SVGNumber", - "SVGNumberList", - "SVGPaint", - "SVGPathElement", - "SVGPathSeg", - "SVGPathSegArcAbs", - "SVGPathSegArcRel", - "SVGPathSegClosePath", - "SVGPathSegCurvetoCubicAbs", - "SVGPathSegCurvetoCubicRel", - "SVGPathSegCurvetoCubicSmoothAbs", - "SVGPathSegCurvetoCubicSmoothRel", - "SVGPathSegCurvetoQuadraticAbs", - "SVGPathSegCurvetoQuadraticRel", - "SVGPathSegCurvetoQuadraticSmoothAbs", - "SVGPathSegCurvetoQuadraticSmoothRel", - "SVGPathSegLinetoAbs", - "SVGPathSegLinetoHorizontalAbs", - "SVGPathSegLinetoHorizontalRel", - "SVGPathSegLinetoRel", - "SVGPathSegLinetoVerticalAbs", - "SVGPathSegLinetoVerticalRel", - "SVGPathSegList", - "SVGPathSegMovetoAbs", - "SVGPathSegMovetoRel", - "SVGPatternElement", - "SVGPoint", - "SVGPointList", - "SVGPolygonElement", - "SVGPolylineElement", - "SVGPreserveAspectRatio", - "SVGRadialGradientElement", - "SVGRect", - "SVGRectElement", - "SVGRenderingIntent", - "SVGSVGElement", - "SVGScriptElement", - "SVGSetElement", - "SVGStopElement", - "SVGStringList", - "SVGStyleElement", - "SVGSwitchElement", - "SVGSymbolElement", - "SVGTRefElement", - "SVGTSpanElement", - "SVGTextContentElement", - "SVGTextElement", - "SVGTextPathElement", - "SVGTextPositioningElement", - "SVGTitleElement", - "SVGTransform", - "SVGTransformList", - "SVGUnitTypes", - "SVGUseElement", - "SVGVKernElement", - "SVGViewElement", - "SVGViewSpec", - "SVGZoomAndPan", - "SVGZoomEvent", - "SVG_ANGLETYPE_DEG", - "SVG_ANGLETYPE_GRAD", - "SVG_ANGLETYPE_RAD", - "SVG_ANGLETYPE_UNKNOWN", - "SVG_ANGLETYPE_UNSPECIFIED", - "SVG_CHANNEL_A", - "SVG_CHANNEL_B", - "SVG_CHANNEL_G", - "SVG_CHANNEL_R", - "SVG_CHANNEL_UNKNOWN", - "SVG_COLORTYPE_CURRENTCOLOR", - "SVG_COLORTYPE_RGBCOLOR", - "SVG_COLORTYPE_RGBCOLOR_ICCCOLOR", - "SVG_COLORTYPE_UNKNOWN", - "SVG_EDGEMODE_DUPLICATE", - "SVG_EDGEMODE_NONE", - "SVG_EDGEMODE_UNKNOWN", - "SVG_EDGEMODE_WRAP", - "SVG_FEBLEND_MODE_COLOR", - "SVG_FEBLEND_MODE_COLOR_BURN", - "SVG_FEBLEND_MODE_COLOR_DODGE", - "SVG_FEBLEND_MODE_DARKEN", - "SVG_FEBLEND_MODE_DIFFERENCE", - "SVG_FEBLEND_MODE_EXCLUSION", - "SVG_FEBLEND_MODE_HARD_LIGHT", - "SVG_FEBLEND_MODE_HUE", - "SVG_FEBLEND_MODE_LIGHTEN", - "SVG_FEBLEND_MODE_LUMINOSITY", - "SVG_FEBLEND_MODE_MULTIPLY", - "SVG_FEBLEND_MODE_NORMAL", - "SVG_FEBLEND_MODE_OVERLAY", - "SVG_FEBLEND_MODE_SATURATION", - "SVG_FEBLEND_MODE_SCREEN", - "SVG_FEBLEND_MODE_SOFT_LIGHT", - "SVG_FEBLEND_MODE_UNKNOWN", - "SVG_FECOLORMATRIX_TYPE_HUEROTATE", - "SVG_FECOLORMATRIX_TYPE_LUMINANCETOALPHA", - "SVG_FECOLORMATRIX_TYPE_MATRIX", - "SVG_FECOLORMATRIX_TYPE_SATURATE", - "SVG_FECOLORMATRIX_TYPE_UNKNOWN", - "SVG_FECOMPONENTTRANSFER_TYPE_DISCRETE", - "SVG_FECOMPONENTTRANSFER_TYPE_GAMMA", - "SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY", - "SVG_FECOMPONENTTRANSFER_TYPE_LINEAR", - "SVG_FECOMPONENTTRANSFER_TYPE_TABLE", - "SVG_FECOMPONENTTRANSFER_TYPE_UNKNOWN", - "SVG_FECOMPOSITE_OPERATOR_ARITHMETIC", - "SVG_FECOMPOSITE_OPERATOR_ATOP", - "SVG_FECOMPOSITE_OPERATOR_IN", - "SVG_FECOMPOSITE_OPERATOR_OUT", - "SVG_FECOMPOSITE_OPERATOR_OVER", - "SVG_FECOMPOSITE_OPERATOR_UNKNOWN", - "SVG_FECOMPOSITE_OPERATOR_XOR", - "SVG_INVALID_VALUE_ERR", - "SVG_LENGTHTYPE_CM", - "SVG_LENGTHTYPE_EMS", - "SVG_LENGTHTYPE_EXS", - "SVG_LENGTHTYPE_IN", - "SVG_LENGTHTYPE_MM", - "SVG_LENGTHTYPE_NUMBER", - "SVG_LENGTHTYPE_PC", - "SVG_LENGTHTYPE_PERCENTAGE", - "SVG_LENGTHTYPE_PT", - "SVG_LENGTHTYPE_PX", - "SVG_LENGTHTYPE_UNKNOWN", - "SVG_MARKERUNITS_STROKEWIDTH", - "SVG_MARKERUNITS_UNKNOWN", - "SVG_MARKERUNITS_USERSPACEONUSE", - "SVG_MARKER_ORIENT_ANGLE", - "SVG_MARKER_ORIENT_AUTO", - "SVG_MARKER_ORIENT_UNKNOWN", - "SVG_MASKTYPE_ALPHA", - "SVG_MASKTYPE_LUMINANCE", - "SVG_MATRIX_NOT_INVERTABLE", - "SVG_MEETORSLICE_MEET", - "SVG_MEETORSLICE_SLICE", - "SVG_MEETORSLICE_UNKNOWN", - "SVG_MORPHOLOGY_OPERATOR_DILATE", - "SVG_MORPHOLOGY_OPERATOR_ERODE", - "SVG_MORPHOLOGY_OPERATOR_UNKNOWN", - "SVG_PAINTTYPE_CURRENTCOLOR", - "SVG_PAINTTYPE_NONE", - "SVG_PAINTTYPE_RGBCOLOR", - "SVG_PAINTTYPE_RGBCOLOR_ICCCOLOR", - "SVG_PAINTTYPE_UNKNOWN", - "SVG_PAINTTYPE_URI", - "SVG_PAINTTYPE_URI_CURRENTCOLOR", - "SVG_PAINTTYPE_URI_NONE", - "SVG_PAINTTYPE_URI_RGBCOLOR", - "SVG_PAINTTYPE_URI_RGBCOLOR_ICCCOLOR", - "SVG_PRESERVEASPECTRATIO_NONE", - "SVG_PRESERVEASPECTRATIO_UNKNOWN", - "SVG_PRESERVEASPECTRATIO_XMAXYMAX", - "SVG_PRESERVEASPECTRATIO_XMAXYMID", - "SVG_PRESERVEASPECTRATIO_XMAXYMIN", - "SVG_PRESERVEASPECTRATIO_XMIDYMAX", - "SVG_PRESERVEASPECTRATIO_XMIDYMID", - "SVG_PRESERVEASPECTRATIO_XMIDYMIN", - "SVG_PRESERVEASPECTRATIO_XMINYMAX", - "SVG_PRESERVEASPECTRATIO_XMINYMID", - "SVG_PRESERVEASPECTRATIO_XMINYMIN", - "SVG_SPREADMETHOD_PAD", - "SVG_SPREADMETHOD_REFLECT", - "SVG_SPREADMETHOD_REPEAT", - "SVG_SPREADMETHOD_UNKNOWN", - "SVG_STITCHTYPE_NOSTITCH", - "SVG_STITCHTYPE_STITCH", - "SVG_STITCHTYPE_UNKNOWN", - "SVG_TRANSFORM_MATRIX", - "SVG_TRANSFORM_ROTATE", - "SVG_TRANSFORM_SCALE", - "SVG_TRANSFORM_SKEWX", - "SVG_TRANSFORM_SKEWY", - "SVG_TRANSFORM_TRANSLATE", - "SVG_TRANSFORM_UNKNOWN", - "SVG_TURBULENCE_TYPE_FRACTALNOISE", - "SVG_TURBULENCE_TYPE_TURBULENCE", - "SVG_TURBULENCE_TYPE_UNKNOWN", - "SVG_UNIT_TYPE_OBJECTBOUNDINGBOX", - "SVG_UNIT_TYPE_UNKNOWN", - "SVG_UNIT_TYPE_USERSPACEONUSE", - "SVG_WRONG_TYPE_ERR", - "SVG_ZOOMANDPAN_DISABLE", - "SVG_ZOOMANDPAN_MAGNIFY", - "SVG_ZOOMANDPAN_UNKNOWN", - "SYNTAX_ERR", - "SavedPages", - "Screen", - "ScreenOrientation", - "Script", - "ScriptProcessorNode", - "ScrollAreaEvent", - "SecurityPolicyViolationEvent", - "Selection", - "ServiceWorker", - "ServiceWorkerContainer", - "ServiceWorkerRegistration", - "SessionDescription", - "Set", - "ShadowRoot", - "SharedWorker", - "SimpleGestureEvent", - "SpeechSynthesisEvent", - "SpeechSynthesisUtterance", - "StopIteration", - "Storage", - "StorageEvent", - "String", - "StyleSheet", - "StyleSheetList", - "SubtleCrypto", - "Symbol", - "SyntaxError", - "TEMPORARY", - "TEXTPATH_METHODTYPE_ALIGN", - "TEXTPATH_METHODTYPE_STRETCH", - "TEXTPATH_METHODTYPE_UNKNOWN", - "TEXTPATH_SPACINGTYPE_AUTO", - "TEXTPATH_SPACINGTYPE_EXACT", - "TEXTPATH_SPACINGTYPE_UNKNOWN", - "TEXTURE", - "TEXTURE0", - "TEXTURE1", - "TEXTURE10", - "TEXTURE11", - "TEXTURE12", - "TEXTURE13", - "TEXTURE14", - "TEXTURE15", - "TEXTURE16", - "TEXTURE17", - "TEXTURE18", - "TEXTURE19", - "TEXTURE2", - "TEXTURE20", - "TEXTURE21", - "TEXTURE22", - "TEXTURE23", - "TEXTURE24", - "TEXTURE25", - "TEXTURE26", - "TEXTURE27", - "TEXTURE28", - "TEXTURE29", - "TEXTURE3", - "TEXTURE30", - "TEXTURE31", - "TEXTURE4", - "TEXTURE5", - "TEXTURE6", - "TEXTURE7", - "TEXTURE8", - "TEXTURE9", - "TEXTURE_2D", - "TEXTURE_BINDING_2D", - "TEXTURE_BINDING_CUBE_MAP", - "TEXTURE_CUBE_MAP", - "TEXTURE_CUBE_MAP_NEGATIVE_X", - "TEXTURE_CUBE_MAP_NEGATIVE_Y", - "TEXTURE_CUBE_MAP_NEGATIVE_Z", - "TEXTURE_CUBE_MAP_POSITIVE_X", - "TEXTURE_CUBE_MAP_POSITIVE_Y", - "TEXTURE_CUBE_MAP_POSITIVE_Z", - "TEXTURE_MAG_FILTER", - "TEXTURE_MAX_ANISOTROPY_EXT", - "TEXTURE_MIN_FILTER", - "TEXTURE_WRAP_S", - "TEXTURE_WRAP_T", - "TEXT_NODE", - "TIMEOUT", - "TIMEOUT_ERR", - "TOO_LARGE_ERR", - "TRANSACTION_INACTIVE_ERR", - "TRIANGLE", - "TRIANGLES", - "TRIANGLE_FAN", - "TRIANGLE_STRIP", - "TYPE_BACK_FORWARD", - "TYPE_ERR", - "TYPE_MISMATCH_ERR", - "TYPE_NAVIGATE", - "TYPE_RELOAD", - "TYPE_RESERVED", - "Text", - "TextDecoder", - "TextEncoder", - "TextEvent", - "TextMetrics", - "TextTrack", - "TextTrackCue", - "TextTrackCueList", - "TextTrackList", - "TimeEvent", - "TimeRanges", - "Touch", - "TouchEvent", - "TouchList", - "TrackEvent", - "TransitionEvent", - "TreeWalker", - "TypeError", - "UIEvent", - "UNCACHED", - "UNKNOWN_ERR", - "UNKNOWN_RULE", - "UNMASKED_RENDERER_WEBGL", - "UNMASKED_VENDOR_WEBGL", - "UNORDERED_NODE_ITERATOR_TYPE", - "UNORDERED_NODE_SNAPSHOT_TYPE", - "UNPACK_ALIGNMENT", - "UNPACK_COLORSPACE_CONVERSION_WEBGL", - "UNPACK_FLIP_Y_WEBGL", - "UNPACK_PREMULTIPLY_ALPHA_WEBGL", - "UNSCHEDULED_STATE", - "UNSENT", - "UNSIGNED_BYTE", - "UNSIGNED_INT", - "UNSIGNED_SHORT", - "UNSIGNED_SHORT_4_4_4_4", - "UNSIGNED_SHORT_5_5_5_1", - "UNSIGNED_SHORT_5_6_5", - "UNSPECIFIED_EVENT_TYPE_ERR", - "UPDATEREADY", - "URIError", - "URL", - "URLSearchParams", - "URLUnencoded", - "URL_MISMATCH_ERR", - "UTC", - "Uint16Array", - "Uint32Array", - "Uint8Array", - "Uint8ClampedArray", - "UserMessageHandler", - "UserMessageHandlersNamespace", - "UserProximityEvent", - "VALIDATE_STATUS", - "VALIDATION_ERR", - "VARIABLES_RULE", - "VENDOR", - "VERSION", - "VERSION_CHANGE", - "VERSION_ERR", - "VERTEX_ATTRIB_ARRAY_BUFFER_BINDING", - "VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE", - "VERTEX_ATTRIB_ARRAY_ENABLED", - "VERTEX_ATTRIB_ARRAY_NORMALIZED", - "VERTEX_ATTRIB_ARRAY_POINTER", - "VERTEX_ATTRIB_ARRAY_SIZE", - "VERTEX_ATTRIB_ARRAY_STRIDE", - "VERTEX_ATTRIB_ARRAY_TYPE", - "VERTEX_SHADER", - "VERTICAL", - "VERTICAL_AXIS", - "VER_ERR", - "VIEWPORT", - "VIEWPORT_RULE", - "VTTCue", - "VTTRegion", - "ValidityState", - "VideoStreamTrack", - "WEBKIT_FILTER_RULE", - "WEBKIT_KEYFRAMES_RULE", - "WEBKIT_KEYFRAME_RULE", - "WEBKIT_REGION_RULE", - "WRONG_DOCUMENT_ERR", - "WaveShaperNode", - "WeakMap", - "WeakSet", - "WebGLActiveInfo", - "WebGLBuffer", - "WebGLContextEvent", - "WebGLFramebuffer", - "WebGLProgram", - "WebGLRenderbuffer", - "WebGLRenderingContext", - "WebGLShader", - "WebGLShaderPrecisionFormat", - "WebGLTexture", - "WebGLUniformLocation", - "WebGLVertexArray", - "WebKitAnimationEvent", - "WebKitBlobBuilder", - "WebKitCSSFilterRule", - "WebKitCSSFilterValue", - "WebKitCSSKeyframeRule", - "WebKitCSSKeyframesRule", - "WebKitCSSMatrix", - "WebKitCSSRegionRule", - "WebKitCSSTransformValue", - "WebKitDataCue", - "WebKitGamepad", - "WebKitMediaKeyError", - "WebKitMediaKeyMessageEvent", - "WebKitMediaKeySession", - "WebKitMediaKeys", - "WebKitMediaSource", - "WebKitMutationObserver", - "WebKitNamespace", - "WebKitPlaybackTargetAvailabilityEvent", - "WebKitPoint", - "WebKitShadowRoot", - "WebKitSourceBuffer", - "WebKitSourceBufferList", - "WebKitTransitionEvent", - "WebSocket", - "WheelEvent", - "Window", - "Worker", - "XMLDocument", - "XMLHttpRequest", - "XMLHttpRequestEventTarget", - "XMLHttpRequestException", - "XMLHttpRequestProgressEvent", - "XMLHttpRequestUpload", - "XMLSerializer", - "XMLStylesheetProcessingInstruction", - "XPathEvaluator", - "XPathException", - "XPathExpression", - "XPathNSResolver", - "XPathResult", - "XSLTProcessor", - "ZERO", - "_XD0M_", - "_YD0M_", - "__defineGetter__", - "__defineSetter__", - "__lookupGetter__", - "__lookupSetter__", - "__opera", - "__proto__", - "_browserjsran", - "a", - "aLink", - "abbr", - "abort", - "abs", - "absolute", - "acceleration", - "accelerationIncludingGravity", - "accelerator", - "accept", - "acceptCharset", - "acceptNode", - "accessKey", - "accessKeyLabel", - "accuracy", - "acos", - "acosh", - "action", - "actionURL", - "active", - "activeCues", - "activeElement", - "activeSourceBuffers", - "activeSourceCount", - "activeTexture", - "add", - "addBehavior", - "addCandidate", - "addColorStop", - "addCue", - "addElement", - "addEventListener", - "addFilter", - "addFromString", - "addFromUri", - "addIceCandidate", - "addImport", - "addListener", - "addNamed", - "addPageRule", - "addPath", - "addPointer", - "addRange", - "addRegion", - "addRule", - "addSearchEngine", - "addSourceBuffer", - "addStream", - "addTextTrack", - "addTrack", - "addWakeLockListener", - "addedNodes", - "additionalName", - "additiveSymbols", - "addons", - "adoptNode", - "adr", - "advance", - "alert", - "algorithm", - "align", - "align-content", - "align-items", - "align-self", - "alignContent", - "alignItems", - "alignSelf", - "alignmentBaseline", - "alinkColor", - "all", - "allowFullscreen", - "allowedDirections", - "alpha", - "alt", - "altGraphKey", - "altHtml", - "altKey", - "altLeft", - "altitude", - "altitudeAccuracy", - "amplitude", - "ancestorOrigins", - "anchor", - "anchorNode", - "anchorOffset", - "anchors", - "angle", - "animVal", - "animate", - "animatedInstanceRoot", - "animatedNormalizedPathSegList", - "animatedPathSegList", - "animatedPoints", - "animation", - "animation-delay", - "animation-direction", - "animation-duration", - "animation-fill-mode", - "animation-iteration-count", - "animation-name", - "animation-play-state", - "animation-timing-function", - "animationDelay", - "animationDirection", - "animationDuration", - "animationFillMode", - "animationIterationCount", - "animationName", - "animationPlayState", - "animationStartTime", - "animationTimingFunction", - "animationsPaused", - "anniversary", - "app", - "appCodeName", - "appMinorVersion", - "appName", - "appNotifications", - "appVersion", - "append", - "appendBuffer", - "appendChild", - "appendData", - "appendItem", - "appendMedium", - "appendNamed", - "appendRule", - "appendStream", - "appendWindowEnd", - "appendWindowStart", - "applets", - "applicationCache", - "apply", - "applyElement", - "arc", - "arcTo", - "archive", - "areas", - "arguments", - "arrayBuffer", - "asin", - "asinh", - "assert", - "assign", - "async", - "atEnd", - "atan", - "atan2", - "atanh", - "atob", - "attachEvent", - "attachShader", - "attachments", - "attack", - "attrChange", - "attrName", - "attributeFilter", - "attributeName", - "attributeNamespace", - "attributeOldValue", - "attributes", - "audioTracks", - "autoIncrement", - "autobuffer", - "autocapitalize", - "autocomplete", - "autocorrect", - "autofocus", - "autoplay", - "availHeight", - "availLeft", - "availTop", - "availWidth", - "availability", - "available", - "aversion", - "axes", - "axis", - "azimuth", - "b", - "back", - "backface-visibility", - "backfaceVisibility", - "background", - "background-attachment", - "background-blend-mode", - "background-clip", - "background-color", - "background-image", - "background-origin", - "background-position", - "background-repeat", - "background-size", - "backgroundAttachment", - "backgroundBlendMode", - "backgroundClip", - "backgroundColor", - "backgroundImage", - "backgroundOrigin", - "backgroundPosition", - "backgroundPositionX", - "backgroundPositionY", - "backgroundRepeat", - "backgroundSize", - "badInput", - "balance", - "baseFrequencyX", - "baseFrequencyY", - "baseNode", - "baseOffset", - "baseURI", - "baseVal", - "baselineShift", - "battery", - "bday", - "beginElement", - "beginElementAt", - "beginPath", - "behavior", - "behaviorCookie", - "behaviorPart", - "behaviorUrns", - "beta", - "bezierCurveTo", - "bgColor", - "bgProperties", - "bias", - "big", - "binaryType", - "bind", - "bindAttribLocation", - "bindBuffer", - "bindFramebuffer", - "bindRenderbuffer", - "bindTexture", - "blendColor", - "blendEquation", - "blendEquationSeparate", - "blendFunc", - "blendFuncSeparate", - "blink", - "blob", - "blockDirection", - "blue", - "blur", - "body", - "bodyUsed", - "bold", - "bookmarks", - "booleanValue", - "border", - "border-bottom", - "border-bottom-color", - "border-bottom-left-radius", - "border-bottom-right-radius", - "border-bottom-style", - "border-bottom-width", - "border-collapse", - "border-color", - "border-image", - "border-image-outset", - "border-image-repeat", - "border-image-slice", - "border-image-source", - "border-image-width", - "border-left", - "border-left-color", - "border-left-style", - "border-left-width", - "border-radius", - "border-right", - "border-right-color", - "border-right-style", - "border-right-width", - "border-spacing", - "border-style", - "border-top", - "border-top-color", - "border-top-left-radius", - "border-top-right-radius", - "border-top-style", - "border-top-width", - "border-width", - "borderBottom", - "borderBottomColor", - "borderBottomLeftRadius", - "borderBottomRightRadius", - "borderBottomStyle", - "borderBottomWidth", - "borderCollapse", - "borderColor", - "borderColorDark", - "borderColorLight", - "borderImage", - "borderImageOutset", - "borderImageRepeat", - "borderImageSlice", - "borderImageSource", - "borderImageWidth", - "borderLeft", - "borderLeftColor", - "borderLeftStyle", - "borderLeftWidth", - "borderRadius", - "borderRight", - "borderRightColor", - "borderRightStyle", - "borderRightWidth", - "borderSpacing", - "borderStyle", - "borderTop", - "borderTopColor", - "borderTopLeftRadius", - "borderTopRightRadius", - "borderTopStyle", - "borderTopWidth", - "borderWidth", - "bottom", - "bottomMargin", - "bound", - "boundElements", - "boundingClientRect", - "boundingHeight", - "boundingLeft", - "boundingTop", - "boundingWidth", - "bounds", - "box-decoration-break", - "box-shadow", - "box-sizing", - "boxDecorationBreak", - "boxShadow", - "boxSizing", - "breakAfter", - "breakBefore", - "breakInside", - "browserLanguage", - "btoa", - "bubbles", - "buffer", - "bufferData", - "bufferDepth", - "bufferSize", - "bufferSubData", - "buffered", - "bufferedAmount", - "buildID", - "buildNumber", - "button", - "buttonID", - "buttons", - "byteLength", - "byteOffset", - "c", - "call", - "caller", - "canBeFormatted", - "canBeMounted", - "canBeShared", - "canHaveChildren", - "canHaveHTML", - "canPlayType", - "cancel", - "cancelAnimationFrame", - "cancelBubble", - "cancelScheduledValues", - "cancelable", - "candidate", - "canvas", - "caption", - "caption-side", - "captionSide", - "captureEvents", - "captureStackTrace", - "caretPositionFromPoint", - "caretRangeFromPoint", - "cast", - "catch", - "category", - "cbrt", - "cd", - "ceil", - "cellIndex", - "cellPadding", - "cellSpacing", - "cells", - "ch", - "chOff", - "chain", - "challenge", - "changedTouches", - "channel", - "channelCount", - "channelCountMode", - "channelInterpretation", - "char", - "charAt", - "charCode", - "charCodeAt", - "charIndex", - "characterSet", - "characterData", - "characterDataOldValue", - "charging", - "chargingTime", - "charset", - "checkEnclosure", - "checkFramebufferStatus", - "checkIntersection", - "checkValidity", - "checked", - "childElementCount", - "childList", - "childNodes", - "children", - "chrome", - "ciphertext", - "cite", - "classList", - "className", - "classid", - "clear", - "clearAttributes", - "clearColor", - "clearData", - "clearDepth", - "clearImmediate", - "clearInterval", - "clearMarks", - "clearMeasures", - "clearParameters", - "clearRect", - "clearResourceTimings", - "clearShadow", - "clearStencil", - "clearTimeout", - "clearWatch", - "click", - "clickCount", - "clientHeight", - "clientInformation", - "clientLeft", - "clientRect", - "clientRects", - "clientTop", - "clientWidth", - "clientX", - "clientY", - "clip", - "clip-path", - "clip-rule", - "clipBottom", - "clipLeft", - "clipPath", - "clipPathUnits", - "clipRight", - "clipRule", - "clipTop", - "clipboardData", - "clone", - "cloneContents", - "cloneNode", - "cloneRange", - "close", - "closePath", - "closed", - "closest", - "clz", - "clz32", - "cmp", - "code", - "codeBase", - "codePointAt", - "codeType", - "colSpan", - "collapse", - "collapseToEnd", - "collapseToStart", - "collapsed", - "collect", - "colno", - "color", - "color-interpolation", - "color-interpolation-filters", - "colorDepth", - "colorInterpolation", - "colorInterpolationFilters", - "colorMask", - "colorType", - "cols", - "columnCount", - "columnFill", - "columnGap", - "columnNumber", - "columnRule", - "columnRuleColor", - "columnRuleStyle", - "columnRuleWidth", - "columnSpan", - "columnWidth", - "columns", - "command", - "commitPreferences", - "commonAncestorContainer", - "compact", - "compareBoundaryPoints", - "compareDocumentPosition", - "compareEndPoints", - "compareNode", - "comparePoint", - "compatMode", - "compatible", - "compile", - "compileShader", - "complete", - "componentFromPoint", - "compositionEndOffset", - "compositionStartOffset", - "compressedTexImage2D", - "compressedTexSubImage2D", - "concat", - "conditionText", - "coneInnerAngle", - "coneOuterAngle", - "coneOuterGain", - "confirm", - "confirmComposition", - "confirmSiteSpecificTrackingException", - "confirmWebWideTrackingException", - "connect", - "connectEnd", - "connectStart", - "connected", - "connection", - "connectionSpeed", - "console", - "consolidate", - "constrictionActive", - "constructor", - "contactID", - "contains", - "containsNode", - "content", - "contentDocument", - "contentEditable", - "contentOverflow", - "contentScriptType", - "contentStyleType", - "contentType", - "contentWindow", - "context", - "contextMenu", - "contextmenu", - "continue", - "continuous", - "control", - "controller", - "controls", - "convertToSpecifiedUnits", - "cookie", - "cookieEnabled", - "coords", - "copyFromChannel", - "copyTexImage2D", - "copyTexSubImage2D", - "copyToChannel", - "copyWithin", - "correspondingElement", - "correspondingUseElement", - "cos", - "cosh", - "count", - "counter-increment", - "counter-reset", - "counterIncrement", - "counterReset", - "cpuClass", - "cpuSleepAllowed", - "create", - "createAnalyser", - "createAnswer", - "createAttribute", - "createAttributeNS", - "createBiquadFilter", - "createBuffer", - "createBufferSource", - "createCDATASection", - "createCSSStyleSheet", - "createCaption", - "createChannelMerger", - "createChannelSplitter", - "createComment", - "createContextualFragment", - "createControlRange", - "createConvolver", - "createDTMFSender", - "createDataChannel", - "createDelay", - "createDelayNode", - "createDocument", - "createDocumentFragment", - "createDocumentType", - "createDynamicsCompressor", - "createElement", - "createElementNS", - "createEntityReference", - "createEvent", - "createEventObject", - "createExpression", - "createFramebuffer", - "createFunction", - "createGain", - "createGainNode", - "createHTMLDocument", - "createImageBitmap", - "createImageData", - "createIndex", - "createJavaScriptNode", - "createLinearGradient", - "createMediaElementSource", - "createMediaKeys", - "createMediaStreamDestination", - "createMediaStreamSource", - "createMutableFile", - "createNSResolver", - "createNodeIterator", - "createNotification", - "createObjectStore", - "createObjectURL", - "createOffer", - "createOscillator", - "createPanner", - "createPattern", - "createPeriodicWave", - "createPopup", - "createProcessingInstruction", - "createProgram", - "createRadialGradient", - "createRange", - "createRangeCollection", - "createRenderbuffer", - "createSVGAngle", - "createSVGLength", - "createSVGMatrix", - "createSVGNumber", - "createSVGPathSegArcAbs", - "createSVGPathSegArcRel", - "createSVGPathSegClosePath", - "createSVGPathSegCurvetoCubicAbs", - "createSVGPathSegCurvetoCubicRel", - "createSVGPathSegCurvetoCubicSmoothAbs", - "createSVGPathSegCurvetoCubicSmoothRel", - "createSVGPathSegCurvetoQuadraticAbs", - "createSVGPathSegCurvetoQuadraticRel", - "createSVGPathSegCurvetoQuadraticSmoothAbs", - "createSVGPathSegCurvetoQuadraticSmoothRel", - "createSVGPathSegLinetoAbs", - "createSVGPathSegLinetoHorizontalAbs", - "createSVGPathSegLinetoHorizontalRel", - "createSVGPathSegLinetoRel", - "createSVGPathSegLinetoVerticalAbs", - "createSVGPathSegLinetoVerticalRel", - "createSVGPathSegMovetoAbs", - "createSVGPathSegMovetoRel", - "createSVGPoint", - "createSVGRect", - "createSVGTransform", - "createSVGTransformFromMatrix", - "createScriptProcessor", - "createSession", - "createShader", - "createShadowRoot", - "createStereoPanner", - "createStyleSheet", - "createTBody", - "createTFoot", - "createTHead", - "createTextNode", - "createTextRange", - "createTexture", - "createTouch", - "createTouchList", - "createTreeWalker", - "createWaveShaper", - "creationTime", - "crossOrigin", - "crypto", - "csi", - "cssFloat", - "cssRules", - "cssText", - "cssValueType", - "ctrlKey", - "ctrlLeft", - "cues", - "cullFace", - "currentNode", - "currentPage", - "currentScale", - "currentScript", - "currentSrc", - "currentState", - "currentStyle", - "currentTarget", - "currentTime", - "currentTranslate", - "currentView", - "cursor", - "curve", - "customError", - "cx", - "cy", - "d", - "data", - "dataFld", - "dataFormatAs", - "dataPageSize", - "dataSrc", - "dataTransfer", - "database", - "dataset", - "dateTime", - "db", - "debug", - "debuggerEnabled", - "declare", - "decode", - "decodeAudioData", - "decodingInfo", - "decodeURI", - "decodeURIComponent", - "decrypt", - "default", - "defaultCharset", - "defaultChecked", - "defaultMuted", - "defaultPlaybackRate", - "defaultPrevented", - "defaultSelected", - "defaultStatus", - "defaultURL", - "defaultValue", - "defaultView", - "defaultstatus", - "defer", - "defineMagicFunction", - "defineMagicVariable", - "defineProperties", - "defineProperty", - "delayTime", - "delete", - "deleteBuffer", - "deleteCaption", - "deleteCell", - "deleteContents", - "deleteData", - "deleteDatabase", - "deleteFramebuffer", - "deleteFromDocument", - "deleteIndex", - "deleteMedium", - "deleteObjectStore", - "deleteProgram", - "deleteRenderbuffer", - "deleteRow", - "deleteRule", - "deleteShader", - "deleteTFoot", - "deleteTHead", - "deleteTexture", - "deliverChangeRecords", - "delivery", - "deliveryInfo", - "deliveryStatus", - "deliveryTimestamp", - "delta", - "deltaMode", - "deltaX", - "deltaY", - "deltaZ", - "depthFunc", - "depthMask", - "depthRange", - "deriveBits", - "deriveKey", - "description", - "deselectAll", - "designMode", - "destination", - "destinationURL", - "detach", - "detachEvent", - "detachShader", - "detail", - "detune", - "devicePixelRatio", - "deviceXDPI", - "deviceYDPI", - "diffuseConstant", - "digest", - "dimensions", - "dir", - "dirName", - "direction", - "dirxml", - "disable", - "disableVertexAttribArray", - "disabled", - "dischargingTime", - "disconnect", - "dispatchEvent", - "display", - "distanceModel", - "divisor", - "djsapi", - "djsproxy", - "doImport", - "doNotTrack", - "doScroll", - "doctype", - "document", - "documentElement", - "documentMode", - "documentURI", - "dolphin", - "dolphinGameCenter", - "dolphininfo", - "dolphinmeta", - "domComplete", - "domContentLoadedEventEnd", - "domContentLoadedEventStart", - "domInteractive", - "domLoading", - "domain", - "domainLookupEnd", - "domainLookupStart", - "dominant-baseline", - "dominantBaseline", - "done", - "dopplerFactor", - "download", - "dragDrop", - "draggable", - "drawArrays", - "drawArraysInstancedANGLE", - "drawCustomFocusRing", - "drawElements", - "drawElementsInstancedANGLE", - "drawFocusIfNeeded", - "drawImage", - "drawImageFromRect", - "drawSystemFocusRing", - "drawingBufferHeight", - "drawingBufferWidth", - "dropEffect", - "droppedVideoFrames", - "dropzone", - "dump", - "duplicate", - "duration", - "dvname", - "dvnum", - "dx", - "dy", - "dynsrc", - "e", - "edgeMode", - "effectAllowed", - "elapsedTime", - "elementFromPoint", - "elements", - "elevation", - "ellipse", - "email", - "embeds", - "empty", - "empty-cells", - "emptyCells", - "enable", - "enableBackground", - "enableStyleSheetsForSet", - "enableVertexAttribArray", - "enabled", - "enabledPlugin", - "encode", - "encodeURI", - "encodeURIComponent", - "encoding", - "encrypt", - "enctype", - "end", - "endContainer", - "endElement", - "endElementAt", - "endOfStream", - "endOffset", - "endTime", - "ended", - "endsWith", - "entities", - "entries", - "entryType", - "enumerate", - "enumerateEditable", - "error", - "errorCode", - "escape", - "eval", - "evaluate", - "event", - "eventPhase", - "every", - "exception", - "exec", - "execCommand", - "execCommandShowHelp", - "execScript", - "exitFullscreen", - "exitPointerLock", - "exp", - "expand", - "expandEntityReferences", - "expando", - "expansion", - "expiryDate", - "explicitOriginalTarget", - "expm1", - "exponent", - "exponentialRampToValueAtTime", - "exportKey", - "extend", - "extensions", - "extentNode", - "extentOffset", - "external", - "externalResourcesRequired", - "extractContents", - "extractable", - "f", - "face", - "factoryReset", - "fallback", - "familyName", - "farthestViewportElement", - "fastSeek", - "fatal", - "fetch", - "fetchStart", - "fftSize", - "fgColor", - "fileCreatedDate", - "fileHandle", - "fileModifiedDate", - "fileName", - "fileSize", - "fileUpdatedDate", - "filename", - "files", - "fill", - "fill-opacity", - "fill-rule", - "fillOpacity", - "fillRect", - "fillRule", - "fillStyle", - "fillText", - "filter", - "filterResX", - "filterResY", - "filterUnits", - "filters", - "finally", - "find", - "findIndex", - "findRule", - "findText", - "finish", - "fireEvent", - "firstChild", - "firstElementChild", - "firstPage", - "fixed", - "flex", - "flex-basis", - "flex-direction", - "flex-flow", - "flex-grow", - "flex-shrink", - "flex-wrap", - "flexBasis", - "flexDirection", - "flexFlow", - "flexGrow", - "flexShrink", - "flexWrap", - "flipX", - "flipY", - "float", - "flood-color", - "flood-opacity", - "floodColor", - "floodOpacity", - "floor", - "flush", - "focus", - "focusNode", - "focusOffset", - "font", - "font-family", - "font-feature-settings", - "font-kerning", - "font-language-override", - "font-size", - "font-size-adjust", - "font-stretch", - "font-style", - "font-synthesis", - "font-variant", - "font-variant-alternates", - "font-variant-caps", - "font-variant-east-asian", - "font-variant-ligatures", - "font-variant-numeric", - "font-variant-position", - "font-weight", - "fontFamily", - "fontFeatureSettings", - "fontKerning", - "fontLanguageOverride", - "fontSize", - "fontSizeAdjust", - "fontSmoothingEnabled", - "fontStretch", - "fontStyle", - "fontSynthesis", - "fontVariant", - "fontVariantAlternates", - "fontVariantCaps", - "fontVariantEastAsian", - "fontVariantLigatures", - "fontVariantNumeric", - "fontVariantPosition", - "fontWeight", - "fontcolor", - "fonts", - "fontsize", - "for", - "forEach", - "forceRedraw", - "form", - "formAction", - "formEnctype", - "formMethod", - "formNoValidate", - "formTarget", - "format", - "forms", - "forward", - "fr", - "frame", - "frameBorder", - "frameElement", - "frameSpacing", - "framebufferRenderbuffer", - "framebufferTexture2D", - "frames", - "freeSpace", - "freeze", - "frequency", - "frequencyBinCount", - "from", - "fromCharCode", - "fromCodePoint", - "fromElement", - "frontFace", - "fround", - "fullScreen", - "fullscreenElement", - "fullscreenEnabled", - "fx", - "fy", - "gain", - "gamepad", - "gamma", - "genderIdentity", - "generateKey", - "generateMipmap", - "generateRequest", - "geolocation", - "gestureObject", - "get", - "getActiveAttrib", - "getActiveUniform", - "getAdjacentText", - "getAll", - "getAllResponseHeaders", - "getAsFile", - "getAsString", - "getAttachedShaders", - "getAttribLocation", - "getAttribute", - "getAttributeNS", - "getAttributeNode", - "getAttributeNodeNS", - "getAudioTracks", - "getBBox", - "getBattery", - "getBlob", - "getBookmark", - "getBoundingClientRect", - "getBufferParameter", - "getByteFrequencyData", - "getByteTimeDomainData", - "getCSSCanvasContext", - "getCTM", - "getCandidateWindowClientRect", - "getChannelData", - "getCharNumAtPosition", - "getClientRect", - "getClientRects", - "getCompositionAlternatives", - "getComputedStyle", - "getComputedTextLength", - "getConfiguration", - "getContext", - "getContextAttributes", - "getCounterValue", - "getCueAsHTML", - "getCueById", - "getCurrentPosition", - "getCurrentTime", - "getData", - "getDatabaseNames", - "getDate", - "getDay", - "getDefaultComputedStyle", - "getDestinationInsertionPoints", - "getDistributedNodes", - "getEditable", - "getElementById", - "getElementsByClassName", - "getElementsByName", - "getElementsByTagName", - "getElementsByTagNameNS", - "getEnclosureList", - "getEndPositionOfChar", - "getEntries", - "getEntriesByName", - "getEntriesByType", - "getError", - "getExtension", - "getExtentOfChar", - "getFeature", - "getFile", - "getFloat32", - "getFloat64", - "getFloatFrequencyData", - "getFloatTimeDomainData", - "getFloatValue", - "getFramebufferAttachmentParameter", - "getFrequencyResponse", - "getFullYear", - "getGamepads", - "getHours", - "getImageData", - "getInt16", - "getInt32", - "getInt8", - "getIntersectionList", - "getItem", - "getItems", - "getKey", - "getLineDash", - "getLocalStreams", - "getMarks", - "getMatchedCSSRules", - "getMeasures", - "getMetadata", - "getMilliseconds", - "getMinutes", - "getModifierState", - "getMonth", - "getNamedItem", - "getNamedItemNS", - "getNotifier", - "getNumberOfChars", - "getOverrideHistoryNavigationMode", - "getOverrideStyle", - "getOwnPropertyDescriptor", - "getOwnPropertyNames", - "getOwnPropertySymbols", - "getParameter", - "getPathSegAtLength", - "getPointAtLength", - "getPreference", - "getPreferenceDefault", - "getPresentationAttribute", - "getPreventDefault", - "getProgramInfoLog", - "getProgramParameter", - "getPropertyCSSValue", - "getPropertyPriority", - "getPropertyShorthand", - "getPropertyValue", - "getPrototypeOf", - "getRGBColorValue", - "getRandomValues", - "getRangeAt", - "getReceivers", - "getRectValue", - "getRegistration", - "getRemoteStreams", - "getRenderbufferParameter", - "getResponseHeader", - "getRoot", - "getRotationOfChar", - "getSVGDocument", - "getScreenCTM", - "getSeconds", - "getSelection", - "getSenders", - "getShaderInfoLog", - "getShaderParameter", - "getShaderPrecisionFormat", - "getShaderSource", - "getSimpleDuration", - "getSiteIcons", - "getSources", - "getSpeculativeParserUrls", - "getStartPositionOfChar", - "getStartTime", - "getStats", - "getStorageUpdates", - "getStreamById", - "getStringValue", - "getSubStringLength", - "getSubscription", - "getSupportedExtensions", - "getTexParameter", - "getTime", - "getTimezoneOffset", - "getTotalLength", - "getTrackById", - "getTracks", - "getTransformToElement", - "getUTCDate", - "getUTCDay", - "getUTCFullYear", - "getUTCHours", - "getUTCMilliseconds", - "getUTCMinutes", - "getUTCMonth", - "getUTCSeconds", - "getUint16", - "getUint32", - "getUint8", - "getUniform", - "getUniformLocation", - "getUserMedia", - "getValues", - "getVarDate", - "getVariableValue", - "getVertexAttrib", - "getVertexAttribOffset", - "getVideoPlaybackQuality", - "getVideoTracks", - "getWakeLockState", - "getYear", - "givenName", - "global", - "globalAlpha", - "globalCompositeOperation", - "glyphOrientationHorizontal", - "glyphOrientationVertical", - "glyphRef", - "go", - "gradientTransform", - "gradientUnits", - "grammars", - "green", - "group", - "groupCollapsed", - "groupEnd", - "hardwareConcurrency", - "has", - "hasAttribute", - "hasAttributeNS", - "hasAttributes", - "hasChildNodes", - "hasComposition", - "hasExtension", - "hasFeature", - "hasFocus", - "hasLayout", - "hasOwnProperty", - "hash", - "head", - "headers", - "heading", - "height", - "hidden", - "hide", - "hideFocus", - "high", - "hint", - "history", - "honorificPrefix", - "honorificSuffix", - "horizontalOverflow", - "host", - "hostname", - "href", - "hreflang", - "hspace", - "html5TagCheckInerface", - "htmlFor", - "htmlText", - "httpEquiv", - "hwTimestamp", - "hypot", - "iccId", - "iceConnectionState", - "iceGatheringState", - "icon", - "id", - "identifier", - "identity", - "ignoreBOM", - "ignoreCase", - "image-orientation", - "image-rendering", - "imageOrientation", - "imageRendering", - "images", - "ime-mode", - "imeMode", - "implementation", - "importKey", - "importNode", - "importStylesheet", - "imports", - "impp", - "imul", - "in1", - "in2", - "inBandMetadataTrackDispatchType", - "inRange", - "includes", - "incremental", - "indeterminate", - "index", - "indexNames", - "indexOf", - "indexedDB", - "inertiaDestinationX", - "inertiaDestinationY", - "info", - "init", - "initAnimationEvent", - "initBeforeLoadEvent", - "initClipboardEvent", - "initCloseEvent", - "initCommandEvent", - "initCompositionEvent", - "initCustomEvent", - "initData", - "initDeviceMotionEvent", - "initDeviceOrientationEvent", - "initDragEvent", - "initErrorEvent", - "initEvent", - "initFocusEvent", - "initGestureEvent", - "initHashChangeEvent", - "initKeyEvent", - "initKeyboardEvent", - "initMSManipulationEvent", - "initMessageEvent", - "initMouseEvent", - "initMouseScrollEvent", - "initMouseWheelEvent", - "initMutationEvent", - "initNSMouseEvent", - "initOverflowEvent", - "initPageEvent", - "initPageTransitionEvent", - "initPointerEvent", - "initPopStateEvent", - "initProgressEvent", - "initScrollAreaEvent", - "initSimpleGestureEvent", - "initStorageEvent", - "initTextEvent", - "initTimeEvent", - "initTouchEvent", - "initTransitionEvent", - "initUIEvent", - "initWebKitAnimationEvent", - "initWebKitTransitionEvent", - "initWebKitWheelEvent", - "initWheelEvent", - "initialTime", - "initialize", - "initiatorType", - "inner", - "innerHTML", - "innerHeight", - "innerText", - "innerWidth", - "input", - "inputBuffer", - "inputEncoding", - "inputMethod", - "insertAdjacentElement", - "insertAdjacentHTML", - "insertAdjacentText", - "insertBefore", - "insertCell", - "insertData", - "insertItemBefore", - "insertNode", - "insertRow", - "insertRule", - "instanceRoot", - "intercept", - "interimResults", - "internalSubset", - "intersectsNode", - "interval", - "invalidIteratorState", - "inverse", - "invertSelf", - "is", - "is2D", - "isAlternate", - "isArray", - "isBingCurrentSearchDefault", - "isBuffer", - "isCandidateWindowVisible", - "isChar", - "isCollapsed", - "isComposing", - "isContentEditable", - "isContentHandlerRegistered", - "isContextLost", - "isDefaultNamespace", - "isDisabled", - "isEnabled", - "isEqual", - "isEqualNode", - "isExtensible", - "isFinite", - "isFramebuffer", - "isFrozen", - "isGenerator", - "isId", - "isInjected", - "isInteger", - "isMap", - "isMultiLine", - "isNaN", - "isOpen", - "isPointInFill", - "isPointInPath", - "isPointInRange", - "isPointInStroke", - "isPrefAlternate", - "isPrimary", - "isProgram", - "isPropertyImplicit", - "isProtocolHandlerRegistered", - "isPrototypeOf", - "isRenderbuffer", - "isSafeInteger", - "isSameNode", - "isSealed", - "isShader", - "isSupported", - "isTextEdit", - "isTexture", - "isTrusted", - "isTypeSupported", - "isView", - "isolation", - "italics", - "item", - "itemId", - "itemProp", - "itemRef", - "itemScope", - "itemType", - "itemValue", - "iterateNext", - "iterator", - "javaEnabled", - "jobTitle", - "join", - "json", - "justify-content", - "justifyContent", - "k1", - "k2", - "k3", - "k4", - "kernelMatrix", - "kernelUnitLengthX", - "kernelUnitLengthY", - "kerning", - "key", - "keyCode", - "keyFor", - "keyIdentifier", - "keyLightEnabled", - "keyLocation", - "keyPath", - "keySystem", - "keyText", - "keyUsage", - "keys", - "keytype", - "kind", - "knee", - "label", - "labels", - "lang", - "language", - "languages", - "largeArcFlag", - "lastChild", - "lastElementChild", - "lastEventId", - "lastIndex", - "lastIndexOf", - "lastMatch", - "lastMessageSubject", - "lastMessageType", - "lastModified", - "lastModifiedDate", - "lastPage", - "lastParen", - "lastState", - "lastStyleSheetSet", - "latitude", - "layerX", - "layerY", - "layoutFlow", - "layoutGrid", - "layoutGridChar", - "layoutGridLine", - "layoutGridMode", - "layoutGridType", - "lbound", - "left", - "leftContext", - "leftMargin", - "length", - "lengthAdjust", - "lengthComputable", - "letter-spacing", - "letterSpacing", - "level", - "lighting-color", - "lightingColor", - "limitingConeAngle", - "line", - "line-height", - "lineAlign", - "lineBreak", - "lineCap", - "lineDashOffset", - "lineHeight", - "lineJoin", - "lineNumber", - "lineTo", - "lineWidth", - "linearRampToValueAtTime", - "lineno", - "link", - "linkColor", - "linkProgram", - "links", - "list", - "list-style", - "list-style-image", - "list-style-position", - "list-style-type", - "listStyle", - "listStyleImage", - "listStylePosition", - "listStyleType", - "listener", - "load", - "loadEventEnd", - "loadEventStart", - "loadTimes", - "loaded", - "localDescription", - "localName", - "localStorage", - "locale", - "localeCompare", - "location", - "locationbar", - "lock", - "lockedFile", - "log", - "log10", - "log1p", - "log2", - "logicalXDPI", - "logicalYDPI", - "longDesc", - "longitude", - "lookupNamespaceURI", - "lookupPrefix", - "loop", - "loopEnd", - "loopStart", - "looping", - "low", - "lower", - "lowerBound", - "lowerOpen", - "lowsrc", - "m11", - "m12", - "m13", - "m14", - "m21", - "m22", - "m23", - "m24", - "m31", - "m32", - "m33", - "m34", - "m41", - "m42", - "m43", - "m44", - "manifest", - "map", - "mapping", - "margin", - "margin-bottom", - "margin-left", - "margin-right", - "margin-top", - "marginBottom", - "marginHeight", - "marginLeft", - "marginRight", - "marginTop", - "marginWidth", - "mark", - "marker", - "marker-end", - "marker-mid", - "marker-offset", - "marker-start", - "markerEnd", - "markerHeight", - "markerMid", - "markerOffset", - "markerStart", - "markerUnits", - "markerWidth", - "marks", - "mask", - "mask-type", - "maskContentUnits", - "maskType", - "maskUnits", - "match", - "matchMedia", - "matchMedium", - "matches", - "matrix", - "matrixTransform", - "max", - "max-height", - "max-width", - "maxAlternatives", - "maxChannelCount", - "maxConnectionsPerServer", - "maxDecibels", - "maxDistance", - "maxHeight", - "maxLength", - "maxTouchPoints", - "maxValue", - "maxWidth", - "measure", - "measureText", - "media", - "mediaCapabilities", - "mediaDevices", - "mediaElement", - "mediaGroup", - "mediaKeys", - "mediaText", - "meetOrSlice", - "memory", - "menubar", - "mergeAttributes", - "message", - "messageClass", - "messageHandlers", - "metaKey", - "method", - "mimeType", - "mimeTypes", - "min", - "min-height", - "min-width", - "minDecibels", - "minHeight", - "minValue", - "minWidth", - "miterLimit", - "mix-blend-mode", - "mixBlendMode", - "mode", - "modify", - "mount", - "move", - "moveBy", - "moveEnd", - "moveFirst", - "moveFocusDown", - "moveFocusLeft", - "moveFocusRight", - "moveFocusUp", - "moveNext", - "moveRow", - "moveStart", - "moveTo", - "moveToBookmark", - "moveToElementText", - "moveToPoint", - "mozAdd", - "mozAnimationStartTime", - "mozAnon", - "mozApps", - "mozAudioCaptured", - "mozAudioChannelType", - "mozAutoplayEnabled", - "mozCancelAnimationFrame", - "mozCancelFullScreen", - "mozCancelRequestAnimationFrame", - "mozCaptureStream", - "mozCaptureStreamUntilEnded", - "mozClearDataAt", - "mozContact", - "mozContacts", - "mozCreateFileHandle", - "mozCurrentTransform", - "mozCurrentTransformInverse", - "mozCursor", - "mozDash", - "mozDashOffset", - "mozDecodedFrames", - "mozExitPointerLock", - "mozFillRule", - "mozFragmentEnd", - "mozFrameDelay", - "mozFullScreen", - "mozFullScreenElement", - "mozFullScreenEnabled", - "mozGetAll", - "mozGetAllKeys", - "mozGetAsFile", - "mozGetDataAt", - "mozGetMetadata", - "mozGetUserMedia", - "mozHasAudio", - "mozHasItem", - "mozHidden", - "mozImageSmoothingEnabled", - "mozIndexedDB", - "mozInnerScreenX", - "mozInnerScreenY", - "mozInputSource", - "mozIsTextField", - "mozItem", - "mozItemCount", - "mozItems", - "mozLength", - "mozLockOrientation", - "mozMatchesSelector", - "mozMovementX", - "mozMovementY", - "mozOpaque", - "mozOrientation", - "mozPaintCount", - "mozPaintedFrames", - "mozParsedFrames", - "mozPay", - "mozPointerLockElement", - "mozPresentedFrames", - "mozPreservesPitch", - "mozPressure", - "mozPrintCallback", - "mozRTCIceCandidate", - "mozRTCPeerConnection", - "mozRTCSessionDescription", - "mozRemove", - "mozRequestAnimationFrame", - "mozRequestFullScreen", - "mozRequestPointerLock", - "mozSetDataAt", - "mozSetImageElement", - "mozSourceNode", - "mozSrcObject", - "mozSystem", - "mozTCPSocket", - "mozTextStyle", - "mozTypesAt", - "mozUnlockOrientation", - "mozUserCancelled", - "mozVisibilityState", - "msAnimation", - "msAnimationDelay", - "msAnimationDirection", - "msAnimationDuration", - "msAnimationFillMode", - "msAnimationIterationCount", - "msAnimationName", - "msAnimationPlayState", - "msAnimationStartTime", - "msAnimationTimingFunction", - "msBackfaceVisibility", - "msBlockProgression", - "msCSSOMElementFloatMetrics", - "msCaching", - "msCachingEnabled", - "msCancelRequestAnimationFrame", - "msCapsLockWarningOff", - "msClearImmediate", - "msClose", - "msContentZoomChaining", - "msContentZoomFactor", - "msContentZoomLimit", - "msContentZoomLimitMax", - "msContentZoomLimitMin", - "msContentZoomSnap", - "msContentZoomSnapPoints", - "msContentZoomSnapType", - "msContentZooming", - "msConvertURL", - "msCrypto", - "msDoNotTrack", - "msElementsFromPoint", - "msElementsFromRect", - "msExitFullscreen", - "msExtendedCode", - "msFillRule", - "msFirstPaint", - "msFlex", - "msFlexAlign", - "msFlexDirection", - "msFlexFlow", - "msFlexItemAlign", - "msFlexLinePack", - "msFlexNegative", - "msFlexOrder", - "msFlexPack", - "msFlexPositive", - "msFlexPreferredSize", - "msFlexWrap", - "msFlowFrom", - "msFlowInto", - "msFontFeatureSettings", - "msFullscreenElement", - "msFullscreenEnabled", - "msGetInputContext", - "msGetRegionContent", - "msGetUntransformedBounds", - "msGraphicsTrustStatus", - "msGridColumn", - "msGridColumnAlign", - "msGridColumnSpan", - "msGridColumns", - "msGridRow", - "msGridRowAlign", - "msGridRowSpan", - "msGridRows", - "msHidden", - "msHighContrastAdjust", - "msHyphenateLimitChars", - "msHyphenateLimitLines", - "msHyphenateLimitZone", - "msHyphens", - "msImageSmoothingEnabled", - "msImeAlign", - "msIndexedDB", - "msInterpolationMode", - "msIsStaticHTML", - "msKeySystem", - "msKeys", - "msLaunchUri", - "msLockOrientation", - "msManipulationViewsEnabled", - "msMatchMedia", - "msMatchesSelector", - "msMaxTouchPoints", - "msOrientation", - "msOverflowStyle", - "msPerspective", - "msPerspectiveOrigin", - "msPlayToDisabled", - "msPlayToPreferredSourceUri", - "msPlayToPrimary", - "msPointerEnabled", - "msRegionOverflow", - "msReleasePointerCapture", - "msRequestAnimationFrame", - "msRequestFullscreen", - "msSaveBlob", - "msSaveOrOpenBlob", - "msScrollChaining", - "msScrollLimit", - "msScrollLimitXMax", - "msScrollLimitXMin", - "msScrollLimitYMax", - "msScrollLimitYMin", - "msScrollRails", - "msScrollSnapPointsX", - "msScrollSnapPointsY", - "msScrollSnapType", - "msScrollSnapX", - "msScrollSnapY", - "msScrollTranslation", - "msSetImmediate", - "msSetMediaKeys", - "msSetPointerCapture", - "msTextCombineHorizontal", - "msTextSizeAdjust", - "msToBlob", - "msTouchAction", - "msTouchSelect", - "msTraceAsyncCallbackCompleted", - "msTraceAsyncCallbackStarting", - "msTraceAsyncOperationCompleted", - "msTraceAsyncOperationStarting", - "msTransform", - "msTransformOrigin", - "msTransformStyle", - "msTransition", - "msTransitionDelay", - "msTransitionDuration", - "msTransitionProperty", - "msTransitionTimingFunction", - "msUnlockOrientation", - "msUpdateAsyncCallbackRelation", - "msUserSelect", - "msVisibilityState", - "msWrapFlow", - "msWrapMargin", - "msWrapThrough", - "msWriteProfilerMark", - "msZoom", - "msZoomTo", - "mt", - "multiEntry", - "multiSelectionObj", - "multiline", - "multiple", - "multiply", - "multiplySelf", - "mutableFile", - "muted", - "n", - "name", - "nameProp", - "namedItem", - "namedRecordset", - "names", - "namespaceURI", - "namespaces", - "naturalHeight", - "naturalWidth", - "navigate", - "navigation", - "navigationMode", - "navigationStart", - "navigator", - "near", - "nearestViewportElement", - "negative", - "netscape", - "networkState", - "newScale", - "newTranslate", - "newURL", - "newValue", - "newValueSpecifiedUnits", - "newVersion", - "newhome", - "next", - "nextElementSibling", - "nextNode", - "nextPage", - "nextSibling", - "nickname", - "noHref", - "noResize", - "noShade", - "noValidate", - "noWrap", - "nodeName", - "nodeType", - "nodeValue", - "normalize", - "normalizedPathSegList", - "notationName", - "notations", - "note", - "noteGrainOn", - "noteOff", - "noteOn", - "now", - "numOctaves", - "number", - "numberOfChannels", - "numberOfInputs", - "numberOfItems", - "numberOfOutputs", - "numberValue", - "oMatchesSelector", - "object", - "object-fit", - "object-position", - "objectFit", - "objectPosition", - "objectStore", - "objectStoreNames", - "observe", - "of", - "offscreenBuffering", - "offset", - "offsetHeight", - "offsetLeft", - "offsetNode", - "offsetParent", - "offsetTop", - "offsetWidth", - "offsetX", - "offsetY", - "ok", - "oldURL", - "oldValue", - "oldVersion", - "olderShadowRoot", - "onLine", - "onabort", - "onactivate", - "onactive", - "onaddstream", - "onaddtrack", - "onafterprint", - "onafterscriptexecute", - "onafterupdate", - "onaudioend", - "onaudioprocess", - "onaudiostart", - "onautocomplete", - "onautocompleteerror", - "onbeforeactivate", - "onbeforecopy", - "onbeforecut", - "onbeforedeactivate", - "onbeforeeditfocus", - "onbeforepaste", - "onbeforeprint", - "onbeforescriptexecute", - "onbeforeunload", - "onbeforeupdate", - "onblocked", - "onblur", - "onbounce", - "onboundary", - "oncached", - "oncancel", - "oncandidatewindowhide", - "oncandidatewindowshow", - "oncandidatewindowupdate", - "oncanplay", - "oncanplaythrough", - "oncellchange", - "onchange", - "onchargingchange", - "onchargingtimechange", - "onchecking", - "onclick", - "onclose", - "oncompassneedscalibration", - "oncomplete", - "oncontextmenu", - "oncontrolselect", - "oncopy", - "oncuechange", - "oncut", - "ondataavailable", - "ondatachannel", - "ondatasetchanged", - "ondatasetcomplete", - "ondblclick", - "ondeactivate", - "ondevicelight", - "ondevicemotion", - "ondeviceorientation", - "ondeviceproximity", - "ondischargingtimechange", - "ondisplay", - "ondownloading", - "ondrag", - "ondragend", - "ondragenter", - "ondragleave", - "ondragover", - "ondragstart", - "ondrop", - "ondurationchange", - "onemptied", - "onencrypted", - "onend", - "onended", - "onenter", - "onerror", - "onerrorupdate", - "onexit", - "onfilterchange", - "onfinish", - "onfocus", - "onfocusin", - "onfocusout", - "onfullscreenchange", - "onfullscreenerror", - "ongesturechange", - "ongestureend", - "ongesturestart", - "ongotpointercapture", - "onhashchange", - "onhelp", - "onicecandidate", - "oniceconnectionstatechange", - "oninactive", - "oninput", - "oninvalid", - "onkeydown", - "onkeypress", - "onkeyup", - "onlanguagechange", - "onlayoutcomplete", - "onlevelchange", - "onload", - "onloadeddata", - "onloadedmetadata", - "onloadend", - "onloadstart", - "onlosecapture", - "onlostpointercapture", - "only", - "onmark", - "onmessage", - "onmousedown", - "onmouseenter", - "onmouseleave", - "onmousemove", - "onmouseout", - "onmouseover", - "onmouseup", - "onmousewheel", - "onmove", - "onmoveend", - "onmovestart", - "onmozfullscreenchange", - "onmozfullscreenerror", - "onmozorientationchange", - "onmozpointerlockchange", - "onmozpointerlockerror", - "onmscontentzoom", - "onmsfullscreenchange", - "onmsfullscreenerror", - "onmsgesturechange", - "onmsgesturedoubletap", - "onmsgestureend", - "onmsgesturehold", - "onmsgesturestart", - "onmsgesturetap", - "onmsgotpointercapture", - "onmsinertiastart", - "onmslostpointercapture", - "onmsmanipulationstatechanged", - "onmsneedkey", - "onmsorientationchange", - "onmspointercancel", - "onmspointerdown", - "onmspointerenter", - "onmspointerhover", - "onmspointerleave", - "onmspointermove", - "onmspointerout", - "onmspointerover", - "onmspointerup", - "onmssitemodejumplistitemremoved", - "onmsthumbnailclick", - "onnegotiationneeded", - "onnomatch", - "onnoupdate", - "onobsolete", - "onoffline", - "ononline", - "onopen", - "onorientationchange", - "onpagechange", - "onpagehide", - "onpageshow", - "onpaste", - "onpause", - "onplay", - "onplaying", - "onpluginstreamstart", - "onpointercancel", - "onpointerdown", - "onpointerenter", - "onpointerleave", - "onpointerlockchange", - "onpointerlockerror", - "onpointermove", - "onpointerout", - "onpointerover", - "onpointerup", - "onpopstate", - "onprogress", - "onpropertychange", - "onratechange", - "onreadystatechange", - "onremovestream", - "onremovetrack", - "onreset", - "onresize", - "onresizeend", - "onresizestart", - "onresourcetimingbufferfull", - "onresult", - "onresume", - "onrowenter", - "onrowexit", - "onrowsdelete", - "onrowsinserted", - "onscroll", - "onsearch", - "onseeked", - "onseeking", - "onselect", - "onselectionchange", - "onselectstart", - "onshow", - "onsignalingstatechange", - "onsoundend", - "onsoundstart", - "onspeechend", - "onspeechstart", - "onstalled", - "onstart", - "onstatechange", - "onstop", - "onstorage", - "onstoragecommit", - "onsubmit", - "onsuccess", - "onsuspend", - "ontextinput", - "ontimeout", - "ontimeupdate", - "ontoggle", - "ontouchcancel", - "ontouchend", - "ontouchmove", - "ontouchstart", - "ontransitionend", - "onunload", - "onupdateready", - "onupgradeneeded", - "onuserproximity", - "onversionchange", - "onvoiceschanged", - "onvolumechange", - "onwaiting", - "onwarning", - "onwebkitanimationend", - "onwebkitanimationiteration", - "onwebkitanimationstart", - "onwebkitcurrentplaybacktargetiswirelesschanged", - "onwebkitfullscreenchange", - "onwebkitfullscreenerror", - "onwebkitkeyadded", - "onwebkitkeyerror", - "onwebkitkeymessage", - "onwebkitneedkey", - "onwebkitorientationchange", - "onwebkitplaybacktargetavailabilitychanged", - "onwebkitpointerlockchange", - "onwebkitpointerlockerror", - "onwebkitresourcetimingbufferfull", - "onwebkittransitionend", - "onwheel", - "onzoom", - "opacity", - "open", - "openCursor", - "openDatabase", - "openKeyCursor", - "opener", - "opera", - "operationType", - "operator", - "opr", - "optimum", - "options", - "order", - "orderX", - "orderY", - "ordered", - "org", - "orient", - "orientAngle", - "orientType", - "orientation", - "origin", - "originalTarget", - "orphans", - "oscpu", - "outerHTML", - "outerHeight", - "outerText", - "outerWidth", - "outline", - "outline-color", - "outline-offset", - "outline-style", - "outline-width", - "outlineColor", - "outlineOffset", - "outlineStyle", - "outlineWidth", - "outputBuffer", - "overflow", - "overflow-x", - "overflow-y", - "overflowX", - "overflowY", - "overrideMimeType", - "oversample", - "ownerDocument", - "ownerElement", - "ownerNode", - "ownerRule", - "ownerSVGElement", - "owningElement", - "p1", - "p2", - "p3", - "p4", - "pad", - "padding", - "padding-bottom", - "padding-left", - "padding-right", - "padding-top", - "paddingBottom", - "paddingLeft", - "paddingRight", - "paddingTop", - "page", - "page-break-after", - "page-break-before", - "page-break-inside", - "pageBreakAfter", - "pageBreakBefore", - "pageBreakInside", - "pageCount", - "pageX", - "pageXOffset", - "pageY", - "pageYOffset", - "pages", - "paint-order", - "paintOrder", - "paintRequests", - "paintType", - "palette", - "panningModel", - "parent", - "parentElement", - "parentNode", - "parentRule", - "parentStyleSheet", - "parentTextEdit", - "parentWindow", - "parse", - "parseFloat", - "parseFromString", - "parseInt", - "participants", - "password", - "pasteHTML", - "path", - "pathLength", - "pathSegList", - "pathSegType", - "pathSegTypeAsLetter", - "pathname", - "pattern", - "patternContentUnits", - "patternMismatch", - "patternTransform", - "patternUnits", - "pause", - "pauseAnimations", - "pauseOnExit", - "paused", - "pending", - "performance", - "permission", - "persisted", - "personalbar", - "perspective", - "perspective-origin", - "perspectiveOrigin", - "phoneticFamilyName", - "phoneticGivenName", - "photo", - "ping", - "pitch", - "pixelBottom", - "pixelDepth", - "pixelHeight", - "pixelLeft", - "pixelRight", - "pixelStorei", - "pixelTop", - "pixelUnitToMillimeterX", - "pixelUnitToMillimeterY", - "pixelWidth", - "placeholder", - "platform", - "play", - "playbackRate", - "playbackState", - "playbackTime", - "played", - "plugins", - "pluginspage", - "pname", - "pointer-events", - "pointerBeforeReferenceNode", - "pointerEnabled", - "pointerEvents", - "pointerId", - "pointerLockElement", - "pointerType", - "points", - "pointsAtX", - "pointsAtY", - "pointsAtZ", - "polygonOffset", - "pop", - "popupWindowFeatures", - "popupWindowName", - "popupWindowURI", - "port", - "port1", - "port2", - "ports", - "posBottom", - "posHeight", - "posLeft", - "posRight", - "posTop", - "posWidth", - "position", - "positionAlign", - "postError", - "postMessage", - "poster", - "pow", - "powerOff", - "preMultiplySelf", - "precision", - "preferredStyleSheetSet", - "preferredStylesheetSet", - "prefix", - "preload", - "preserveAlpha", - "preserveAspectRatio", - "preserveAspectRatioString", - "pressed", - "pressure", - "prevValue", - "preventDefault", - "preventExtensions", - "previousElementSibling", - "previousNode", - "previousPage", - "previousScale", - "previousSibling", - "previousTranslate", - "primaryKey", - "primitiveType", - "primitiveUnits", - "principals", - "print", - "privateKey", - "probablySupportsContext", - "process", - "processIceMessage", - "product", - "productSub", - "profile", - "profileEnd", - "profiles", - "prompt", - "properties", - "propertyIsEnumerable", - "propertyName", - "protocol", - "protocolLong", - "prototype", - "pseudoClass", - "pseudoElement", - "publicId", - "publicKey", - "published", - "push", - "pushNotification", - "pushState", - "put", - "putImageData", - "quadraticCurveTo", - "qualifier", - "queryCommandEnabled", - "queryCommandIndeterm", - "queryCommandState", - "queryCommandSupported", - "queryCommandText", - "queryCommandValue", - "querySelector", - "querySelectorAll", - "quote", - "quotes", - "r", - "r1", - "r2", - "race", - "radiogroup", - "radiusX", - "radiusY", - "random", - "range", - "rangeCount", - "rangeMax", - "rangeMin", - "rangeOffset", - "rangeOverflow", - "rangeParent", - "rangeUnderflow", - "rate", - "ratio", - "raw", - "read", - "readAsArrayBuffer", - "readAsBinaryString", - "readAsBlob", - "readAsDataURL", - "readAsText", - "readOnly", - "readPixels", - "readReportRequested", - "readyState", - "reason", - "reboot", - "receiver", - "receivers", - "recordNumber", - "recordset", - "rect", - "red", - "redirectCount", - "redirectEnd", - "redirectStart", - "reduce", - "reduceRight", - "reduction", - "refDistance", - "refX", - "refY", - "referenceNode", - "referrer", - "refresh", - "region", - "regionAnchorX", - "regionAnchorY", - "regionId", - "regions", - "register", - "registerContentHandler", - "registerElement", - "registerProtocolHandler", - "reject", - "rel", - "relList", - "relatedNode", - "relatedTarget", - "release", - "releaseCapture", - "releaseEvents", - "releasePointerCapture", - "releaseShaderCompiler", - "reliable", - "reload", - "remainingSpace", - "remoteDescription", - "remove", - "removeAllRanges", - "removeAttribute", - "removeAttributeNS", - "removeAttributeNode", - "removeBehavior", - "removeChild", - "removeCue", - "removeEventListener", - "removeFilter", - "removeImport", - "removeItem", - "removeListener", - "removeNamedItem", - "removeNamedItemNS", - "removeNode", - "removeParameter", - "removeProperty", - "removeRange", - "removeRegion", - "removeRule", - "removeSiteSpecificTrackingException", - "removeSourceBuffer", - "removeStream", - "removeTrack", - "removeVariable", - "removeWakeLockListener", - "removeWebWideTrackingException", - "removedNodes", - "renderbufferStorage", - "renderedBuffer", - "renderingMode", - "repeat", - "replace", - "replaceAdjacentText", - "replaceChild", - "replaceData", - "replaceId", - "replaceItem", - "replaceNode", - "replaceState", - "replaceTrack", - "replaceWholeText", - "reportValidity", - "requestAnimationFrame", - "requestAutocomplete", - "requestData", - "requestFullscreen", - "requestMediaKeySystemAccess", - "requestPermission", - "requestPointerLock", - "requestStart", - "requestingWindow", - "required", - "requiredExtensions", - "requiredFeatures", - "reset", - "resetTransform", - "resize", - "resizeBy", - "resizeTo", - "resolve", - "response", - "responseBody", - "responseEnd", - "responseStart", - "responseText", - "responseType", - "responseURL", - "responseXML", - "restore", - "result", - "resultType", - "resume", - "returnValue", - "rev", - "reverse", - "reversed", - "revocable", - "revokeObjectURL", - "rgbColor", - "right", - "rightContext", - "rightMargin", - "rolloffFactor", - "root", - "rootElement", - "rotate", - "rotateAxisAngle", - "rotateAxisAngleSelf", - "rotateFromVector", - "rotateFromVectorSelf", - "rotateSelf", - "rotation", - "rotationRate", - "round", - "rowIndex", - "rowSpan", - "rows", - "rubyAlign", - "rubyOverhang", - "rubyPosition", - "rules", - "runtime", - "runtimeStyle", - "rx", - "ry", - "safari", - "sampleCoverage", - "sampleRate", - "sandbox", - "save", - "scale", - "scale3d", - "scale3dSelf", - "scaleNonUniform", - "scaleNonUniformSelf", - "scaleSelf", - "scheme", - "scissor", - "scope", - "scopeName", - "scoped", - "screen", - "screenBrightness", - "screenEnabled", - "screenLeft", - "screenPixelToMillimeterX", - "screenPixelToMillimeterY", - "screenTop", - "screenX", - "screenY", - "scripts", - "scroll", - "scroll-behavior", - "scrollAmount", - "scrollBehavior", - "scrollBy", - "scrollByLines", - "scrollByPages", - "scrollDelay", - "scrollHeight", - "scrollIntoView", - "scrollIntoViewIfNeeded", - "scrollLeft", - "scrollLeftMax", - "scrollMaxX", - "scrollMaxY", - "scrollTo", - "scrollTop", - "scrollTopMax", - "scrollWidth", - "scrollX", - "scrollY", - "scrollbar3dLightColor", - "scrollbarArrowColor", - "scrollbarBaseColor", - "scrollbarDarkShadowColor", - "scrollbarFaceColor", - "scrollbarHighlightColor", - "scrollbarShadowColor", - "scrollbarTrackColor", - "scrollbars", - "scrolling", - "sdp", - "sdpMLineIndex", - "sdpMid", - "seal", - "search", - "searchBox", - "searchBoxJavaBridge_", - "searchParams", - "sectionRowIndex", - "secureConnectionStart", - "security", - "seed", - "seekable", - "seeking", - "select", - "selectAllChildren", - "selectNode", - "selectNodeContents", - "selectNodes", - "selectSingleNode", - "selectSubString", - "selected", - "selectedIndex", - "selectedOptions", - "selectedStyleSheetSet", - "selectedStylesheetSet", - "selection", - "selectionDirection", - "selectionEnd", - "selectionStart", - "selector", - "selectorText", - "self", - "send", - "sendAsBinary", - "sendBeacon", - "sender", - "sentTimestamp", - "separator", - "serializeToString", - "serviceWorker", - "sessionId", - "sessionStorage", - "set", - "setActive", - "setAlpha", - "setAttribute", - "setAttributeNS", - "setAttributeNode", - "setAttributeNodeNS", - "setBaseAndExtent", - "setBingCurrentSearchDefault", - "setCapture", - "setColor", - "setCompositeOperation", - "setCurrentTime", - "setCustomValidity", - "setData", - "setDate", - "setDragImage", - "setEnd", - "setEndAfter", - "setEndBefore", - "setEndPoint", - "setFillColor", - "setFilterRes", - "setFloat32", - "setFloat64", - "setFloatValue", - "setFullYear", - "setHours", - "setImmediate", - "setInt16", - "setInt32", - "setInt8", - "setInterval", - "setItem", - "setLineCap", - "setLineDash", - "setLineJoin", - "setLineWidth", - "setLocalDescription", - "setMatrix", - "setMatrixValue", - "setMediaKeys", - "setMilliseconds", - "setMinutes", - "setMiterLimit", - "setMonth", - "setNamedItem", - "setNamedItemNS", - "setNonUserCodeExceptions", - "setOrientToAngle", - "setOrientToAuto", - "setOrientation", - "setOverrideHistoryNavigationMode", - "setPaint", - "setParameter", - "setPeriodicWave", - "setPointerCapture", - "setPosition", - "setPreference", - "setProperty", - "setPrototypeOf", - "setRGBColor", - "setRGBColorICCColor", - "setRadius", - "setRangeText", - "setRemoteDescription", - "setRequestHeader", - "setResizable", - "setResourceTimingBufferSize", - "setRotate", - "setScale", - "setSeconds", - "setSelectionRange", - "setServerCertificate", - "setShadow", - "setSkewX", - "setSkewY", - "setStart", - "setStartAfter", - "setStartBefore", - "setStdDeviation", - "setStringValue", - "setStrokeColor", - "setSuggestResult", - "setTargetAtTime", - "setTargetValueAtTime", - "setTime", - "setTimeout", - "setTransform", - "setTranslate", - "setUTCDate", - "setUTCFullYear", - "setUTCHours", - "setUTCMilliseconds", - "setUTCMinutes", - "setUTCMonth", - "setUTCSeconds", - "setUint16", - "setUint32", - "setUint8", - "setUri", - "setValueAtTime", - "setValueCurveAtTime", - "setVariable", - "setVelocity", - "setVersion", - "setYear", - "settingName", - "settingValue", - "sex", - "shaderSource", - "shadowBlur", - "shadowColor", - "shadowOffsetX", - "shadowOffsetY", - "shadowRoot", - "shape", - "shape-rendering", - "shapeRendering", - "sheet", - "shift", - "shiftKey", - "shiftLeft", - "show", - "showHelp", - "showModal", - "showModalDialog", - "showModelessDialog", - "showNotification", - "sidebar", - "sign", - "signalingState", - "sin", - "singleNodeValue", - "sinh", - "size", - "sizeToContent", - "sizes", - "skewX", - "skewXSelf", - "skewY", - "skewYSelf", - "slice", - "slope", - "small", - "smooth", - "smil", - "smoothingTimeConstant", - "snapToLines", - "snapshotItem", - "snapshotLength", - "some", - "sort", - "source", - "sourceBuffer", - "sourceBuffers", - "sourceIndex", - "spacing", - "span", - "speakAs", - "speaking", - "specified", - "specularConstant", - "specularExponent", - "speechSynthesis", - "speed", - "speedOfSound", - "spellcheck", - "splice", - "split", - "splitText", - "spreadMethod", - "sqrt", - "src", - "srcElement", - "srcFilter", - "srcUrn", - "srcdoc", - "srclang", - "srcset", - "stack", - "stackTraceLimit", - "stacktrace", - "standalone", - "standby", - "start", - "startContainer", - "startIce", - "startOffset", - "startRendering", - "startTime", - "startsWith", - "state", - "status", - "statusMessage", - "statusText", - "statusbar", - "stdDeviationX", - "stdDeviationY", - "stencilFunc", - "stencilFuncSeparate", - "stencilMask", - "stencilMaskSeparate", - "stencilOp", - "stencilOpSeparate", - "step", - "stepDown", - "stepMismatch", - "stepUp", - "sticky", - "stitchTiles", - "stop", - "stop-color", - "stop-opacity", - "stopColor", - "stopImmediatePropagation", - "stopOpacity", - "stopPropagation", - "storageArea", - "storageName", - "storageStatus", - "storeSiteSpecificTrackingException", - "storeWebWideTrackingException", - "stpVersion", - "stream", - "strike", - "stringValue", - "stringify", - "stroke", - "stroke-dasharray", - "stroke-dashoffset", - "stroke-linecap", - "stroke-linejoin", - "stroke-miterlimit", - "stroke-opacity", - "stroke-width", - "strokeDasharray", - "strokeDashoffset", - "strokeLinecap", - "strokeLinejoin", - "strokeMiterlimit", - "strokeOpacity", - "strokeRect", - "strokeStyle", - "strokeText", - "strokeWidth", - "style", - "styleFloat", - "styleMedia", - "styleSheet", - "styleSheetSets", - "styleSheets", - "sub", - "subarray", - "subject", - "submit", - "subscribe", - "substr", - "substring", - "substringData", - "subtle", - "subtree", - "suffix", - "suffixes", - "summary", - "sup", - "supports", - "surfaceScale", - "surroundContents", - "suspend", - "suspendRedraw", - "swapCache", - "swapNode", - "sweepFlag", - "symbols", - "system", - "systemCode", - "systemId", - "systemLanguage", - "systemXDPI", - "systemYDPI", - "tBodies", - "tFoot", - "tHead", - "tabIndex", - "table", - "table-layout", - "tableLayout", - "tableValues", - "tag", - "tagName", - "tagUrn", - "tags", - "taintEnabled", - "takeRecords", - "tan", - "tanh", - "target", - "targetElement", - "targetTouches", - "targetX", - "targetY", - "tel", - "terminate", - "test", - "texImage2D", - "texParameterf", - "texParameteri", - "texSubImage2D", - "text", - "text-align", - "text-anchor", - "text-decoration", - "text-decoration-color", - "text-decoration-line", - "text-decoration-style", - "text-indent", - "text-overflow", - "text-rendering", - "text-shadow", - "text-transform", - "textAlign", - "textAlignLast", - "textAnchor", - "textAutospace", - "textBaseline", - "textContent", - "textDecoration", - "textDecorationBlink", - "textDecorationColor", - "textDecorationLine", - "textDecorationLineThrough", - "textDecorationNone", - "textDecorationOverline", - "textDecorationStyle", - "textDecorationUnderline", - "textIndent", - "textJustify", - "textJustifyTrim", - "textKashida", - "textKashidaSpace", - "textLength", - "textOverflow", - "textRendering", - "textShadow", - "textTracks", - "textTransform", - "textUnderlinePosition", - "then", - "threadId", - "threshold", - "tiltX", - "tiltY", - "time", - "timeEnd", - "timeStamp", - "timeout", - "timestamp", - "timestampOffset", - "timing", - "title", - "toArray", - "toBlob", - "toDataURL", - "toDateString", - "toElement", - "toExponential", - "toFixed", - "toFloat32Array", - "toFloat64Array", - "toGMTString", - "toISOString", - "toJSON", - "toLocaleDateString", - "toLocaleFormat", - "toLocaleLowerCase", - "toLocaleString", - "toLocaleTimeString", - "toLocaleUpperCase", - "toLowerCase", - "toMethod", - "toPrecision", - "toSdp", - "toSource", - "toStaticHTML", - "toString", - "toStringTag", - "toTimeString", - "toUTCString", - "toUpperCase", - "toggle", - "toggleLongPressEnabled", - "tooLong", - "toolbar", - "top", - "topMargin", - "total", - "totalFrameDelay", - "totalVideoFrames", - "touchAction", - "touches", - "trace", - "track", - "transaction", - "transactions", - "transform", - "transform-origin", - "transform-style", - "transformOrigin", - "transformPoint", - "transformString", - "transformStyle", - "transformToDocument", - "transformToFragment", - "transition", - "transition-delay", - "transition-duration", - "transition-property", - "transition-timing-function", - "transitionDelay", - "transitionDuration", - "transitionProperty", - "transitionTimingFunction", - "translate", - "translateSelf", - "translationX", - "translationY", - "trim", - "trimLeft", - "trimRight", - "trueSpeed", - "trunc", - "truncate", - "type", - "typeDetail", - "typeMismatch", - "typeMustMatch", - "types", - "ubound", - "undefined", - "unescape", - "uneval", - "unicode-bidi", - "unicodeBidi", - "uniform1f", - "uniform1fv", - "uniform1i", - "uniform1iv", - "uniform2f", - "uniform2fv", - "uniform2i", - "uniform2iv", - "uniform3f", - "uniform3fv", - "uniform3i", - "uniform3iv", - "uniform4f", - "uniform4fv", - "uniform4i", - "uniform4iv", - "uniformMatrix2fv", - "uniformMatrix3fv", - "uniformMatrix4fv", - "unique", - "uniqueID", - "uniqueNumber", - "unitType", - "units", - "unloadEventEnd", - "unloadEventStart", - "unlock", - "unmount", - "unobserve", - "unpause", - "unpauseAnimations", - "unreadCount", - "unregister", - "unregisterContentHandler", - "unregisterProtocolHandler", - "unscopables", - "unselectable", - "unshift", - "unsubscribe", - "unsuspendRedraw", - "unsuspendRedrawAll", - "unwatch", - "unwrapKey", - "update", - "updateCommands", - "updateIce", - "updateInterval", - "updateSettings", - "updated", - "updating", - "upload", - "upper", - "upperBound", - "upperOpen", - "uri", - "url", - "urn", - "urns", - "usages", - "useCurrentView", - "useMap", - "useProgram", - "usedSpace", - "userAgent", - "userLanguage", - "username", - "v8BreakIterator", - "vAlign", - "vLink", - "valid", - "validateProgram", - "validationMessage", - "validity", - "value", - "valueAsDate", - "valueAsNumber", - "valueAsString", - "valueInSpecifiedUnits", - "valueMissing", - "valueOf", - "valueText", - "valueType", - "values", - "vector-effect", - "vectorEffect", - "velocityAngular", - "velocityExpansion", - "velocityX", - "velocityY", - "vendor", - "vendorSub", - "verify", - "version", - "vertexAttrib1f", - "vertexAttrib1fv", - "vertexAttrib2f", - "vertexAttrib2fv", - "vertexAttrib3f", - "vertexAttrib3fv", - "vertexAttrib4f", - "vertexAttrib4fv", - "vertexAttribDivisorANGLE", - "vertexAttribPointer", - "vertical", - "vertical-align", - "verticalAlign", - "verticalOverflow", - "vibrate", - "videoHeight", - "videoTracks", - "videoWidth", - "view", - "viewBox", - "viewBoxString", - "viewTarget", - "viewTargetString", - "viewport", - "viewportAnchorX", - "viewportAnchorY", - "viewportElement", - "visibility", - "visibilityState", - "visible", - "vlinkColor", - "voice", - "volume", - "vrml", - "vspace", - "w", - "wand", - "warn", - "wasClean", - "watch", - "watchPosition", - "webdriver", - "webkitAddKey", - "webkitAnimation", - "webkitAnimationDelay", - "webkitAnimationDirection", - "webkitAnimationDuration", - "webkitAnimationFillMode", - "webkitAnimationIterationCount", - "webkitAnimationName", - "webkitAnimationPlayState", - "webkitAnimationTimingFunction", - "webkitAppearance", - "webkitAudioContext", - "webkitAudioDecodedByteCount", - "webkitAudioPannerNode", - "webkitBackfaceVisibility", - "webkitBackground", - "webkitBackgroundAttachment", - "webkitBackgroundClip", - "webkitBackgroundColor", - "webkitBackgroundImage", - "webkitBackgroundOrigin", - "webkitBackgroundPosition", - "webkitBackgroundPositionX", - "webkitBackgroundPositionY", - "webkitBackgroundRepeat", - "webkitBackgroundSize", - "webkitBackingStorePixelRatio", - "webkitBorderImage", - "webkitBorderImageOutset", - "webkitBorderImageRepeat", - "webkitBorderImageSlice", - "webkitBorderImageSource", - "webkitBorderImageWidth", - "webkitBoxAlign", - "webkitBoxDirection", - "webkitBoxFlex", - "webkitBoxOrdinalGroup", - "webkitBoxOrient", - "webkitBoxPack", - "webkitBoxSizing", - "webkitCancelAnimationFrame", - "webkitCancelFullScreen", - "webkitCancelKeyRequest", - "webkitCancelRequestAnimationFrame", - "webkitClearResourceTimings", - "webkitClosedCaptionsVisible", - "webkitConvertPointFromNodeToPage", - "webkitConvertPointFromPageToNode", - "webkitCreateShadowRoot", - "webkitCurrentFullScreenElement", - "webkitCurrentPlaybackTargetIsWireless", - "webkitDirectionInvertedFromDevice", - "webkitDisplayingFullscreen", - "webkitEnterFullScreen", - "webkitEnterFullscreen", - "webkitExitFullScreen", - "webkitExitFullscreen", - "webkitExitPointerLock", - "webkitFullScreenKeyboardInputAllowed", - "webkitFullscreenElement", - "webkitFullscreenEnabled", - "webkitGenerateKeyRequest", - "webkitGetAsEntry", - "webkitGetDatabaseNames", - "webkitGetEntries", - "webkitGetEntriesByName", - "webkitGetEntriesByType", - "webkitGetFlowByName", - "webkitGetGamepads", - "webkitGetImageDataHD", - "webkitGetNamedFlows", - "webkitGetRegionFlowRanges", - "webkitGetUserMedia", - "webkitHasClosedCaptions", - "webkitHidden", - "webkitIDBCursor", - "webkitIDBDatabase", - "webkitIDBDatabaseError", - "webkitIDBDatabaseException", - "webkitIDBFactory", - "webkitIDBIndex", - "webkitIDBKeyRange", - "webkitIDBObjectStore", - "webkitIDBRequest", - "webkitIDBTransaction", - "webkitImageSmoothingEnabled", - "webkitIndexedDB", - "webkitInitMessageEvent", - "webkitIsFullScreen", - "webkitKeys", - "webkitLineDashOffset", - "webkitLockOrientation", - "webkitMatchesSelector", - "webkitMediaStream", - "webkitNotifications", - "webkitOfflineAudioContext", - "webkitOrientation", - "webkitPeerConnection00", - "webkitPersistentStorage", - "webkitPointerLockElement", - "webkitPostMessage", - "webkitPreservesPitch", - "webkitPutImageDataHD", - "webkitRTCPeerConnection", - "webkitRegionOverset", - "webkitRequestAnimationFrame", - "webkitRequestFileSystem", - "webkitRequestFullScreen", - "webkitRequestFullscreen", - "webkitRequestPointerLock", - "webkitResolveLocalFileSystemURL", - "webkitSetMediaKeys", - "webkitSetResourceTimingBufferSize", - "webkitShadowRoot", - "webkitShowPlaybackTargetPicker", - "webkitSlice", - "webkitSpeechGrammar", - "webkitSpeechGrammarList", - "webkitSpeechRecognition", - "webkitSpeechRecognitionError", - "webkitSpeechRecognitionEvent", - "webkitStorageInfo", - "webkitSupportsFullscreen", - "webkitTemporaryStorage", - "webkitTextSizeAdjust", - "webkitTransform", - "webkitTransformOrigin", - "webkitTransition", - "webkitTransitionDelay", - "webkitTransitionDuration", - "webkitTransitionProperty", - "webkitTransitionTimingFunction", - "webkitURL", - "webkitUnlockOrientation", - "webkitUserSelect", - "webkitVideoDecodedByteCount", - "webkitVisibilityState", - "webkitWirelessVideoPlaybackDisabled", - "webkitdropzone", - "webstore", - "weight", - "whatToShow", - "wheelDelta", - "wheelDeltaX", - "wheelDeltaY", - "which", - "white-space", - "whiteSpace", - "wholeText", - "widows", - "width", - "will-change", - "willChange", - "willValidate", - "window", - "withCredentials", - "word-break", - "word-spacing", - "word-wrap", - "wordBreak", - "wordSpacing", - "wordWrap", - "wrap", - "wrapKey", - "write", - "writeln", - "writingMode", - "x", - "x1", - "x2", - "xChannelSelector", - "xmlEncoding", - "xmlStandalone", - "xmlVersion", - "xmlbase", - "xmllang", - "xmlspace", - "y", - "y1", - "y2", - "yChannelSelector", - "yandex", - "z", - "z-index", - "zIndex", - "zoom", - "zoomAndPan", - "zoomRectScreen" - ]; - - /*********************************************************************** - - A JavaScript tokenizer / parser / beautifier / compressor. - https://github.com/mishoo/UglifyJS2 - - -------------------------------- (C) --------------------------------- - - Author: Mihai Bazon - - http://mihai.bazon.net/blog - - Distributed under the BSD license: - - Copyright 2012 (c) Mihai Bazon - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - * Redistributions of source code must retain the above - copyright notice, this list of conditions and the following - disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials - provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY - EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - SUCH DAMAGE. - - ***********************************************************************/ - - function find_builtins(reserved) { - domprops.forEach(add); - - // Compatibility fix for some standard defined globals not defined on every js environment - var new_globals = ["Symbol", "Map", "Promise", "Proxy", "Reflect", "Set", "WeakMap", "WeakSet"]; - var objects = {}; - var global_ref = typeof global === "object" ? global : self; - - new_globals.forEach(function (new_global) { - objects[new_global] = global_ref[new_global] || new Function(); - }); - - // NaN will be included due to Number.NaN - [ - "null", - "true", - "false", - "Infinity", - "-Infinity", - "undefined", - ].forEach(add); - [ Object, Array, Function, Number, - String, Boolean, Error, Math, - Date, RegExp, objects.Symbol, ArrayBuffer, - DataView, decodeURI, decodeURIComponent, - encodeURI, encodeURIComponent, eval, EvalError, - Float32Array, Float64Array, Int8Array, Int16Array, - Int32Array, isFinite, isNaN, JSON, objects.Map, parseFloat, - parseInt, objects.Promise, objects.Proxy, RangeError, ReferenceError, - objects.Reflect, objects.Set, SyntaxError, TypeError, Uint8Array, - Uint8ClampedArray, Uint16Array, Uint32Array, URIError, - objects.WeakMap, objects.WeakSet - ].forEach(function(ctor) { - Object.getOwnPropertyNames(ctor).map(add); - if (ctor.prototype) { - Object.getOwnPropertyNames(ctor.prototype).map(add); - } - }); - function add(name) { - reserved.add(name); - } - } - - function reserve_quoted_keys(ast, reserved) { - function add(name) { - push_uniq(reserved, name); - } - - ast.walk(new TreeWalker(function(node) { - if (node instanceof AST_ObjectKeyVal && node.quote) { - add(node.key); - } else if (node instanceof AST_ObjectProperty && node.quote) { - add(node.key.name); - } else if (node instanceof AST_Sub) { - addStrings(node.property, add); - } - })); - } - - function addStrings(node, add) { - node.walk(new TreeWalker(function(node) { - if (node instanceof AST_Sequence) { - addStrings(node.tail_node(), add); - } else if (node instanceof AST_String) { - add(node.value); - } else if (node instanceof AST_Conditional) { - addStrings(node.consequent, add); - addStrings(node.alternative, add); - } - return true; - })); - } - - function mangle_properties(ast, options) { - options = defaults(options, { - builtins: false, - cache: null, - debug: false, - keep_quoted: false, - only_cache: false, - regex: null, - reserved: null, - }, true); - - var reserved_option = options.reserved; - if (!Array.isArray(reserved_option)) reserved_option = [reserved_option]; - var reserved = new Set(reserved_option); - if (!options.builtins) find_builtins(reserved); - - var cname = -1; - var cache; - if (options.cache) { - cache = options.cache.props; - cache.forEach(function(mangled_name) { - reserved.add(mangled_name); - }); - } else { - cache = new Map(); - } - - var regex = options.regex && new RegExp(options.regex); - - // note debug is either false (disabled), or a string of the debug suffix to use (enabled). - // note debug may be enabled as an empty string, which is falsey. Also treat passing 'true' - // the same as passing an empty string. - var debug = options.debug !== false; - var debug_name_suffix; - if (debug) { - debug_name_suffix = (options.debug === true ? "" : options.debug); - } - - var names_to_mangle = new Set(); - var unmangleable = new Set(); - - var keep_quoted_strict = options.keep_quoted === "strict"; - - // step 1: find candidates to mangle - ast.walk(new TreeWalker(function(node) { - if (node instanceof AST_ObjectKeyVal) { - if (typeof node.key == "string" && - (!keep_quoted_strict || !node.quote)) { - add(node.key); - } - } else if (node instanceof AST_ObjectProperty) { - // setter or getter, since KeyVal is handled above - if (!keep_quoted_strict || !node.key.end.quote) { - add(node.key.name); - } - } else if (node instanceof AST_Dot) { - var root = node; - while (root.expression) { - root = root.expression; - } - if (!(root.thedef && root.thedef.undeclared) && - (!keep_quoted_strict || !node.quote)) { - add(node.property); - } - } else if (node instanceof AST_Sub) { - if (!keep_quoted_strict) { - addStrings(node.property, add); - } - } else if (node instanceof AST_Call - && node.expression.print_to_string() == "Object.defineProperty") { - addStrings(node.args[1], add); - } - })); - - // step 2: transform the tree, renaming properties - return ast.transform(new TreeTransformer(function(node) { - if (node instanceof AST_ObjectKeyVal) { - if (typeof node.key == "string" && - (!keep_quoted_strict || !node.quote)) { - node.key = mangle(node.key); - } - } else if (node instanceof AST_ObjectProperty) { - // setter or getter - if (!keep_quoted_strict || !node.key.end.quote) { - node.key.name = mangle(node.key.name); - } - } else if (node instanceof AST_Dot) { - if (!keep_quoted_strict || !node.quote) { - node.property = mangle(node.property); - } - } else if (!options.keep_quoted && node instanceof AST_Sub) { - node.property = mangleStrings(node.property); - } else if (node instanceof AST_Call - && node.expression.print_to_string() == "Object.defineProperty") { - node.args[1] = mangleStrings(node.args[1]); - } - })); - - // only function declarations after this line - - function can_mangle(name) { - if (unmangleable.has(name)) return false; - if (reserved.has(name)) return false; - if (options.only_cache) { - return cache.has(name); - } - if (/^-?[0-9]+(\.[0-9]+)?(e[+-][0-9]+)?$/.test(name)) return false; - return true; - } - - function should_mangle(name) { - if (regex && !regex.test(name)) return false; - if (reserved.has(name)) return false; - return cache.has(name) - || names_to_mangle.has(name); - } - - function add(name) { - if (can_mangle(name)) - names_to_mangle.add(name); - - if (!should_mangle(name)) { - unmangleable.add(name); - } - } - - function mangle(name) { - if (!should_mangle(name)) { - return name; - } - - var mangled = cache.get(name); - if (!mangled) { - if (debug) { - // debug mode: use a prefix and suffix to preserve readability, e.g. o.foo -> o._$foo$NNN_. - var debug_mangled = "_$" + name + "$" + debug_name_suffix + "_"; - - if (can_mangle(debug_mangled)) { - mangled = debug_mangled; - } - } +AST_Undefined.prototype._size = () => 6; // "void 0" - // either debug mode is off, or it is on and we could not use the mangled name - if (!mangled) { - do { - mangled = base54(++cname); - } while (!can_mangle(mangled)); - } +AST_Hole.prototype._size = () => 0; // comma is taken into account by list_overhead() - cache.set(name, mangled); - } - return mangled; - } - - function mangleStrings(node) { - return node.transform(new TreeTransformer(function(node) { - if (node instanceof AST_Sequence) { - var last = node.expressions.length - 1; - node.expressions[last] = mangleStrings(node.expressions[last]); - } else if (node instanceof AST_String) { - node.value = mangle(node.value); - } else if (node instanceof AST_Conditional) { - node.consequent = mangleStrings(node.consequent); - node.alternative = mangleStrings(node.alternative); - } - return node; - })); - } - } - - /*********************************************************************** - - A JavaScript tokenizer / parser / beautifier / compressor. - https://github.com/mishoo/UglifyJS2 - - -------------------------------- (C) --------------------------------- - - Author: Mihai Bazon - - http://mihai.bazon.net/blog - - Distributed under the BSD license: - - Copyright 2012 (c) Mihai Bazon - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - * Redistributions of source code must retain the above - copyright notice, this list of conditions and the following - disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials - provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY - EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF - THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - SUCH DAMAGE. - - ***********************************************************************/ - - (function() { - - var normalize_directives = function(body) { - var in_directive = true; - - for (var i = 0; i < body.length; i++) { - if (in_directive && body[i] instanceof AST_Statement && body[i].body instanceof AST_String) { - body[i] = new AST_Directive({ - start: body[i].start, - end: body[i].end, - value: body[i].body.value - }); - } else if (in_directive && !(body[i] instanceof AST_Statement && body[i].body instanceof AST_String)) { - in_directive = false; - } - } - - return body; - }; - - var MOZ_TO_ME = { - Program: function(M) { - return new AST_Toplevel({ - start: my_start_token(M), - end: my_end_token(M), - body: normalize_directives(M.body.map(from_moz)) - }); - }, - ArrayPattern: function(M) { - return new AST_Destructuring({ - start: my_start_token(M), - end: my_end_token(M), - names: M.elements.map(function(elm) { - if (elm === null) { - return new AST_Hole(); - } - return from_moz(elm); - }), - is_array: true - }); - }, - ObjectPattern: function(M) { - return new AST_Destructuring({ - start: my_start_token(M), - end: my_end_token(M), - names: M.properties.map(from_moz), - is_array: false - }); - }, - AssignmentPattern: function(M) { - var Type = AST_Binary; - if(FROM_MOZ_STACK.length > 2) { - var p = FROM_MOZ_STACK[FROM_MOZ_STACK.length - 2]; - if(p.type === "FunctionDeclaration" - || p.type === "FunctionExpression" - || p.type === "ArrowFunctionExpression") { - Type = AST_DefaultAssign; - } - } - return new Type({ - start: my_start_token(M), - end: my_end_token(M), - left: from_moz(M.left), - operator: "=", - right: from_moz(M.right) - }); - }, - SpreadElement: function(M) { - return new AST_Expansion({ - start: my_start_token(M), - end: my_end_token(M), - expression: from_moz(M.argument) - }); - }, - RestElement: function(M) { - return new AST_Expansion({ - start: my_start_token(M), - end: my_end_token(M), - expression: from_moz(M.argument) - }); - }, - TemplateElement: function(M) { - return new AST_TemplateSegment({ - start: my_start_token(M), - end: my_end_token(M), - value: M.value.cooked, - raw: M.value.raw - }); - }, - TemplateLiteral: function(M) { - var segments = []; - for (var i = 0; i < M.quasis.length; i++) { - segments.push(from_moz(M.quasis[i])); - if (M.expressions[i]) { - segments.push(from_moz(M.expressions[i])); - } - } - return new AST_TemplateString({ - start: my_start_token(M), - end: my_end_token(M), - segments: segments - }); - }, - TaggedTemplateExpression: function(M) { - return new AST_PrefixedTemplateString({ - start: my_start_token(M), - end: my_end_token(M), - template_string: from_moz(M.quasi), - prefix: from_moz(M.tag) - }); - }, - FunctionDeclaration: function(M) { - return new AST_Defun({ - start: my_start_token(M), - end: my_end_token(M), - name: from_moz(M.id), - argnames: M.params.map(from_moz), - is_generator: M.generator, - async: M.async, - body: normalize_directives(from_moz(M.body).body) - }); - }, - FunctionExpression: function(M) { - return new AST_Function({ - start: my_start_token(M), - end: my_end_token(M), - name: from_moz(M.id), - argnames: M.params.map(from_moz), - is_generator: M.generator, - async: M.async, - body: normalize_directives(from_moz(M.body).body) - }); - }, - ArrowFunctionExpression: function(M) { - return new AST_Arrow({ - start: my_start_token(M), - end: my_end_token(M), - argnames: M.params.map(from_moz), - body: from_moz(M.body), - async: M.async, - }); - }, - ExpressionStatement: function(M) { - return new AST_SimpleStatement({ - start: my_start_token(M), - end: my_end_token(M), - body: from_moz(M.expression) - }); - }, - // XXX Emscripten localmod: Add a node type for a parenthesized expression so that we can retain - // Closure annotations that need a form "/**annotation*/(expression)" - ParenthesizedExpression: function(M) { - return new AST_ParenthesizedExpression({ - start: my_start_token(M), - end: my_end_token(M), - body: from_moz(M.expression) - }); - }, - // XXX End Emscripten localmod - TryStatement: function(M) { - var handlers = M.handlers || [M.handler]; - if (handlers.length > 1 || M.guardedHandlers && M.guardedHandlers.length) { - throw new Error("Multiple catch clauses are not supported."); - } - return new AST_Try({ - start : my_start_token(M), - end : my_end_token(M), - body : from_moz(M.block).body, - bcatch : from_moz(handlers[0]), - bfinally : M.finalizer ? new AST_Finally(from_moz(M.finalizer)) : null - }); - }, - Property: function(M) { - var key = M.key; - var args = { - start : my_start_token(key || M.value), - end : my_end_token(M.value), - key : key.type == "Identifier" ? key.name : key.value, - value : from_moz(M.value) - }; - if (M.computed) { - args.key = from_moz(M.key); - } - if (M.method) { - args.is_generator = M.value.generator; - args.async = M.value.async; - if (!M.computed) { - args.key = new AST_SymbolMethod({ name: args.key }); - } else { - args.key = from_moz(M.key); - } - return new AST_ConciseMethod(args); - } - if (M.kind == "init") { - if (key.type != "Identifier" && key.type != "Literal") { - args.key = from_moz(key); - } - return new AST_ObjectKeyVal(args); - } - if (typeof args.key === "string" || typeof args.key === "number") { - args.key = new AST_SymbolMethod({ - name: args.key - }); - } - args.value = new AST_Accessor(args.value); - if (M.kind == "get") return new AST_ObjectGetter(args); - if (M.kind == "set") return new AST_ObjectSetter(args); - if (M.kind == "method") { - args.async = M.value.async; - args.is_generator = M.value.generator; - args.quote = M.computed ? "\"" : null; - return new AST_ConciseMethod(args); - } - }, - MethodDefinition: function(M) { - var args = { - start : my_start_token(M), - end : my_end_token(M), - key : M.computed ? from_moz(M.key) : new AST_SymbolMethod({ name: M.key.name || M.key.value }), - value : from_moz(M.value), - static : M.static, - }; - if (M.kind == "get") { - return new AST_ObjectGetter(args); - } - if (M.kind == "set") { - return new AST_ObjectSetter(args); - } - args.is_generator = M.value.generator; - args.async = M.value.async; - return new AST_ConciseMethod(args); - }, - ArrayExpression: function(M) { - return new AST_Array({ - start : my_start_token(M), - end : my_end_token(M), - elements : M.elements.map(function(elem) { - return elem === null ? new AST_Hole() : from_moz(elem); - }) - }); - }, - ObjectExpression: function(M) { - return new AST_Object({ - start : my_start_token(M), - end : my_end_token(M), - properties : M.properties.map(function(prop) { - if (prop.type === "SpreadElement") { - return from_moz(prop); - } - prop.type = "Property"; - // XXX EMSCRIPTEN preserve quoted properties - // https://github.com/mishoo/UglifyJS2/pull/3323 - var ret = from_moz(prop); - if (prop.key.type === "Literal" && - (prop.key.raw[0] === '"' || prop.key.raw[0] === "'")) { - ret.quote = true; - } - return ret; - }) - }); - }, - SequenceExpression: function(M) { - return new AST_Sequence({ - start : my_start_token(M), - end : my_end_token(M), - expressions: M.expressions.map(from_moz) - }); - }, - MemberExpression: function(M) { - return new (M.computed ? AST_Sub : AST_Dot)({ - start : my_start_token(M), - end : my_end_token(M), - property : M.computed ? from_moz(M.property) : M.property.name, - expression : from_moz(M.object) - }); - }, - SwitchCase: function(M) { - return new (M.test ? AST_Case : AST_Default)({ - start : my_start_token(M), - end : my_end_token(M), - expression : from_moz(M.test), - body : M.consequent.map(from_moz) - }); - }, - VariableDeclaration: function(M) { - return new (M.kind === "const" ? AST_Const : - M.kind === "let" ? AST_Let : AST_Var)({ - start : my_start_token(M), - end : my_end_token(M), - definitions : M.declarations.map(from_moz) - }); - }, - - ImportDeclaration: function(M) { - var imported_name = null; - var imported_names = null; - M.specifiers.forEach(function (specifier) { - if (specifier.type === "ImportSpecifier") { - if (!imported_names) { imported_names = []; } - imported_names.push(new AST_NameMapping({ - start: my_start_token(specifier), - end: my_end_token(specifier), - foreign_name: from_moz(specifier.imported), - name: from_moz(specifier.local) - })); - } else if (specifier.type === "ImportDefaultSpecifier") { - imported_name = from_moz(specifier.local); - } else if (specifier.type === "ImportNamespaceSpecifier") { - if (!imported_names) { imported_names = []; } - imported_names.push(new AST_NameMapping({ - start: my_start_token(specifier), - end: my_end_token(specifier), - foreign_name: new AST_SymbolImportForeign({ name: "*" }), - name: from_moz(specifier.local) - })); - } - }); - return new AST_Import({ - start : my_start_token(M), - end : my_end_token(M), - imported_name: imported_name, - imported_names : imported_names, - module_name : from_moz(M.source) - }); - }, - ExportAllDeclaration: function(M) { - return new AST_Export({ - start: my_start_token(M), - end: my_end_token(M), - exported_names: [ - new AST_NameMapping({ - name: new AST_SymbolExportForeign({ name: "*" }), - foreign_name: new AST_SymbolExportForeign({ name: "*" }) - }) - ], - module_name: from_moz(M.source) - }); - }, - ExportNamedDeclaration: function(M) { - return new AST_Export({ - start: my_start_token(M), - end: my_end_token(M), - exported_definition: from_moz(M.declaration), - exported_names: M.specifiers && M.specifiers.length ? M.specifiers.map(function (specifier) { - return new AST_NameMapping({ - foreign_name: from_moz(specifier.exported), - name: from_moz(specifier.local) - }); - }) : null, - module_name: from_moz(M.source) - }); - }, - ExportDefaultDeclaration: function(M) { - return new AST_Export({ - start: my_start_token(M), - end: my_end_token(M), - exported_value: from_moz(M.declaration), - is_default: true - }); - }, - Literal: function(M) { - var val = M.value, args = { - start : my_start_token(M), - end : my_end_token(M) - }; - if (val === null) return new AST_Null(args); - var rx = M.regex; - if (rx && rx.pattern) { - // RegExpLiteral as per ESTree AST spec - args.value = new RegExp(rx.pattern, rx.flags); - var raw = args.value.toString(); - args.value.raw_source = rx.flags - ? raw.substring(0, raw.length - rx.flags.length) + rx.flags - : raw; - return new AST_RegExp(args); - } else if (rx) { - // support legacy RegExp - args.value = M.regex && M.raw ? M.raw : val; - return new AST_RegExp(args); - } - switch (typeof val) { - case "string": - args.value = val; - return new AST_String(args); - case "number": - args.value = val; - return new AST_Number(args); - case "boolean": - return new (val ? AST_True : AST_False)(args); - case "bigint": - args.value = val; - return new AST_BigInt(args); - case "undefined": - return undefined; - default: - throw new Error("Unhandled value type: " + typeof val); - } - }, - MetaProperty: function(M) { - if (M.meta.name === "new" && M.property.name === "target") { - return new AST_NewTarget({ - start: my_start_token(M), - end: my_end_token(M) - }); - } - }, - Identifier: function(M) { - var p = FROM_MOZ_STACK[FROM_MOZ_STACK.length - 2]; - return new ( p.type == "LabeledStatement" ? AST_Label - : p.type == "VariableDeclarator" && p.id === M ? (p.kind == "const" ? AST_SymbolConst : p.kind == "let" ? AST_SymbolLet : AST_SymbolVar) - : /Import.*Specifier/.test(p.type) ? (p.local === M ? AST_SymbolImport : AST_SymbolImportForeign) - : p.type == "ExportSpecifier" ? (p.local === M ? AST_SymbolExport : AST_SymbolExportForeign) - : p.type == "FunctionExpression" ? (p.id === M ? AST_SymbolLambda : AST_SymbolFunarg) - : p.type == "FunctionDeclaration" ? (p.id === M ? AST_SymbolDefun : AST_SymbolFunarg) - : p.type == "ArrowFunctionExpression" ? (p.params.includes(M)) ? AST_SymbolFunarg : AST_SymbolRef - : p.type == "ClassExpression" ? (p.id === M ? AST_SymbolClass : AST_SymbolRef) - : p.type == "Property" ? (p.key === M && p.computed || p.value === M ? AST_SymbolRef : AST_SymbolMethod) - : p.type == "ClassDeclaration" ? (p.id === M ? AST_SymbolDefClass : AST_SymbolRef) - : p.type == "MethodDefinition" ? (p.computed ? AST_SymbolRef : AST_SymbolMethod) - : p.type == "CatchClause" ? AST_SymbolCatch - : p.type == "BreakStatement" || p.type == "ContinueStatement" ? AST_LabelRef - : AST_SymbolRef)({ - start : my_start_token(M), - end : my_end_token(M), - name : M.name - }); - }, - BigIntLiteral(M) { - return new AST_BigInt({ - start : my_start_token(M), - end : my_end_token(M), - value : M.value - }); - }, - ImportExpression: function(M) { - let import_token = my_start_token(M); - return new AST_Call({ - start : import_token, - end : my_end_token(M), - expression : new AST_SymbolRef({ - start : import_token, - end : import_token, - name : "import" - }), - args : [from_moz(M.source)] +AST_Infinity.prototype._size = () => 8; + +AST_True.prototype._size = () => 4; + +AST_False.prototype._size = () => 5; + +AST_Await.prototype._size = () => 6; + +AST_Yield.prototype._size = () => 6; + +/*********************************************************************** + + A JavaScript tokenizer / parser / beautifier / compressor. + https://github.com/mishoo/UglifyJS2 + + -------------------------------- (C) --------------------------------- + + Author: Mihai Bazon + + http://mihai.bazon.net/blog + + Distributed under the BSD license: + + Copyright 2012 (c) Mihai Bazon + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + ***********************************************************************/ + +// bitfield flags to be stored in node.flags. +// These are set and unset during compression, and store information in the node without requiring multiple fields. +const UNUSED = 0b00000001; +const TRUTHY = 0b00000010; +const FALSY = 0b00000100; +const UNDEFINED = 0b00001000; +const INLINED = 0b00010000; + +// Nodes to which values are ever written. Used when keep_assign is part of the unused option string. +const WRITE_ONLY = 0b00100000; + +// information specific to a single compression pass +const SQUEEZED = 0b0000000100000000; +const OPTIMIZED = 0b0000001000000000; +const TOP = 0b0000010000000000; +const CLEAR_BETWEEN_PASSES = SQUEEZED | OPTIMIZED | TOP; + +const has_flag = (node, flag) => node.flags & flag; +const set_flag = (node, flag) => { node.flags |= flag; }; +const clear_flag = (node, flag) => { node.flags &= ~flag; }; + +/*********************************************************************** + + A JavaScript tokenizer / parser / beautifier / compressor. + https://github.com/mishoo/UglifyJS2 + + -------------------------------- (C) --------------------------------- + + Author: Mihai Bazon + + http://mihai.bazon.net/blog + + Distributed under the BSD license: + + Copyright 2012 (c) Mihai Bazon + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + ***********************************************************************/ + +function merge_sequence(array, node) { + if (node instanceof AST_Sequence) { + array.push(...node.expressions); + } else { + array.push(node); + } + return array; +} + +function make_sequence(orig, expressions) { + if (expressions.length == 1) return expressions[0]; + if (expressions.length == 0) throw new Error("trying to create a sequence with length zero!"); + return make_node(AST_Sequence, orig, { + expressions: expressions.reduce(merge_sequence, []) + }); +} + +function make_node_from_constant(val, orig) { + switch (typeof val) { + case "string": + return make_node(AST_String, orig, { + value: val + }); + case "number": + if (isNaN(val)) return make_node(AST_NaN, orig); + if (isFinite(val)) { + return 1 / val < 0 ? make_node(AST_UnaryPrefix, orig, { + operator: "-", + expression: make_node(AST_Number, orig, { value: -val }) + }) : make_node(AST_Number, orig, { value: val }); + } + return val < 0 ? make_node(AST_UnaryPrefix, orig, { + operator: "-", + expression: make_node(AST_Infinity, orig) + }) : make_node(AST_Infinity, orig); + case "boolean": + return make_node(val ? AST_True : AST_False, orig); + case "undefined": + return make_node(AST_Undefined, orig); + default: + if (val === null) { + return make_node(AST_Null, orig, { value: null }); + } + if (val instanceof RegExp) { + return make_node(AST_RegExp, orig, { + value: { + source: regexp_source_fix(val.source), + flags: val.flags + } }); - } - }; - - MOZ_TO_ME.UpdateExpression = - MOZ_TO_ME.UnaryExpression = function To_Moz_Unary(M) { - var prefix = "prefix" in M ? M.prefix - : M.type == "UnaryExpression" ? true : false; - return new (prefix ? AST_UnaryPrefix : AST_UnaryPostfix)({ - start : my_start_token(M), - end : my_end_token(M), - operator : M.operator, - expression : from_moz(M.argument) - }); - }; - - MOZ_TO_ME.ClassDeclaration = - MOZ_TO_ME.ClassExpression = function From_Moz_Class(M) { - return new (M.type === "ClassDeclaration" ? AST_DefClass : AST_ClassExpression)({ - start : my_start_token(M), - end : my_end_token(M), - name : from_moz(M.id), - extends : from_moz(M.superClass), - properties: M.body.body.map(from_moz) - }); - }; - - map("EmptyStatement", AST_EmptyStatement); - map("BlockStatement", AST_BlockStatement, "body@body"); - map("IfStatement", AST_If, "test>condition, consequent>body, alternate>alternative"); - map("LabeledStatement", AST_LabeledStatement, "label>label, body>body"); - map("BreakStatement", AST_Break, "label>label"); - map("ContinueStatement", AST_Continue, "label>label"); - map("WithStatement", AST_With, "object>expression, body>body"); - map("SwitchStatement", AST_Switch, "discriminant>expression, cases@body"); - map("ReturnStatement", AST_Return, "argument>value"); - map("ThrowStatement", AST_Throw, "argument>value"); - map("WhileStatement", AST_While, "test>condition, body>body"); - map("DoWhileStatement", AST_Do, "test>condition, body>body"); - map("ForStatement", AST_For, "init>init, test>condition, update>step, body>body"); - map("ForInStatement", AST_ForIn, "left>init, right>object, body>body"); - map("ForOfStatement", AST_ForOf, "left>init, right>object, body>body, await=await"); - map("AwaitExpression", AST_Await, "argument>expression"); - map("YieldExpression", AST_Yield, "argument>expression, delegate=is_star"); - map("DebuggerStatement", AST_Debugger); - map("VariableDeclarator", AST_VarDef, "id>name, init>value"); - map("CatchClause", AST_Catch, "param>argname, body%body"); - - map("ThisExpression", AST_This); - map("Super", AST_Super); - map("BinaryExpression", AST_Binary, "operator=operator, left>left, right>right"); - map("LogicalExpression", AST_Binary, "operator=operator, left>left, right>right"); - map("AssignmentExpression", AST_Assign, "operator=operator, left>left, right>right"); - map("ConditionalExpression", AST_Conditional, "test>condition, consequent>consequent, alternate>alternative"); - map("NewExpression", AST_New, "callee>expression, arguments@args"); - map("CallExpression", AST_Call, "callee>expression, arguments@args"); - - def_to_moz(AST_Toplevel, function To_Moz_Program(M) { - return to_moz_scope("Program", M); - }); - - def_to_moz(AST_Expansion, function To_Moz_Spread(M, parent) { - return { - type: to_moz_in_destructuring() ? "RestElement" : "SpreadElement", - argument: to_moz(M.expression) - }; - }); - - def_to_moz(AST_PrefixedTemplateString, function To_Moz_TaggedTemplateExpression(M) { - return { - type: "TaggedTemplateExpression", - tag: to_moz(M.prefix), - quasi: to_moz(M.template_string) - }; - }); - - def_to_moz(AST_TemplateString, function To_Moz_TemplateLiteral(M) { - var quasis = []; - var expressions = []; - for (var i = 0; i < M.segments.length; i++) { - if (i % 2 !== 0) { - expressions.push(to_moz(M.segments[i])); - } else { - quasis.push({ - type: "TemplateElement", - value: { - raw: M.segments[i].raw, - cooked: M.segments[i].value - }, - tail: i === M.segments.length - 1 - }); - } - } - return { - type: "TemplateLiteral", - quasis: quasis, - expressions: expressions - }; - }); - - def_to_moz(AST_Defun, function To_Moz_FunctionDeclaration(M) { - return { - type: "FunctionDeclaration", - id: to_moz(M.name), - params: M.argnames.map(to_moz), - generator: M.is_generator, - async: M.async, - body: to_moz_scope("BlockStatement", M) - }; - }); - - def_to_moz(AST_Function, function To_Moz_FunctionExpression(M, parent) { - var is_generator = parent.is_generator !== undefined ? - parent.is_generator : M.is_generator; - return { - type: "FunctionExpression", - id: to_moz(M.name), - params: M.argnames.map(to_moz), - generator: is_generator, - async: M.async, - body: to_moz_scope("BlockStatement", M) - }; - }); - - def_to_moz(AST_Arrow, function To_Moz_ArrowFunctionExpression(M) { - var body = M.body instanceof Array ? { - type: "BlockStatement", - body: M.body.map(to_moz) - } : to_moz(M.body); - return { - type: "ArrowFunctionExpression", - params: M.argnames.map(to_moz), - async: M.async, - body: body - }; - }); - - def_to_moz(AST_Destructuring, function To_Moz_ObjectPattern(M) { - if (M.is_array) { - return { - type: "ArrayPattern", - elements: M.names.map(to_moz) - }; - } - return { - type: "ObjectPattern", - properties: M.names.map(to_moz) - }; - }); - - def_to_moz(AST_Directive, function To_Moz_Directive(M) { - return { - type: "ExpressionStatement", - expression: { - type: "Literal", - value: M.value - } - }; - }); - - def_to_moz(AST_SimpleStatement, function To_Moz_ExpressionStatement(M) { - return { - type: "ExpressionStatement", - expression: to_moz(M.body) - }; - }); - - def_to_moz(AST_SwitchBranch, function To_Moz_SwitchCase(M) { - return { - type: "SwitchCase", - test: to_moz(M.expression), - consequent: M.body.map(to_moz) - }; - }); - - def_to_moz(AST_Try, function To_Moz_TryStatement(M) { - return { - type: "TryStatement", - block: to_moz_block(M), - handler: to_moz(M.bcatch), - guardedHandlers: [], - finalizer: to_moz(M.bfinally) - }; - }); - - def_to_moz(AST_Catch, function To_Moz_CatchClause(M) { - return { - type: "CatchClause", - param: to_moz(M.argname), - guard: null, - body: to_moz_block(M) - }; - }); - - def_to_moz(AST_Definitions, function To_Moz_VariableDeclaration(M) { - return { - type: "VariableDeclaration", - kind: - M instanceof AST_Const ? "const" : - M instanceof AST_Let ? "let" : "var", - declarations: M.definitions.map(to_moz) - }; - }); - - def_to_moz(AST_Export, function To_Moz_ExportDeclaration(M) { - if (M.exported_names) { - if (M.exported_names[0].name.name === "*") { - return { - type: "ExportAllDeclaration", - source: to_moz(M.module_name) - }; - } - return { - type: "ExportNamedDeclaration", - specifiers: M.exported_names.map(function (name_mapping) { - return { - type: "ExportSpecifier", - exported: to_moz(name_mapping.foreign_name), - local: to_moz(name_mapping.name) - }; - }), - declaration: to_moz(M.exported_definition), - source: to_moz(M.module_name) - }; - } - return { - type: M.is_default ? "ExportDefaultDeclaration" : "ExportNamedDeclaration", - declaration: to_moz(M.exported_value || M.exported_definition) - }; - }); - - def_to_moz(AST_Import, function To_Moz_ImportDeclaration(M) { - var specifiers = []; - if (M.imported_name) { - specifiers.push({ - type: "ImportDefaultSpecifier", - local: to_moz(M.imported_name) - }); - } - if (M.imported_names && M.imported_names[0].foreign_name.name === "*") { - specifiers.push({ - type: "ImportNamespaceSpecifier", - local: to_moz(M.imported_names[0].name) - }); - } else if (M.imported_names) { - M.imported_names.forEach(function(name_mapping) { - specifiers.push({ - type: "ImportSpecifier", - local: to_moz(name_mapping.name), - imported: to_moz(name_mapping.foreign_name) - }); - }); - } - return { - type: "ImportDeclaration", - specifiers: specifiers, - source: to_moz(M.module_name) - }; - }); - - def_to_moz(AST_Sequence, function To_Moz_SequenceExpression(M) { - return { - type: "SequenceExpression", - expressions: M.expressions.map(to_moz) - }; - }); - - def_to_moz(AST_PropAccess, function To_Moz_MemberExpression(M) { - var isComputed = M instanceof AST_Sub; - return { - type: "MemberExpression", - object: to_moz(M.expression), - computed: isComputed, - property: isComputed ? to_moz(M.property) : {type: "Identifier", name: M.property} - }; - }); - - def_to_moz(AST_Unary, function To_Moz_Unary(M) { - return { - type: M.operator == "++" || M.operator == "--" ? "UpdateExpression" : "UnaryExpression", - operator: M.operator, - prefix: M instanceof AST_UnaryPrefix, - argument: to_moz(M.expression) - }; - }); - - def_to_moz(AST_Binary, function To_Moz_BinaryExpression(M) { - if (M.operator == "=" && to_moz_in_destructuring()) { - return { - type: "AssignmentPattern", - left: to_moz(M.left), - right: to_moz(M.right) - }; - } - return { - type: M.operator == "&&" || M.operator == "||" ? "LogicalExpression" : "BinaryExpression", - left: to_moz(M.left), - operator: M.operator, - right: to_moz(M.right) - }; - }); - - def_to_moz(AST_Array, function To_Moz_ArrayExpression(M) { - return { - type: "ArrayExpression", - elements: M.elements.map(to_moz) - }; - }); - - def_to_moz(AST_Object, function To_Moz_ObjectExpression(M) { - return { - type: "ObjectExpression", - properties: M.properties.map(to_moz) - }; - }); - - def_to_moz(AST_ObjectProperty, function To_Moz_Property(M, parent) { - var key = M.key instanceof AST_Node ? to_moz(M.key) : { - type: "Identifier", - value: M.key - }; - if (typeof M.key === "number") { - key = { - type: "Literal", - value: Number(M.key) - }; - } - if (typeof M.key === "string") { - key = { - type: "Identifier", - name: M.key - }; - } - var kind; - var string_or_num = typeof M.key === "string" || typeof M.key === "number"; - var computed = string_or_num ? false : !(M.key instanceof AST_Symbol) || M.key instanceof AST_SymbolRef; - if (M instanceof AST_ObjectKeyVal) { - kind = "init"; - computed = !string_or_num; - } else - if (M instanceof AST_ObjectGetter) { - kind = "get"; - } else - if (M instanceof AST_ObjectSetter) { - kind = "set"; - } - if (parent instanceof AST_Class) { - return { - type: "MethodDefinition", - computed: computed, - kind: kind, - static: M.static, - key: to_moz(M.key), - value: to_moz(M.value) - }; - } - return { - type: "Property", - computed: computed, - kind: kind, - key: key, - value: to_moz(M.value) - }; - }); - - def_to_moz(AST_ConciseMethod, function To_Moz_MethodDefinition(M, parent) { - if (parent instanceof AST_Object) { - return { - type: "Property", - computed: !(M.key instanceof AST_Symbol) || M.key instanceof AST_SymbolRef, - kind: "init", - method: true, - shorthand: false, - key: to_moz(M.key), - value: to_moz(M.value) - }; - } - return { - type: "MethodDefinition", - computed: !(M.key instanceof AST_Symbol) || M.key instanceof AST_SymbolRef, - kind: M.key === "constructor" ? "constructor" : "method", - static: M.static, - key: to_moz(M.key), - value: to_moz(M.value) - }; - }); - - def_to_moz(AST_Class, function To_Moz_Class(M) { - var type = M instanceof AST_ClassExpression ? "ClassExpression" : "ClassDeclaration"; - return { - type: type, - superClass: to_moz(M.extends), - id: M.name ? to_moz(M.name) : null, - body: { - type: "ClassBody", - body: M.properties.map(to_moz) - } - }; - }); - - def_to_moz(AST_NewTarget, function To_Moz_MetaProperty(M) { - return { - type: "MetaProperty", - meta: { - type: "Identifier", - name: "new" - }, - property: { - type: "Identifier", - name: "target" - } - }; - }); - - def_to_moz(AST_Symbol, function To_Moz_Identifier(M, parent) { - if (M instanceof AST_SymbolMethod && parent.quote) { - return { - type: "Literal", - value: M.name - }; - } - var def = M.definition(); - return { - type: "Identifier", - name: def ? def.mangled_name || def.name : M.name - }; - }); - - def_to_moz(AST_RegExp, function To_Moz_RegExpLiteral(M) { - var pattern = M.value.source; - var flags = M.value.toString().match(/[gimuys]*$/)[0]; - return { - type: "Literal", - value: new RegExp(pattern, flags), - raw: M.value.raw_source, - regex: { - pattern: pattern, - flags: flags, - } - }; - }); - - def_to_moz(AST_Constant, function To_Moz_Literal(M) { - var value = M.value; - if (typeof value === "number" && (value < 0 || (value === 0 && 1 / value < 0))) { - return { - type: "UnaryExpression", - operator: "-", - prefix: true, - argument: { - type: "Literal", - value: -value, - raw: M.start.raw - } - }; - } - return { - type: "Literal", - value: value, - raw: M.start.raw - }; - }); - - def_to_moz(AST_Atom, function To_Moz_Atom(M) { - return { - type: "Identifier", - name: String(M.value) - }; - }); - - def_to_moz(AST_BigInt, M => ({ - type: "BigIntLiteral", - value: M.value - })); - - AST_Boolean.DEFMETHOD("to_mozilla_ast", AST_Constant.prototype.to_mozilla_ast); - AST_Null.DEFMETHOD("to_mozilla_ast", AST_Constant.prototype.to_mozilla_ast); - AST_Hole.DEFMETHOD("to_mozilla_ast", function To_Moz_ArrayHole() { return null; }); - - AST_Block.DEFMETHOD("to_mozilla_ast", AST_BlockStatement.prototype.to_mozilla_ast); - AST_Lambda.DEFMETHOD("to_mozilla_ast", AST_Function.prototype.to_mozilla_ast); - - /* -----[ tools ]----- */ - - function raw_token(moznode) { - if (moznode.type == "Literal") { - return moznode.raw != null ? moznode.raw : moznode.value + ""; - } - } - - function my_start_token(moznode) { - var loc = moznode.loc, start = loc && loc.start; - var range = moznode.range; - return new AST_Token({ - file : loc && loc.source, - line : start && start.line, - col : start && start.column, - pos : range ? range[0] : moznode.start, - endline : start && start.line, - endcol : start && start.column, - endpos : range ? range[0] : moznode.start, - raw : raw_token(moznode), - }); - } - - function my_end_token(moznode) { - var loc = moznode.loc, end = loc && loc.end; - var range = moznode.range; - return new AST_Token({ - file : loc && loc.source, - line : end && end.line, - col : end && end.column, - pos : range ? range[1] : moznode.end, - endline : end && end.line, - endcol : end && end.column, - endpos : range ? range[1] : moznode.end, - raw : raw_token(moznode), - }); - } - - function map(moztype, mytype, propmap) { - var moz_to_me = "function From_Moz_" + moztype + "(M){\n"; - moz_to_me += "return new U2." + mytype.name + "({\n" + - "start: my_start_token(M),\n" + - "end: my_end_token(M)"; - - var me_to_moz = "function To_Moz_" + moztype + "(M){\n"; - me_to_moz += "return {\n" + - "type: " + JSON.stringify(moztype); - - if (propmap) propmap.split(/\s*,\s*/).forEach(function(prop) { - var m = /([a-z0-9$_]+)([=@>%])([a-z0-9$_]+)/i.exec(prop); - if (!m) throw new Error("Can't understand property map: " + prop); - var moz = m[1], how = m[2], my = m[3]; - moz_to_me += ",\n" + my + ": "; - me_to_moz += ",\n" + moz + ": "; - switch (how) { - case "@": - moz_to_me += "M." + moz + ".map(from_moz)"; - me_to_moz += "M." + my + ".map(to_moz)"; - break; - case ">": - moz_to_me += "from_moz(M." + moz + ")"; - me_to_moz += "to_moz(M." + my + ")"; - break; - case "=": - moz_to_me += "M." + moz; - me_to_moz += "M." + my; - break; - case "%": - moz_to_me += "from_moz(M." + moz + ").body"; - me_to_moz += "to_moz_block(M)"; - break; + } + throw new Error(string_template("Can't handle constant of type: {type}", { + type: typeof val + })); + } +} + +function best_of_expression(ast1, ast2) { + return ast1.size() > ast2.size() ? ast2 : ast1; +} + +function best_of_statement(ast1, ast2) { + return best_of_expression( + make_node(AST_SimpleStatement, ast1, { + body: ast1 + }), + make_node(AST_SimpleStatement, ast2, { + body: ast2 + }) + ).body; +} + +/** Find which node is smaller, and return that */ +function best_of(compressor, ast1, ast2) { + if (first_in_statement(compressor)) { + return best_of_statement(ast1, ast2); + } else { + return best_of_expression(ast1, ast2); + } +} + +/** Simplify an object property's key, if possible */ +function get_simple_key(key) { + if (key instanceof AST_Constant) { + return key.getValue(); + } + if (key instanceof AST_UnaryPrefix + && key.operator == "void" + && key.expression instanceof AST_Constant) { + return; + } + return key; +} + +function read_property(obj, key) { + key = get_simple_key(key); + if (key instanceof AST_Node) return; + + var value; + if (obj instanceof AST_Array) { + var elements = obj.elements; + if (key == "length") return make_node_from_constant(elements.length, obj); + if (typeof key == "number" && key in elements) value = elements[key]; + } else if (obj instanceof AST_Object) { + key = "" + key; + var props = obj.properties; + for (var i = props.length; --i >= 0;) { + var prop = props[i]; + if (!(prop instanceof AST_ObjectKeyVal)) return; + if (!value && props[i].key === key) value = props[i].value; + } + } + + return value instanceof AST_SymbolRef && value.fixed_value() || value; +} + +function has_break_or_continue(loop, parent) { + var found = false; + var tw = new TreeWalker(function(node) { + if (found || node instanceof AST_Scope) return true; + if (node instanceof AST_LoopControl && tw.loopcontrol_target(node) === loop) { + return found = true; + } + }); + if (parent instanceof AST_LabeledStatement) tw.push(parent); + tw.push(loop); + loop.body.walk(tw); + return found; +} + +// we shouldn't compress (1,func)(something) to +// func(something) because that changes the meaning of +// the func (becomes lexical instead of global). +function maintain_this_binding(parent, orig, val) { + if ( + parent instanceof AST_UnaryPrefix && parent.operator == "delete" + || parent instanceof AST_Call && parent.expression === orig + && ( + val instanceof AST_Chain + || val instanceof AST_PropAccess + || val instanceof AST_SymbolRef && val.name == "eval" + ) + ) { + const zero = make_node(AST_Number, orig, { value: 0 }); + return make_sequence(orig, [ zero, val ]); + } else { + return val; + } +} + +function is_func_expr(node) { + return node instanceof AST_Arrow || node instanceof AST_Function; +} + +/** + * Used to determine whether the node can benefit from negation. + * Not the case with arrow functions (you need an extra set of parens). */ +function is_iife_call(node) { + if (node.TYPE != "Call") return false; + return node.expression instanceof AST_Function || is_iife_call(node.expression); +} + +function is_empty(thing) { + if (thing === null) return true; + if (thing instanceof AST_EmptyStatement) return true; + if (thing instanceof AST_BlockStatement) return thing.body.length == 0; + return false; +} + +const identifier_atom = makePredicate("Infinity NaN undefined"); +function is_identifier_atom(node) { + return node instanceof AST_Infinity + || node instanceof AST_NaN + || node instanceof AST_Undefined; +} + +/** Check if this is a SymbolRef node which has one def of a certain AST type */ +function is_ref_of(ref, type) { + if (!(ref instanceof AST_SymbolRef)) return false; + var orig = ref.definition().orig; + for (var i = orig.length; --i >= 0;) { + if (orig[i] instanceof type) return true; + } +} + +/**Can we turn { block contents... } into just the block contents ? + * Not if one of these is inside. + **/ +function can_be_evicted_from_block(node) { + return !( + node instanceof AST_DefClass || + node instanceof AST_Defun || + node instanceof AST_Let || + node instanceof AST_Const || + node instanceof AST_Export || + node instanceof AST_Import + ); +} + +function as_statement_array(thing) { + if (thing === null) return []; + if (thing instanceof AST_BlockStatement) return thing.body; + if (thing instanceof AST_EmptyStatement) return []; + if (thing instanceof AST_Statement) return [ thing ]; + throw new Error("Can't convert thing to statement array"); +} + +function is_reachable(scope_node, defs) { + const find_ref = node => { + if (node instanceof AST_SymbolRef && defs.includes(node.definition())) { + return walk_abort; + } + }; + + return walk_parent(scope_node, (node, info) => { + if (node instanceof AST_Scope && node !== scope_node) { + var parent = info.parent(); + + if ( + parent instanceof AST_Call + && parent.expression === node + // Async/Generators aren't guaranteed to sync evaluate all of + // their body steps, so it's possible they close over the variable. + && !(node.async || node.is_generator) + ) { + return; + } + + if (walk(node, find_ref)) return walk_abort; + + return true; + } + }); +} + +/** Check if a ref refers to the name of a function/class it's defined within */ +function is_recursive_ref(compressor, def) { + var node; + for (var i = 0; node = compressor.parent(i); i++) { + if (node instanceof AST_Lambda || node instanceof AST_Class) { + var name = node.name; + if (name && name.definition() === def) { + return true; + } + } + } + return false; +} + +// TODO this only works with AST_Defun, shouldn't it work for other ways of defining functions? +function retain_top_func(fn, compressor) { + return compressor.top_retain + && fn instanceof AST_Defun + && has_flag(fn, TOP) + && fn.name + && compressor.top_retain(fn.name); +} + +/*********************************************************************** + + A JavaScript tokenizer / parser / beautifier / compressor. + https://github.com/mishoo/UglifyJS2 + + -------------------------------- (C) --------------------------------- + + Author: Mihai Bazon + + http://mihai.bazon.net/blog + + Distributed under the BSD license: + + Copyright 2012 (c) Mihai Bazon + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + ***********************************************************************/ + +// Lists of native methods, useful for `unsafe` option which assumes they exist. +// Note: Lots of methods and functions are missing here, in case they aren't pure +// or not available in all JS environments. + +function make_nested_lookup(obj) { + const out = new Map(); + for (var key of Object.keys(obj)) { + out.set(key, makePredicate(obj[key])); + } + + const does_have = (global_name, fname) => { + const inner_map = out.get(global_name); + return inner_map != null && inner_map.has(fname); + }; + return does_have; +} + +// Objects which are safe to access without throwing or causing a side effect. +// Usually we'd check the `unsafe` option first but these are way too common for that +const pure_prop_access_globals = new Set([ + "Number", + "String", + "Array", + "Object", + "Function", + "Promise", +]); + +const object_methods = [ + "constructor", + "toString", + "valueOf", +]; + +const is_pure_native_method = make_nested_lookup({ + Array: [ + "at", + "flat", + "includes", + "indexOf", + "join", + "lastIndexOf", + "slice", + ...object_methods, + ], + Boolean: object_methods, + Function: object_methods, + Number: [ + "toExponential", + "toFixed", + "toPrecision", + ...object_methods, + ], + Object: object_methods, + RegExp: [ + "test", + ...object_methods, + ], + String: [ + "at", + "charAt", + "charCodeAt", + "charPointAt", + "concat", + "endsWith", + "fromCharCode", + "fromCodePoint", + "includes", + "indexOf", + "italics", + "lastIndexOf", + "localeCompare", + "match", + "matchAll", + "normalize", + "padStart", + "padEnd", + "repeat", + "replace", + "replaceAll", + "search", + "slice", + "split", + "startsWith", + "substr", + "substring", + "repeat", + "toLocaleLowerCase", + "toLocaleUpperCase", + "toLowerCase", + "toUpperCase", + "trim", + "trimEnd", + "trimStart", + ...object_methods, + ], +}); + +const is_pure_native_fn = make_nested_lookup({ + Array: [ + "isArray", + ], + Math: [ + "abs", + "acos", + "asin", + "atan", + "ceil", + "cos", + "exp", + "floor", + "log", + "round", + "sin", + "sqrt", + "tan", + "atan2", + "pow", + "max", + "min", + ], + Number: [ + "isFinite", + "isNaN", + ], + Object: [ + "create", + "getOwnPropertyDescriptor", + "getOwnPropertyNames", + "getPrototypeOf", + "isExtensible", + "isFrozen", + "isSealed", + "hasOwn", + "keys", + ], + String: [ + "fromCharCode", + ], +}); + +// Known numeric values which come with JS environments +const is_pure_native_value = make_nested_lookup({ + Math: [ + "E", + "LN10", + "LN2", + "LOG2E", + "LOG10E", + "PI", + "SQRT1_2", + "SQRT2", + ], + Number: [ + "MAX_VALUE", + "MIN_VALUE", + "NaN", + "NEGATIVE_INFINITY", + "POSITIVE_INFINITY", + ], +}); + +/*********************************************************************** + + A JavaScript tokenizer / parser / beautifier / compressor. + https://github.com/mishoo/UglifyJS2 + + -------------------------------- (C) --------------------------------- + + Author: Mihai Bazon + + http://mihai.bazon.net/blog + + Distributed under the BSD license: + + Copyright 2012 (c) Mihai Bazon + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + ***********************************************************************/ + +// Functions and methods to infer certain facts about expressions +// It's not always possible to be 100% sure about something just by static analysis, +// so `true` means yes, and `false` means maybe + +const is_undeclared_ref = (node) => + node instanceof AST_SymbolRef && node.definition().undeclared; + +const lazy_op = makePredicate("&& || ??"); +const unary_side_effects = makePredicate("delete ++ --"); + +// methods to determine whether an expression has a boolean result type +(function(def_is_boolean) { + const unary_bool = makePredicate("! delete"); + const binary_bool = makePredicate("in instanceof == != === !== < <= >= >"); + def_is_boolean(AST_Node, return_false); + def_is_boolean(AST_UnaryPrefix, function() { + return unary_bool.has(this.operator); + }); + def_is_boolean(AST_Binary, function() { + return binary_bool.has(this.operator) + || lazy_op.has(this.operator) + && this.left.is_boolean() + && this.right.is_boolean(); + }); + def_is_boolean(AST_Conditional, function() { + return this.consequent.is_boolean() && this.alternative.is_boolean(); + }); + def_is_boolean(AST_Assign, function() { + return this.operator == "=" && this.right.is_boolean(); + }); + def_is_boolean(AST_Sequence, function() { + return this.tail_node().is_boolean(); + }); + def_is_boolean(AST_True, return_true); + def_is_boolean(AST_False, return_true); +})(function(node, func) { + node.DEFMETHOD("is_boolean", func); +}); + +// methods to determine if an expression has a numeric result type +(function(def_is_number) { + def_is_number(AST_Node, return_false); + def_is_number(AST_Number, return_true); + const unary = makePredicate("+ - ~ ++ --"); + def_is_number(AST_Unary, function() { + return unary.has(this.operator) && !(this.expression instanceof AST_BigInt); + }); + const numeric_ops = makePredicate("- * / % & | ^ << >> >>>"); + def_is_number(AST_Binary, function(compressor) { + return numeric_ops.has(this.operator) || this.operator == "+" + && this.left.is_number(compressor) + && this.right.is_number(compressor); + }); + def_is_number(AST_Assign, function(compressor) { + return numeric_ops.has(this.operator.slice(0, -1)) + || this.operator == "=" && this.right.is_number(compressor); + }); + def_is_number(AST_Sequence, function(compressor) { + return this.tail_node().is_number(compressor); + }); + def_is_number(AST_Conditional, function(compressor) { + return this.consequent.is_number(compressor) && this.alternative.is_number(compressor); + }); +})(function(node, func) { + node.DEFMETHOD("is_number", func); +}); + +// methods to determine if an expression has a string result type +(function(def_is_string) { + def_is_string(AST_Node, return_false); + def_is_string(AST_String, return_true); + def_is_string(AST_TemplateString, return_true); + def_is_string(AST_UnaryPrefix, function() { + return this.operator == "typeof"; + }); + def_is_string(AST_Binary, function(compressor) { + return this.operator == "+" && + (this.left.is_string(compressor) || this.right.is_string(compressor)); + }); + def_is_string(AST_Assign, function(compressor) { + return (this.operator == "=" || this.operator == "+=") && this.right.is_string(compressor); + }); + def_is_string(AST_Sequence, function(compressor) { + return this.tail_node().is_string(compressor); + }); + def_is_string(AST_Conditional, function(compressor) { + return this.consequent.is_string(compressor) && this.alternative.is_string(compressor); + }); +})(function(node, func) { + node.DEFMETHOD("is_string", func); +}); + +function is_undefined(node, compressor) { + return ( + has_flag(node, UNDEFINED) + || node instanceof AST_Undefined + || node instanceof AST_UnaryPrefix + && node.operator == "void" + && !node.expression.has_side_effects(compressor) + ); +} + +// Is the node explicitly null or undefined. +function is_null_or_undefined(node, compressor) { + let fixed; + return ( + node instanceof AST_Null + || is_undefined(node, compressor) + || ( + node instanceof AST_SymbolRef + && (fixed = node.definition().fixed) instanceof AST_Node + && is_nullish(fixed, compressor) + ) + ); +} + +// Find out if this expression is optionally chained from a base-point that we +// can statically analyze as null or undefined. +function is_nullish_shortcircuited(node, compressor) { + if (node instanceof AST_PropAccess || node instanceof AST_Call) { + return ( + (node.optional && is_null_or_undefined(node.expression, compressor)) + || is_nullish_shortcircuited(node.expression, compressor) + ); + } + if (node instanceof AST_Chain) return is_nullish_shortcircuited(node.expression, compressor); + return false; +} + +// Find out if something is == null, or can short circuit into nullish. +// Used to optimize ?. and ?? +function is_nullish(node, compressor) { + if (is_null_or_undefined(node, compressor)) return true; + return is_nullish_shortcircuited(node, compressor); +} + +// Determine if expression might cause side effects +// If there's a possibility that a node may change something when it's executed, this returns true +(function(def_has_side_effects) { + def_has_side_effects(AST_Node, return_true); + + def_has_side_effects(AST_EmptyStatement, return_false); + def_has_side_effects(AST_Constant, return_false); + def_has_side_effects(AST_This, return_false); + + function any(list, compressor) { + for (var i = list.length; --i >= 0;) + if (list[i].has_side_effects(compressor)) + return true; + return false; + } + + def_has_side_effects(AST_Block, function(compressor) { + return any(this.body, compressor); + }); + def_has_side_effects(AST_Call, function(compressor) { + if ( + !this.is_callee_pure(compressor) + && (!this.expression.is_call_pure(compressor) + || this.expression.has_side_effects(compressor)) + ) { + return true; + } + return any(this.args, compressor); + }); + def_has_side_effects(AST_Switch, function(compressor) { + return this.expression.has_side_effects(compressor) + || any(this.body, compressor); + }); + def_has_side_effects(AST_Case, function(compressor) { + return this.expression.has_side_effects(compressor) + || any(this.body, compressor); + }); + def_has_side_effects(AST_Try, function(compressor) { + return this.body.has_side_effects(compressor) + || this.bcatch && this.bcatch.has_side_effects(compressor) + || this.bfinally && this.bfinally.has_side_effects(compressor); + }); + def_has_side_effects(AST_If, function(compressor) { + return this.condition.has_side_effects(compressor) + || this.body && this.body.has_side_effects(compressor) + || this.alternative && this.alternative.has_side_effects(compressor); + }); + def_has_side_effects(AST_ImportMeta, return_false); + def_has_side_effects(AST_LabeledStatement, function(compressor) { + return this.body.has_side_effects(compressor); + }); + def_has_side_effects(AST_SimpleStatement, function(compressor) { + return this.body.has_side_effects(compressor); + }); + def_has_side_effects(AST_Lambda, return_false); + def_has_side_effects(AST_Class, function (compressor) { + if (this.extends && this.extends.has_side_effects(compressor)) { + return true; + } + return any(this.properties, compressor); + }); + def_has_side_effects(AST_ClassStaticBlock, function(compressor) { + return any(this.body, compressor); + }); + def_has_side_effects(AST_Binary, function(compressor) { + return this.left.has_side_effects(compressor) + || this.right.has_side_effects(compressor); + }); + def_has_side_effects(AST_Assign, return_true); + def_has_side_effects(AST_Conditional, function(compressor) { + return this.condition.has_side_effects(compressor) + || this.consequent.has_side_effects(compressor) + || this.alternative.has_side_effects(compressor); + }); + def_has_side_effects(AST_Unary, function(compressor) { + return unary_side_effects.has(this.operator) + || this.expression.has_side_effects(compressor); + }); + def_has_side_effects(AST_SymbolRef, function(compressor) { + return !this.is_declared(compressor) && !pure_prop_access_globals.has(this.name); + }); + def_has_side_effects(AST_SymbolClassProperty, return_false); + def_has_side_effects(AST_SymbolDeclaration, return_false); + def_has_side_effects(AST_Object, function(compressor) { + return any(this.properties, compressor); + }); + def_has_side_effects(AST_ObjectProperty, function(compressor) { + return ( + this.computed_key() && this.key.has_side_effects(compressor) + || this.value && this.value.has_side_effects(compressor) + ); + }); + def_has_side_effects(AST_ClassProperty, function(compressor) { + return ( + this.computed_key() && this.key.has_side_effects(compressor) + || this.static && this.value && this.value.has_side_effects(compressor) + ); + }); + def_has_side_effects(AST_ConciseMethod, function(compressor) { + return this.computed_key() && this.key.has_side_effects(compressor); + }); + def_has_side_effects(AST_ObjectGetter, function(compressor) { + return this.computed_key() && this.key.has_side_effects(compressor); + }); + def_has_side_effects(AST_ObjectSetter, function(compressor) { + return this.computed_key() && this.key.has_side_effects(compressor); + }); + def_has_side_effects(AST_Array, function(compressor) { + return any(this.elements, compressor); + }); + def_has_side_effects(AST_Dot, function(compressor) { + if (is_nullish(this, compressor)) return false; + return !this.optional && this.expression.may_throw_on_access(compressor) + || this.expression.has_side_effects(compressor); + }); + def_has_side_effects(AST_Sub, function(compressor) { + if (is_nullish(this, compressor)) return false; + + return !this.optional && this.expression.may_throw_on_access(compressor) + || this.expression.has_side_effects(compressor) + || this.property.has_side_effects(compressor); + }); + def_has_side_effects(AST_Chain, function (compressor) { + return this.expression.has_side_effects(compressor); + }); + def_has_side_effects(AST_Sequence, function(compressor) { + return any(this.expressions, compressor); + }); + def_has_side_effects(AST_Definitions, function(compressor) { + return any(this.definitions, compressor); + }); + def_has_side_effects(AST_VarDef, function() { + return this.value; + }); + def_has_side_effects(AST_TemplateSegment, return_false); + def_has_side_effects(AST_TemplateString, function(compressor) { + return any(this.segments, compressor); + }); +})(function(node, func) { + node.DEFMETHOD("has_side_effects", func); +}); + +// determine if expression may throw +(function(def_may_throw) { + def_may_throw(AST_Node, return_true); + + def_may_throw(AST_Constant, return_false); + def_may_throw(AST_EmptyStatement, return_false); + def_may_throw(AST_Lambda, return_false); + def_may_throw(AST_SymbolDeclaration, return_false); + def_may_throw(AST_This, return_false); + def_may_throw(AST_ImportMeta, return_false); + + function any(list, compressor) { + for (var i = list.length; --i >= 0;) + if (list[i].may_throw(compressor)) + return true; + return false; + } + + def_may_throw(AST_Class, function(compressor) { + if (this.extends && this.extends.may_throw(compressor)) return true; + return any(this.properties, compressor); + }); + def_may_throw(AST_ClassStaticBlock, function (compressor) { + return any(this.body, compressor); + }); + + def_may_throw(AST_Array, function(compressor) { + return any(this.elements, compressor); + }); + def_may_throw(AST_Assign, function(compressor) { + if (this.right.may_throw(compressor)) return true; + if (!compressor.has_directive("use strict") + && this.operator == "=" + && this.left instanceof AST_SymbolRef) { + return false; + } + return this.left.may_throw(compressor); + }); + def_may_throw(AST_Binary, function(compressor) { + return this.left.may_throw(compressor) + || this.right.may_throw(compressor); + }); + def_may_throw(AST_Block, function(compressor) { + return any(this.body, compressor); + }); + def_may_throw(AST_Call, function(compressor) { + if (is_nullish(this, compressor)) return false; + if (any(this.args, compressor)) return true; + if (this.is_callee_pure(compressor)) return false; + if (this.expression.may_throw(compressor)) return true; + return !(this.expression instanceof AST_Lambda) + || any(this.expression.body, compressor); + }); + def_may_throw(AST_Case, function(compressor) { + return this.expression.may_throw(compressor) + || any(this.body, compressor); + }); + def_may_throw(AST_Conditional, function(compressor) { + return this.condition.may_throw(compressor) + || this.consequent.may_throw(compressor) + || this.alternative.may_throw(compressor); + }); + def_may_throw(AST_Definitions, function(compressor) { + return any(this.definitions, compressor); + }); + def_may_throw(AST_If, function(compressor) { + return this.condition.may_throw(compressor) + || this.body && this.body.may_throw(compressor) + || this.alternative && this.alternative.may_throw(compressor); + }); + def_may_throw(AST_LabeledStatement, function(compressor) { + return this.body.may_throw(compressor); + }); + def_may_throw(AST_Object, function(compressor) { + return any(this.properties, compressor); + }); + def_may_throw(AST_ObjectProperty, function(compressor) { + // TODO key may throw too + return this.value ? this.value.may_throw(compressor) : false; + }); + def_may_throw(AST_ClassProperty, function(compressor) { + return ( + this.computed_key() && this.key.may_throw(compressor) + || this.static && this.value && this.value.may_throw(compressor) + ); + }); + def_may_throw(AST_ConciseMethod, function(compressor) { + return this.computed_key() && this.key.may_throw(compressor); + }); + def_may_throw(AST_ObjectGetter, function(compressor) { + return this.computed_key() && this.key.may_throw(compressor); + }); + def_may_throw(AST_ObjectSetter, function(compressor) { + return this.computed_key() && this.key.may_throw(compressor); + }); + def_may_throw(AST_Return, function(compressor) { + return this.value && this.value.may_throw(compressor); + }); + def_may_throw(AST_Sequence, function(compressor) { + return any(this.expressions, compressor); + }); + def_may_throw(AST_SimpleStatement, function(compressor) { + return this.body.may_throw(compressor); + }); + def_may_throw(AST_Dot, function(compressor) { + if (is_nullish(this, compressor)) return false; + return !this.optional && this.expression.may_throw_on_access(compressor) + || this.expression.may_throw(compressor); + }); + def_may_throw(AST_Sub, function(compressor) { + if (is_nullish(this, compressor)) return false; + return !this.optional && this.expression.may_throw_on_access(compressor) + || this.expression.may_throw(compressor) + || this.property.may_throw(compressor); + }); + def_may_throw(AST_Chain, function(compressor) { + return this.expression.may_throw(compressor); + }); + def_may_throw(AST_Switch, function(compressor) { + return this.expression.may_throw(compressor) + || any(this.body, compressor); + }); + def_may_throw(AST_SymbolRef, function(compressor) { + return !this.is_declared(compressor) && !pure_prop_access_globals.has(this.name); + }); + def_may_throw(AST_SymbolClassProperty, return_false); + def_may_throw(AST_Try, function(compressor) { + return this.bcatch ? this.bcatch.may_throw(compressor) : this.body.may_throw(compressor) + || this.bfinally && this.bfinally.may_throw(compressor); + }); + def_may_throw(AST_Unary, function(compressor) { + if (this.operator == "typeof" && this.expression instanceof AST_SymbolRef) + return false; + return this.expression.may_throw(compressor); + }); + def_may_throw(AST_VarDef, function(compressor) { + if (!this.value) return false; + return this.value.may_throw(compressor); + }); +})(function(node, func) { + node.DEFMETHOD("may_throw", func); +}); + +// determine if expression is constant +(function(def_is_constant_expression) { + function all_refs_local(scope) { + let result = true; + walk(this, node => { + if (node instanceof AST_SymbolRef) { + if (has_flag(this, INLINED)) { + result = false; + return walk_abort; + } + var def = node.definition(); + if ( + member(def, this.enclosed) + && !this.variables.has(def.name) + ) { + if (scope) { + var scope_def = scope.find_variable(node); + if (def.undeclared ? !scope_def : scope_def === def) { + result = "f"; + return true; + } + } + result = false; + return walk_abort; + } + return true; + } + if (node instanceof AST_This && this instanceof AST_Arrow) { + result = false; + return walk_abort; + } + }); + return result; + } + + def_is_constant_expression(AST_Node, return_false); + def_is_constant_expression(AST_Constant, return_true); + def_is_constant_expression(AST_Class, function(scope) { + if (this.extends && !this.extends.is_constant_expression(scope)) { + return false; + } + + for (const prop of this.properties) { + if (prop.computed_key() && !prop.key.is_constant_expression(scope)) { + return false; + } + if (prop.static && prop.value && !prop.value.is_constant_expression(scope)) { + return false; + } + if (prop instanceof AST_ClassStaticBlock) { + return false; + } + } + + return all_refs_local.call(this, scope); + }); + def_is_constant_expression(AST_Lambda, all_refs_local); + def_is_constant_expression(AST_Unary, function() { + return this.expression.is_constant_expression(); + }); + def_is_constant_expression(AST_Binary, function() { + return this.left.is_constant_expression() + && this.right.is_constant_expression(); + }); + def_is_constant_expression(AST_Array, function() { + return this.elements.every((l) => l.is_constant_expression()); + }); + def_is_constant_expression(AST_Object, function() { + return this.properties.every((l) => l.is_constant_expression()); + }); + def_is_constant_expression(AST_ObjectProperty, function() { + return !!(!(this.key instanceof AST_Node) && this.value && this.value.is_constant_expression()); + }); +})(function(node, func) { + node.DEFMETHOD("is_constant_expression", func); +}); + + +// may_throw_on_access() +// returns true if this node may be null, undefined or contain `AST_Accessor` +(function(def_may_throw_on_access) { + AST_Node.DEFMETHOD("may_throw_on_access", function(compressor) { + return !compressor.option("pure_getters") + || this._dot_throw(compressor); + }); + + function is_strict(compressor) { + return /strict/.test(compressor.option("pure_getters")); + } + + def_may_throw_on_access(AST_Node, is_strict); + def_may_throw_on_access(AST_Null, return_true); + def_may_throw_on_access(AST_Undefined, return_true); + def_may_throw_on_access(AST_Constant, return_false); + def_may_throw_on_access(AST_Array, return_false); + def_may_throw_on_access(AST_Object, function(compressor) { + if (!is_strict(compressor)) return false; + for (var i = this.properties.length; --i >=0;) + if (this.properties[i]._dot_throw(compressor)) return true; + return false; + }); + // Do not be as strict with classes as we are with objects. + // Hopefully the community is not going to abuse static getters and setters. + // https://github.com/terser/terser/issues/724#issuecomment-643655656 + def_may_throw_on_access(AST_Class, return_false); + def_may_throw_on_access(AST_ObjectProperty, return_false); + def_may_throw_on_access(AST_ObjectGetter, return_true); + def_may_throw_on_access(AST_Expansion, function(compressor) { + return this.expression._dot_throw(compressor); + }); + def_may_throw_on_access(AST_Function, return_false); + def_may_throw_on_access(AST_Arrow, return_false); + def_may_throw_on_access(AST_UnaryPostfix, return_false); + def_may_throw_on_access(AST_UnaryPrefix, function() { + return this.operator == "void"; + }); + def_may_throw_on_access(AST_Binary, function(compressor) { + return (this.operator == "&&" || this.operator == "||" || this.operator == "??") + && (this.left._dot_throw(compressor) || this.right._dot_throw(compressor)); + }); + def_may_throw_on_access(AST_Assign, function(compressor) { + if (this.logical) return true; + + return this.operator == "=" + && this.right._dot_throw(compressor); + }); + def_may_throw_on_access(AST_Conditional, function(compressor) { + return this.consequent._dot_throw(compressor) + || this.alternative._dot_throw(compressor); + }); + def_may_throw_on_access(AST_Dot, function(compressor) { + if (!is_strict(compressor)) return false; + + if (this.property == "prototype") { + return !( + this.expression instanceof AST_Function + || this.expression instanceof AST_Class + ); + } + return true; + }); + def_may_throw_on_access(AST_Chain, function(compressor) { + return this.expression._dot_throw(compressor); + }); + def_may_throw_on_access(AST_Sequence, function(compressor) { + return this.tail_node()._dot_throw(compressor); + }); + def_may_throw_on_access(AST_SymbolRef, function(compressor) { + if (this.name === "arguments" && this.scope instanceof AST_Lambda) return false; + if (has_flag(this, UNDEFINED)) return true; + if (!is_strict(compressor)) return false; + if (is_undeclared_ref(this) && this.is_declared(compressor)) return false; + if (this.is_immutable()) return false; + var fixed = this.fixed_value(); + return !fixed || fixed._dot_throw(compressor); + }); +})(function(node, func) { + node.DEFMETHOD("_dot_throw", func); +}); + +function is_lhs(node, parent) { + if (parent instanceof AST_Unary && unary_side_effects.has(parent.operator)) return parent.expression; + if (parent instanceof AST_Assign && parent.left === node) return node; + if (parent instanceof AST_ForIn && parent.init === node) return node; +} + +(function(def_find_defs) { + function to_node(value, orig) { + if (value instanceof AST_Node) { + if (!(value instanceof AST_Constant)) { + // Value may be a function, an array including functions and even a complex assign / block expression, + // so it should never be shared in different places. + // Otherwise wrong information may be used in the compression phase + value = value.clone(true); + } + return make_node(value.CTOR, orig, value); + } + if (Array.isArray(value)) return make_node(AST_Array, orig, { + elements: value.map(function(value) { + return to_node(value, orig); + }) + }); + if (value && typeof value == "object") { + var props = []; + for (var key in value) if (HOP(value, key)) { + props.push(make_node(AST_ObjectKeyVal, orig, { + key: key, + value: to_node(value[key], orig) + })); + } + return make_node(AST_Object, orig, { + properties: props + }); + } + return make_node_from_constant(value, orig); + } + + AST_Toplevel.DEFMETHOD("resolve_defines", function(compressor) { + if (!compressor.option("global_defs")) return this; + this.figure_out_scope({ ie8: compressor.option("ie8") }); + return this.transform(new TreeTransformer(function(node) { + var def = node._find_defs(compressor, ""); + if (!def) return; + var level = 0, child = node, parent; + while (parent = this.parent(level++)) { + if (!(parent instanceof AST_PropAccess)) break; + if (parent.expression !== child) break; + child = parent; + } + if (is_lhs(child, parent)) { + return; + } + return def; + })); + }); + def_find_defs(AST_Node, noop); + def_find_defs(AST_Chain, function(compressor, suffix) { + return this.expression._find_defs(compressor, suffix); + }); + def_find_defs(AST_Dot, function(compressor, suffix) { + return this.expression._find_defs(compressor, "." + this.property + suffix); + }); + def_find_defs(AST_SymbolDeclaration, function() { + if (!this.global()) return; + }); + def_find_defs(AST_SymbolRef, function(compressor, suffix) { + if (!this.global()) return; + var defines = compressor.option("global_defs"); + var name = this.name + suffix; + if (HOP(defines, name)) return to_node(defines[name], this); + }); + def_find_defs(AST_ImportMeta, function(compressor, suffix) { + var defines = compressor.option("global_defs"); + var name = "import.meta" + suffix; + if (HOP(defines, name)) return to_node(defines[name], this); + }); +})(function(node, func) { + node.DEFMETHOD("_find_defs", func); +}); + +// method to negate an expression +(function(def_negate) { + function basic_negation(exp) { + return make_node(AST_UnaryPrefix, exp, { + operator: "!", + expression: exp + }); + } + function best(orig, alt, first_in_statement) { + var negated = basic_negation(orig); + if (first_in_statement) { + var stat = make_node(AST_SimpleStatement, alt, { + body: alt + }); + return best_of_expression(negated, stat) === stat ? alt : negated; + } + return best_of_expression(negated, alt); + } + def_negate(AST_Node, function() { + return basic_negation(this); + }); + def_negate(AST_Statement, function() { + throw new Error("Cannot negate a statement"); + }); + def_negate(AST_Function, function() { + return basic_negation(this); + }); + def_negate(AST_Class, function() { + return basic_negation(this); + }); + def_negate(AST_Arrow, function() { + return basic_negation(this); + }); + def_negate(AST_UnaryPrefix, function() { + if (this.operator == "!") + return this.expression; + return basic_negation(this); + }); + def_negate(AST_Sequence, function(compressor) { + var expressions = this.expressions.slice(); + expressions.push(expressions.pop().negate(compressor)); + return make_sequence(this, expressions); + }); + def_negate(AST_Conditional, function(compressor, first_in_statement) { + var self = this.clone(); + self.consequent = self.consequent.negate(compressor); + self.alternative = self.alternative.negate(compressor); + return best(this, self, first_in_statement); + }); + def_negate(AST_Binary, function(compressor, first_in_statement) { + var self = this.clone(), op = this.operator; + if (compressor.option("unsafe_comps")) { + switch (op) { + case "<=" : self.operator = ">" ; return self; + case "<" : self.operator = ">=" ; return self; + case ">=" : self.operator = "<" ; return self; + case ">" : self.operator = "<=" ; return self; + } + } + switch (op) { + case "==" : self.operator = "!="; return self; + case "!=" : self.operator = "=="; return self; + case "===": self.operator = "!=="; return self; + case "!==": self.operator = "==="; return self; + case "&&": + self.operator = "||"; + self.left = self.left.negate(compressor, first_in_statement); + self.right = self.right.negate(compressor); + return best(this, self, first_in_statement); + case "||": + self.operator = "&&"; + self.left = self.left.negate(compressor, first_in_statement); + self.right = self.right.negate(compressor); + return best(this, self, first_in_statement); + } + return basic_negation(this); + }); +})(function(node, func) { + node.DEFMETHOD("negate", function(compressor, first_in_statement) { + return func.call(this, compressor, first_in_statement); + }); +}); + +// Is the callee of this function pure? +var global_pure_fns = makePredicate("Boolean decodeURI decodeURIComponent Date encodeURI encodeURIComponent Error escape EvalError isFinite isNaN Number Object parseFloat parseInt RangeError ReferenceError String SyntaxError TypeError unescape URIError"); +AST_Call.DEFMETHOD("is_callee_pure", function(compressor) { + if (compressor.option("unsafe")) { + var expr = this.expression; + var first_arg = (this.args && this.args[0] && this.args[0].evaluate(compressor)); + if ( + expr.expression && expr.expression.name === "hasOwnProperty" && + (first_arg == null || first_arg.thedef && first_arg.thedef.undeclared) + ) { + return false; + } + if (is_undeclared_ref(expr) && global_pure_fns.has(expr.name)) return true; + if ( + expr instanceof AST_Dot + && is_undeclared_ref(expr.expression) + && is_pure_native_fn(expr.expression.name, expr.property) + ) { + return true; + } + } + return !!has_annotation(this, _PURE) || !compressor.pure_funcs(this); +}); + +// If I call this, is it a pure function? +AST_Node.DEFMETHOD("is_call_pure", return_false); +AST_Dot.DEFMETHOD("is_call_pure", function(compressor) { + if (!compressor.option("unsafe")) return; + const expr = this.expression; + + let native_obj; + if (expr instanceof AST_Array) { + native_obj = "Array"; + } else if (expr.is_boolean()) { + native_obj = "Boolean"; + } else if (expr.is_number(compressor)) { + native_obj = "Number"; + } else if (expr instanceof AST_RegExp) { + native_obj = "RegExp"; + } else if (expr.is_string(compressor)) { + native_obj = "String"; + } else if (!this.may_throw_on_access(compressor)) { + native_obj = "Object"; + } + return native_obj != null && is_pure_native_method(native_obj, this.property); +}); + +// tell me if a statement aborts +const aborts = (thing) => thing && thing.aborts(); + +(function(def_aborts) { + def_aborts(AST_Statement, return_null); + def_aborts(AST_Jump, return_this); + function block_aborts() { + for (var i = 0; i < this.body.length; i++) { + if (aborts(this.body[i])) { + return this.body[i]; + } + } + return null; + } + def_aborts(AST_Import, return_null); + def_aborts(AST_BlockStatement, block_aborts); + def_aborts(AST_SwitchBranch, block_aborts); + def_aborts(AST_DefClass, function () { + for (const prop of this.properties) { + if (prop instanceof AST_ClassStaticBlock) { + if (prop.aborts()) return prop; + } + } + return null; + }); + def_aborts(AST_ClassStaticBlock, block_aborts); + def_aborts(AST_If, function() { + return this.alternative && aborts(this.body) && aborts(this.alternative) && this; + }); +})(function(node, func) { + node.DEFMETHOD("aborts", func); +}); + +AST_Node.DEFMETHOD("contains_this", function() { + return walk(this, node => { + if (node instanceof AST_This) return walk_abort; + if ( + node !== this + && node instanceof AST_Scope + && !(node instanceof AST_Arrow) + ) { + return true; + } + }); +}); + +function is_modified(compressor, tw, node, value, level, immutable) { + var parent = tw.parent(level); + var lhs = is_lhs(node, parent); + if (lhs) return lhs; + if (!immutable + && parent instanceof AST_Call + && parent.expression === node + && !(value instanceof AST_Arrow) + && !(value instanceof AST_Class) + && !parent.is_callee_pure(compressor) + && (!(value instanceof AST_Function) + || !(parent instanceof AST_New) && value.contains_this())) { + return true; + } + if (parent instanceof AST_Array) { + return is_modified(compressor, tw, parent, parent, level + 1); + } + if (parent instanceof AST_ObjectKeyVal && node === parent.value) { + var obj = tw.parent(level + 1); + return is_modified(compressor, tw, obj, obj, level + 2); + } + if (parent instanceof AST_PropAccess && parent.expression === node) { + var prop = read_property(value, parent.property); + return !immutable && is_modified(compressor, tw, parent, prop, level + 1); + } +} + +/*********************************************************************** + + A JavaScript tokenizer / parser / beautifier / compressor. + https://github.com/mishoo/UglifyJS2 + + -------------------------------- (C) --------------------------------- + + Author: Mihai Bazon + + http://mihai.bazon.net/blog + + Distributed under the BSD license: + + Copyright 2012 (c) Mihai Bazon + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + ***********************************************************************/ + +// methods to evaluate a constant expression + +function def_eval(node, func) { + node.DEFMETHOD("_eval", func); +} + +// Used to propagate a nullish short-circuit signal upwards through the chain. +const nullish = Symbol("This AST_Chain is nullish"); + +// If the node has been successfully reduced to a constant, +// then its value is returned; otherwise the element itself +// is returned. +// They can be distinguished as constant value is never a +// descendant of AST_Node. +AST_Node.DEFMETHOD("evaluate", function (compressor) { + if (!compressor.option("evaluate")) + return this; + var val = this._eval(compressor, 1); + if (!val || val instanceof RegExp) + return val; + if (typeof val == "function" || typeof val == "object" || val == nullish) + return this; + + // Evaluated strings can be larger than the original expression + if (typeof val === "string") { + const unevaluated_size = this.size(compressor); + if (val.length + 2 > unevaluated_size) return this; + } + + return val; +}); + +var unaryPrefix = makePredicate("! ~ - + void"); +AST_Node.DEFMETHOD("is_constant", function () { + // Accomodate when compress option evaluate=false + // as well as the common constant expressions !0 and -1 + if (this instanceof AST_Constant) { + return !(this instanceof AST_RegExp); + } else { + return this instanceof AST_UnaryPrefix + && this.expression instanceof AST_Constant + && unaryPrefix.has(this.operator); + } +}); + +def_eval(AST_Statement, function () { + throw new Error(string_template("Cannot evaluate a statement [{file}:{line},{col}]", this.start)); +}); + +def_eval(AST_Lambda, return_this); +def_eval(AST_Class, return_this); +def_eval(AST_Node, return_this); +def_eval(AST_Constant, function () { + return this.getValue(); +}); + +def_eval(AST_BigInt, return_this); + +def_eval(AST_RegExp, function (compressor) { + let evaluated = compressor.evaluated_regexps.get(this.value); + if (evaluated === undefined && regexp_is_safe(this.value.source)) { + try { + const { source, flags } = this.value; + evaluated = new RegExp(source, flags); + } catch (e) { + evaluated = null; + } + compressor.evaluated_regexps.set(this.value, evaluated); + } + return evaluated || this; +}); + +def_eval(AST_TemplateString, function () { + if (this.segments.length !== 1) return this; + return this.segments[0].value; +}); + +def_eval(AST_Function, function (compressor) { + if (compressor.option("unsafe")) { + var fn = function () { }; + fn.node = this; + fn.toString = () => this.print_to_string(); + return fn; + } + return this; +}); + +def_eval(AST_Array, function (compressor, depth) { + if (compressor.option("unsafe")) { + var elements = []; + for (var i = 0, len = this.elements.length; i < len; i++) { + var element = this.elements[i]; + var value = element._eval(compressor, depth); + if (element === value) + return this; + elements.push(value); + } + return elements; + } + return this; +}); + +def_eval(AST_Object, function (compressor, depth) { + if (compressor.option("unsafe")) { + var val = {}; + for (var i = 0, len = this.properties.length; i < len; i++) { + var prop = this.properties[i]; + if (prop instanceof AST_Expansion) + return this; + var key = prop.key; + if (key instanceof AST_Symbol) { + key = key.name; + } else if (key instanceof AST_Node) { + key = key._eval(compressor, depth); + if (key === prop.key) + return this; + } + if (typeof Object.prototype[key] === "function") { + return this; + } + if (prop.value instanceof AST_Function) + continue; + val[key] = prop.value._eval(compressor, depth); + if (val[key] === prop.value) + return this; + } + return val; + } + return this; +}); + +var non_converting_unary = makePredicate("! typeof void"); +def_eval(AST_UnaryPrefix, function (compressor, depth) { + var e = this.expression; + // Function would be evaluated to an array and so typeof would + // incorrectly return 'object'. Hence making is a special case. + if (compressor.option("typeofs") + && this.operator == "typeof" + && (e instanceof AST_Lambda + || e instanceof AST_SymbolRef + && e.fixed_value() instanceof AST_Lambda)) { + return typeof function () { }; + } + if (!non_converting_unary.has(this.operator)) + depth++; + e = e._eval(compressor, depth); + if (e === this.expression) + return this; + switch (this.operator) { + case "!": return !e; + case "typeof": + // typeof returns "object" or "function" on different platforms + // so cannot evaluate reliably + if (e instanceof RegExp) + return this; + return typeof e; + case "void": return void e; + case "~": return ~e; + case "-": return -e; + case "+": return +e; + } + return this; +}); + +var non_converting_binary = makePredicate("&& || ?? === !=="); +const identity_comparison = makePredicate("== != === !=="); +const has_identity = value => typeof value === "object" + || typeof value === "function" + || typeof value === "symbol"; + +def_eval(AST_Binary, function (compressor, depth) { + if (!non_converting_binary.has(this.operator)) + depth++; + + var left = this.left._eval(compressor, depth); + if (left === this.left) + return this; + var right = this.right._eval(compressor, depth); + if (right === this.right) + return this; + var result; + + if (left != null + && right != null + && identity_comparison.has(this.operator) + && has_identity(left) + && has_identity(right) + && typeof left === typeof right) { + // Do not compare by reference + return this; + } + + switch (this.operator) { + case "&&": result = left && right; break; + case "||": result = left || right; break; + case "??": result = left != null ? left : right; break; + case "|": result = left | right; break; + case "&": result = left & right; break; + case "^": result = left ^ right; break; + case "+": result = left + right; break; + case "*": result = left * right; break; + case "**": result = Math.pow(left, right); break; + case "/": result = left / right; break; + case "%": result = left % right; break; + case "-": result = left - right; break; + case "<<": result = left << right; break; + case ">>": result = left >> right; break; + case ">>>": result = left >>> right; break; + case "==": result = left == right; break; + case "===": result = left === right; break; + case "!=": result = left != right; break; + case "!==": result = left !== right; break; + case "<": result = left < right; break; + case "<=": result = left <= right; break; + case ">": result = left > right; break; + case ">=": result = left >= right; break; + default: + return this; + } + if (isNaN(result) && compressor.find_parent(AST_With)) { + // leave original expression as is + return this; + } + return result; +}); + +def_eval(AST_Conditional, function (compressor, depth) { + var condition = this.condition._eval(compressor, depth); + if (condition === this.condition) + return this; + var node = condition ? this.consequent : this.alternative; + var value = node._eval(compressor, depth); + return value === node ? this : value; +}); + +// Set of AST_SymbolRef which are currently being evaluated. +// Avoids infinite recursion of ._eval() +const reentrant_ref_eval = new Set(); +def_eval(AST_SymbolRef, function (compressor, depth) { + if (reentrant_ref_eval.has(this)) + return this; + + var fixed = this.fixed_value(); + if (!fixed) + return this; + + reentrant_ref_eval.add(this); + const value = fixed._eval(compressor, depth); + reentrant_ref_eval.delete(this); + + if (value === fixed) + return this; + + if (value && typeof value == "object") { + var escaped = this.definition().escaped; + if (escaped && depth > escaped) + return this; + } + return value; +}); + +const global_objs = { Array, Math, Number, Object, String }; + +const regexp_flags = new Set([ + "dotAll", + "global", + "ignoreCase", + "multiline", + "sticky", + "unicode", +]); + +def_eval(AST_PropAccess, function (compressor, depth) { + let obj = this.expression._eval(compressor, depth + 1); + if (obj === nullish || (this.optional && obj == null)) return nullish; + + // `.length` of strings and arrays is always safe + if (this.property === "length") { + if (typeof obj === "string") { + return obj.length; + } + + const is_spreadless_array = + obj instanceof AST_Array + && obj.elements.every(el => !(el instanceof AST_Expansion)); + + if ( + is_spreadless_array + && obj.elements.every(el => !el.has_side_effects(compressor)) + ) { + return obj.elements.length; + } + } + + if (compressor.option("unsafe")) { + var key = this.property; + if (key instanceof AST_Node) { + key = key._eval(compressor, depth); + if (key === this.property) + return this; + } + + var exp = this.expression; + if (is_undeclared_ref(exp)) { + var aa; + var first_arg = exp.name === "hasOwnProperty" + && key === "call" + && (aa = compressor.parent() && compressor.parent().args) + && (aa && aa[0] + && aa[0].evaluate(compressor)); + + first_arg = first_arg instanceof AST_Dot ? first_arg.expression : first_arg; + + if (first_arg == null || first_arg.thedef && first_arg.thedef.undeclared) { + return this.clone(); + } + if (!is_pure_native_value(exp.name, key)) + return this; + obj = global_objs[exp.name]; + } else { + if (obj instanceof RegExp) { + if (key == "source") { + return regexp_source_fix(obj.source); + } else if (key == "flags" || regexp_flags.has(key)) { + return obj[key]; + } + } + if (!obj || obj === exp || !HOP(obj, key)) + return this; + + if (typeof obj == "function") + switch (key) { + case "name": + return obj.node.name ? obj.node.name.name : ""; + case "length": + return obj.node.length_property(); + default: + return this; + } + } + return obj[key]; + } + return this; +}); + +def_eval(AST_Chain, function (compressor, depth) { + const evaluated = this.expression._eval(compressor, depth); + return evaluated === nullish + ? undefined + : evaluated === this.expression + ? this + : evaluated; +}); + +def_eval(AST_Call, function (compressor, depth) { + var exp = this.expression; + + const callee = exp._eval(compressor, depth); + if (callee === nullish || (this.optional && callee == null)) return nullish; + + if (compressor.option("unsafe") && exp instanceof AST_PropAccess) { + var key = exp.property; + if (key instanceof AST_Node) { + key = key._eval(compressor, depth); + if (key === exp.property) + return this; + } + var val; + var e = exp.expression; + if (is_undeclared_ref(e)) { + var first_arg = e.name === "hasOwnProperty" && + key === "call" && + (this.args[0] && this.args[0].evaluate(compressor)); + + first_arg = first_arg instanceof AST_Dot ? first_arg.expression : first_arg; + + if ((first_arg == null || first_arg.thedef && first_arg.thedef.undeclared)) { + return this.clone(); + } + if (!is_pure_native_fn(e.name, key)) return this; + val = global_objs[e.name]; + } else { + val = e._eval(compressor, depth + 1); + if (val === e || !val) + return this; + if (!is_pure_native_method(val.constructor.name, key)) + return this; + } + var args = []; + for (var i = 0, len = this.args.length; i < len; i++) { + var arg = this.args[i]; + var value = arg._eval(compressor, depth); + if (arg === value) + return this; + if (arg instanceof AST_Lambda) + return this; + args.push(value); + } + try { + return val[key].apply(val, args); + } catch (ex) { + // We don't really care + } + } + return this; +}); + +// Also a subclass of AST_Call +def_eval(AST_New, return_this); + +/*********************************************************************** + + A JavaScript tokenizer / parser / beautifier / compressor. + https://github.com/mishoo/UglifyJS2 + + -------------------------------- (C) --------------------------------- + + Author: Mihai Bazon + + http://mihai.bazon.net/blog + + Distributed under the BSD license: + + Copyright 2012 (c) Mihai Bazon + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + ***********************************************************************/ + +// AST_Node#drop_side_effect_free() gets called when we don't care about the value, +// only about side effects. We'll be defining this method for each node type in this module +// +// Examples: +// foo++ -> foo++ +// 1 + func() -> func() +// 10 -> (nothing) +// knownPureFunc(foo++) -> foo++ + +function def_drop_side_effect_free(node, func) { + node.DEFMETHOD("drop_side_effect_free", func); +} + +// Drop side-effect-free elements from an array of expressions. +// Returns an array of expressions with side-effects or null +// if all elements were dropped. Note: original array may be +// returned if nothing changed. +function trim(nodes, compressor, first_in_statement) { + var len = nodes.length; + if (!len) return null; + + var ret = [], changed = false; + for (var i = 0; i < len; i++) { + var node = nodes[i].drop_side_effect_free(compressor, first_in_statement); + changed |= node !== nodes[i]; + if (node) { + ret.push(node); + first_in_statement = false; + } + } + return changed ? ret.length ? ret : null : nodes; +} + +def_drop_side_effect_free(AST_Node, return_this); +def_drop_side_effect_free(AST_Constant, return_null); +def_drop_side_effect_free(AST_This, return_null); + +def_drop_side_effect_free(AST_Call, function (compressor, first_in_statement) { + if (is_nullish_shortcircuited(this, compressor)) { + return this.expression.drop_side_effect_free(compressor, first_in_statement); + } + + if (!this.is_callee_pure(compressor)) { + if (this.expression.is_call_pure(compressor)) { + var exprs = this.args.slice(); + exprs.unshift(this.expression.expression); + exprs = trim(exprs, compressor, first_in_statement); + return exprs && make_sequence(this, exprs); + } + if (is_func_expr(this.expression) + && (!this.expression.name || !this.expression.name.definition().references.length)) { + var node = this.clone(); + node.expression.process_expression(false, compressor); + return node; + } + return this; + } + + var args = trim(this.args, compressor, first_in_statement); + return args && make_sequence(this, args); +}); + +def_drop_side_effect_free(AST_Accessor, return_null); + +def_drop_side_effect_free(AST_Function, return_null); + +def_drop_side_effect_free(AST_Arrow, return_null); + +def_drop_side_effect_free(AST_Class, function (compressor) { + const with_effects = []; + const trimmed_extends = this.extends && this.extends.drop_side_effect_free(compressor); + if (trimmed_extends) + with_effects.push(trimmed_extends); + + for (const prop of this.properties) { + if (prop instanceof AST_ClassStaticBlock) { + if (prop.has_side_effects(compressor)) { + return this; // Be cautious about these + } + } else { + const trimmed_prop = prop.drop_side_effect_free(compressor); + if (trimmed_prop) { + if (trimmed_prop.contains_this()) return this; + + with_effects.push(trimmed_prop); + } + } + } + + if (!with_effects.length) + return null; + + const exprs = make_sequence(this, with_effects); + if (this instanceof AST_DefClass) { + // We want a statement + return make_node(AST_SimpleStatement, this, { body: exprs }); + } else { + return exprs; + } +}); + +def_drop_side_effect_free(AST_ClassProperty, function (compressor) { + const key = this.computed_key() && this.key.drop_side_effect_free(compressor); + + const value = this.static && this.value + && this.value.drop_side_effect_free(compressor); + + if (key && value) + return make_sequence(this, [key, value]); + return key || value || null; +}); + +def_drop_side_effect_free(AST_Binary, function (compressor, first_in_statement) { + var right = this.right.drop_side_effect_free(compressor); + if (!right) + return this.left.drop_side_effect_free(compressor, first_in_statement); + if (lazy_op.has(this.operator)) { + if (right === this.right) + return this; + var node = this.clone(); + node.right = right; + return node; + } else { + var left = this.left.drop_side_effect_free(compressor, first_in_statement); + if (!left) + return this.right.drop_side_effect_free(compressor, first_in_statement); + return make_sequence(this, [left, right]); + } +}); + +def_drop_side_effect_free(AST_Assign, function (compressor) { + if (this.logical) + return this; + + var left = this.left; + if (left.has_side_effects(compressor) + || compressor.has_directive("use strict") + && left instanceof AST_PropAccess + && left.expression.is_constant()) { + return this; + } + set_flag(this, WRITE_ONLY); + while (left instanceof AST_PropAccess) { + left = left.expression; + } + if (left.is_constant_expression(compressor.find_parent(AST_Scope))) { + return this.right.drop_side_effect_free(compressor); + } + return this; +}); + +def_drop_side_effect_free(AST_Conditional, function (compressor) { + var consequent = this.consequent.drop_side_effect_free(compressor); + var alternative = this.alternative.drop_side_effect_free(compressor); + if (consequent === this.consequent && alternative === this.alternative) + return this; + if (!consequent) + return alternative ? make_node(AST_Binary, this, { + operator: "||", + left: this.condition, + right: alternative + }) : this.condition.drop_side_effect_free(compressor); + if (!alternative) + return make_node(AST_Binary, this, { + operator: "&&", + left: this.condition, + right: consequent + }); + var node = this.clone(); + node.consequent = consequent; + node.alternative = alternative; + return node; +}); + +def_drop_side_effect_free(AST_Unary, function (compressor, first_in_statement) { + if (unary_side_effects.has(this.operator)) { + if (!this.expression.has_side_effects(compressor)) { + set_flag(this, WRITE_ONLY); + } else { + clear_flag(this, WRITE_ONLY); + } + return this; + } + if (this.operator == "typeof" && this.expression instanceof AST_SymbolRef) + return null; + var expression = this.expression.drop_side_effect_free(compressor, first_in_statement); + if (first_in_statement && expression && is_iife_call(expression)) { + if (expression === this.expression && this.operator == "!") + return this; + return expression.negate(compressor, first_in_statement); + } + return expression; +}); + +def_drop_side_effect_free(AST_SymbolRef, function (compressor) { + const safe_access = this.is_declared(compressor) + || pure_prop_access_globals.has(this.name); + return safe_access ? null : this; +}); + +def_drop_side_effect_free(AST_Object, function (compressor, first_in_statement) { + var values = trim(this.properties, compressor, first_in_statement); + return values && make_sequence(this, values); +}); + +def_drop_side_effect_free(AST_ObjectProperty, function (compressor, first_in_statement) { + const computed_key = this instanceof AST_ObjectKeyVal && this.key instanceof AST_Node; + const key = computed_key && this.key.drop_side_effect_free(compressor, first_in_statement); + const value = this.value && this.value.drop_side_effect_free(compressor, first_in_statement); + if (key && value) { + return make_sequence(this, [key, value]); + } + return key || value; +}); + +def_drop_side_effect_free(AST_ConciseMethod, function () { + return this.computed_key() ? this.key : null; +}); + +def_drop_side_effect_free(AST_ObjectGetter, function () { + return this.computed_key() ? this.key : null; +}); + +def_drop_side_effect_free(AST_ObjectSetter, function () { + return this.computed_key() ? this.key : null; +}); + +def_drop_side_effect_free(AST_Array, function (compressor, first_in_statement) { + var values = trim(this.elements, compressor, first_in_statement); + return values && make_sequence(this, values); +}); + +def_drop_side_effect_free(AST_Dot, function (compressor, first_in_statement) { + if (is_nullish_shortcircuited(this, compressor)) { + return this.expression.drop_side_effect_free(compressor, first_in_statement); + } + if (this.expression.may_throw_on_access(compressor)) return this; + + return this.expression.drop_side_effect_free(compressor, first_in_statement); +}); + +def_drop_side_effect_free(AST_Sub, function (compressor, first_in_statement) { + if (is_nullish_shortcircuited(this, compressor)) { + return this.expression.drop_side_effect_free(compressor, first_in_statement); + } + if (this.expression.may_throw_on_access(compressor)) return this; + + var expression = this.expression.drop_side_effect_free(compressor, first_in_statement); + if (!expression) + return this.property.drop_side_effect_free(compressor, first_in_statement); + var property = this.property.drop_side_effect_free(compressor); + if (!property) + return expression; + return make_sequence(this, [expression, property]); +}); + +def_drop_side_effect_free(AST_Chain, function (compressor, first_in_statement) { + return this.expression.drop_side_effect_free(compressor, first_in_statement); +}); + +def_drop_side_effect_free(AST_Sequence, function (compressor) { + var last = this.tail_node(); + var expr = last.drop_side_effect_free(compressor); + if (expr === last) + return this; + var expressions = this.expressions.slice(0, -1); + if (expr) + expressions.push(expr); + if (!expressions.length) { + return make_node(AST_Number, this, { value: 0 }); + } + return make_sequence(this, expressions); +}); + +def_drop_side_effect_free(AST_Expansion, function (compressor, first_in_statement) { + return this.expression.drop_side_effect_free(compressor, first_in_statement); +}); + +def_drop_side_effect_free(AST_TemplateSegment, return_null); + +def_drop_side_effect_free(AST_TemplateString, function (compressor) { + var values = trim(this.segments, compressor, first_in_statement); + return values && make_sequence(this, values); +}); + +/*********************************************************************** + + A JavaScript tokenizer / parser / beautifier / compressor. + https://github.com/mishoo/UglifyJS2 + + -------------------------------- (C) --------------------------------- + + Author: Mihai Bazon + + http://mihai.bazon.net/blog + + Distributed under the BSD license: + + Copyright 2012 (c) Mihai Bazon + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + ***********************************************************************/ + +const r_keep_assign = /keep_assign/; + +/** Drop unused variables from this scope */ +AST_Scope.DEFMETHOD("drop_unused", function(compressor) { + if (!compressor.option("unused")) return; + if (compressor.has_directive("use asm")) return; + var self = this; + if (self.pinned()) return; + var drop_funcs = !(self instanceof AST_Toplevel) || compressor.toplevel.funcs; + var drop_vars = !(self instanceof AST_Toplevel) || compressor.toplevel.vars; + const assign_as_unused = r_keep_assign.test(compressor.option("unused")) ? return_false : function(node) { + if (node instanceof AST_Assign + && !node.logical + && (has_flag(node, WRITE_ONLY) || node.operator == "=") + ) { + return node.left; + } + if (node instanceof AST_Unary && has_flag(node, WRITE_ONLY)) { + return node.expression; + } + }; + var in_use_ids = new Map(); + var fixed_ids = new Map(); + if (self instanceof AST_Toplevel && compressor.top_retain) { + self.variables.forEach(function(def) { + if (compressor.top_retain(def) && !in_use_ids.has(def.id)) { + in_use_ids.set(def.id, def); + } + }); + } + var var_defs_by_id = new Map(); + var initializations = new Map(); + // pass 1: find out which symbols are directly used in + // this scope (not in nested scopes). + var scope = this; + var tw = new TreeWalker(function(node, descend) { + if (node instanceof AST_Lambda && node.uses_arguments && !tw.has_directive("use strict")) { + node.argnames.forEach(function(argname) { + if (!(argname instanceof AST_SymbolDeclaration)) return; + var def = argname.definition(); + if (!in_use_ids.has(def.id)) { + in_use_ids.set(def.id, def); + } + }); + } + if (node === self) return; + if (node instanceof AST_Class) { + if (node.has_side_effects(compressor)) { + node.visit_nondeferred_class_parts(tw); + } + } + if (node instanceof AST_Defun || node instanceof AST_DefClass) { + var node_def = node.name.definition(); + const in_export = tw.parent() instanceof AST_Export; + if (in_export || !drop_funcs && scope === self) { + if (node_def.global && !in_use_ids.has(node_def.id)) { + in_use_ids.set(node_def.id, node_def); + } + } + + map_add(initializations, node_def.id, node); + return true; // don't go in nested scopes + } + if (node instanceof AST_SymbolFunarg && scope === self) { + map_add(var_defs_by_id, node.definition().id, node); + } + if (node instanceof AST_Definitions && scope === self) { + const in_export = tw.parent() instanceof AST_Export; + node.definitions.forEach(function(def) { + if (def.name instanceof AST_SymbolVar) { + map_add(var_defs_by_id, def.name.definition().id, def); + } + if (in_export || !drop_vars) { + walk(def.name, node => { + if (node instanceof AST_SymbolDeclaration) { + const def = node.definition(); + if (def.global && !in_use_ids.has(def.id)) { + in_use_ids.set(def.id, def); + } + } + }); + } + if (def.name instanceof AST_Destructuring) { + def.walk(tw); + } + if (def.name instanceof AST_SymbolDeclaration && def.value) { + var node_def = def.name.definition(); + map_add(initializations, node_def.id, def.value); + if (!node_def.chained && def.name.fixed_value() === def.value) { + fixed_ids.set(node_def.id, def); + } + if (def.value.has_side_effects(compressor)) { + def.value.walk(tw); + } + } + }); + return true; + } + return scan_ref_scoped(node, descend); + }); + self.walk(tw); + // pass 2: for every used symbol we need to walk its + // initialization code to figure out if it uses other + // symbols (that may not be in_use). + tw = new TreeWalker(scan_ref_scoped); + in_use_ids.forEach(function (def) { + var init = initializations.get(def.id); + if (init) init.forEach(function(init) { + init.walk(tw); + }); + }); + // pass 3: we should drop declarations not in_use + var tt = new TreeTransformer( + function before(node, descend, in_list) { + var parent = tt.parent(); + if (drop_vars) { + const sym = assign_as_unused(node); + if (sym instanceof AST_SymbolRef) { + var def = sym.definition(); + var in_use = in_use_ids.has(def.id); + if (node instanceof AST_Assign) { + if (!in_use || fixed_ids.has(def.id) && fixed_ids.get(def.id) !== node) { + return maintain_this_binding(parent, node, node.right.transform(tt)); + } + } else if (!in_use) { + return in_list ? MAP.skip : make_node(AST_Number, node, { value: 0 }); + } + } + } + if (scope !== self) return; + var def; + if (node.name + && (node instanceof AST_ClassExpression + && !keep_name(compressor.option("keep_classnames"), (def = node.name.definition()).name) + || node instanceof AST_Function + && !keep_name(compressor.option("keep_fnames"), (def = node.name.definition()).name))) { + // any declarations with same name will overshadow + // name of this anonymous function and can therefore + // never be used anywhere + if (!in_use_ids.has(def.id) || def.orig.length > 1) node.name = null; + } + if (node instanceof AST_Lambda && !(node instanceof AST_Accessor)) { + var trim = !compressor.option("keep_fargs"); + for (var a = node.argnames, i = a.length; --i >= 0;) { + var sym = a[i]; + if (sym instanceof AST_Expansion) { + sym = sym.expression; + } + if (sym instanceof AST_DefaultAssign) { + sym = sym.left; + } + // Do not drop destructuring arguments. + // They constitute a type assertion of sorts + if ( + !(sym instanceof AST_Destructuring) + && !in_use_ids.has(sym.definition().id) + ) { + set_flag(sym, UNUSED); + if (trim) { + a.pop(); + } + } else { + trim = false; + } + } + } + if ((node instanceof AST_Defun || node instanceof AST_DefClass) && node !== self) { + const def = node.name.definition(); + const keep = def.global && !drop_funcs || in_use_ids.has(def.id); + if (!keep) { + // Class "extends" and static blocks may have side effects + if (node instanceof AST_Class) { + const kept = node.drop_side_effect_free(compressor); + if (kept !== node) { + def.eliminated++; + if (kept) return kept; + return in_list ? MAP.skip : make_node(AST_EmptyStatement, node); + } else { + return kept; + } + } + def.eliminated++; + return in_list ? MAP.skip : make_node(AST_EmptyStatement, node); + } + } + if (node instanceof AST_Definitions && !(parent instanceof AST_ForIn && parent.init === node)) { + var drop_block = !(parent instanceof AST_Toplevel) && !(node instanceof AST_Var); + // place uninitialized names at the start + var body = [], head = [], tail = []; + // for unused names whose initialization has + // side effects, we can cascade the init. code + // into the next one, or next statement. + var side_effects = []; + node.definitions.forEach(function(def) { + if (def.value) def.value = def.value.transform(tt); + var is_destructure = def.name instanceof AST_Destructuring; + var sym = is_destructure + ? new SymbolDef(null, { name: "" }) /* fake SymbolDef */ + : def.name.definition(); + if (drop_block && sym.global) return tail.push(def); + if (!(drop_vars || drop_block) + || is_destructure + && (def.name.names.length + || def.name.is_array + || compressor.option("pure_getters") != true) + || in_use_ids.has(sym.id) + ) { + if (def.value && fixed_ids.has(sym.id) && fixed_ids.get(sym.id) !== def) { + def.value = def.value.drop_side_effect_free(compressor); + } + if (def.name instanceof AST_SymbolVar) { + var var_defs = var_defs_by_id.get(sym.id); + if (var_defs.length > 1 && (!def.value || sym.orig.indexOf(def.name) > sym.eliminated)) { + if (def.value) { + var ref = make_node(AST_SymbolRef, def.name, def.name); + sym.references.push(ref); + var assign = make_node(AST_Assign, def, { + operator: "=", + logical: false, + left: ref, + right: def.value + }); + if (fixed_ids.get(sym.id) === def) { + fixed_ids.set(sym.id, assign); + } + side_effects.push(assign.transform(tt)); + } + remove(var_defs, def); + sym.eliminated++; + return; + } + } + if (def.value) { + if (side_effects.length > 0) { + if (tail.length > 0) { + side_effects.push(def.value); + def.value = make_sequence(def.value, side_effects); + } else { + body.push(make_node(AST_SimpleStatement, node, { + body: make_sequence(node, side_effects) + })); + } + side_effects = []; + } + tail.push(def); + } else { + head.push(def); + } + } else if (sym.orig[0] instanceof AST_SymbolCatch) { + var value = def.value && def.value.drop_side_effect_free(compressor); + if (value) side_effects.push(value); + def.value = null; + head.push(def); + } else { + var value = def.value && def.value.drop_side_effect_free(compressor); + if (value) { + side_effects.push(value); + } + sym.eliminated++; + } + }); + if (head.length > 0 || tail.length > 0) { + node.definitions = head.concat(tail); + body.push(node); + } + if (side_effects.length > 0) { + body.push(make_node(AST_SimpleStatement, node, { + body: make_sequence(node, side_effects) + })); + } + switch (body.length) { + case 0: + return in_list ? MAP.skip : make_node(AST_EmptyStatement, node); + case 1: + return body[0]; default: - throw new Error("Can't understand operator in propmap: " + prop); - } - }); + return in_list ? MAP.splice(body) : make_node(AST_BlockStatement, node, { body }); + } + } + // certain combination of unused name + side effect leads to: + // https://github.com/mishoo/UglifyJS2/issues/44 + // https://github.com/mishoo/UglifyJS2/issues/1830 + // https://github.com/mishoo/UglifyJS2/issues/1838 + // that's an invalid AST. + // We fix it at this stage by moving the `var` outside the `for`. + if (node instanceof AST_For) { + descend(node, this); + var block; + if (node.init instanceof AST_BlockStatement) { + block = node.init; + node.init = block.body.pop(); + block.body.push(node); + } + if (node.init instanceof AST_SimpleStatement) { + node.init = node.init.body; + } else if (is_empty(node.init)) { + node.init = null; + } + return !block ? node : in_list ? MAP.splice(block.body) : block; + } + if (node instanceof AST_LabeledStatement + && node.body instanceof AST_For + ) { + descend(node, this); + if (node.body instanceof AST_BlockStatement) { + var block = node.body; + node.body = block.body.pop(); + block.body.push(node); + return in_list ? MAP.splice(block.body) : block; + } + return node; + } + if (node instanceof AST_BlockStatement) { + descend(node, this); + if (in_list && node.body.every(can_be_evicted_from_block)) { + return MAP.splice(node.body); + } + return node; + } + if (node instanceof AST_Scope && !(node instanceof AST_ClassStaticBlock)) { + const save_scope = scope; + scope = node; + descend(node, this); + scope = save_scope; + return node; + } + } + ); + + self.transform(tt); + + function scan_ref_scoped(node, descend) { + var node_def; + const sym = assign_as_unused(node); + if (sym instanceof AST_SymbolRef + && !is_ref_of(node.left, AST_SymbolBlockDeclaration) + && self.variables.get(sym.name) === (node_def = sym.definition()) + ) { + if (node instanceof AST_Assign) { + node.right.walk(tw); + if (!node_def.chained && node.left.fixed_value() === node.right) { + fixed_ids.set(node_def.id, node); + } + } + return true; + } + if (node instanceof AST_SymbolRef) { + node_def = node.definition(); + if (!in_use_ids.has(node_def.id)) { + in_use_ids.set(node_def.id, node_def); + if (node_def.orig[0] instanceof AST_SymbolCatch) { + const redef = node_def.scope.is_block_scope() + && node_def.scope.get_defun_scope().variables.get(node_def.name); + if (redef) in_use_ids.set(redef.id, redef); + } + } + return true; + } + if (node instanceof AST_Class) { + descend(); + return true; + } + if (node instanceof AST_Scope && !(node instanceof AST_ClassStaticBlock)) { + var save_scope = scope; + scope = node; + descend(); + scope = save_scope; + return true; + } + } +}); + +/*********************************************************************** + + A JavaScript tokenizer / parser / beautifier / compressor. + https://github.com/mishoo/UglifyJS2 + + -------------------------------- (C) --------------------------------- + + Author: Mihai Bazon + + http://mihai.bazon.net/blog + + Distributed under the BSD license: + + Copyright 2012 (c) Mihai Bazon + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + ***********************************************************************/ + +/** + * Define the method AST_Node#reduce_vars, which goes through the AST in + * execution order to perform basic flow analysis + */ +function def_reduce_vars(node, func) { + node.DEFMETHOD("reduce_vars", func); +} + +def_reduce_vars(AST_Node, noop); + +/** Clear definition properties */ +function reset_def(compressor, def) { + def.assignments = 0; + def.chained = false; + def.direct_access = false; + def.escaped = 0; + def.recursive_refs = 0; + def.references = []; + def.single_use = undefined; + if ( + def.scope.pinned() + || (def.orig[0] instanceof AST_SymbolFunarg && def.scope.uses_arguments) + ) { + def.fixed = false; + } else if (def.orig[0] instanceof AST_SymbolConst || !compressor.exposed(def)) { + def.fixed = def.init; + } else { + def.fixed = false; + } +} + +function reset_variables(tw, compressor, node) { + node.variables.forEach(function(def) { + reset_def(compressor, def); + if (def.fixed === null) { + tw.defs_to_safe_ids.set(def.id, tw.safe_ids); + mark(tw, def, true); + } else if (def.fixed) { + tw.loop_ids.set(def.id, tw.in_loop); + mark(tw, def, true); + } + }); +} + +function reset_block_variables(compressor, node) { + if (node.block_scope) node.block_scope.variables.forEach((def) => { + reset_def(compressor, def); + }); +} + +function push(tw) { + tw.safe_ids = Object.create(tw.safe_ids); +} + +function pop(tw) { + tw.safe_ids = Object.getPrototypeOf(tw.safe_ids); +} + +function mark(tw, def, safe) { + tw.safe_ids[def.id] = safe; +} + +function safe_to_read(tw, def) { + if (def.single_use == "m") return false; + if (tw.safe_ids[def.id]) { + if (def.fixed == null) { + var orig = def.orig[0]; + if (orig instanceof AST_SymbolFunarg || orig.name == "arguments") return false; + def.fixed = make_node(AST_Undefined, orig); + } + return true; + } + return def.fixed instanceof AST_Defun; +} + +function safe_to_assign(tw, def, scope, value) { + if (def.fixed === undefined) return true; + let def_safe_ids; + if (def.fixed === null + && (def_safe_ids = tw.defs_to_safe_ids.get(def.id)) + ) { + def_safe_ids[def.id] = false; + tw.defs_to_safe_ids.delete(def.id); + return true; + } + if (!HOP(tw.safe_ids, def.id)) return false; + if (!safe_to_read(tw, def)) return false; + if (def.fixed === false) return false; + if (def.fixed != null && (!value || def.references.length > def.assignments)) return false; + if (def.fixed instanceof AST_Defun) { + return value instanceof AST_Node && def.fixed.parent_scope === scope; + } + return def.orig.every((sym) => { + return !(sym instanceof AST_SymbolConst + || sym instanceof AST_SymbolDefun + || sym instanceof AST_SymbolLambda); + }); +} + +function ref_once(tw, compressor, def) { + return compressor.option("unused") + && !def.scope.pinned() + && def.references.length - def.recursive_refs == 1 + && tw.loop_ids.get(def.id) === tw.in_loop; +} + +function is_immutable(value) { + if (!value) return false; + return value.is_constant() + || value instanceof AST_Lambda + || value instanceof AST_This; +} + +// A definition "escapes" when its value can leave the point of use. +// Example: `a = b || c` +// In this example, "b" and "c" are escaping, because they're going into "a" +// +// def.escaped is != 0 when it escapes. +// +// When greater than 1, it means that N chained properties will be read off +// of that def before an escape occurs. This is useful for evaluating +// property accesses, where you need to know when to stop. +function mark_escaped(tw, d, scope, node, value, level = 0, depth = 1) { + var parent = tw.parent(level); + if (value) { + if (value.is_constant()) return; + if (value instanceof AST_ClassExpression) return; + } + + if ( + parent instanceof AST_Assign && (parent.operator === "=" || parent.logical) && node === parent.right + || parent instanceof AST_Call && (node !== parent.expression || parent instanceof AST_New) + || parent instanceof AST_Exit && node === parent.value && node.scope !== d.scope + || parent instanceof AST_VarDef && node === parent.value + || parent instanceof AST_Yield && node === parent.value && node.scope !== d.scope + ) { + if (depth > 1 && !(value && value.is_constant_expression(scope))) depth = 1; + if (!d.escaped || d.escaped > depth) d.escaped = depth; + return; + } else if ( + parent instanceof AST_Array + || parent instanceof AST_Await + || parent instanceof AST_Binary && lazy_op.has(parent.operator) + || parent instanceof AST_Conditional && node !== parent.condition + || parent instanceof AST_Expansion + || parent instanceof AST_Sequence && node === parent.tail_node() + ) { + mark_escaped(tw, d, scope, parent, parent, level + 1, depth); + } else if (parent instanceof AST_ObjectKeyVal && node === parent.value) { + var obj = tw.parent(level + 1); + + mark_escaped(tw, d, scope, obj, obj, level + 2, depth); + } else if (parent instanceof AST_PropAccess && node === parent.expression) { + value = read_property(value, parent.property); + + mark_escaped(tw, d, scope, parent, value, level + 1, depth + 1); + if (value) return; + } + + if (level > 0) return; + if (parent instanceof AST_Sequence && node !== parent.tail_node()) return; + if (parent instanceof AST_SimpleStatement) return; + + d.direct_access = true; +} + +const suppress = node => walk(node, node => { + if (!(node instanceof AST_Symbol)) return; + var d = node.definition(); + if (!d) return; + if (node instanceof AST_SymbolRef) d.references.push(node); + d.fixed = false; +}); + +def_reduce_vars(AST_Accessor, function(tw, descend, compressor) { + push(tw); + reset_variables(tw, compressor, this); + descend(); + pop(tw); + return true; +}); + +def_reduce_vars(AST_Assign, function(tw, descend, compressor) { + var node = this; + if (node.left instanceof AST_Destructuring) { + suppress(node.left); + return; + } + + const finish_walk = () => { + if (node.logical) { + node.left.walk(tw); + + push(tw); + node.right.walk(tw); + pop(tw); + + return true; + } + }; + + var sym = node.left; + if (!(sym instanceof AST_SymbolRef)) return finish_walk(); + + var def = sym.definition(); + var safe = safe_to_assign(tw, def, sym.scope, node.right); + def.assignments++; + if (!safe) return finish_walk(); + + var fixed = def.fixed; + if (!fixed && node.operator != "=" && !node.logical) return finish_walk(); + + var eq = node.operator == "="; + var value = eq ? node.right : node; + if (is_modified(compressor, tw, node, value, 0)) return finish_walk(); + + def.references.push(sym); + + if (!node.logical) { + if (!eq) def.chained = true; + + def.fixed = eq ? function() { + return node.right; + } : function() { + return make_node(AST_Binary, node, { + operator: node.operator.slice(0, -1), + left: fixed instanceof AST_Node ? fixed : fixed(), + right: node.right + }); + }; + } + + if (node.logical) { + mark(tw, def, false); + push(tw); + node.right.walk(tw); + pop(tw); + return true; + } + + mark(tw, def, false); + node.right.walk(tw); + mark(tw, def, true); + + mark_escaped(tw, def, sym.scope, node, value, 0, 1); + + return true; +}); + +def_reduce_vars(AST_Binary, function(tw) { + if (!lazy_op.has(this.operator)) return; + this.left.walk(tw); + push(tw); + this.right.walk(tw); + pop(tw); + return true; +}); + +def_reduce_vars(AST_Block, function(tw, descend, compressor) { + reset_block_variables(compressor, this); +}); + +def_reduce_vars(AST_Case, function(tw) { + push(tw); + this.expression.walk(tw); + pop(tw); + push(tw); + walk_body(this, tw); + pop(tw); + return true; +}); + +def_reduce_vars(AST_Class, function(tw, descend) { + clear_flag(this, INLINED); + push(tw); + descend(); + pop(tw); + return true; +}); + +def_reduce_vars(AST_ClassStaticBlock, function(tw, descend, compressor) { + reset_block_variables(compressor, this); +}); + +def_reduce_vars(AST_Conditional, function(tw) { + this.condition.walk(tw); + push(tw); + this.consequent.walk(tw); + pop(tw); + push(tw); + this.alternative.walk(tw); + pop(tw); + return true; +}); + +def_reduce_vars(AST_Chain, function(tw, descend) { + // Chains' conditions apply left-to-right, cumulatively. + // If we walk normally we don't go in that order because we would pop before pushing again + // Solution: AST_PropAccess and AST_Call push when they are optional, and never pop. + // Then we pop everything when they are done being walked. + const safe_ids = tw.safe_ids; + + descend(); + + // Unroll back to start + tw.safe_ids = safe_ids; + return true; +}); + +def_reduce_vars(AST_Call, function (tw) { + this.expression.walk(tw); + + if (this.optional) { + // Never pop -- it's popped at AST_Chain above + push(tw); + } + + for (const arg of this.args) arg.walk(tw); + + return true; +}); + +def_reduce_vars(AST_PropAccess, function (tw) { + if (!this.optional) return; + + this.expression.walk(tw); + + // Never pop -- it's popped at AST_Chain above + push(tw); + + if (this.property instanceof AST_Node) this.property.walk(tw); + + return true; +}); + +def_reduce_vars(AST_Default, function(tw, descend) { + push(tw); + descend(); + pop(tw); + return true; +}); + +function mark_lambda(tw, descend, compressor) { + clear_flag(this, INLINED); + push(tw); + reset_variables(tw, compressor, this); + + var iife; + if (!this.name + && !this.uses_arguments + && !this.pinned() + && (iife = tw.parent()) instanceof AST_Call + && iife.expression === this + && !iife.args.some(arg => arg instanceof AST_Expansion) + && this.argnames.every(arg_name => arg_name instanceof AST_Symbol) + ) { + // Virtually turn IIFE parameters into variable definitions: + // (function(a,b) {...})(c,d) => (function() {var a=c,b=d; ...})() + // So existing transformation rules can work on them. + this.argnames.forEach((arg, i) => { + if (!arg.definition) return; + var d = arg.definition(); + // Avoid setting fixed when there's more than one origin for a variable value + if (d.orig.length > 1) return; + if (d.fixed === undefined && (!this.uses_arguments || tw.has_directive("use strict"))) { + d.fixed = function() { + return iife.args[i] || make_node(AST_Undefined, iife); + }; + tw.loop_ids.set(d.id, tw.in_loop); + mark(tw, d, true); + } else { + d.fixed = false; + } + }); + } + + descend(); + pop(tw); + + handle_defined_after_hoist(this); + + return true; +} + +/** + * It's possible for a hoisted function to use something that's not defined yet. Example: + * + * hoisted(); + * var defined_after = true; + * function hoisted() { + * // use defined_after + * } + * + * This function is called on the parent to handle this issue. + */ +function handle_defined_after_hoist(parent) { + const defuns = []; + walk(parent, node => { + if (node === parent) return; + if (node instanceof AST_Defun) defuns.push(node); + if ( + node instanceof AST_Scope + || node instanceof AST_SimpleStatement + ) return true; + }); + + const symbols_of_interest = new Set(); + const defuns_of_interest = new Set(); + const potential_conflicts = []; + + for (const defun of defuns) { + const fname_def = defun.name.definition(); + const found_self_ref_in_other_defuns = defuns.some( + d => d !== defun && d.enclosed.indexOf(fname_def) !== -1 + ); + + for (const def of defun.enclosed) { + if ( + def.fixed === false + || def === fname_def + || def.scope.get_defun_scope() !== parent + ) { + continue; + } + + // defun is hoisted, so always safe + if ( + def.assignments === 0 + && def.orig.length === 1 + && def.orig[0] instanceof AST_SymbolDefun + ) { + continue; + } + + if (found_self_ref_in_other_defuns) { + def.fixed = false; + continue; + } + + // for the slower checks below this loop + potential_conflicts.push({ defun, def, fname_def }); + symbols_of_interest.add(def.id); + symbols_of_interest.add(fname_def.id); + defuns_of_interest.add(defun); + } + } + + // linearize all symbols, and locate defs that are read after the defun + if (potential_conflicts.length) { + // All "symbols of interest", that is, defuns or defs, that we found. + // These are placed in order so we can check which is after which. + const found_symbols = []; + // Indices of `found_symbols` which are writes + const found_symbol_writes = new Set(); + // Defun ranges are recorded because we don't care if a function uses the def internally + const defun_ranges = new Map(); + + let tw; + parent.walk((tw = new TreeWalker((node, descend) => { + if (node instanceof AST_Defun && defuns_of_interest.has(node)) { + const start = found_symbols.length; + descend(); + const end = found_symbols.length; + + defun_ranges.set(node, { start, end }); + return true; + } + // if we found a defun on the list, mark IN_DEFUN=id and descend + + if (node instanceof AST_Symbol && node.thedef) { + const id = node.definition().id; + if (symbols_of_interest.has(id)) { + if (node instanceof AST_SymbolDeclaration || is_lhs(node, tw)) { + found_symbol_writes.add(found_symbols.length); + } + found_symbols.push(id); + } + } + }))); + + for (const { def, defun, fname_def } of potential_conflicts) { + const defun_range = defun_ranges.get(defun); + + // find the index in `found_symbols`, with some special rules: + const find = (sym_id, starting_at = 0, must_be_write = false) => { + let index = starting_at; + + for (;;) { + index = found_symbols.indexOf(sym_id, index); + + if (index === -1) { + break; + } else if (index >= defun_range.start && index < defun_range.end) { + index = defun_range.end; + continue; + } else if (must_be_write && !found_symbol_writes.has(index)) { + index++; + continue; + } else { + break; + } + } - moz_to_me += "\n})\n}"; - me_to_moz += "\n}\n}"; - - //moz_to_me = parse(moz_to_me).print_to_string({ beautify: true }); - //me_to_moz = parse(me_to_moz).print_to_string({ beautify: true }); - //console.log(moz_to_me); - - moz_to_me = new Function("U2", "my_start_token", "my_end_token", "from_moz", "return(" + moz_to_me + ")")( - ast, my_start_token, my_end_token, from_moz - ); - me_to_moz = new Function("to_moz", "to_moz_block", "to_moz_scope", "return(" + me_to_moz + ")")( - to_moz, to_moz_block, to_moz_scope - ); - MOZ_TO_ME[moztype] = moz_to_me; - def_to_moz(mytype, me_to_moz); - } - - var FROM_MOZ_STACK = null; - - function from_moz(node) { - FROM_MOZ_STACK.push(node); - var ret = node != null ? MOZ_TO_ME[node.type](node) : null; - FROM_MOZ_STACK.pop(); - return ret; - } - - AST_Node.from_mozilla_ast = function(node) { - var save_stack = FROM_MOZ_STACK; - FROM_MOZ_STACK = []; - var ast = from_moz(node); - FROM_MOZ_STACK = save_stack; - return ast; - }; - - function set_moz_loc(mynode, moznode, myparent) { - var start = mynode.start; - var end = mynode.end; - if (start.pos != null && end.endpos != null) { - moznode.range = [start.pos, end.endpos]; - } - if (start.line) { - moznode.loc = { - start: {line: start.line, column: start.col}, - end: end.endline ? {line: end.endline, column: end.endcol} : null - }; - if (start.file) { - moznode.loc.source = start.file; - } - } - return moznode; - } + return index; + }; + + const read_defun_at = find(fname_def.id); + const wrote_def_at = find(def.id, read_defun_at + 1, true); + + const wrote_def_after_reading_defun = read_defun_at != -1 && wrote_def_at != -1 && wrote_def_at > read_defun_at; + + if (wrote_def_after_reading_defun) { + def.fixed = false; + } + } + } +} + +def_reduce_vars(AST_Lambda, mark_lambda); + +def_reduce_vars(AST_Do, function(tw, descend, compressor) { + reset_block_variables(compressor, this); + const saved_loop = tw.in_loop; + tw.in_loop = this; + push(tw); + this.body.walk(tw); + if (has_break_or_continue(this)) { + pop(tw); + push(tw); + } + this.condition.walk(tw); + pop(tw); + tw.in_loop = saved_loop; + return true; +}); + +def_reduce_vars(AST_For, function(tw, descend, compressor) { + reset_block_variables(compressor, this); + if (this.init) this.init.walk(tw); + const saved_loop = tw.in_loop; + tw.in_loop = this; + push(tw); + if (this.condition) this.condition.walk(tw); + this.body.walk(tw); + if (this.step) { + if (has_break_or_continue(this)) { + pop(tw); + push(tw); + } + this.step.walk(tw); + } + pop(tw); + tw.in_loop = saved_loop; + return true; +}); + +def_reduce_vars(AST_ForIn, function(tw, descend, compressor) { + reset_block_variables(compressor, this); + suppress(this.init); + this.object.walk(tw); + const saved_loop = tw.in_loop; + tw.in_loop = this; + push(tw); + this.body.walk(tw); + pop(tw); + tw.in_loop = saved_loop; + return true; +}); + +def_reduce_vars(AST_If, function(tw) { + this.condition.walk(tw); + push(tw); + this.body.walk(tw); + pop(tw); + if (this.alternative) { + push(tw); + this.alternative.walk(tw); + pop(tw); + } + return true; +}); + +def_reduce_vars(AST_LabeledStatement, function(tw) { + push(tw); + this.body.walk(tw); + pop(tw); + return true; +}); + +def_reduce_vars(AST_SymbolCatch, function() { + this.definition().fixed = false; +}); + +def_reduce_vars(AST_SymbolRef, function(tw, descend, compressor) { + var d = this.definition(); + d.references.push(this); + if (d.references.length == 1 + && !d.fixed + && d.orig[0] instanceof AST_SymbolDefun) { + tw.loop_ids.set(d.id, tw.in_loop); + } + var fixed_value; + if (d.fixed === undefined || !safe_to_read(tw, d)) { + d.fixed = false; + } else if (d.fixed) { + fixed_value = this.fixed_value(); + if ( + fixed_value instanceof AST_Lambda + && is_recursive_ref(tw, d) + ) { + d.recursive_refs++; + } else if (fixed_value + && !compressor.exposed(d) + && ref_once(tw, compressor, d) + ) { + d.single_use = + fixed_value instanceof AST_Lambda && !fixed_value.pinned() + || fixed_value instanceof AST_Class + || d.scope === this.scope && fixed_value.is_constant_expression(); + } else { + d.single_use = false; + } + if (is_modified(compressor, tw, this, fixed_value, 0, is_immutable(fixed_value))) { + if (d.single_use) { + d.single_use = "m"; + } else { + d.fixed = false; + } + } + } + mark_escaped(tw, d, this.scope, this, fixed_value, 0, 1); +}); + +def_reduce_vars(AST_Toplevel, function(tw, descend, compressor) { + this.globals.forEach(function(def) { + reset_def(compressor, def); + }); + reset_variables(tw, compressor, this); + descend(); + handle_defined_after_hoist(this); + return true; +}); + +def_reduce_vars(AST_Try, function(tw, descend, compressor) { + reset_block_variables(compressor, this); + push(tw); + this.body.walk(tw); + pop(tw); + if (this.bcatch) { + push(tw); + this.bcatch.walk(tw); + pop(tw); + } + if (this.bfinally) this.bfinally.walk(tw); + return true; +}); + +def_reduce_vars(AST_Unary, function(tw) { + var node = this; + if (node.operator !== "++" && node.operator !== "--") return; + var exp = node.expression; + if (!(exp instanceof AST_SymbolRef)) return; + var def = exp.definition(); + var safe = safe_to_assign(tw, def, exp.scope, true); + def.assignments++; + if (!safe) return; + var fixed = def.fixed; + if (!fixed) return; + def.references.push(exp); + def.chained = true; + def.fixed = function() { + return make_node(AST_Binary, node, { + operator: node.operator.slice(0, -1), + left: make_node(AST_UnaryPrefix, node, { + operator: "+", + expression: fixed instanceof AST_Node ? fixed : fixed() + }), + right: make_node(AST_Number, node, { + value: 1 + }) + }); + }; + mark(tw, def, true); + return true; +}); + +def_reduce_vars(AST_VarDef, function(tw, descend) { + var node = this; + if (node.name instanceof AST_Destructuring) { + suppress(node.name); + return; + } + var d = node.name.definition(); + if (node.value) { + if (safe_to_assign(tw, d, node.name.scope, node.value)) { + d.fixed = function() { + return node.value; + }; + tw.loop_ids.set(d.id, tw.in_loop); + mark(tw, d, false); + descend(); + mark(tw, d, true); + return true; + } else { + d.fixed = false; + } + } +}); + +def_reduce_vars(AST_While, function(tw, descend, compressor) { + reset_block_variables(compressor, this); + const saved_loop = tw.in_loop; + tw.in_loop = this; + push(tw); + descend(); + pop(tw); + tw.in_loop = saved_loop; + return true; +}); + +/*********************************************************************** + + A JavaScript tokenizer / parser / beautifier / compressor. + https://github.com/mishoo/UglifyJS2 + + -------------------------------- (C) --------------------------------- + + Author: Mihai Bazon + + http://mihai.bazon.net/blog + + Distributed under the BSD license: + + Copyright 2012 (c) Mihai Bazon + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + ***********************************************************************/ + +function loop_body(x) { + if (x instanceof AST_IterationStatement) { + return x.body instanceof AST_BlockStatement ? x.body : x; + } + return x; +} + +function is_lhs_read_only(lhs) { + if (lhs instanceof AST_This) return true; + if (lhs instanceof AST_SymbolRef) return lhs.definition().orig[0] instanceof AST_SymbolLambda; + if (lhs instanceof AST_PropAccess) { + lhs = lhs.expression; + if (lhs instanceof AST_SymbolRef) { + if (lhs.is_immutable()) return false; + lhs = lhs.fixed_value(); + } + if (!lhs) return true; + if (lhs instanceof AST_RegExp) return false; + if (lhs instanceof AST_Constant) return true; + return is_lhs_read_only(lhs); + } + return false; +} + +/** var a = 1 --> var a*/ +function remove_initializers(var_statement) { + var decls = []; + var_statement.definitions.forEach(function(def) { + if (def.name instanceof AST_SymbolDeclaration) { + def.value = null; + decls.push(def); + } else { + def.declarations_as_names().forEach(name => { + decls.push(make_node(AST_VarDef, def, { + name, + value: null + })); + }); + } + }); + return decls.length ? make_node(AST_Var, var_statement, { definitions: decls }) : null; +} + +/** Called on code which we know is unreachable, to keep elements that affect outside of it. */ +function trim_unreachable_code(compressor, stat, target) { + walk(stat, node => { + if (node instanceof AST_Var) { + const no_initializers = remove_initializers(node); + if (no_initializers) target.push(no_initializers); + return true; + } + if ( + node instanceof AST_Defun + && (node === stat || !compressor.has_directive("use strict")) + ) { + target.push(node === stat ? node : make_node(AST_Var, node, { + definitions: [ + make_node(AST_VarDef, node, { + name: make_node(AST_SymbolVar, node.name, node.name), + value: null + }) + ] + })); + return true; + } + if (node instanceof AST_Export || node instanceof AST_Import) { + target.push(node); + return true; + } + if (node instanceof AST_Scope) { + return true; + } + }); +} + +/** Tighten a bunch of statements together, and perform statement-level optimization. */ +function tighten_body(statements, compressor) { + const nearest_scope = compressor.find_scope(); + const defun_scope = nearest_scope.get_defun_scope(); + const { in_loop, in_try } = find_loop_scope_try(); + + var CHANGED, max_iter = 10; + do { + CHANGED = false; + eliminate_spurious_blocks(statements); + if (compressor.option("dead_code")) { + eliminate_dead_code(statements, compressor); + } + if (compressor.option("if_return")) { + handle_if_return(statements, compressor); + } + if (compressor.sequences_limit > 0) { + sequencesize(statements, compressor); + sequencesize_2(statements, compressor); + } + if (compressor.option("join_vars")) { + join_consecutive_vars(statements); + } + if (compressor.option("collapse_vars")) { + collapse(statements, compressor); + } + } while (CHANGED && max_iter-- > 0); + + function find_loop_scope_try() { + var node = compressor.self(), level = 0, in_loop = false, in_try = false; + do { + if (node instanceof AST_IterationStatement) { + in_loop = true; + } else if (node instanceof AST_Scope) { + break; + } else if (node instanceof AST_TryBlock) { + in_try = true; + } + } while (node = compressor.parent(level++)); + + return { in_loop, in_try }; + } + + // Search from right to left for assignment-like expressions: + // - `var a = x;` + // - `a = x;` + // - `++a` + // For each candidate, scan from left to right for first usage, then try + // to fold assignment into the site for compression. + // Will not attempt to collapse assignments into or past code blocks + // which are not sequentially executed, e.g. loops and conditionals. + function collapse(statements, compressor) { + if (nearest_scope.pinned() || defun_scope.pinned()) + return statements; + var args; + var candidates = []; + var stat_index = statements.length; + var scanner = new TreeTransformer(function (node) { + if (abort) + return node; + // Skip nodes before `candidate` as quickly as possible + if (!hit) { + if (node !== hit_stack[hit_index]) + return node; + hit_index++; + if (hit_index < hit_stack.length) + return handle_custom_scan_order(node); + hit = true; + stop_after = find_stop(node, 0); + if (stop_after === node) + abort = true; + return node; + } + // Stop immediately if these node types are encountered + var parent = scanner.parent(); + if (node instanceof AST_Assign + && (node.logical || node.operator != "=" && lhs.equivalent_to(node.left)) + || node instanceof AST_Await + || node instanceof AST_Call && lhs instanceof AST_PropAccess && lhs.equivalent_to(node.expression) + || + (node instanceof AST_Call || node instanceof AST_PropAccess) + && node.optional + || node instanceof AST_Debugger + || node instanceof AST_Destructuring + || node instanceof AST_Expansion + && node.expression instanceof AST_Symbol + && ( + node.expression instanceof AST_This + || node.expression.definition().references.length > 1 + ) + || node instanceof AST_IterationStatement && !(node instanceof AST_For) + || node instanceof AST_LoopControl + || node instanceof AST_Try + || node instanceof AST_With + || node instanceof AST_Yield + || node instanceof AST_Export + || node instanceof AST_Class + || parent instanceof AST_For && node !== parent.init + || !replace_all + && ( + node instanceof AST_SymbolRef + && !node.is_declared(compressor) + && !pure_prop_access_globals.has(node) + ) + || node instanceof AST_SymbolRef + && parent instanceof AST_Call + && has_annotation(parent, _NOINLINE) + ) { + abort = true; + return node; + } + // Stop only if candidate is found within conditional branches + if (!stop_if_hit && (!lhs_local || !replace_all) + && (parent instanceof AST_Binary && lazy_op.has(parent.operator) && parent.left !== node + || parent instanceof AST_Conditional && parent.condition !== node + || parent instanceof AST_If && parent.condition !== node)) { + stop_if_hit = parent; + } + // Replace variable with assignment when found + if ( + can_replace + && !(node instanceof AST_SymbolDeclaration) + && lhs.equivalent_to(node) + && !shadows(scanner.find_scope() || nearest_scope, lvalues) + ) { + if (stop_if_hit) { + abort = true; + return node; + } + if (is_lhs(node, parent)) { + if (value_def) + replaced++; + return node; + } else { + replaced++; + if (value_def && candidate instanceof AST_VarDef) + return node; + } + CHANGED = abort = true; + if (candidate instanceof AST_UnaryPostfix) { + return make_node(AST_UnaryPrefix, candidate, candidate); + } + if (candidate instanceof AST_VarDef) { + var def = candidate.name.definition(); + var value = candidate.value; + if (def.references.length - def.replaced == 1 && !compressor.exposed(def)) { + def.replaced++; + if (funarg && is_identifier_atom(value)) { + return value.transform(compressor); + } else { + return maintain_this_binding(parent, node, value); + } + } + return make_node(AST_Assign, candidate, { + operator: "=", + logical: false, + left: make_node(AST_SymbolRef, candidate.name, candidate.name), + right: value + }); + } + clear_flag(candidate, WRITE_ONLY); + return candidate; + } + // These node types have child nodes that execute sequentially, + // but are otherwise not safe to scan into or beyond them. + var sym; + if (node instanceof AST_Call + || node instanceof AST_Exit + && (side_effects || lhs instanceof AST_PropAccess || may_modify(lhs)) + || node instanceof AST_PropAccess + && (side_effects || node.expression.may_throw_on_access(compressor)) + || node instanceof AST_SymbolRef + && ((lvalues.has(node.name) && lvalues.get(node.name).modified) || side_effects && may_modify(node)) + || node instanceof AST_VarDef && node.value + && (lvalues.has(node.name.name) || side_effects && may_modify(node.name)) + || (sym = is_lhs(node.left, node)) + && (sym instanceof AST_PropAccess || lvalues.has(sym.name)) + || may_throw + && (in_try ? node.has_side_effects(compressor) : side_effects_external(node))) { + stop_after = node; + if (node instanceof AST_Scope) + abort = true; + } + return handle_custom_scan_order(node); + }, function (node) { + if (abort) + return; + if (stop_after === node) + abort = true; + if (stop_if_hit === node) + stop_if_hit = null; + }); + + var multi_replacer = new TreeTransformer(function (node) { + if (abort) + return node; + // Skip nodes before `candidate` as quickly as possible + if (!hit) { + if (node !== hit_stack[hit_index]) + return node; + hit_index++; + if (hit_index < hit_stack.length) + return; + hit = true; + return node; + } + // Replace variable when found + if (node instanceof AST_SymbolRef + && node.name == def.name) { + if (!--replaced) + abort = true; + if (is_lhs(node, multi_replacer.parent())) + return node; + def.replaced++; + value_def.replaced--; + return candidate.value; + } + // Skip (non-executed) functions and (leading) default case in switch statements + if (node instanceof AST_Default || node instanceof AST_Scope) + return node; + }); + + while (--stat_index >= 0) { + // Treat parameters as collapsible in IIFE, i.e. + // function(a, b){ ... }(x()); + // would be translated into equivalent assignments: + // var a = x(), b = undefined; + if (stat_index == 0 && compressor.option("unused")) + extract_args(); + // Find collapsible assignments + var hit_stack = []; + extract_candidates(statements[stat_index]); + while (candidates.length > 0) { + hit_stack = candidates.pop(); + var hit_index = 0; + var candidate = hit_stack[hit_stack.length - 1]; + var value_def = null; + var stop_after = null; + var stop_if_hit = null; + var lhs = get_lhs(candidate); + if (!lhs || is_lhs_read_only(lhs) || lhs.has_side_effects(compressor)) + continue; + // Locate symbols which may execute code outside of scanning range + var lvalues = get_lvalues(candidate); + var lhs_local = is_lhs_local(lhs); + if (lhs instanceof AST_SymbolRef) { + lvalues.set(lhs.name, { def: lhs.definition(), modified: false }); + } + var side_effects = value_has_side_effects(candidate); + var replace_all = replace_all_symbols(); + var may_throw = candidate.may_throw(compressor); + var funarg = candidate.name instanceof AST_SymbolFunarg; + var hit = funarg; + var abort = false, replaced = 0, can_replace = !args || !hit; + if (!can_replace) { + for ( + let j = compressor.self().argnames.lastIndexOf(candidate.name) + 1; + !abort && j < args.length; + j++ + ) { + args[j].transform(scanner); + } + can_replace = true; + } + for (var i = stat_index; !abort && i < statements.length; i++) { + statements[i].transform(scanner); + } + if (value_def) { + var def = candidate.name.definition(); + if (abort && def.references.length - def.replaced > replaced) + replaced = false; + else { + abort = false; + hit_index = 0; + hit = funarg; + for (var i = stat_index; !abort && i < statements.length; i++) { + statements[i].transform(multi_replacer); + } + value_def.single_use = false; + } + } + if (replaced && !remove_candidate(candidate)) + statements.splice(stat_index, 1); + } + } + + function handle_custom_scan_order(node) { + // Skip (non-executed) functions + if (node instanceof AST_Scope) + return node; + + // Scan case expressions first in a switch statement + if (node instanceof AST_Switch) { + node.expression = node.expression.transform(scanner); + for (var i = 0, len = node.body.length; !abort && i < len; i++) { + var branch = node.body[i]; + if (branch instanceof AST_Case) { + if (!hit) { + if (branch !== hit_stack[hit_index]) + continue; + hit_index++; + } + branch.expression = branch.expression.transform(scanner); + if (!replace_all) + break; + } + } + abort = true; + return node; + } + } + + function redefined_within_scope(def, scope) { + if (def.global) + return false; + let cur_scope = def.scope; + while (cur_scope && cur_scope !== scope) { + if (cur_scope.variables.has(def.name)) { + return true; + } + cur_scope = cur_scope.parent_scope; + } + return false; + } + + function has_overlapping_symbol(fn, arg, fn_strict) { + var found = false, scan_this = !(fn instanceof AST_Arrow); + arg.walk(new TreeWalker(function (node, descend) { + if (found) + return true; + if (node instanceof AST_SymbolRef && (fn.variables.has(node.name) || redefined_within_scope(node.definition(), fn))) { + var s = node.definition().scope; + if (s !== defun_scope) + while (s = s.parent_scope) { + if (s === defun_scope) + return true; + } + return found = true; + } + if ((fn_strict || scan_this) && node instanceof AST_This) { + return found = true; + } + if (node instanceof AST_Scope && !(node instanceof AST_Arrow)) { + var prev = scan_this; + scan_this = false; + descend(); + scan_this = prev; + return true; + } + })); + return found; + } + + function extract_args() { + var iife, fn = compressor.self(); + if (is_func_expr(fn) + && !fn.name + && !fn.uses_arguments + && !fn.pinned() + && (iife = compressor.parent()) instanceof AST_Call + && iife.expression === fn + && iife.args.every((arg) => !(arg instanceof AST_Expansion))) { + var fn_strict = compressor.has_directive("use strict"); + if (fn_strict && !member(fn_strict, fn.body)) + fn_strict = false; + var len = fn.argnames.length; + args = iife.args.slice(len); + var names = new Set(); + for (var i = len; --i >= 0;) { + var sym = fn.argnames[i]; + var arg = iife.args[i]; + // The following two line fix is a duplicate of the fix at + // https://github.com/terser/terser/commit/011d3eb08cefe6922c7d1bdfa113fc4aeaca1b75 + // This might mean that these two pieces of code (one here in collapse_vars and another in reduce_vars + // Might be doing the exact same thing. + const def = sym.definition && sym.definition(); + const is_reassigned = def && def.orig.length > 1; + if (is_reassigned) + continue; + args.unshift(make_node(AST_VarDef, sym, { + name: sym, + value: arg + })); + if (names.has(sym.name)) + continue; + names.add(sym.name); + if (sym instanceof AST_Expansion) { + var elements = iife.args.slice(i); + if (elements.every((arg) => !has_overlapping_symbol(fn, arg, fn_strict) + )) { + candidates.unshift([make_node(AST_VarDef, sym, { + name: sym.expression, + value: make_node(AST_Array, iife, { + elements: elements + }) + })]); + } + } else { + if (!arg) { + arg = make_node(AST_Undefined, sym).transform(compressor); + } else if (arg instanceof AST_Lambda && arg.pinned() + || has_overlapping_symbol(fn, arg, fn_strict)) { + arg = null; + } + if (arg) + candidates.unshift([make_node(AST_VarDef, sym, { + name: sym, + value: arg + })]); + } + } + } + } + + function extract_candidates(expr) { + hit_stack.push(expr); + if (expr instanceof AST_Assign) { + if (!expr.left.has_side_effects(compressor) + && !(expr.right instanceof AST_Chain)) { + candidates.push(hit_stack.slice()); + } + extract_candidates(expr.right); + } else if (expr instanceof AST_Binary) { + extract_candidates(expr.left); + extract_candidates(expr.right); + } else if (expr instanceof AST_Call && !has_annotation(expr, _NOINLINE)) { + extract_candidates(expr.expression); + expr.args.forEach(extract_candidates); + } else if (expr instanceof AST_Case) { + extract_candidates(expr.expression); + } else if (expr instanceof AST_Conditional) { + extract_candidates(expr.condition); + extract_candidates(expr.consequent); + extract_candidates(expr.alternative); + } else if (expr instanceof AST_Definitions) { + var len = expr.definitions.length; + // limit number of trailing variable definitions for consideration + var i = len - 200; + if (i < 0) + i = 0; + for (; i < len; i++) { + extract_candidates(expr.definitions[i]); + } + } else if (expr instanceof AST_DWLoop) { + extract_candidates(expr.condition); + if (!(expr.body instanceof AST_Block)) { + extract_candidates(expr.body); + } + } else if (expr instanceof AST_Exit) { + if (expr.value) + extract_candidates(expr.value); + } else if (expr instanceof AST_For) { + if (expr.init) + extract_candidates(expr.init); + if (expr.condition) + extract_candidates(expr.condition); + if (expr.step) + extract_candidates(expr.step); + if (!(expr.body instanceof AST_Block)) { + extract_candidates(expr.body); + } + } else if (expr instanceof AST_ForIn) { + extract_candidates(expr.object); + if (!(expr.body instanceof AST_Block)) { + extract_candidates(expr.body); + } + } else if (expr instanceof AST_If) { + extract_candidates(expr.condition); + if (!(expr.body instanceof AST_Block)) { + extract_candidates(expr.body); + } + if (expr.alternative && !(expr.alternative instanceof AST_Block)) { + extract_candidates(expr.alternative); + } + } else if (expr instanceof AST_Sequence) { + expr.expressions.forEach(extract_candidates); + } else if (expr instanceof AST_SimpleStatement) { + extract_candidates(expr.body); + } else if (expr instanceof AST_Switch) { + extract_candidates(expr.expression); + expr.body.forEach(extract_candidates); + } else if (expr instanceof AST_Unary) { + if (expr.operator == "++" || expr.operator == "--") { + candidates.push(hit_stack.slice()); + } + } else if (expr instanceof AST_VarDef) { + if (expr.value && !(expr.value instanceof AST_Chain)) { + candidates.push(hit_stack.slice()); + extract_candidates(expr.value); + } + } + hit_stack.pop(); + } + + function find_stop(node, level, write_only) { + var parent = scanner.parent(level); + if (parent instanceof AST_Assign) { + if (write_only + && !parent.logical + && !(parent.left instanceof AST_PropAccess + || lvalues.has(parent.left.name))) { + return find_stop(parent, level + 1, write_only); + } + return node; + } + if (parent instanceof AST_Binary) { + if (write_only && (!lazy_op.has(parent.operator) || parent.left === node)) { + return find_stop(parent, level + 1, write_only); + } + return node; + } + if (parent instanceof AST_Call) + return node; + if (parent instanceof AST_Case) + return node; + if (parent instanceof AST_Conditional) { + if (write_only && parent.condition === node) { + return find_stop(parent, level + 1, write_only); + } + return node; + } + if (parent instanceof AST_Definitions) { + return find_stop(parent, level + 1, true); + } + if (parent instanceof AST_Exit) { + return write_only ? find_stop(parent, level + 1, write_only) : node; + } + if (parent instanceof AST_If) { + if (write_only && parent.condition === node) { + return find_stop(parent, level + 1, write_only); + } + return node; + } + if (parent instanceof AST_IterationStatement) + return node; + if (parent instanceof AST_Sequence) { + return find_stop(parent, level + 1, parent.tail_node() !== node); + } + if (parent instanceof AST_SimpleStatement) { + return find_stop(parent, level + 1, true); + } + if (parent instanceof AST_Switch) + return node; + if (parent instanceof AST_VarDef) + return node; + return null; + } + + function mangleable_var(var_def) { + var value = var_def.value; + if (!(value instanceof AST_SymbolRef)) + return; + if (value.name == "arguments") + return; + var def = value.definition(); + if (def.undeclared) + return; + return value_def = def; + } + + function get_lhs(expr) { + if (expr instanceof AST_Assign && expr.logical) { + return false; + } else if (expr instanceof AST_VarDef && expr.name instanceof AST_SymbolDeclaration) { + var def = expr.name.definition(); + if (!member(expr.name, def.orig)) + return; + var referenced = def.references.length - def.replaced; + if (!referenced) + return; + var declared = def.orig.length - def.eliminated; + if (declared > 1 && !(expr.name instanceof AST_SymbolFunarg) + || (referenced > 1 ? mangleable_var(expr) : !compressor.exposed(def))) { + return make_node(AST_SymbolRef, expr.name, expr.name); + } + } else { + const lhs = expr instanceof AST_Assign + ? expr.left + : expr.expression; + return !is_ref_of(lhs, AST_SymbolConst) + && !is_ref_of(lhs, AST_SymbolLet) && lhs; + } + } + + function get_rvalue(expr) { + if (expr instanceof AST_Assign) { + return expr.right; + } else { + return expr.value; + } + } + + function get_lvalues(expr) { + var lvalues = new Map(); + if (expr instanceof AST_Unary) + return lvalues; + var tw = new TreeWalker(function (node) { + var sym = node; + while (sym instanceof AST_PropAccess) + sym = sym.expression; + if (sym instanceof AST_SymbolRef) { + const prev = lvalues.get(sym.name); + if (!prev || !prev.modified) { + lvalues.set(sym.name, { + def: sym.definition(), + modified: is_modified(compressor, tw, node, node, 0) + }); + } + } + }); + get_rvalue(expr).walk(tw); + return lvalues; + } + + function remove_candidate(expr) { + if (expr.name instanceof AST_SymbolFunarg) { + var iife = compressor.parent(), argnames = compressor.self().argnames; + var index = argnames.indexOf(expr.name); + if (index < 0) { + iife.args.length = Math.min(iife.args.length, argnames.length - 1); + } else { + var args = iife.args; + if (args[index]) + args[index] = make_node(AST_Number, args[index], { + value: 0 + }); + } + return true; + } + var found = false; + return statements[stat_index].transform(new TreeTransformer(function (node, descend, in_list) { + if (found) + return node; + if (node === expr || node.body === expr) { + found = true; + if (node instanceof AST_VarDef) { + node.value = node.name instanceof AST_SymbolConst + ? make_node(AST_Undefined, node.value) // `const` always needs value. + : null; + return node; + } + return in_list ? MAP.skip : null; + } + }, function (node) { + if (node instanceof AST_Sequence) + switch (node.expressions.length) { + case 0: return null; + case 1: return node.expressions[0]; + } + })); + } + + function is_lhs_local(lhs) { + while (lhs instanceof AST_PropAccess) + lhs = lhs.expression; + return lhs instanceof AST_SymbolRef + && lhs.definition().scope.get_defun_scope() === defun_scope + && !(in_loop + && (lvalues.has(lhs.name) + || candidate instanceof AST_Unary + || (candidate instanceof AST_Assign + && !candidate.logical + && candidate.operator != "="))); + } + + function value_has_side_effects(expr) { + if (expr instanceof AST_Unary) + return unary_side_effects.has(expr.operator); + return get_rvalue(expr).has_side_effects(compressor); + } + + function replace_all_symbols() { + if (side_effects) + return false; + if (value_def) + return true; + if (lhs instanceof AST_SymbolRef) { + var def = lhs.definition(); + if (def.references.length - def.replaced == (candidate instanceof AST_VarDef ? 1 : 2)) { + return true; + } + } + return false; + } + + function may_modify(sym) { + if (!sym.definition) + return true; // AST_Destructuring + var def = sym.definition(); + if (def.orig.length == 1 && def.orig[0] instanceof AST_SymbolDefun) + return false; + if (def.scope.get_defun_scope() !== defun_scope) + return true; + return def.references.some((ref) => + ref.scope.get_defun_scope() !== defun_scope + ); + } + + function side_effects_external(node, lhs) { + if (node instanceof AST_Assign) + return side_effects_external(node.left, true); + if (node instanceof AST_Unary) + return side_effects_external(node.expression, true); + if (node instanceof AST_VarDef) + return node.value && side_effects_external(node.value); + if (lhs) { + if (node instanceof AST_Dot) + return side_effects_external(node.expression, true); + if (node instanceof AST_Sub) + return side_effects_external(node.expression, true); + if (node instanceof AST_SymbolRef) + return node.definition().scope.get_defun_scope() !== defun_scope; + } + return false; + } + + /** + * Will any of the pulled-in lvalues shadow a variable in newScope or parents? + * similar to scope_encloses_variables_in_this_scope */ + function shadows(my_scope, lvalues) { + for (const { def } of lvalues.values()) { + const looked_up = my_scope.find_variable(def.name); + if (looked_up) { + if (looked_up === def) continue; + return true; + } + } + return false; + } + } + + function eliminate_spurious_blocks(statements) { + var seen_dirs = []; + for (var i = 0; i < statements.length;) { + var stat = statements[i]; + if (stat instanceof AST_BlockStatement && stat.body.every(can_be_evicted_from_block)) { + CHANGED = true; + eliminate_spurious_blocks(stat.body); + statements.splice(i, 1, ...stat.body); + i += stat.body.length; + } else if (stat instanceof AST_EmptyStatement) { + CHANGED = true; + statements.splice(i, 1); + } else if (stat instanceof AST_Directive) { + if (seen_dirs.indexOf(stat.value) < 0) { + i++; + seen_dirs.push(stat.value); + } else { + CHANGED = true; + statements.splice(i, 1); + } + } else + i++; + } + } + + function handle_if_return(statements, compressor) { + var self = compressor.self(); + var multiple_if_returns = has_multiple_if_returns(statements); + var in_lambda = self instanceof AST_Lambda; + for (var i = statements.length; --i >= 0;) { + var stat = statements[i]; + var j = next_index(i); + var next = statements[j]; + + if (in_lambda && !next && stat instanceof AST_Return) { + if (!stat.value) { + CHANGED = true; + statements.splice(i, 1); + continue; + } + if (stat.value instanceof AST_UnaryPrefix && stat.value.operator == "void") { + CHANGED = true; + statements[i] = make_node(AST_SimpleStatement, stat, { + body: stat.value.expression + }); + continue; + } + } + + if (stat instanceof AST_If) { + let ab, new_else; + + ab = aborts(stat.body); + if ( + can_merge_flow(ab) + && (new_else = as_statement_array_with_return(stat.body, ab)) + ) { + if (ab.label) { + remove(ab.label.thedef.references, ab); + } + CHANGED = true; + stat = stat.clone(); + stat.condition = stat.condition.negate(compressor); + stat.body = make_node(AST_BlockStatement, stat, { + body: as_statement_array(stat.alternative).concat(extract_functions()) + }); + stat.alternative = make_node(AST_BlockStatement, stat, { + body: new_else + }); + statements[i] = stat.transform(compressor); + continue; + } - function def_to_moz(mytype, handler) { - mytype.DEFMETHOD("to_mozilla_ast", function(parent) { - return set_moz_loc(this, handler(this, parent)); - }); - } - - var TO_MOZ_STACK = null; - - function to_moz(node) { - if (TO_MOZ_STACK === null) { TO_MOZ_STACK = []; } - TO_MOZ_STACK.push(node); - var ast = node != null ? node.to_mozilla_ast(TO_MOZ_STACK[TO_MOZ_STACK.length - 2]) : null; - TO_MOZ_STACK.pop(); - if (TO_MOZ_STACK.length === 0) { TO_MOZ_STACK = null; } - return ast; - } - - function to_moz_in_destructuring() { - var i = TO_MOZ_STACK.length; - while (i--) { - if (TO_MOZ_STACK[i] instanceof AST_Destructuring) { - return true; - } - } - return false; - } - - function to_moz_block(node) { - return { - type: "BlockStatement", - body: node.body.map(to_moz) - }; - } - - function to_moz_scope(type, node) { - var body = node.body.map(to_moz); - if (node.body[0] instanceof AST_SimpleStatement && node.body[0].body instanceof AST_String) { - body.unshift(to_moz(new AST_EmptyStatement(node.body[0]))); - } - return { - type: type, - body: body - }; - } - })(); - - exports.AST_Accessor = AST_Accessor; - exports.AST_Array = AST_Array; - exports.AST_Arrow = AST_Arrow; - exports.AST_Assign = AST_Assign; - exports.AST_Atom = AST_Atom; - exports.AST_Await = AST_Await; - exports.AST_Binary = AST_Binary; - exports.AST_Block = AST_Block; - exports.AST_BlockStatement = AST_BlockStatement; - exports.AST_Boolean = AST_Boolean; - exports.AST_Break = AST_Break; - exports.AST_Call = AST_Call; - exports.AST_Case = AST_Case; - exports.AST_Catch = AST_Catch; - exports.AST_Class = AST_Class; - exports.AST_ClassExpression = AST_ClassExpression; - exports.AST_ConciseMethod = AST_ConciseMethod; - exports.AST_Conditional = AST_Conditional; - exports.AST_Const = AST_Const; - exports.AST_Constant = AST_Constant; - exports.AST_Continue = AST_Continue; - exports.AST_DWLoop = AST_DWLoop; - exports.AST_Debugger = AST_Debugger; - exports.AST_DefClass = AST_DefClass; - exports.AST_Default = AST_Default; - exports.AST_DefaultAssign = AST_DefaultAssign; - exports.AST_Definitions = AST_Definitions; - exports.AST_Defun = AST_Defun; - exports.AST_Destructuring = AST_Destructuring; - exports.AST_Directive = AST_Directive; - exports.AST_Do = AST_Do; - exports.AST_Dot = AST_Dot; - exports.AST_EmptyStatement = AST_EmptyStatement; - exports.AST_Exit = AST_Exit; - exports.AST_Expansion = AST_Expansion; - exports.AST_Export = AST_Export; - exports.AST_False = AST_False; - exports.AST_Finally = AST_Finally; - exports.AST_For = AST_For; - exports.AST_ForIn = AST_ForIn; - exports.AST_ForOf = AST_ForOf; - exports.AST_Function = AST_Function; - exports.AST_Hole = AST_Hole; - exports.AST_If = AST_If; - exports.AST_Import = AST_Import; - exports.AST_Infinity = AST_Infinity; - exports.AST_IterationStatement = AST_IterationStatement; - exports.AST_Jump = AST_Jump; - exports.AST_Label = AST_Label; - exports.AST_LabelRef = AST_LabelRef; - exports.AST_LabeledStatement = AST_LabeledStatement; - exports.AST_Lambda = AST_Lambda; - exports.AST_Let = AST_Let; - exports.AST_LoopControl = AST_LoopControl; - exports.AST_NaN = AST_NaN; - exports.AST_NameMapping = AST_NameMapping; - exports.AST_New = AST_New; - exports.AST_NewTarget = AST_NewTarget; - exports.AST_Node = AST_Node; - exports.AST_Null = AST_Null; - exports.AST_Number = AST_Number; - exports.AST_Object = AST_Object; - exports.AST_ObjectGetter = AST_ObjectGetter; - exports.AST_ObjectKeyVal = AST_ObjectKeyVal; - exports.AST_ObjectProperty = AST_ObjectProperty; - exports.AST_ObjectSetter = AST_ObjectSetter; - exports.AST_PrefixedTemplateString = AST_PrefixedTemplateString; - exports.AST_PropAccess = AST_PropAccess; - exports.AST_RegExp = AST_RegExp; - exports.AST_Return = AST_Return; - exports.AST_Scope = AST_Scope; - exports.AST_Sequence = AST_Sequence; - exports.AST_SimpleStatement = AST_SimpleStatement; - exports.AST_Statement = AST_Statement; - exports.AST_StatementWithBody = AST_StatementWithBody; - exports.AST_String = AST_String; - exports.AST_Sub = AST_Sub; - exports.AST_Super = AST_Super; - exports.AST_Switch = AST_Switch; - exports.AST_SwitchBranch = AST_SwitchBranch; - exports.AST_Symbol = AST_Symbol; - exports.AST_SymbolBlockDeclaration = AST_SymbolBlockDeclaration; - exports.AST_SymbolCatch = AST_SymbolCatch; - exports.AST_SymbolClass = AST_SymbolClass; - exports.AST_SymbolConst = AST_SymbolConst; - exports.AST_SymbolDeclaration = AST_SymbolDeclaration; - exports.AST_SymbolDefClass = AST_SymbolDefClass; - exports.AST_SymbolDefun = AST_SymbolDefun; - exports.AST_SymbolExport = AST_SymbolExport; - exports.AST_SymbolExportForeign = AST_SymbolExportForeign; - exports.AST_SymbolFunarg = AST_SymbolFunarg; - exports.AST_SymbolImport = AST_SymbolImport; - exports.AST_SymbolImportForeign = AST_SymbolImportForeign; - exports.AST_SymbolLambda = AST_SymbolLambda; - exports.AST_SymbolLet = AST_SymbolLet; - exports.AST_SymbolMethod = AST_SymbolMethod; - exports.AST_SymbolRef = AST_SymbolRef; - exports.AST_SymbolVar = AST_SymbolVar; - exports.AST_TemplateSegment = AST_TemplateSegment; - exports.AST_TemplateString = AST_TemplateString; - exports.AST_This = AST_This; - exports.AST_Throw = AST_Throw; - exports.AST_Token = AST_Token; - exports.AST_Toplevel = AST_Toplevel; - exports.AST_True = AST_True; - exports.AST_Try = AST_Try; - exports.AST_Unary = AST_Unary; - exports.AST_UnaryPostfix = AST_UnaryPostfix; - exports.AST_UnaryPrefix = AST_UnaryPrefix; - exports.AST_Undefined = AST_Undefined; - exports.AST_Var = AST_Var; - exports.AST_VarDef = AST_VarDef; - exports.AST_While = AST_While; - exports.AST_With = AST_With; - exports.AST_Yield = AST_Yield; - exports.Compressor = Compressor; - exports.OutputStream = OutputStream; - exports.TreeTransformer = TreeTransformer; - exports.TreeWalker = TreeWalker; - exports.base54 = base54; - exports.defaults = defaults; - exports.mangle_properties = mangle_properties; - exports.parse = parse; - exports.push_uniq = push_uniq; - exports.reserve_quoted_keys = reserve_quoted_keys; - exports.string_template = string_template; + ab = aborts(stat.alternative); + if ( + can_merge_flow(ab) + && (new_else = as_statement_array_with_return(stat.alternative, ab)) + ) { + if (ab.label) { + remove(ab.label.thedef.references, ab); + } + CHANGED = true; + stat = stat.clone(); + stat.body = make_node(AST_BlockStatement, stat.body, { + body: as_statement_array(stat.body).concat(extract_functions()) + }); + stat.alternative = make_node(AST_BlockStatement, stat.alternative, { + body: new_else + }); + statements[i] = stat.transform(compressor); + continue; + } + } + + if (stat instanceof AST_If && stat.body instanceof AST_Return) { + var value = stat.body.value; + //--- + // pretty silly case, but: + // if (foo()) return; return; ==> foo(); return; + if (!value && !stat.alternative + && (in_lambda && !next || next instanceof AST_Return && !next.value)) { + CHANGED = true; + statements[i] = make_node(AST_SimpleStatement, stat.condition, { + body: stat.condition + }); + continue; + } + //--- + // if (foo()) return x; return y; ==> return foo() ? x : y; + if (value && !stat.alternative && next instanceof AST_Return && next.value) { + CHANGED = true; + stat = stat.clone(); + stat.alternative = next; + statements[i] = stat.transform(compressor); + statements.splice(j, 1); + continue; + } + //--- + // if (foo()) return x; [ return ; ] ==> return foo() ? x : undefined; + if (value && !stat.alternative + && (!next && in_lambda && multiple_if_returns + || next instanceof AST_Return)) { + CHANGED = true; + stat = stat.clone(); + stat.alternative = next || make_node(AST_Return, stat, { + value: null + }); + statements[i] = stat.transform(compressor); + if (next) + statements.splice(j, 1); + continue; + } + //--- + // if (a) return b; if (c) return d; e; ==> return a ? b : c ? d : void e; + // + // if sequences is not enabled, this can lead to an endless loop (issue #866). + // however, with sequences on this helps producing slightly better output for + // the example code. + var prev = statements[prev_index(i)]; + if (compressor.option("sequences") && in_lambda && !stat.alternative + && prev instanceof AST_If && prev.body instanceof AST_Return + && next_index(j) == statements.length && next instanceof AST_SimpleStatement) { + CHANGED = true; + stat = stat.clone(); + stat.alternative = make_node(AST_BlockStatement, next, { + body: [ + next, + make_node(AST_Return, next, { + value: null + }) + ] + }); + statements[i] = stat.transform(compressor); + statements.splice(j, 1); + continue; + } + } + } + + function has_multiple_if_returns(statements) { + var n = 0; + for (var i = statements.length; --i >= 0;) { + var stat = statements[i]; + if (stat instanceof AST_If && stat.body instanceof AST_Return) { + if (++n > 1) + return true; + } + } + return false; + } + + function is_return_void(value) { + return !value || value instanceof AST_UnaryPrefix && value.operator == "void"; + } + + function can_merge_flow(ab) { + if (!ab) + return false; + for (var j = i + 1, len = statements.length; j < len; j++) { + var stat = statements[j]; + if (stat instanceof AST_Const || stat instanceof AST_Let) + return false; + } + var lct = ab instanceof AST_LoopControl ? compressor.loopcontrol_target(ab) : null; + return ab instanceof AST_Return && in_lambda && is_return_void(ab.value) + || ab instanceof AST_Continue && self === loop_body(lct) + || ab instanceof AST_Break && lct instanceof AST_BlockStatement && self === lct; + } + + function extract_functions() { + var tail = statements.slice(i + 1); + statements.length = i + 1; + return tail.filter(function (stat) { + if (stat instanceof AST_Defun) { + statements.push(stat); + return false; + } + return true; + }); + } + + function as_statement_array_with_return(node, ab) { + var body = as_statement_array(node); + if (ab !== body[body.length - 1]) { + return undefined; + } + body = body.slice(0, -1); + if (ab.value) { + body.push(make_node(AST_SimpleStatement, ab.value, { + body: ab.value.expression + })); + } + return body; + } + + function next_index(i) { + for (var j = i + 1, len = statements.length; j < len; j++) { + var stat = statements[j]; + if (!(stat instanceof AST_Var && declarations_only(stat))) { + break; + } + } + return j; + } + + function prev_index(i) { + for (var j = i; --j >= 0;) { + var stat = statements[j]; + if (!(stat instanceof AST_Var && declarations_only(stat))) { + break; + } + } + return j; + } + } + + function eliminate_dead_code(statements, compressor) { + var has_quit; + var self = compressor.self(); + for (var i = 0, n = 0, len = statements.length; i < len; i++) { + var stat = statements[i]; + if (stat instanceof AST_LoopControl) { + var lct = compressor.loopcontrol_target(stat); + if (stat instanceof AST_Break + && !(lct instanceof AST_IterationStatement) + && loop_body(lct) === self + || stat instanceof AST_Continue + && loop_body(lct) === self) { + if (stat.label) { + remove(stat.label.thedef.references, stat); + } + } else { + statements[n++] = stat; + } + } else { + statements[n++] = stat; + } + if (aborts(stat)) { + has_quit = statements.slice(i + 1); + break; + } + } + statements.length = n; + CHANGED = n != len; + if (has_quit) + has_quit.forEach(function (stat) { + trim_unreachable_code(compressor, stat, statements); + }); + } + + function declarations_only(node) { + return node.definitions.every((var_def) => !var_def.value); + } + + function sequencesize(statements, compressor) { + if (statements.length < 2) + return; + var seq = [], n = 0; + function push_seq() { + if (!seq.length) + return; + var body = make_sequence(seq[0], seq); + statements[n++] = make_node(AST_SimpleStatement, body, { body: body }); + seq = []; + } + for (var i = 0, len = statements.length; i < len; i++) { + var stat = statements[i]; + if (stat instanceof AST_SimpleStatement) { + if (seq.length >= compressor.sequences_limit) + push_seq(); + var body = stat.body; + if (seq.length > 0) + body = body.drop_side_effect_free(compressor); + if (body) + merge_sequence(seq, body); + } else if (stat instanceof AST_Definitions && declarations_only(stat) + || stat instanceof AST_Defun) { + statements[n++] = stat; + } else { + push_seq(); + statements[n++] = stat; + } + } + push_seq(); + statements.length = n; + if (n != len) + CHANGED = true; + } + + function to_simple_statement(block, decls) { + if (!(block instanceof AST_BlockStatement)) + return block; + var stat = null; + for (var i = 0, len = block.body.length; i < len; i++) { + var line = block.body[i]; + if (line instanceof AST_Var && declarations_only(line)) { + decls.push(line); + } else if (stat || line instanceof AST_Const || line instanceof AST_Let) { + return false; + } else { + stat = line; + } + } + return stat; + } + + function sequencesize_2(statements, compressor) { + function cons_seq(right) { + n--; + CHANGED = true; + var left = prev.body; + return make_sequence(left, [left, right]).transform(compressor); + } + var n = 0, prev; + for (var i = 0; i < statements.length; i++) { + var stat = statements[i]; + if (prev) { + if (stat instanceof AST_Exit) { + stat.value = cons_seq(stat.value || make_node(AST_Undefined, stat).transform(compressor)); + } else if (stat instanceof AST_For) { + if (!(stat.init instanceof AST_Definitions)) { + const abort = walk(prev.body, node => { + if (node instanceof AST_Scope) + return true; + if (node instanceof AST_Binary + && node.operator === "in") { + return walk_abort; + } + }); + if (!abort) { + if (stat.init) + stat.init = cons_seq(stat.init); + else { + stat.init = prev.body; + n--; + CHANGED = true; + } + } + } + } else if (stat instanceof AST_ForIn) { + if (!(stat.init instanceof AST_Const) && !(stat.init instanceof AST_Let)) { + stat.object = cons_seq(stat.object); + } + } else if (stat instanceof AST_If) { + stat.condition = cons_seq(stat.condition); + } else if (stat instanceof AST_Switch) { + stat.expression = cons_seq(stat.expression); + } else if (stat instanceof AST_With) { + stat.expression = cons_seq(stat.expression); + } + } + if (compressor.option("conditionals") && stat instanceof AST_If) { + var decls = []; + var body = to_simple_statement(stat.body, decls); + var alt = to_simple_statement(stat.alternative, decls); + if (body !== false && alt !== false && decls.length > 0) { + var len = decls.length; + decls.push(make_node(AST_If, stat, { + condition: stat.condition, + body: body || make_node(AST_EmptyStatement, stat.body), + alternative: alt + })); + decls.unshift(n, 1); + [].splice.apply(statements, decls); + i += len; + n += len + 1; + prev = null; + CHANGED = true; + continue; + } + } + statements[n++] = stat; + prev = stat instanceof AST_SimpleStatement ? stat : null; + } + statements.length = n; + } + + function join_object_assignments(defn, body) { + if (!(defn instanceof AST_Definitions)) + return; + var def = defn.definitions[defn.definitions.length - 1]; + if (!(def.value instanceof AST_Object)) + return; + var exprs; + if (body instanceof AST_Assign && !body.logical) { + exprs = [body]; + } else if (body instanceof AST_Sequence) { + exprs = body.expressions.slice(); + } + if (!exprs) + return; + var trimmed = false; + do { + var node = exprs[0]; + if (!(node instanceof AST_Assign)) + break; + if (node.operator != "=") + break; + if (!(node.left instanceof AST_PropAccess)) + break; + var sym = node.left.expression; + if (!(sym instanceof AST_SymbolRef)) + break; + if (def.name.name != sym.name) + break; + if (!node.right.is_constant_expression(nearest_scope)) + break; + var prop = node.left.property; + if (prop instanceof AST_Node) { + prop = prop.evaluate(compressor); + } + if (prop instanceof AST_Node) + break; + prop = "" + prop; + var diff = compressor.option("ecma") < 2015 + && compressor.has_directive("use strict") ? function (node) { + return node.key != prop && (node.key && node.key.name != prop); + } : function (node) { + return node.key && node.key.name != prop; + }; + if (!def.value.properties.every(diff)) + break; + var p = def.value.properties.filter(function (p) { return p.key === prop; })[0]; + if (!p) { + def.value.properties.push(make_node(AST_ObjectKeyVal, node, { + key: prop, + value: node.right + })); + } else { + p.value = new AST_Sequence({ + start: p.start, + expressions: [p.value.clone(), node.right.clone()], + end: p.end + }); + } + exprs.shift(); + trimmed = true; + } while (exprs.length); + return trimmed && exprs; + } + + function join_consecutive_vars(statements) { + var defs; + for (var i = 0, j = -1, len = statements.length; i < len; i++) { + var stat = statements[i]; + var prev = statements[j]; + if (stat instanceof AST_Definitions) { + if (prev && prev.TYPE == stat.TYPE) { + prev.definitions = prev.definitions.concat(stat.definitions); + CHANGED = true; + } else if (defs && defs.TYPE == stat.TYPE && declarations_only(stat)) { + defs.definitions = defs.definitions.concat(stat.definitions); + CHANGED = true; + } else { + statements[++j] = stat; + defs = stat; + } + } else if (stat instanceof AST_Exit) { + stat.value = extract_object_assignments(stat.value); + } else if (stat instanceof AST_For) { + var exprs = join_object_assignments(prev, stat.init); + if (exprs) { + CHANGED = true; + stat.init = exprs.length ? make_sequence(stat.init, exprs) : null; + statements[++j] = stat; + } else if ( + prev instanceof AST_Var + && (!stat.init || stat.init.TYPE == prev.TYPE) + ) { + if (stat.init) { + prev.definitions = prev.definitions.concat(stat.init.definitions); + } + stat.init = prev; + statements[j] = stat; + CHANGED = true; + } else if ( + defs instanceof AST_Var + && stat.init instanceof AST_Var + && declarations_only(stat.init) + ) { + defs.definitions = defs.definitions.concat(stat.init.definitions); + stat.init = null; + statements[++j] = stat; + CHANGED = true; + } else { + statements[++j] = stat; + } + } else if (stat instanceof AST_ForIn) { + stat.object = extract_object_assignments(stat.object); + } else if (stat instanceof AST_If) { + stat.condition = extract_object_assignments(stat.condition); + } else if (stat instanceof AST_SimpleStatement) { + var exprs = join_object_assignments(prev, stat.body); + if (exprs) { + CHANGED = true; + if (!exprs.length) + continue; + stat.body = make_sequence(stat.body, exprs); + } + statements[++j] = stat; + } else if (stat instanceof AST_Switch) { + stat.expression = extract_object_assignments(stat.expression); + } else if (stat instanceof AST_With) { + stat.expression = extract_object_assignments(stat.expression); + } else { + statements[++j] = stat; + } + } + statements.length = j + 1; + + function extract_object_assignments(value) { + statements[++j] = stat; + var exprs = join_object_assignments(prev, value); + if (exprs) { + CHANGED = true; + if (exprs.length) { + return make_sequence(value, exprs); + } else if (value instanceof AST_Sequence) { + return value.tail_node().left; + } else { + return value.left; + } + } + return value; + } + } +} + +/*********************************************************************** + + A JavaScript tokenizer / parser / beautifier / compressor. + https://github.com/mishoo/UglifyJS2 + + -------------------------------- (C) --------------------------------- + + Author: Mihai Bazon + + http://mihai.bazon.net/blog + + Distributed under the BSD license: + + Copyright 2012 (c) Mihai Bazon + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + ***********************************************************************/ + +/** + * Module that contains the inlining logic. + * + * @module + * + * The stars of the show are `inline_into_symbolref` and `inline_into_call`. + */ + +function within_array_or_object_literal(compressor) { + var node, level = 0; + while (node = compressor.parent(level++)) { + if (node instanceof AST_Statement) return false; + if (node instanceof AST_Array + || node instanceof AST_ObjectKeyVal + || node instanceof AST_Object) { + return true; + } + } + return false; +} + +function scope_encloses_variables_in_this_scope(scope, pulled_scope) { + for (const enclosed of pulled_scope.enclosed) { + if (pulled_scope.variables.has(enclosed.name)) { + continue; + } + const looked_up = scope.find_variable(enclosed.name); + if (looked_up) { + if (looked_up === enclosed) continue; + return true; + } + } + return false; +} + +function inline_into_symbolref(self, compressor) { + const parent = compressor.parent(); + + const def = self.definition(); + const nearest_scope = compressor.find_scope(); + if (compressor.top_retain && def.global && compressor.top_retain(def)) { + def.fixed = false; + def.single_use = false; + return self; + } + + let fixed = self.fixed_value(); + let single_use = def.single_use + && !(parent instanceof AST_Call + && (parent.is_callee_pure(compressor)) + || has_annotation(parent, _NOINLINE)) + && !(parent instanceof AST_Export + && fixed instanceof AST_Lambda + && fixed.name); + + if (single_use && fixed instanceof AST_Node) { + single_use = + !fixed.has_side_effects(compressor) + && !fixed.may_throw(compressor); + } + + if (single_use && (fixed instanceof AST_Lambda || fixed instanceof AST_Class)) { + if (retain_top_func(fixed, compressor)) { + single_use = false; + } else if (def.scope !== self.scope + && (def.escaped == 1 + || has_flag(fixed, INLINED) + || within_array_or_object_literal(compressor) + || !compressor.option("reduce_funcs"))) { + single_use = false; + } else if (is_recursive_ref(compressor, def)) { + single_use = false; + } else if (def.scope !== self.scope || def.orig[0] instanceof AST_SymbolFunarg) { + single_use = fixed.is_constant_expression(self.scope); + if (single_use == "f") { + var scope = self.scope; + do { + if (scope instanceof AST_Defun || is_func_expr(scope)) { + set_flag(scope, INLINED); + } + } while (scope = scope.parent_scope); + } + } + } + + if (single_use && (fixed instanceof AST_Lambda || fixed instanceof AST_Class)) { + single_use = + def.scope === self.scope + && !scope_encloses_variables_in_this_scope(nearest_scope, fixed) + || parent instanceof AST_Call + && parent.expression === self + && !scope_encloses_variables_in_this_scope(nearest_scope, fixed) + && !(fixed.name && fixed.name.definition().recursive_refs > 0); + } + + if (single_use && fixed) { + if (fixed instanceof AST_DefClass) { + set_flag(fixed, SQUEEZED); + fixed = make_node(AST_ClassExpression, fixed, fixed); + } + if (fixed instanceof AST_Defun) { + set_flag(fixed, SQUEEZED); + fixed = make_node(AST_Function, fixed, fixed); + } + if (def.recursive_refs > 0 && fixed.name instanceof AST_SymbolDefun) { + const defun_def = fixed.name.definition(); + let lambda_def = fixed.variables.get(fixed.name.name); + let name = lambda_def && lambda_def.orig[0]; + if (!(name instanceof AST_SymbolLambda)) { + name = make_node(AST_SymbolLambda, fixed.name, fixed.name); + name.scope = fixed; + fixed.name = name; + lambda_def = fixed.def_function(name); + } + walk(fixed, node => { + if (node instanceof AST_SymbolRef && node.definition() === defun_def) { + node.thedef = lambda_def; + lambda_def.references.push(node); + } + }); + } + if ( + (fixed instanceof AST_Lambda || fixed instanceof AST_Class) + && fixed.parent_scope !== nearest_scope + ) { + fixed = fixed.clone(true, compressor.get_toplevel()); + + nearest_scope.add_child_scope(fixed); + } + return fixed.optimize(compressor); + } + + // multiple uses + if (fixed) { + let replace; + + if (fixed instanceof AST_This) { + if (!(def.orig[0] instanceof AST_SymbolFunarg) + && def.references.every((ref) => + def.scope === ref.scope + )) { + replace = fixed; + } + } else { + var ev = fixed.evaluate(compressor); + if ( + ev !== fixed + && (compressor.option("unsafe_regexp") || !(ev instanceof RegExp)) + ) { + replace = make_node_from_constant(ev, fixed); + } + } + + if (replace) { + const name_length = self.size(compressor); + const replace_size = replace.size(compressor); + + let overhead = 0; + if (compressor.option("unused") && !compressor.exposed(def)) { + overhead = + (name_length + 2 + replace_size) / + (def.references.length - def.assignments); + } + + if (replace_size <= name_length + overhead) { + return replace; + } + } + } + + return self; +} + +function inline_into_call(self, fn, compressor) { + var exp = self.expression; + var simple_args = self.args.every((arg) => !(arg instanceof AST_Expansion)); + + if (compressor.option("reduce_vars") + && fn instanceof AST_SymbolRef + && !has_annotation(self, _NOINLINE) + ) { + const fixed = fn.fixed_value(); + if (!retain_top_func(fixed, compressor)) { + fn = fixed; + } + } + + var is_func = fn instanceof AST_Lambda; + + var stat = is_func && fn.body[0]; + var is_regular_func = is_func && !fn.is_generator && !fn.async; + var can_inline = is_regular_func && compressor.option("inline") && !self.is_callee_pure(compressor); + if (can_inline && stat instanceof AST_Return) { + let returned = stat.value; + if (!returned || returned.is_constant_expression()) { + if (returned) { + returned = returned.clone(true); + } else { + returned = make_node(AST_Undefined, self); + } + const args = self.args.concat(returned); + return make_sequence(self, args).optimize(compressor); + } + + // optimize identity function + if ( + fn.argnames.length === 1 + && (fn.argnames[0] instanceof AST_SymbolFunarg) + && self.args.length < 2 + && !(self.args[0] instanceof AST_Expansion) + && returned instanceof AST_SymbolRef + && returned.name === fn.argnames[0].name + ) { + const replacement = + (self.args[0] || make_node(AST_Undefined)).optimize(compressor); + + let parent; + if ( + replacement instanceof AST_PropAccess + && (parent = compressor.parent()) instanceof AST_Call + && parent.expression === self + ) { + // identity function was being used to remove `this`, like in + // + // id(bag.no_this)(...) + // + // Replace with a larger but more effish (0, bag.no_this) wrapper. + + return make_sequence(self, [ + make_node(AST_Number, self, { value: 0 }), + replacement + ]); + } + // replace call with first argument or undefined if none passed + return replacement; + } + } + + if (can_inline) { + var scope, in_loop, level = -1; + let def; + let returned_value; + let nearest_scope; + if (simple_args + && !fn.uses_arguments + && !(compressor.parent() instanceof AST_Class) + && !(fn.name && fn instanceof AST_Function) + && (returned_value = can_flatten_body(stat)) + && (exp === fn + || has_annotation(self, _INLINE) + || compressor.option("unused") + && (def = exp.definition()).references.length == 1 + && !is_recursive_ref(compressor, def) + && fn.is_constant_expression(exp.scope)) + && !has_annotation(self, _PURE | _NOINLINE) + && !fn.contains_this() + && can_inject_symbols() + && (nearest_scope = compressor.find_scope()) + && !scope_encloses_variables_in_this_scope(nearest_scope, fn) + && !(function in_default_assign() { + // Due to the fact function parameters have their own scope + // which can't use `var something` in the function body within, + // we simply don't inline into DefaultAssign. + let i = 0; + let p; + while ((p = compressor.parent(i++))) { + if (p instanceof AST_DefaultAssign) return true; + if (p instanceof AST_Block) break; + } + return false; + })() + && !(scope instanceof AST_Class) + ) { + set_flag(fn, SQUEEZED); + nearest_scope.add_child_scope(fn); + return make_sequence(self, flatten_fn(returned_value)).optimize(compressor); + } + } + + if (can_inline && has_annotation(self, _INLINE)) { + set_flag(fn, SQUEEZED); + fn = make_node(fn.CTOR === AST_Defun ? AST_Function : fn.CTOR, fn, fn); + fn = fn.clone(true); + fn.figure_out_scope({}, { + parent_scope: compressor.find_scope(), + toplevel: compressor.get_toplevel() + }); + + return make_node(AST_Call, self, { + expression: fn, + args: self.args, + }).optimize(compressor); + } + + const can_drop_this_call = is_regular_func && compressor.option("side_effects") && fn.body.every(is_empty); + if (can_drop_this_call) { + var args = self.args.concat(make_node(AST_Undefined, self)); + return make_sequence(self, args).optimize(compressor); + } + + if (compressor.option("negate_iife") + && compressor.parent() instanceof AST_SimpleStatement + && is_iife_call(self)) { + return self.negate(compressor, true); + } + + var ev = self.evaluate(compressor); + if (ev !== self) { + ev = make_node_from_constant(ev, self).optimize(compressor); + return best_of(compressor, ev, self); + } + + return self; + + function return_value(stat) { + if (!stat) return make_node(AST_Undefined, self); + if (stat instanceof AST_Return) { + if (!stat.value) return make_node(AST_Undefined, self); + return stat.value.clone(true); + } + if (stat instanceof AST_SimpleStatement) { + return make_node(AST_UnaryPrefix, stat, { + operator: "void", + expression: stat.body.clone(true) + }); + } + } + + function can_flatten_body(stat) { + var body = fn.body; + var len = body.length; + if (compressor.option("inline") < 3) { + return len == 1 && return_value(stat); + } + stat = null; + for (var i = 0; i < len; i++) { + var line = body[i]; + if (line instanceof AST_Var) { + if (stat && !line.definitions.every((var_def) => + !var_def.value + )) { + return false; + } + } else if (stat) { + return false; + } else if (!(line instanceof AST_EmptyStatement)) { + stat = line; + } + } + return return_value(stat); + } + + function can_inject_args(block_scoped, safe_to_inject) { + for (var i = 0, len = fn.argnames.length; i < len; i++) { + var arg = fn.argnames[i]; + if (arg instanceof AST_DefaultAssign) { + if (has_flag(arg.left, UNUSED)) continue; + return false; + } + if (arg instanceof AST_Destructuring) return false; + if (arg instanceof AST_Expansion) { + if (has_flag(arg.expression, UNUSED)) continue; + return false; + } + if (has_flag(arg, UNUSED)) continue; + if (!safe_to_inject + || block_scoped.has(arg.name) + || identifier_atom.has(arg.name) + || scope.conflicting_def(arg.name)) { + return false; + } + if (in_loop) in_loop.push(arg.definition()); + } + return true; + } + + function can_inject_vars(block_scoped, safe_to_inject) { + var len = fn.body.length; + for (var i = 0; i < len; i++) { + var stat = fn.body[i]; + if (!(stat instanceof AST_Var)) continue; + if (!safe_to_inject) return false; + for (var j = stat.definitions.length; --j >= 0;) { + var name = stat.definitions[j].name; + if (name instanceof AST_Destructuring + || block_scoped.has(name.name) + || identifier_atom.has(name.name) + || scope.conflicting_def(name.name)) { + return false; + } + if (in_loop) in_loop.push(name.definition()); + } + } + return true; + } + + function can_inject_symbols() { + var block_scoped = new Set(); + do { + scope = compressor.parent(++level); + if (scope.is_block_scope() && scope.block_scope) { + // TODO this is sometimes undefined during compression. + // But it should always have a value! + scope.block_scope.variables.forEach(function (variable) { + block_scoped.add(variable.name); + }); + } + if (scope instanceof AST_Catch) { + // TODO can we delete? AST_Catch is a block scope. + if (scope.argname) { + block_scoped.add(scope.argname.name); + } + } else if (scope instanceof AST_IterationStatement) { + in_loop = []; + } else if (scope instanceof AST_SymbolRef) { + if (scope.fixed_value() instanceof AST_Scope) return false; + } + } while (!(scope instanceof AST_Scope)); + + var safe_to_inject = !(scope instanceof AST_Toplevel) || compressor.toplevel.vars; + var inline = compressor.option("inline"); + if (!can_inject_vars(block_scoped, inline >= 3 && safe_to_inject)) return false; + if (!can_inject_args(block_scoped, inline >= 2 && safe_to_inject)) return false; + return !in_loop || in_loop.length == 0 || !is_reachable(fn, in_loop); + } + + function append_var(decls, expressions, name, value) { + var def = name.definition(); + + // Name already exists, only when a function argument had the same name + const already_appended = scope.variables.has(name.name); + if (!already_appended) { + scope.variables.set(name.name, def); + scope.enclosed.push(def); + decls.push(make_node(AST_VarDef, name, { + name: name, + value: null + })); + } + + var sym = make_node(AST_SymbolRef, name, name); + def.references.push(sym); + if (value) expressions.push(make_node(AST_Assign, self, { + operator: "=", + logical: false, + left: sym, + right: value.clone() + })); + } + + function flatten_args(decls, expressions) { + var len = fn.argnames.length; + for (var i = self.args.length; --i >= len;) { + expressions.push(self.args[i]); + } + for (i = len; --i >= 0;) { + var name = fn.argnames[i]; + var value = self.args[i]; + if (has_flag(name, UNUSED) || !name.name || scope.conflicting_def(name.name)) { + if (value) expressions.push(value); + } else { + var symbol = make_node(AST_SymbolVar, name, name); + name.definition().orig.push(symbol); + if (!value && in_loop) value = make_node(AST_Undefined, self); + append_var(decls, expressions, symbol, value); + } + } + decls.reverse(); + expressions.reverse(); + } + + function flatten_vars(decls, expressions) { + var pos = expressions.length; + for (var i = 0, lines = fn.body.length; i < lines; i++) { + var stat = fn.body[i]; + if (!(stat instanceof AST_Var)) continue; + for (var j = 0, defs = stat.definitions.length; j < defs; j++) { + var var_def = stat.definitions[j]; + var name = var_def.name; + append_var(decls, expressions, name, var_def.value); + if (in_loop && fn.argnames.every((argname) => + argname.name != name.name + )) { + var def = fn.variables.get(name.name); + var sym = make_node(AST_SymbolRef, name, name); + def.references.push(sym); + expressions.splice(pos++, 0, make_node(AST_Assign, var_def, { + operator: "=", + logical: false, + left: sym, + right: make_node(AST_Undefined, name) + })); + } + } + } + } + + function flatten_fn(returned_value) { + var decls = []; + var expressions = []; + flatten_args(decls, expressions); + flatten_vars(decls, expressions); + expressions.push(returned_value); + + if (decls.length) { + const i = scope.body.indexOf(compressor.parent(level - 1)) + 1; + scope.body.splice(i, 0, make_node(AST_Var, fn, { + definitions: decls + })); + } + + return expressions.map(exp => exp.clone(true)); + } +} + +/*********************************************************************** + + A JavaScript tokenizer / parser / beautifier / compressor. + https://github.com/mishoo/UglifyJS2 + + -------------------------------- (C) --------------------------------- + + Author: Mihai Bazon + + http://mihai.bazon.net/blog + + Distributed under the BSD license: + + Copyright 2012 (c) Mihai Bazon + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + ***********************************************************************/ + +class Compressor extends TreeWalker { + constructor(options, { false_by_default = false, mangle_options = false }) { + super(); + if (options.defaults !== undefined && !options.defaults) false_by_default = true; + this.options = defaults(options, { + arguments : false, + arrows : !false_by_default, + booleans : !false_by_default, + booleans_as_integers : false, + collapse_vars : !false_by_default, + comparisons : !false_by_default, + computed_props: !false_by_default, + conditionals : !false_by_default, + dead_code : !false_by_default, + defaults : true, + directives : !false_by_default, + drop_console : false, + drop_debugger : !false_by_default, + ecma : 5, + evaluate : !false_by_default, + expression : false, + global_defs : false, + hoist_funs : false, + hoist_props : !false_by_default, + hoist_vars : false, + ie8 : false, + if_return : !false_by_default, + inline : !false_by_default, + join_vars : !false_by_default, + keep_classnames: false, + keep_fargs : true, + keep_fnames : false, + keep_infinity : false, + lhs_constants : !false_by_default, + loops : !false_by_default, + module : false, + negate_iife : !false_by_default, + passes : 1, + properties : !false_by_default, + pure_getters : !false_by_default && "strict", + pure_funcs : null, + reduce_funcs : !false_by_default, + reduce_vars : !false_by_default, + sequences : !false_by_default, + side_effects : !false_by_default, + switches : !false_by_default, + top_retain : null, + toplevel : !!(options && options["top_retain"]), + typeofs : !false_by_default, + unsafe : false, + unsafe_arrows : false, + unsafe_comps : false, + unsafe_Function: false, + unsafe_math : false, + unsafe_symbols: false, + unsafe_methods: false, + unsafe_proto : false, + unsafe_regexp : false, + unsafe_undefined: false, + unused : !false_by_default, + warnings : false // legacy + }, true); + var global_defs = this.options["global_defs"]; + if (typeof global_defs == "object") for (var key in global_defs) { + if (key[0] === "@" && HOP(global_defs, key)) { + global_defs[key.slice(1)] = parse(global_defs[key], { + expression: true + }); + } + } + if (this.options["inline"] === true) this.options["inline"] = 3; + var pure_funcs = this.options["pure_funcs"]; + if (typeof pure_funcs == "function") { + this.pure_funcs = pure_funcs; + } else { + this.pure_funcs = pure_funcs ? function(node) { + return !pure_funcs.includes(node.expression.print_to_string()); + } : return_true; + } + var top_retain = this.options["top_retain"]; + if (top_retain instanceof RegExp) { + this.top_retain = function(def) { + return top_retain.test(def.name); + }; + } else if (typeof top_retain == "function") { + this.top_retain = top_retain; + } else if (top_retain) { + if (typeof top_retain == "string") { + top_retain = top_retain.split(/,/); + } + this.top_retain = function(def) { + return top_retain.includes(def.name); + }; + } + if (this.options["module"]) { + this.directives["use strict"] = true; + this.options["toplevel"] = true; + } + var toplevel = this.options["toplevel"]; + this.toplevel = typeof toplevel == "string" ? { + funcs: /funcs/.test(toplevel), + vars: /vars/.test(toplevel) + } : { + funcs: toplevel, + vars: toplevel + }; + var sequences = this.options["sequences"]; + this.sequences_limit = sequences == 1 ? 800 : sequences | 0; + this.evaluated_regexps = new Map(); + this._toplevel = undefined; + this.mangle_options = mangle_options + ? format_mangler_options(mangle_options) + : mangle_options; + } + + option(key) { + return this.options[key]; + } + + exposed(def) { + if (def.export) return true; + if (def.global) for (var i = 0, len = def.orig.length; i < len; i++) + if (!this.toplevel[def.orig[i] instanceof AST_SymbolDefun ? "funcs" : "vars"]) + return true; + return false; + } + + in_boolean_context() { + if (!this.option("booleans")) return false; + var self = this.self(); + for (var i = 0, p; p = this.parent(i); i++) { + if (p instanceof AST_SimpleStatement + || p instanceof AST_Conditional && p.condition === self + || p instanceof AST_DWLoop && p.condition === self + || p instanceof AST_For && p.condition === self + || p instanceof AST_If && p.condition === self + || p instanceof AST_UnaryPrefix && p.operator == "!" && p.expression === self) { + return true; + } + if ( + p instanceof AST_Binary + && ( + p.operator == "&&" + || p.operator == "||" + || p.operator == "??" + ) + || p instanceof AST_Conditional + || p.tail_node() === self + ) { + self = p; + } else { + return false; + } + } + } + + get_toplevel() { + return this._toplevel; + } + + compress(toplevel) { + toplevel = toplevel.resolve_defines(this); + this._toplevel = toplevel; + if (this.option("expression")) { + this._toplevel.process_expression(true); + } + var passes = +this.options.passes || 1; + var min_count = 1 / 0; + var stopping = false; + var nth_identifier = this.mangle_options && this.mangle_options.nth_identifier || base54; + var mangle = { ie8: this.option("ie8"), nth_identifier: nth_identifier }; + for (var pass = 0; pass < passes; pass++) { + this._toplevel.figure_out_scope(mangle); + if (pass === 0 && this.option("drop_console")) { + // must be run before reduce_vars and compress pass + this._toplevel = this._toplevel.drop_console(); + } + if (pass > 0 || this.option("reduce_vars")) { + this._toplevel.reset_opt_flags(this); + } + this._toplevel = this._toplevel.transform(this); + if (passes > 1) { + let count = 0; + walk(this._toplevel, () => { count++; }); + if (count < min_count) { + min_count = count; + stopping = false; + } else if (stopping) { + break; + } else { + stopping = true; + } + } + } + if (this.option("expression")) { + this._toplevel.process_expression(false); + } + toplevel = this._toplevel; + this._toplevel = undefined; + return toplevel; + } + + before(node, descend) { + if (has_flag(node, SQUEEZED)) return node; + var was_scope = false; + if (node instanceof AST_Scope) { + node = node.hoist_properties(this); + node = node.hoist_declarations(this); + was_scope = true; + } + // Before https://github.com/mishoo/UglifyJS2/pull/1602 AST_Node.optimize() + // would call AST_Node.transform() if a different instance of AST_Node is + // produced after def_optimize(). + // This corrupts TreeWalker.stack, which cause AST look-ups to malfunction. + // Migrate and defer all children's AST_Node.transform() to below, which + // will now happen after this parent AST_Node has been properly substituted + // thus gives a consistent AST snapshot. + descend(node, this); + // Existing code relies on how AST_Node.optimize() worked, and omitting the + // following replacement call would result in degraded efficiency of both + // output and performance. + descend(node, this); + var opt = node.optimize(this); + if (was_scope && opt instanceof AST_Scope) { + opt.drop_unused(this); + descend(opt, this); + } + if (opt === node) set_flag(opt, SQUEEZED); + return opt; + } + + /** Alternative to plain is_lhs() which doesn't work within .optimize() */ + is_lhs() { + const self = this.stack[this.stack.length - 1]; + const parent = this.stack[this.stack.length - 2]; + return is_lhs(self, parent); + } +} + +function def_optimize(node, optimizer) { + node.DEFMETHOD("optimize", function(compressor) { + var self = this; + if (has_flag(self, OPTIMIZED)) return self; + if (compressor.has_directive("use asm")) return self; + var opt = optimizer(self, compressor); + set_flag(opt, OPTIMIZED); + return opt; + }); +} + +def_optimize(AST_Node, function(self) { + return self; +}); + +AST_Toplevel.DEFMETHOD("drop_console", function() { + return this.transform(new TreeTransformer(function(self) { + if (self.TYPE == "Call") { + var exp = self.expression; + if (exp instanceof AST_PropAccess) { + var name = exp.expression; + while (name.expression) { + name = name.expression; + } + if (is_undeclared_ref(name) && name.name == "console") { + return make_node(AST_Undefined, self); + } + } + } + })); +}); + +AST_Node.DEFMETHOD("equivalent_to", function(node) { + return equivalent_to(this, node); +}); + +AST_Scope.DEFMETHOD("process_expression", function(insert, compressor) { + var self = this; + var tt = new TreeTransformer(function(node) { + if (insert && node instanceof AST_SimpleStatement) { + return make_node(AST_Return, node, { + value: node.body + }); + } + if (!insert && node instanceof AST_Return) { + if (compressor) { + var value = node.value && node.value.drop_side_effect_free(compressor, true); + return value + ? make_node(AST_SimpleStatement, node, { body: value }) + : make_node(AST_EmptyStatement, node); + } + return make_node(AST_SimpleStatement, node, { + body: node.value || make_node(AST_UnaryPrefix, node, { + operator: "void", + expression: make_node(AST_Number, node, { + value: 0 + }) + }) + }); + } + if (node instanceof AST_Class || node instanceof AST_Lambda && node !== self) { + return node; + } + if (node instanceof AST_Block) { + var index = node.body.length - 1; + if (index >= 0) { + node.body[index] = node.body[index].transform(tt); + } + } else if (node instanceof AST_If) { + node.body = node.body.transform(tt); + if (node.alternative) { + node.alternative = node.alternative.transform(tt); + } + } else if (node instanceof AST_With) { + node.body = node.body.transform(tt); + } + return node; + }); + self.transform(tt); +}); + +AST_Toplevel.DEFMETHOD("reset_opt_flags", function(compressor) { + const self = this; + const reduce_vars = compressor.option("reduce_vars"); + + const preparation = new TreeWalker(function(node, descend) { + clear_flag(node, CLEAR_BETWEEN_PASSES); + if (reduce_vars) { + if (compressor.top_retain + && node instanceof AST_Defun // Only functions are retained + && preparation.parent() === self + ) { + set_flag(node, TOP); + } + return node.reduce_vars(preparation, descend, compressor); + } + }); + // Stack of look-up tables to keep track of whether a `SymbolDef` has been + // properly assigned before use: + // - `push()` & `pop()` when visiting conditional branches + preparation.safe_ids = Object.create(null); + preparation.in_loop = null; + preparation.loop_ids = new Map(); + preparation.defs_to_safe_ids = new Map(); + self.walk(preparation); +}); + +AST_Symbol.DEFMETHOD("fixed_value", function() { + var fixed = this.thedef.fixed; + if (!fixed || fixed instanceof AST_Node) return fixed; + return fixed(); +}); + +AST_SymbolRef.DEFMETHOD("is_immutable", function() { + var orig = this.definition().orig; + return orig.length == 1 && orig[0] instanceof AST_SymbolLambda; +}); + +function find_variable(compressor, name) { + var scope, i = 0; + while (scope = compressor.parent(i++)) { + if (scope instanceof AST_Scope) break; + if (scope instanceof AST_Catch && scope.argname) { + scope = scope.argname.definition().scope; + break; + } + } + return scope.find_variable(name); +} + +var global_names = makePredicate("Array Boolean clearInterval clearTimeout console Date decodeURI decodeURIComponent encodeURI encodeURIComponent Error escape eval EvalError Function isFinite isNaN JSON Math Number parseFloat parseInt RangeError ReferenceError RegExp Object setInterval setTimeout String SyntaxError TypeError unescape URIError"); +AST_SymbolRef.DEFMETHOD("is_declared", function(compressor) { + return !this.definition().undeclared + || compressor.option("unsafe") && global_names.has(this.name); +}); + +/* -----[ optimizers ]----- */ + +var directives = new Set(["use asm", "use strict"]); +def_optimize(AST_Directive, function(self, compressor) { + if (compressor.option("directives") + && (!directives.has(self.value) || compressor.has_directive(self.value) !== self)) { + return make_node(AST_EmptyStatement, self); + } + return self; +}); + +def_optimize(AST_Debugger, function(self, compressor) { + if (compressor.option("drop_debugger")) + return make_node(AST_EmptyStatement, self); + return self; +}); + +def_optimize(AST_LabeledStatement, function(self, compressor) { + if (self.body instanceof AST_Break + && compressor.loopcontrol_target(self.body) === self.body) { + return make_node(AST_EmptyStatement, self); + } + return self.label.references.length == 0 ? self.body : self; +}); + +def_optimize(AST_Block, function(self, compressor) { + tighten_body(self.body, compressor); + return self; +}); + +function can_be_extracted_from_if_block(node) { + return !( + node instanceof AST_Const + || node instanceof AST_Let + || node instanceof AST_Class + ); +} + +def_optimize(AST_BlockStatement, function(self, compressor) { + tighten_body(self.body, compressor); + switch (self.body.length) { + case 1: + if (!compressor.has_directive("use strict") + && compressor.parent() instanceof AST_If + && can_be_extracted_from_if_block(self.body[0]) + || can_be_evicted_from_block(self.body[0])) { + return self.body[0]; + } + break; + case 0: return make_node(AST_EmptyStatement, self); + } + return self; +}); + +function opt_AST_Lambda(self, compressor) { + tighten_body(self.body, compressor); + if (compressor.option("side_effects") + && self.body.length == 1 + && self.body[0] === compressor.has_directive("use strict")) { + self.body.length = 0; + } + return self; +} +def_optimize(AST_Lambda, opt_AST_Lambda); + +AST_Scope.DEFMETHOD("hoist_declarations", function(compressor) { + var self = this; + if (compressor.has_directive("use asm")) return self; + + var hoist_funs = compressor.option("hoist_funs"); + var hoist_vars = compressor.option("hoist_vars"); + + if (hoist_funs || hoist_vars) { + var dirs = []; + var hoisted = []; + var vars = new Map(), vars_found = 0, var_decl = 0; + // let's count var_decl first, we seem to waste a lot of + // space if we hoist `var` when there's only one. + walk(self, node => { + if (node instanceof AST_Scope && node !== self) + return true; + if (node instanceof AST_Var) { + ++var_decl; + return true; + } + }); + hoist_vars = hoist_vars && var_decl > 1; + var tt = new TreeTransformer( + function before(node) { + if (node !== self) { + if (node instanceof AST_Directive) { + dirs.push(node); + return make_node(AST_EmptyStatement, node); + } + if (hoist_funs && node instanceof AST_Defun + && !(tt.parent() instanceof AST_Export) + && tt.parent() === self) { + hoisted.push(node); + return make_node(AST_EmptyStatement, node); + } + if ( + hoist_vars + && node instanceof AST_Var + && !node.definitions.some(def => def.name instanceof AST_Destructuring) + ) { + node.definitions.forEach(function(def) { + vars.set(def.name.name, def); + ++vars_found; + }); + var seq = node.to_assignments(compressor); + var p = tt.parent(); + if (p instanceof AST_ForIn && p.init === node) { + if (seq == null) { + var def = node.definitions[0].name; + return make_node(AST_SymbolRef, def, def); + } + return seq; + } + if (p instanceof AST_For && p.init === node) { + return seq; + } + if (!seq) return make_node(AST_EmptyStatement, node); + return make_node(AST_SimpleStatement, node, { + body: seq + }); + } + if (node instanceof AST_Scope) + return node; // to avoid descending in nested scopes + } + } + ); + self = self.transform(tt); + if (vars_found > 0) { + // collect only vars which don't show up in self's arguments list + var defs = []; + const is_lambda = self instanceof AST_Lambda; + const args_as_names = is_lambda ? self.args_as_names() : null; + vars.forEach((def, name) => { + if (is_lambda && args_as_names.some((x) => x.name === def.name.name)) { + vars.delete(name); + } else { + def = def.clone(); + def.value = null; + defs.push(def); + vars.set(name, def); + } + }); + if (defs.length > 0) { + // try to merge in assignments + for (var i = 0; i < self.body.length;) { + if (self.body[i] instanceof AST_SimpleStatement) { + var expr = self.body[i].body, sym, assign; + if (expr instanceof AST_Assign + && expr.operator == "=" + && (sym = expr.left) instanceof AST_Symbol + && vars.has(sym.name) + ) { + var def = vars.get(sym.name); + if (def.value) break; + def.value = expr.right; + remove(defs, def); + defs.push(def); + self.body.splice(i, 1); + continue; + } + if (expr instanceof AST_Sequence + && (assign = expr.expressions[0]) instanceof AST_Assign + && assign.operator == "=" + && (sym = assign.left) instanceof AST_Symbol + && vars.has(sym.name) + ) { + var def = vars.get(sym.name); + if (def.value) break; + def.value = assign.right; + remove(defs, def); + defs.push(def); + self.body[i].body = make_sequence(expr, expr.expressions.slice(1)); + continue; + } + } + if (self.body[i] instanceof AST_EmptyStatement) { + self.body.splice(i, 1); + continue; + } + if (self.body[i] instanceof AST_BlockStatement) { + self.body.splice(i, 1, ...self.body[i].body); + continue; + } + break; + } + defs = make_node(AST_Var, self, { + definitions: defs + }); + hoisted.push(defs); + } + } + self.body = dirs.concat(hoisted, self.body); + } + return self; +}); + +AST_Scope.DEFMETHOD("hoist_properties", function(compressor) { + var self = this; + if (!compressor.option("hoist_props") || compressor.has_directive("use asm")) return self; + var top_retain = self instanceof AST_Toplevel && compressor.top_retain || return_false; + var defs_by_id = new Map(); + var hoister = new TreeTransformer(function(node, descend) { + if (node instanceof AST_VarDef) { + const sym = node.name; + let def; + let value; + if (sym.scope === self + && (def = sym.definition()).escaped != 1 + && !def.assignments + && !def.direct_access + && !def.single_use + && !compressor.exposed(def) + && !top_retain(def) + && (value = sym.fixed_value()) === node.value + && value instanceof AST_Object + && !value.properties.some(prop => + prop instanceof AST_Expansion || prop.computed_key() + ) + ) { + descend(node, this); + const defs = new Map(); + const assignments = []; + value.properties.forEach(({ key, value }) => { + const scope = hoister.find_scope(); + const symbol = self.create_symbol(sym.CTOR, { + source: sym, + scope, + conflict_scopes: new Set([ + scope, + ...sym.definition().references.map(ref => ref.scope) + ]), + tentative_name: sym.name + "_" + key + }); + + defs.set(String(key), symbol.definition()); + + assignments.push(make_node(AST_VarDef, node, { + name: symbol, + value + })); + }); + defs_by_id.set(def.id, defs); + return MAP.splice(assignments); + } + } else if (node instanceof AST_PropAccess + && node.expression instanceof AST_SymbolRef + ) { + const defs = defs_by_id.get(node.expression.definition().id); + if (defs) { + const def = defs.get(String(get_simple_key(node.property))); + const sym = make_node(AST_SymbolRef, node, { + name: def.name, + scope: node.expression.scope, + thedef: def + }); + sym.reference({}); + return sym; + } + } + }); + return self.transform(hoister); +}); + +def_optimize(AST_SimpleStatement, function(self, compressor) { + if (compressor.option("side_effects")) { + var body = self.body; + var node = body.drop_side_effect_free(compressor, true); + if (!node) { + return make_node(AST_EmptyStatement, self); + } + if (node !== body) { + return make_node(AST_SimpleStatement, self, { body: node }); + } + } + return self; +}); + +def_optimize(AST_While, function(self, compressor) { + return compressor.option("loops") ? make_node(AST_For, self, self).optimize(compressor) : self; +}); + +def_optimize(AST_Do, function(self, compressor) { + if (!compressor.option("loops")) return self; + var cond = self.condition.tail_node().evaluate(compressor); + if (!(cond instanceof AST_Node)) { + if (cond) return make_node(AST_For, self, { + body: make_node(AST_BlockStatement, self.body, { + body: [ + self.body, + make_node(AST_SimpleStatement, self.condition, { + body: self.condition + }) + ] + }) + }).optimize(compressor); + if (!has_break_or_continue(self, compressor.parent())) { + return make_node(AST_BlockStatement, self.body, { + body: [ + self.body, + make_node(AST_SimpleStatement, self.condition, { + body: self.condition + }) + ] + }).optimize(compressor); + } + } + return self; +}); + +function if_break_in_loop(self, compressor) { + var first = self.body instanceof AST_BlockStatement ? self.body.body[0] : self.body; + if (compressor.option("dead_code") && is_break(first)) { + var body = []; + if (self.init instanceof AST_Statement) { + body.push(self.init); + } else if (self.init) { + body.push(make_node(AST_SimpleStatement, self.init, { + body: self.init + })); + } + if (self.condition) { + body.push(make_node(AST_SimpleStatement, self.condition, { + body: self.condition + })); + } + trim_unreachable_code(compressor, self.body, body); + return make_node(AST_BlockStatement, self, { + body: body + }); + } + if (first instanceof AST_If) { + if (is_break(first.body)) { + if (self.condition) { + self.condition = make_node(AST_Binary, self.condition, { + left: self.condition, + operator: "&&", + right: first.condition.negate(compressor), + }); + } else { + self.condition = first.condition.negate(compressor); + } + drop_it(first.alternative); + } else if (is_break(first.alternative)) { + if (self.condition) { + self.condition = make_node(AST_Binary, self.condition, { + left: self.condition, + operator: "&&", + right: first.condition, + }); + } else { + self.condition = first.condition; + } + drop_it(first.body); + } + } + return self; + + function is_break(node) { + return node instanceof AST_Break + && compressor.loopcontrol_target(node) === compressor.self(); + } + + function drop_it(rest) { + rest = as_statement_array(rest); + if (self.body instanceof AST_BlockStatement) { + self.body = self.body.clone(); + self.body.body = rest.concat(self.body.body.slice(1)); + self.body = self.body.transform(compressor); + } else { + self.body = make_node(AST_BlockStatement, self.body, { + body: rest + }).transform(compressor); + } + self = if_break_in_loop(self, compressor); + } +} + +def_optimize(AST_For, function(self, compressor) { + if (!compressor.option("loops")) return self; + if (compressor.option("side_effects") && self.init) { + self.init = self.init.drop_side_effect_free(compressor); + } + if (self.condition) { + var cond = self.condition.evaluate(compressor); + if (!(cond instanceof AST_Node)) { + if (cond) self.condition = null; + else if (!compressor.option("dead_code")) { + var orig = self.condition; + self.condition = make_node_from_constant(cond, self.condition); + self.condition = best_of_expression(self.condition.transform(compressor), orig); + } + } + if (compressor.option("dead_code")) { + if (cond instanceof AST_Node) cond = self.condition.tail_node().evaluate(compressor); + if (!cond) { + var body = []; + trim_unreachable_code(compressor, self.body, body); + if (self.init instanceof AST_Statement) { + body.push(self.init); + } else if (self.init) { + body.push(make_node(AST_SimpleStatement, self.init, { + body: self.init + })); + } + body.push(make_node(AST_SimpleStatement, self.condition, { + body: self.condition + })); + return make_node(AST_BlockStatement, self, { body: body }).optimize(compressor); + } + } + } + return if_break_in_loop(self, compressor); +}); + +def_optimize(AST_If, function(self, compressor) { + if (is_empty(self.alternative)) self.alternative = null; + + if (!compressor.option("conditionals")) return self; + // if condition can be statically determined, drop + // one of the blocks. note, statically determined implies + // “has no side effects”; also it doesn't work for cases like + // `x && true`, though it probably should. + var cond = self.condition.evaluate(compressor); + if (!compressor.option("dead_code") && !(cond instanceof AST_Node)) { + var orig = self.condition; + self.condition = make_node_from_constant(cond, orig); + self.condition = best_of_expression(self.condition.transform(compressor), orig); + } + if (compressor.option("dead_code")) { + if (cond instanceof AST_Node) cond = self.condition.tail_node().evaluate(compressor); + if (!cond) { + var body = []; + trim_unreachable_code(compressor, self.body, body); + body.push(make_node(AST_SimpleStatement, self.condition, { + body: self.condition + })); + if (self.alternative) body.push(self.alternative); + return make_node(AST_BlockStatement, self, { body: body }).optimize(compressor); + } else if (!(cond instanceof AST_Node)) { + var body = []; + body.push(make_node(AST_SimpleStatement, self.condition, { + body: self.condition + })); + body.push(self.body); + if (self.alternative) { + trim_unreachable_code(compressor, self.alternative, body); + } + return make_node(AST_BlockStatement, self, { body: body }).optimize(compressor); + } + } + var negated = self.condition.negate(compressor); + var self_condition_length = self.condition.size(); + var negated_length = negated.size(); + var negated_is_best = negated_length < self_condition_length; + if (self.alternative && negated_is_best) { + negated_is_best = false; // because we already do the switch here. + // no need to swap values of self_condition_length and negated_length + // here because they are only used in an equality comparison later on. + self.condition = negated; + var tmp = self.body; + self.body = self.alternative || make_node(AST_EmptyStatement, self); + self.alternative = tmp; + } + if (is_empty(self.body) && is_empty(self.alternative)) { + return make_node(AST_SimpleStatement, self.condition, { + body: self.condition.clone() + }).optimize(compressor); + } + if (self.body instanceof AST_SimpleStatement + && self.alternative instanceof AST_SimpleStatement) { + return make_node(AST_SimpleStatement, self, { + body: make_node(AST_Conditional, self, { + condition : self.condition, + consequent : self.body.body, + alternative : self.alternative.body + }) + }).optimize(compressor); + } + if (is_empty(self.alternative) && self.body instanceof AST_SimpleStatement) { + if (self_condition_length === negated_length && !negated_is_best + && self.condition instanceof AST_Binary && self.condition.operator == "||") { + // although the code length of self.condition and negated are the same, + // negated does not require additional surrounding parentheses. + // see https://github.com/mishoo/UglifyJS2/issues/979 + negated_is_best = true; + } + if (negated_is_best) return make_node(AST_SimpleStatement, self, { + body: make_node(AST_Binary, self, { + operator : "||", + left : negated, + right : self.body.body + }) + }).optimize(compressor); + return make_node(AST_SimpleStatement, self, { + body: make_node(AST_Binary, self, { + operator : "&&", + left : self.condition, + right : self.body.body + }) + }).optimize(compressor); + } + if (self.body instanceof AST_EmptyStatement + && self.alternative instanceof AST_SimpleStatement) { + return make_node(AST_SimpleStatement, self, { + body: make_node(AST_Binary, self, { + operator : "||", + left : self.condition, + right : self.alternative.body + }) + }).optimize(compressor); + } + if (self.body instanceof AST_Exit + && self.alternative instanceof AST_Exit + && self.body.TYPE == self.alternative.TYPE) { + return make_node(self.body.CTOR, self, { + value: make_node(AST_Conditional, self, { + condition : self.condition, + consequent : self.body.value || make_node(AST_Undefined, self.body), + alternative : self.alternative.value || make_node(AST_Undefined, self.alternative) + }).transform(compressor) + }).optimize(compressor); + } + if (self.body instanceof AST_If + && !self.body.alternative + && !self.alternative) { + self = make_node(AST_If, self, { + condition: make_node(AST_Binary, self.condition, { + operator: "&&", + left: self.condition, + right: self.body.condition + }), + body: self.body.body, + alternative: null + }); + } + if (aborts(self.body)) { + if (self.alternative) { + var alt = self.alternative; + self.alternative = null; + return make_node(AST_BlockStatement, self, { + body: [ self, alt ] + }).optimize(compressor); + } + } + if (aborts(self.alternative)) { + var body = self.body; + self.body = self.alternative; + self.condition = negated_is_best ? negated : self.condition.negate(compressor); + self.alternative = null; + return make_node(AST_BlockStatement, self, { + body: [ self, body ] + }).optimize(compressor); + } + return self; +}); + +def_optimize(AST_Switch, function(self, compressor) { + if (!compressor.option("switches")) return self; + var branch; + var value = self.expression.evaluate(compressor); + if (!(value instanceof AST_Node)) { + var orig = self.expression; + self.expression = make_node_from_constant(value, orig); + self.expression = best_of_expression(self.expression.transform(compressor), orig); + } + if (!compressor.option("dead_code")) return self; + if (value instanceof AST_Node) { + value = self.expression.tail_node().evaluate(compressor); + } + var decl = []; + var body = []; + var default_branch; + var exact_match; + for (var i = 0, len = self.body.length; i < len && !exact_match; i++) { + branch = self.body[i]; + if (branch instanceof AST_Default) { + if (!default_branch) { + default_branch = branch; + } else { + eliminate_branch(branch, body[body.length - 1]); + } + } else if (!(value instanceof AST_Node)) { + var exp = branch.expression.evaluate(compressor); + if (!(exp instanceof AST_Node) && exp !== value) { + eliminate_branch(branch, body[body.length - 1]); + continue; + } + if (exp instanceof AST_Node) exp = branch.expression.tail_node().evaluate(compressor); + if (exp === value) { + exact_match = branch; + if (default_branch) { + var default_index = body.indexOf(default_branch); + body.splice(default_index, 1); + eliminate_branch(default_branch, body[default_index - 1]); + default_branch = null; + } + } + } + body.push(branch); + } + while (i < len) eliminate_branch(self.body[i++], body[body.length - 1]); + self.body = body; + + let default_or_exact = default_branch || exact_match; + default_branch = null; + exact_match = null; + + // group equivalent branches so they will be located next to each other, + // that way the next micro-optimization will merge them. + // ** bail micro-optimization if not a simple switch case with breaks + if (body.every((branch, i) => + (branch === default_or_exact || branch.expression instanceof AST_Constant) + && (branch.body.length === 0 || aborts(branch) || body.length - 1 === i)) + ) { + for (let i = 0; i < body.length; i++) { + const branch = body[i]; + for (let j = i + 1; j < body.length; j++) { + const next = body[j]; + if (next.body.length === 0) continue; + const last_branch = j === (body.length - 1); + const equivalentBranch = branches_equivalent(next, branch, false); + if (equivalentBranch || (last_branch && branches_equivalent(next, branch, true))) { + if (!equivalentBranch && last_branch) { + next.body.push(make_node(AST_Break)); + } + + // let's find previous siblings with inert fallthrough... + let x = j - 1; + let fallthroughDepth = 0; + while (x > i) { + if (is_inert_body(body[x--])) { + fallthroughDepth++; + } else { + break; + } + } + + const plucked = body.splice(j - fallthroughDepth, 1 + fallthroughDepth); + body.splice(i + 1, 0, ...plucked); + i += plucked.length; + } + } + } + } + + // merge equivalent branches in a row + for (let i = 0; i < body.length; i++) { + let branch = body[i]; + if (branch.body.length === 0) continue; + if (!aborts(branch)) continue; + + for (let j = i + 1; j < body.length; i++, j++) { + let next = body[j]; + if (next.body.length === 0) continue; + if ( + branches_equivalent(next, branch, false) + || (j === body.length - 1 && branches_equivalent(next, branch, true)) + ) { + branch.body = []; + branch = next; + continue; + } + break; + } + } + + // Prune any empty branches at the end of the switch statement. + { + let i = body.length - 1; + for (; i >= 0; i--) { + let bbody = body[i].body; + if (is_break(bbody[bbody.length - 1], compressor)) bbody.pop(); + if (!is_inert_body(body[i])) break; + } + // i now points to the index of a branch that contains a body. By incrementing, it's + // pointing to the first branch that's empty. + i++; + if (!default_or_exact || body.indexOf(default_or_exact) >= i) { + // The default behavior is to do nothing. We can take advantage of that to + // remove all case expressions that are side-effect free that also do + // nothing, since they'll default to doing nothing. But we can't remove any + // case expressions before one that would side-effect, since they may cause + // the side-effect to be skipped. + for (let j = body.length - 1; j >= i; j--) { + let branch = body[j]; + if (branch === default_or_exact) { + default_or_exact = null; + body.pop(); + } else if (!branch.expression.has_side_effects(compressor)) { + body.pop(); + } else { + break; + } + } + } + } + + + // Prune side-effect free branches that fall into default. + DEFAULT: if (default_or_exact) { + let default_index = body.indexOf(default_or_exact); + let default_body_index = default_index; + for (; default_body_index < body.length - 1; default_body_index++) { + if (!is_inert_body(body[default_body_index])) break; + } + if (default_body_index < body.length - 1) { + break DEFAULT; + } + + let side_effect_index = body.length - 1; + for (; side_effect_index >= 0; side_effect_index--) { + let branch = body[side_effect_index]; + if (branch === default_or_exact) continue; + if (branch.expression.has_side_effects(compressor)) break; + } + // If the default behavior comes after any side-effect case expressions, + // then we can fold all side-effect free cases into the default branch. + // If the side-effect case is after the default, then any side-effect + // free cases could prevent the side-effect from occurring. + if (default_body_index > side_effect_index) { + let prev_body_index = default_index - 1; + for (; prev_body_index >= 0; prev_body_index--) { + if (!is_inert_body(body[prev_body_index])) break; + } + let before = Math.max(side_effect_index, prev_body_index) + 1; + let after = default_index; + if (side_effect_index > default_index) { + // If the default falls into the same body as a side-effect + // case, then we need preserve that case and only prune the + // cases after it. + after = side_effect_index; + body[side_effect_index].body = body[default_body_index].body; + } else { + // The default will be the last branch. + default_or_exact.body = body[default_body_index].body; + } + + // Prune everything after the default (or last side-effect case) + // until the next case with a body. + body.splice(after + 1, default_body_index - after); + // Prune everything before the default that falls into it. + body.splice(before, default_index - before); + } + } + + // See if we can remove the switch entirely if all cases (the default) fall into the same case body. + DEFAULT: if (default_or_exact) { + let i = body.findIndex(branch => !is_inert_body(branch)); + let caseBody; + // `i` is equal to one of the following: + // - `-1`, there is no body in the switch statement. + // - `body.length - 1`, all cases fall into the same body. + // - anything else, there are multiple bodies in the switch. + if (i === body.length - 1) { + // All cases fall into the case body. + let branch = body[i]; + if (has_nested_break(self)) break DEFAULT; + + // This is the last case body, and we've already pruned any breaks, so it's + // safe to hoist. + caseBody = make_node(AST_BlockStatement, branch, { + body: branch.body + }); + branch.body = []; + } else if (i !== -1) { + // If there are multiple bodies, then we cannot optimize anything. + break DEFAULT; + } + + let sideEffect = body.find(branch => { + return ( + branch !== default_or_exact + && branch.expression.has_side_effects(compressor) + ); + }); + // If no cases cause a side-effect, we can eliminate the switch entirely. + if (!sideEffect) { + return make_node(AST_BlockStatement, self, { + body: decl.concat( + statement(self.expression), + default_or_exact.expression ? statement(default_or_exact.expression) : [], + caseBody || [] + ) + }).optimize(compressor); + } + + // If we're this far, either there was no body or all cases fell into the same body. + // If there was no body, then we don't need a default branch (because the default is + // do nothing). If there was a body, we'll extract it to after the switch, so the + // switch's new default is to do nothing and we can still prune it. + const default_index = body.indexOf(default_or_exact); + body.splice(default_index, 1); + default_or_exact = null; + + if (caseBody) { + // Recurse into switch statement one more time so that we can append the case body + // outside of the switch. This recursion will only happen once since we've pruned + // the default case. + return make_node(AST_BlockStatement, self, { + body: decl.concat(self, caseBody) + }).optimize(compressor); + } + // If we fall here, there is a default branch somewhere, there are no case bodies, + // and there's a side-effect somewhere. Just let the below paths take care of it. + } + + if (body.length > 0) { + body[0].body = decl.concat(body[0].body); + } + + if (body.length == 0) { + return make_node(AST_BlockStatement, self, { + body: decl.concat(statement(self.expression)) + }).optimize(compressor); + } + if (body.length == 1 && !has_nested_break(self)) { + // This is the last case body, and we've already pruned any breaks, so it's + // safe to hoist. + let branch = body[0]; + return make_node(AST_If, self, { + condition: make_node(AST_Binary, self, { + operator: "===", + left: self.expression, + right: branch.expression, + }), + body: make_node(AST_BlockStatement, branch, { + body: branch.body + }), + alternative: null + }).optimize(compressor); + } + if (body.length === 2 && default_or_exact && !has_nested_break(self)) { + let branch = body[0] === default_or_exact ? body[1] : body[0]; + let exact_exp = default_or_exact.expression && statement(default_or_exact.expression); + if (aborts(body[0])) { + // Only the first branch body could have a break (at the last statement) + let first = body[0]; + if (is_break(first.body[first.body.length - 1], compressor)) { + first.body.pop(); + } + return make_node(AST_If, self, { + condition: make_node(AST_Binary, self, { + operator: "===", + left: self.expression, + right: branch.expression, + }), + body: make_node(AST_BlockStatement, branch, { + body: branch.body + }), + alternative: make_node(AST_BlockStatement, default_or_exact, { + body: [].concat( + exact_exp || [], + default_or_exact.body + ) + }) + }).optimize(compressor); + } + let operator = "==="; + let consequent = make_node(AST_BlockStatement, branch, { + body: branch.body, + }); + let always = make_node(AST_BlockStatement, default_or_exact, { + body: [].concat( + exact_exp || [], + default_or_exact.body + ) + }); + if (body[0] === default_or_exact) { + operator = "!=="; + let tmp = always; + always = consequent; + consequent = tmp; + } + return make_node(AST_BlockStatement, self, { + body: [ + make_node(AST_If, self, { + condition: make_node(AST_Binary, self, { + operator: operator, + left: self.expression, + right: branch.expression, + }), + body: consequent, + alternative: null + }) + ].concat(always) + }).optimize(compressor); + } + return self; + + function eliminate_branch(branch, prev) { + if (prev && !aborts(prev)) { + prev.body = prev.body.concat(branch.body); + } else { + trim_unreachable_code(compressor, branch, decl); + } + } + function branches_equivalent(branch, prev, insertBreak) { + let bbody = branch.body; + let pbody = prev.body; + if (insertBreak) { + bbody = bbody.concat(make_node(AST_Break)); + } + if (bbody.length !== pbody.length) return false; + let bblock = make_node(AST_BlockStatement, branch, { body: bbody }); + let pblock = make_node(AST_BlockStatement, prev, { body: pbody }); + return bblock.equivalent_to(pblock); + } + function statement(expression) { + return make_node(AST_SimpleStatement, expression, { + body: expression + }); + } + function has_nested_break(root) { + let has_break = false; + let tw = new TreeWalker(node => { + if (has_break) return true; + if (node instanceof AST_Lambda) return true; + if (node instanceof AST_SimpleStatement) return true; + if (!is_break(node, tw)) return; + let parent = tw.parent(); + if ( + parent instanceof AST_SwitchBranch + && parent.body[parent.body.length - 1] === node + ) { + return; + } + has_break = true; + }); + root.walk(tw); + return has_break; + } + function is_break(node, stack) { + return node instanceof AST_Break + && stack.loopcontrol_target(node) === self; + } + function is_inert_body(branch) { + return !aborts(branch) && !make_node(AST_BlockStatement, branch, { + body: branch.body + }).has_side_effects(compressor); + } +}); + +def_optimize(AST_Try, function(self, compressor) { + if (self.bcatch && self.bfinally && self.bfinally.body.every(is_empty)) self.bfinally = null; + + if (compressor.option("dead_code") && self.body.body.every(is_empty)) { + var body = []; + if (self.bcatch) { + trim_unreachable_code(compressor, self.bcatch, body); + } + if (self.bfinally) body.push(...self.bfinally.body); + return make_node(AST_BlockStatement, self, { + body: body + }).optimize(compressor); + } + return self; +}); + +AST_Definitions.DEFMETHOD("to_assignments", function(compressor) { + var reduce_vars = compressor.option("reduce_vars"); + var assignments = []; + + for (const def of this.definitions) { + if (def.value) { + var name = make_node(AST_SymbolRef, def.name, def.name); + assignments.push(make_node(AST_Assign, def, { + operator : "=", + logical: false, + left : name, + right : def.value + })); + if (reduce_vars) name.definition().fixed = false; + } + const thedef = def.name.definition(); + thedef.eliminated++; + thedef.replaced--; + } + + if (assignments.length == 0) return null; + return make_sequence(this, assignments); +}); + +def_optimize(AST_Definitions, function(self) { + if (self.definitions.length == 0) { + return make_node(AST_EmptyStatement, self); + } + return self; +}); + +def_optimize(AST_VarDef, function(self, compressor) { + if ( + self.name instanceof AST_SymbolLet + && self.value != null + && is_undefined(self.value, compressor) + ) { + self.value = null; + } + return self; +}); + +def_optimize(AST_Import, function(self) { + return self; +}); + +def_optimize(AST_Call, function(self, compressor) { + var exp = self.expression; + var fn = exp; + inline_array_like_spread(self.args); + var simple_args = self.args.every((arg) => + !(arg instanceof AST_Expansion) + ); + + if (compressor.option("reduce_vars") + && fn instanceof AST_SymbolRef + && !has_annotation(self, _NOINLINE) + ) { + const fixed = fn.fixed_value(); + if (!retain_top_func(fixed, compressor)) { + fn = fixed; + } + } + + var is_func = fn instanceof AST_Lambda; + + if (is_func && fn.pinned()) return self; + + if (compressor.option("unused") + && simple_args + && is_func + && !fn.uses_arguments) { + var pos = 0, last = 0; + for (var i = 0, len = self.args.length; i < len; i++) { + if (fn.argnames[i] instanceof AST_Expansion) { + if (has_flag(fn.argnames[i].expression, UNUSED)) while (i < len) { + var node = self.args[i++].drop_side_effect_free(compressor); + if (node) { + self.args[pos++] = node; + } + } else while (i < len) { + self.args[pos++] = self.args[i++]; + } + last = pos; + break; + } + var trim = i >= fn.argnames.length; + if (trim || has_flag(fn.argnames[i], UNUSED)) { + var node = self.args[i].drop_side_effect_free(compressor); + if (node) { + self.args[pos++] = node; + } else if (!trim) { + self.args[pos++] = make_node(AST_Number, self.args[i], { + value: 0 + }); + continue; + } + } else { + self.args[pos++] = self.args[i]; + } + last = pos; + } + self.args.length = last; + } + + if (compressor.option("unsafe")) { + if (exp instanceof AST_Dot && exp.start.value === "Array" && exp.property === "from" && self.args.length === 1) { + const [argument] = self.args; + if (argument instanceof AST_Array) { + return make_node(AST_Array, argument, { + elements: argument.elements + }).optimize(compressor); + } + } + if (is_undeclared_ref(exp)) switch (exp.name) { + case "Array": + if (self.args.length != 1) { + return make_node(AST_Array, self, { + elements: self.args + }).optimize(compressor); + } else if (self.args[0] instanceof AST_Number && self.args[0].value <= 11) { + const elements = []; + for (let i = 0; i < self.args[0].value; i++) elements.push(new AST_Hole); + return new AST_Array({ elements }); + } + break; + case "Object": + if (self.args.length == 0) { + return make_node(AST_Object, self, { + properties: [] + }); + } + break; + case "String": + if (self.args.length == 0) return make_node(AST_String, self, { + value: "" + }); + if (self.args.length <= 1) return make_node(AST_Binary, self, { + left: self.args[0], + operator: "+", + right: make_node(AST_String, self, { value: "" }) + }).optimize(compressor); + break; + case "Number": + if (self.args.length == 0) return make_node(AST_Number, self, { + value: 0 + }); + if (self.args.length == 1 && compressor.option("unsafe_math")) { + return make_node(AST_UnaryPrefix, self, { + expression: self.args[0], + operator: "+" + }).optimize(compressor); + } + break; + case "Symbol": + if (self.args.length == 1 && self.args[0] instanceof AST_String && compressor.option("unsafe_symbols")) + self.args.length = 0; + break; + case "Boolean": + if (self.args.length == 0) return make_node(AST_False, self); + if (self.args.length == 1) return make_node(AST_UnaryPrefix, self, { + expression: make_node(AST_UnaryPrefix, self, { + expression: self.args[0], + operator: "!" + }), + operator: "!" + }).optimize(compressor); + break; + case "RegExp": + var params = []; + if (self.args.length >= 1 + && self.args.length <= 2 + && self.args.every((arg) => { + var value = arg.evaluate(compressor); + params.push(value); + return arg !== value; + }) + && regexp_is_safe(params[0]) + ) { + let [ source, flags ] = params; + source = regexp_source_fix(new RegExp(source).source); + const rx = make_node(AST_RegExp, self, { + value: { source, flags } + }); + if (rx._eval(compressor) !== rx) { + return rx; + } + } + break; + } else if (exp instanceof AST_Dot) switch(exp.property) { + case "toString": + if (self.args.length == 0 && !exp.expression.may_throw_on_access(compressor)) { + return make_node(AST_Binary, self, { + left: make_node(AST_String, self, { value: "" }), + operator: "+", + right: exp.expression + }).optimize(compressor); + } + break; + case "join": + if (exp.expression instanceof AST_Array) EXIT: { + var separator; + if (self.args.length > 0) { + separator = self.args[0].evaluate(compressor); + if (separator === self.args[0]) break EXIT; // not a constant + } + var elements = []; + var consts = []; + for (var i = 0, len = exp.expression.elements.length; i < len; i++) { + var el = exp.expression.elements[i]; + if (el instanceof AST_Expansion) break EXIT; + var value = el.evaluate(compressor); + if (value !== el) { + consts.push(value); + } else { + if (consts.length > 0) { + elements.push(make_node(AST_String, self, { + value: consts.join(separator) + })); + consts.length = 0; + } + elements.push(el); + } + } + if (consts.length > 0) { + elements.push(make_node(AST_String, self, { + value: consts.join(separator) + })); + } + if (elements.length == 0) return make_node(AST_String, self, { value: "" }); + if (elements.length == 1) { + if (elements[0].is_string(compressor)) { + return elements[0]; + } + return make_node(AST_Binary, elements[0], { + operator : "+", + left : make_node(AST_String, self, { value: "" }), + right : elements[0] + }); + } + if (separator == "") { + var first; + if (elements[0].is_string(compressor) + || elements[1].is_string(compressor)) { + first = elements.shift(); + } else { + first = make_node(AST_String, self, { value: "" }); + } + return elements.reduce(function(prev, el) { + return make_node(AST_Binary, el, { + operator : "+", + left : prev, + right : el + }); + }, first).optimize(compressor); + } + // need this awkward cloning to not affect original element + // best_of will decide which one to get through. + var node = self.clone(); + node.expression = node.expression.clone(); + node.expression.expression = node.expression.expression.clone(); + node.expression.expression.elements = elements; + return best_of(compressor, self, node); + } + break; + case "charAt": + if (exp.expression.is_string(compressor)) { + var arg = self.args[0]; + var index = arg ? arg.evaluate(compressor) : 0; + if (index !== arg) { + return make_node(AST_Sub, exp, { + expression: exp.expression, + property: make_node_from_constant(index | 0, arg || exp) + }).optimize(compressor); + } + } + break; + case "apply": + if (self.args.length == 2 && self.args[1] instanceof AST_Array) { + var args = self.args[1].elements.slice(); + args.unshift(self.args[0]); + return make_node(AST_Call, self, { + expression: make_node(AST_Dot, exp, { + expression: exp.expression, + optional: false, + property: "call" + }), + args: args + }).optimize(compressor); + } + break; + case "call": + var func = exp.expression; + if (func instanceof AST_SymbolRef) { + func = func.fixed_value(); + } + if (func instanceof AST_Lambda && !func.contains_this()) { + return (self.args.length ? make_sequence(this, [ + self.args[0], + make_node(AST_Call, self, { + expression: exp.expression, + args: self.args.slice(1) + }) + ]) : make_node(AST_Call, self, { + expression: exp.expression, + args: [] + })).optimize(compressor); + } + break; + } + } + + if (compressor.option("unsafe_Function") + && is_undeclared_ref(exp) + && exp.name == "Function") { + // new Function() => function(){} + if (self.args.length == 0) return make_node(AST_Function, self, { + argnames: [], + body: [] + }).optimize(compressor); + var nth_identifier = compressor.mangle_options && compressor.mangle_options.nth_identifier || base54; + if (self.args.every((x) => x instanceof AST_String)) { + // quite a corner-case, but we can handle it: + // https://github.com/mishoo/UglifyJS2/issues/203 + // if the code argument is a constant, then we can minify it. + try { + var code = "n(function(" + self.args.slice(0, -1).map(function(arg) { + return arg.value; + }).join(",") + "){" + self.args[self.args.length - 1].value + "})"; + var ast = parse(code); + var mangle = { ie8: compressor.option("ie8"), nth_identifier: nth_identifier }; + ast.figure_out_scope(mangle); + var comp = new Compressor(compressor.options, { + mangle_options: compressor.mangle_options + }); + ast = ast.transform(comp); + ast.figure_out_scope(mangle); + ast.compute_char_frequency(mangle); + ast.mangle_names(mangle); + var fun; + walk(ast, node => { + if (is_func_expr(node)) { + fun = node; + return walk_abort; + } + }); + var code = OutputStream(); + AST_BlockStatement.prototype._codegen.call(fun, fun, code); + self.args = [ + make_node(AST_String, self, { + value: fun.argnames.map(function(arg) { + return arg.print_to_string(); + }).join(",") + }), + make_node(AST_String, self.args[self.args.length - 1], { + value: code.get().replace(/^{|}$/g, "") + }) + ]; + return self; + } catch (ex) { + if (!(ex instanceof JS_Parse_Error)) { + throw ex; + } + + // Otherwise, it crashes at runtime. Or maybe it's nonstandard syntax. + } + } + } + + return inline_into_call(self, fn, compressor); +}); + +def_optimize(AST_New, function(self, compressor) { + if ( + compressor.option("unsafe") && + is_undeclared_ref(self.expression) && + ["Object", "RegExp", "Function", "Error", "Array"].includes(self.expression.name) + ) return make_node(AST_Call, self, self).transform(compressor); + return self; +}); + +def_optimize(AST_Sequence, function(self, compressor) { + if (!compressor.option("side_effects")) return self; + var expressions = []; + filter_for_side_effects(); + var end = expressions.length - 1; + trim_right_for_undefined(); + if (end == 0) { + self = maintain_this_binding(compressor.parent(), compressor.self(), expressions[0]); + if (!(self instanceof AST_Sequence)) self = self.optimize(compressor); + return self; + } + self.expressions = expressions; + return self; + + function filter_for_side_effects() { + var first = first_in_statement(compressor); + var last = self.expressions.length - 1; + self.expressions.forEach(function(expr, index) { + if (index < last) expr = expr.drop_side_effect_free(compressor, first); + if (expr) { + merge_sequence(expressions, expr); + first = false; + } + }); + } + + function trim_right_for_undefined() { + while (end > 0 && is_undefined(expressions[end], compressor)) end--; + if (end < expressions.length - 1) { + expressions[end] = make_node(AST_UnaryPrefix, self, { + operator : "void", + expression : expressions[end] + }); + expressions.length = end + 1; + } + } +}); + +AST_Unary.DEFMETHOD("lift_sequences", function(compressor) { + if (compressor.option("sequences")) { + if (this.expression instanceof AST_Sequence) { + var x = this.expression.expressions.slice(); + var e = this.clone(); + e.expression = x.pop(); + x.push(e); + return make_sequence(this, x).optimize(compressor); + } + } + return this; +}); + +def_optimize(AST_UnaryPostfix, function(self, compressor) { + return self.lift_sequences(compressor); +}); + +def_optimize(AST_UnaryPrefix, function(self, compressor) { + var e = self.expression; + if ( + self.operator == "delete" && + !( + e instanceof AST_SymbolRef || + e instanceof AST_PropAccess || + e instanceof AST_Chain || + is_identifier_atom(e) + ) + ) { + return make_sequence(self, [e, make_node(AST_True, self)]).optimize(compressor); + } + var seq = self.lift_sequences(compressor); + if (seq !== self) { + return seq; + } + if (compressor.option("side_effects") && self.operator == "void") { + e = e.drop_side_effect_free(compressor); + if (e) { + self.expression = e; + return self; + } else { + return make_node(AST_Undefined, self).optimize(compressor); + } + } + if (compressor.in_boolean_context()) { + switch (self.operator) { + case "!": + if (e instanceof AST_UnaryPrefix && e.operator == "!") { + // !!foo ==> foo, if we're in boolean context + return e.expression; + } + if (e instanceof AST_Binary) { + self = best_of(compressor, self, e.negate(compressor, first_in_statement(compressor))); + } + break; + case "typeof": + // typeof always returns a non-empty string, thus it's + // always true in booleans + // And we don't need to check if it's undeclared, because in typeof, that's OK + return (e instanceof AST_SymbolRef ? make_node(AST_True, self) : make_sequence(self, [ + e, + make_node(AST_True, self) + ])).optimize(compressor); + } + } + if (self.operator == "-" && e instanceof AST_Infinity) { + e = e.transform(compressor); + } + if (e instanceof AST_Binary + && (self.operator == "+" || self.operator == "-") + && (e.operator == "*" || e.operator == "/" || e.operator == "%")) { + return make_node(AST_Binary, self, { + operator: e.operator, + left: make_node(AST_UnaryPrefix, e.left, { + operator: self.operator, + expression: e.left + }), + right: e.right + }); + } + // avoids infinite recursion of numerals + if (self.operator != "-" + || !(e instanceof AST_Number || e instanceof AST_Infinity || e instanceof AST_BigInt)) { + var ev = self.evaluate(compressor); + if (ev !== self) { + ev = make_node_from_constant(ev, self).optimize(compressor); + return best_of(compressor, ev, self); + } + } + return self; +}); + +AST_Binary.DEFMETHOD("lift_sequences", function(compressor) { + if (compressor.option("sequences")) { + if (this.left instanceof AST_Sequence) { + var x = this.left.expressions.slice(); + var e = this.clone(); + e.left = x.pop(); + x.push(e); + return make_sequence(this, x).optimize(compressor); + } + if (this.right instanceof AST_Sequence && !this.left.has_side_effects(compressor)) { + var assign = this.operator == "=" && this.left instanceof AST_SymbolRef; + var x = this.right.expressions; + var last = x.length - 1; + for (var i = 0; i < last; i++) { + if (!assign && x[i].has_side_effects(compressor)) break; + } + if (i == last) { + x = x.slice(); + var e = this.clone(); + e.right = x.pop(); + x.push(e); + return make_sequence(this, x).optimize(compressor); + } else if (i > 0) { + var e = this.clone(); + e.right = make_sequence(this.right, x.slice(i)); + x = x.slice(0, i); + x.push(e); + return make_sequence(this, x).optimize(compressor); + } + } + } + return this; +}); + +var commutativeOperators = makePredicate("== === != !== * & | ^"); +function is_object(node) { + return node instanceof AST_Array + || node instanceof AST_Lambda + || node instanceof AST_Object + || node instanceof AST_Class; +} + +def_optimize(AST_Binary, function(self, compressor) { + function reversible() { + return self.left.is_constant() + || self.right.is_constant() + || !self.left.has_side_effects(compressor) + && !self.right.has_side_effects(compressor); + } + function reverse(op) { + if (reversible()) { + if (op) self.operator = op; + var tmp = self.left; + self.left = self.right; + self.right = tmp; + } + } + if (compressor.option("lhs_constants") && commutativeOperators.has(self.operator)) { + if (self.right.is_constant() + && !self.left.is_constant()) { + // if right is a constant, whatever side effects the + // left side might have could not influence the + // result. hence, force switch. + + if (!(self.left instanceof AST_Binary + && PRECEDENCE[self.left.operator] >= PRECEDENCE[self.operator])) { + reverse(); + } + } + } + self = self.lift_sequences(compressor); + if (compressor.option("comparisons")) switch (self.operator) { + case "===": + case "!==": + var is_strict_comparison = true; + if ((self.left.is_string(compressor) && self.right.is_string(compressor)) || + (self.left.is_number(compressor) && self.right.is_number(compressor)) || + (self.left.is_boolean() && self.right.is_boolean()) || + self.left.equivalent_to(self.right)) { + self.operator = self.operator.substr(0, 2); + } + // XXX: intentionally falling down to the next case + case "==": + case "!=": + // void 0 == x => null == x + if (!is_strict_comparison && is_undefined(self.left, compressor)) { + self.left = make_node(AST_Null, self.left); + // x == void 0 => x == null + } else if (!is_strict_comparison && is_undefined(self.right, compressor)) { + self.right = make_node(AST_Null, self.right); + } else if (compressor.option("typeofs") + // "undefined" == typeof x => undefined === x + && self.left instanceof AST_String + && self.left.value == "undefined" + && self.right instanceof AST_UnaryPrefix + && self.right.operator == "typeof") { + var expr = self.right.expression; + if (expr instanceof AST_SymbolRef ? expr.is_declared(compressor) + : !(expr instanceof AST_PropAccess && compressor.option("ie8"))) { + self.right = expr; + self.left = make_node(AST_Undefined, self.left).optimize(compressor); + if (self.operator.length == 2) self.operator += "="; + } + } else if (compressor.option("typeofs") + // typeof x === "undefined" => x === undefined + && self.left instanceof AST_UnaryPrefix + && self.left.operator == "typeof" + && self.right instanceof AST_String + && self.right.value == "undefined") { + var expr = self.left.expression; + if (expr instanceof AST_SymbolRef ? expr.is_declared(compressor) + : !(expr instanceof AST_PropAccess && compressor.option("ie8"))) { + self.left = expr; + self.right = make_node(AST_Undefined, self.right).optimize(compressor); + if (self.operator.length == 2) self.operator += "="; + } + } else if (self.left instanceof AST_SymbolRef + // obj !== obj => false + && self.right instanceof AST_SymbolRef + && self.left.definition() === self.right.definition() + && is_object(self.left.fixed_value())) { + return make_node(self.operator[0] == "=" ? AST_True : AST_False, self); + } + break; + case "&&": + case "||": + var lhs = self.left; + if (lhs.operator == self.operator) { + lhs = lhs.right; + } + if (lhs instanceof AST_Binary + && lhs.operator == (self.operator == "&&" ? "!==" : "===") + && self.right instanceof AST_Binary + && lhs.operator == self.right.operator + && (is_undefined(lhs.left, compressor) && self.right.left instanceof AST_Null + || lhs.left instanceof AST_Null && is_undefined(self.right.left, compressor)) + && !lhs.right.has_side_effects(compressor) + && lhs.right.equivalent_to(self.right.right)) { + var combined = make_node(AST_Binary, self, { + operator: lhs.operator.slice(0, -1), + left: make_node(AST_Null, self), + right: lhs.right + }); + if (lhs !== self.left) { + combined = make_node(AST_Binary, self, { + operator: self.operator, + left: self.left.left, + right: combined + }); + } + return combined; + } + break; + } + if (self.operator == "+" && compressor.in_boolean_context()) { + var ll = self.left.evaluate(compressor); + var rr = self.right.evaluate(compressor); + if (ll && typeof ll == "string") { + return make_sequence(self, [ + self.right, + make_node(AST_True, self) + ]).optimize(compressor); + } + if (rr && typeof rr == "string") { + return make_sequence(self, [ + self.left, + make_node(AST_True, self) + ]).optimize(compressor); + } + } + if (compressor.option("comparisons") && self.is_boolean()) { + if (!(compressor.parent() instanceof AST_Binary) + || compressor.parent() instanceof AST_Assign) { + var negated = make_node(AST_UnaryPrefix, self, { + operator: "!", + expression: self.negate(compressor, first_in_statement(compressor)) + }); + self = best_of(compressor, self, negated); + } + if (compressor.option("unsafe_comps")) { + switch (self.operator) { + case "<": reverse(">"); break; + case "<=": reverse(">="); break; + } + } + } + if (self.operator == "+") { + if (self.right instanceof AST_String + && self.right.getValue() == "" + && self.left.is_string(compressor)) { + return self.left; + } + if (self.left instanceof AST_String + && self.left.getValue() == "" + && self.right.is_string(compressor)) { + return self.right; + } + if (self.left instanceof AST_Binary + && self.left.operator == "+" + && self.left.left instanceof AST_String + && self.left.left.getValue() == "" + && self.right.is_string(compressor)) { + self.left = self.left.right; + return self; + } + } + if (compressor.option("evaluate")) { + switch (self.operator) { + case "&&": + var ll = has_flag(self.left, TRUTHY) + ? true + : has_flag(self.left, FALSY) + ? false + : self.left.evaluate(compressor); + if (!ll) { + return maintain_this_binding(compressor.parent(), compressor.self(), self.left).optimize(compressor); + } else if (!(ll instanceof AST_Node)) { + return make_sequence(self, [ self.left, self.right ]).optimize(compressor); + } + var rr = self.right.evaluate(compressor); + if (!rr) { + if (compressor.in_boolean_context()) { + return make_sequence(self, [ + self.left, + make_node(AST_False, self) + ]).optimize(compressor); + } else { + set_flag(self, FALSY); + } + } else if (!(rr instanceof AST_Node)) { + var parent = compressor.parent(); + if (parent.operator == "&&" && parent.left === compressor.self() || compressor.in_boolean_context()) { + return self.left.optimize(compressor); + } + } + // x || false && y ---> x ? y : false + if (self.left.operator == "||") { + var lr = self.left.right.evaluate(compressor); + if (!lr) return make_node(AST_Conditional, self, { + condition: self.left.left, + consequent: self.right, + alternative: self.left.right + }).optimize(compressor); + } + break; + case "||": + var ll = has_flag(self.left, TRUTHY) + ? true + : has_flag(self.left, FALSY) + ? false + : self.left.evaluate(compressor); + if (!ll) { + return make_sequence(self, [ self.left, self.right ]).optimize(compressor); + } else if (!(ll instanceof AST_Node)) { + return maintain_this_binding(compressor.parent(), compressor.self(), self.left).optimize(compressor); + } + var rr = self.right.evaluate(compressor); + if (!rr) { + var parent = compressor.parent(); + if (parent.operator == "||" && parent.left === compressor.self() || compressor.in_boolean_context()) { + return self.left.optimize(compressor); + } + } else if (!(rr instanceof AST_Node)) { + if (compressor.in_boolean_context()) { + return make_sequence(self, [ + self.left, + make_node(AST_True, self) + ]).optimize(compressor); + } else { + set_flag(self, TRUTHY); + } + } + if (self.left.operator == "&&") { + var lr = self.left.right.evaluate(compressor); + if (lr && !(lr instanceof AST_Node)) return make_node(AST_Conditional, self, { + condition: self.left.left, + consequent: self.left.right, + alternative: self.right + }).optimize(compressor); + } + break; + case "??": + if (is_nullish(self.left, compressor)) { + return self.right; + } + + var ll = self.left.evaluate(compressor); + if (!(ll instanceof AST_Node)) { + // if we know the value for sure we can simply compute right away. + return ll == null ? self.right : self.left; + } + + if (compressor.in_boolean_context()) { + const rr = self.right.evaluate(compressor); + if (!(rr instanceof AST_Node) && !rr) { + return self.left; + } + } + } + var associative = true; + switch (self.operator) { + case "+": + // (x + "foo") + "bar" => x + "foobar" + if (self.right instanceof AST_Constant + && self.left instanceof AST_Binary + && self.left.operator == "+" + && self.left.is_string(compressor)) { + var binary = make_node(AST_Binary, self, { + operator: "+", + left: self.left.right, + right: self.right, + }); + var r = binary.optimize(compressor); + if (binary !== r) { + self = make_node(AST_Binary, self, { + operator: "+", + left: self.left.left, + right: r + }); + } + } + // (x + "foo") + ("bar" + y) => (x + "foobar") + y + if (self.left instanceof AST_Binary + && self.left.operator == "+" + && self.left.is_string(compressor) + && self.right instanceof AST_Binary + && self.right.operator == "+" + && self.right.is_string(compressor)) { + var binary = make_node(AST_Binary, self, { + operator: "+", + left: self.left.right, + right: self.right.left, + }); + var m = binary.optimize(compressor); + if (binary !== m) { + self = make_node(AST_Binary, self, { + operator: "+", + left: make_node(AST_Binary, self.left, { + operator: "+", + left: self.left.left, + right: m + }), + right: self.right.right + }); + } + } + // a + -b => a - b + if (self.right instanceof AST_UnaryPrefix + && self.right.operator == "-" + && self.left.is_number(compressor)) { + self = make_node(AST_Binary, self, { + operator: "-", + left: self.left, + right: self.right.expression + }); + break; + } + // -a + b => b - a + if (self.left instanceof AST_UnaryPrefix + && self.left.operator == "-" + && reversible() + && self.right.is_number(compressor)) { + self = make_node(AST_Binary, self, { + operator: "-", + left: self.right, + right: self.left.expression + }); + break; + } + // `foo${bar}baz` + 1 => `foo${bar}baz1` + if (self.left instanceof AST_TemplateString) { + var l = self.left; + var r = self.right.evaluate(compressor); + if (r != self.right) { + l.segments[l.segments.length - 1].value += String(r); + return l; + } + } + // 1 + `foo${bar}baz` => `1foo${bar}baz` + if (self.right instanceof AST_TemplateString) { + var r = self.right; + var l = self.left.evaluate(compressor); + if (l != self.left) { + r.segments[0].value = String(l) + r.segments[0].value; + return r; + } + } + // `1${bar}2` + `foo${bar}baz` => `1${bar}2foo${bar}baz` + if (self.left instanceof AST_TemplateString + && self.right instanceof AST_TemplateString) { + var l = self.left; + var segments = l.segments; + var r = self.right; + segments[segments.length - 1].value += r.segments[0].value; + for (var i = 1; i < r.segments.length; i++) { + segments.push(r.segments[i]); + } + return l; + } + case "*": + associative = compressor.option("unsafe_math"); + case "&": + case "|": + case "^": + // a + +b => +b + a + if (self.left.is_number(compressor) + && self.right.is_number(compressor) + && reversible() + && !(self.left instanceof AST_Binary + && self.left.operator != self.operator + && PRECEDENCE[self.left.operator] >= PRECEDENCE[self.operator])) { + var reversed = make_node(AST_Binary, self, { + operator: self.operator, + left: self.right, + right: self.left + }); + if (self.right instanceof AST_Constant + && !(self.left instanceof AST_Constant)) { + self = best_of(compressor, reversed, self); + } else { + self = best_of(compressor, self, reversed); + } + } + if (associative && self.is_number(compressor)) { + // a + (b + c) => (a + b) + c + if (self.right instanceof AST_Binary + && self.right.operator == self.operator) { + self = make_node(AST_Binary, self, { + operator: self.operator, + left: make_node(AST_Binary, self.left, { + operator: self.operator, + left: self.left, + right: self.right.left, + start: self.left.start, + end: self.right.left.end + }), + right: self.right.right + }); + } + // (n + 2) + 3 => 5 + n + // (2 * n) * 3 => 6 + n + if (self.right instanceof AST_Constant + && self.left instanceof AST_Binary + && self.left.operator == self.operator) { + if (self.left.left instanceof AST_Constant) { + self = make_node(AST_Binary, self, { + operator: self.operator, + left: make_node(AST_Binary, self.left, { + operator: self.operator, + left: self.left.left, + right: self.right, + start: self.left.left.start, + end: self.right.end + }), + right: self.left.right + }); + } else if (self.left.right instanceof AST_Constant) { + self = make_node(AST_Binary, self, { + operator: self.operator, + left: make_node(AST_Binary, self.left, { + operator: self.operator, + left: self.left.right, + right: self.right, + start: self.left.right.start, + end: self.right.end + }), + right: self.left.left + }); + } + } + // (a | 1) | (2 | d) => (3 | a) | b + if (self.left instanceof AST_Binary + && self.left.operator == self.operator + && self.left.right instanceof AST_Constant + && self.right instanceof AST_Binary + && self.right.operator == self.operator + && self.right.left instanceof AST_Constant) { + self = make_node(AST_Binary, self, { + operator: self.operator, + left: make_node(AST_Binary, self.left, { + operator: self.operator, + left: make_node(AST_Binary, self.left.left, { + operator: self.operator, + left: self.left.right, + right: self.right.left, + start: self.left.right.start, + end: self.right.left.end + }), + right: self.left.left + }), + right: self.right.right + }); + } + } + } + } + // x && (y && z) ==> x && y && z + // x || (y || z) ==> x || y || z + // x + ("y" + z) ==> x + "y" + z + // "x" + (y + "z")==> "x" + y + "z" + if (self.right instanceof AST_Binary + && self.right.operator == self.operator + && (lazy_op.has(self.operator) + || (self.operator == "+" + && (self.right.left.is_string(compressor) + || (self.left.is_string(compressor) + && self.right.right.is_string(compressor))))) + ) { + self.left = make_node(AST_Binary, self.left, { + operator : self.operator, + left : self.left.transform(compressor), + right : self.right.left.transform(compressor) + }); + self.right = self.right.right.transform(compressor); + return self.transform(compressor); + } + var ev = self.evaluate(compressor); + if (ev !== self) { + ev = make_node_from_constant(ev, self).optimize(compressor); + return best_of(compressor, ev, self); + } + return self; +}); + +def_optimize(AST_SymbolExport, function(self) { + return self; +}); + +def_optimize(AST_SymbolRef, function(self, compressor) { + if ( + !compressor.option("ie8") + && is_undeclared_ref(self) + && !compressor.find_parent(AST_With) + ) { + switch (self.name) { + case "undefined": + return make_node(AST_Undefined, self).optimize(compressor); + case "NaN": + return make_node(AST_NaN, self).optimize(compressor); + case "Infinity": + return make_node(AST_Infinity, self).optimize(compressor); + } + } + + if (compressor.option("reduce_vars") && !compressor.is_lhs()) { + return inline_into_symbolref(self, compressor); + } else { + return self; + } +}); + +function is_atomic(lhs, self) { + return lhs instanceof AST_SymbolRef || lhs.TYPE === self.TYPE; +} + +def_optimize(AST_Undefined, function(self, compressor) { + if (compressor.option("unsafe_undefined")) { + var undef = find_variable(compressor, "undefined"); + if (undef) { + var ref = make_node(AST_SymbolRef, self, { + name : "undefined", + scope : undef.scope, + thedef : undef + }); + set_flag(ref, UNDEFINED); + return ref; + } + } + var lhs = compressor.is_lhs(); + if (lhs && is_atomic(lhs, self)) return self; + return make_node(AST_UnaryPrefix, self, { + operator: "void", + expression: make_node(AST_Number, self, { + value: 0 + }) + }); +}); + +def_optimize(AST_Infinity, function(self, compressor) { + var lhs = compressor.is_lhs(); + if (lhs && is_atomic(lhs, self)) return self; + if ( + compressor.option("keep_infinity") + && !(lhs && !is_atomic(lhs, self)) + && !find_variable(compressor, "Infinity") + ) { + return self; + } + return make_node(AST_Binary, self, { + operator: "/", + left: make_node(AST_Number, self, { + value: 1 + }), + right: make_node(AST_Number, self, { + value: 0 + }) + }); +}); + +def_optimize(AST_NaN, function(self, compressor) { + var lhs = compressor.is_lhs(); + if (lhs && !is_atomic(lhs, self) + || find_variable(compressor, "NaN")) { + return make_node(AST_Binary, self, { + operator: "/", + left: make_node(AST_Number, self, { + value: 0 + }), + right: make_node(AST_Number, self, { + value: 0 + }) + }); + } + return self; +}); + +const ASSIGN_OPS = makePredicate("+ - / * % >> << >>> | ^ &"); +const ASSIGN_OPS_COMMUTATIVE = makePredicate("* | ^ &"); +def_optimize(AST_Assign, function(self, compressor) { + if (self.logical) { + return self.lift_sequences(compressor); + } + + var def; + // x = x ---> x + if ( + self.operator === "=" + && self.left instanceof AST_SymbolRef + && self.left.name !== "arguments" + && !(def = self.left.definition()).undeclared + && self.right.equivalent_to(self.left) + ) { + return self.right; + } + + if (compressor.option("dead_code") + && self.left instanceof AST_SymbolRef + && (def = self.left.definition()).scope === compressor.find_parent(AST_Lambda)) { + var level = 0, node, parent = self; + do { + node = parent; + parent = compressor.parent(level++); + if (parent instanceof AST_Exit) { + if (in_try(level, parent)) break; + if (is_reachable(def.scope, [ def ])) break; + if (self.operator == "=") return self.right; + def.fixed = false; + return make_node(AST_Binary, self, { + operator: self.operator.slice(0, -1), + left: self.left, + right: self.right + }).optimize(compressor); + } + } while (parent instanceof AST_Binary && parent.right === node + || parent instanceof AST_Sequence && parent.tail_node() === node); + } + self = self.lift_sequences(compressor); + + if (self.operator == "=" && self.left instanceof AST_SymbolRef && self.right instanceof AST_Binary) { + // x = expr1 OP expr2 + if (self.right.left instanceof AST_SymbolRef + && self.right.left.name == self.left.name + && ASSIGN_OPS.has(self.right.operator)) { + // x = x - 2 ---> x -= 2 + self.operator = self.right.operator + "="; + self.right = self.right.right; + } else if (self.right.right instanceof AST_SymbolRef + && self.right.right.name == self.left.name + && ASSIGN_OPS_COMMUTATIVE.has(self.right.operator) + && !self.right.left.has_side_effects(compressor)) { + // x = 2 & x ---> x &= 2 + self.operator = self.right.operator + "="; + self.right = self.right.left; + } + } + return self; + + function in_try(level, node) { + function may_assignment_throw() { + const right = self.right; + self.right = make_node(AST_Null, right); + const may_throw = node.may_throw(compressor); + self.right = right; + + return may_throw; + } + + var stop_at = self.left.definition().scope.get_defun_scope(); + var parent; + while ((parent = compressor.parent(level++)) !== stop_at) { + if (parent instanceof AST_Try) { + if (parent.bfinally) return true; + if (parent.bcatch && may_assignment_throw()) return true; + } + } + } +}); + +def_optimize(AST_DefaultAssign, function(self, compressor) { + if (!compressor.option("evaluate")) { + return self; + } + var evaluateRight = self.right.evaluate(compressor); + + // `[x = undefined] = foo` ---> `[x] = foo` + // `(arg = undefined) => ...` ---> `(arg) => ...` (unless `keep_fargs`) + // `((arg = undefined) => ...)()` ---> `((arg) => ...)()` + let lambda, iife; + if (evaluateRight === undefined) { + if ( + (lambda = compressor.parent()) instanceof AST_Lambda + ? ( + compressor.option("keep_fargs") === false + || (iife = compressor.parent(1)).TYPE === "Call" + && iife.expression === lambda + ) + : true + ) { + self = self.left; + } + } else if (evaluateRight !== self.right) { + evaluateRight = make_node_from_constant(evaluateRight, self.right); + self.right = best_of_expression(evaluateRight, self.right); + } + + return self; +}); + +function is_nullish_check(check, check_subject, compressor) { + if (check_subject.may_throw(compressor)) return false; + + let nullish_side; + + // foo == null + if ( + check instanceof AST_Binary + && check.operator === "==" + // which side is nullish? + && ( + (nullish_side = is_nullish(check.left, compressor) && check.left) + || (nullish_side = is_nullish(check.right, compressor) && check.right) + ) + // is the other side the same as the check_subject + && ( + nullish_side === check.left + ? check.right + : check.left + ).equivalent_to(check_subject) + ) { + return true; + } + + // foo === null || foo === undefined + if (check instanceof AST_Binary && check.operator === "||") { + let null_cmp; + let undefined_cmp; + + const find_comparison = cmp => { + if (!( + cmp instanceof AST_Binary + && (cmp.operator === "===" || cmp.operator === "==") + )) { + return false; + } + + let found = 0; + let defined_side; + + if (cmp.left instanceof AST_Null) { + found++; + null_cmp = cmp; + defined_side = cmp.right; + } + if (cmp.right instanceof AST_Null) { + found++; + null_cmp = cmp; + defined_side = cmp.left; + } + if (is_undefined(cmp.left, compressor)) { + found++; + undefined_cmp = cmp; + defined_side = cmp.right; + } + if (is_undefined(cmp.right, compressor)) { + found++; + undefined_cmp = cmp; + defined_side = cmp.left; + } + + if (found !== 1) { + return false; + } + + if (!defined_side.equivalent_to(check_subject)) { + return false; + } + + return true; + }; + + if (!find_comparison(check.left)) return false; + if (!find_comparison(check.right)) return false; + + if (null_cmp && undefined_cmp && null_cmp !== undefined_cmp) { + return true; + } + } + + return false; +} + +def_optimize(AST_Conditional, function(self, compressor) { + if (!compressor.option("conditionals")) return self; + // This looks like lift_sequences(), should probably be under "sequences" + if (self.condition instanceof AST_Sequence) { + var expressions = self.condition.expressions.slice(); + self.condition = expressions.pop(); + expressions.push(self); + return make_sequence(self, expressions); + } + var cond = self.condition.evaluate(compressor); + if (cond !== self.condition) { + if (cond) { + return maintain_this_binding(compressor.parent(), compressor.self(), self.consequent); + } else { + return maintain_this_binding(compressor.parent(), compressor.self(), self.alternative); + } + } + var negated = cond.negate(compressor, first_in_statement(compressor)); + if (best_of(compressor, cond, negated) === negated) { + self = make_node(AST_Conditional, self, { + condition: negated, + consequent: self.alternative, + alternative: self.consequent + }); + } + var condition = self.condition; + var consequent = self.consequent; + var alternative = self.alternative; + // x?x:y --> x||y + if (condition instanceof AST_SymbolRef + && consequent instanceof AST_SymbolRef + && condition.definition() === consequent.definition()) { + return make_node(AST_Binary, self, { + operator: "||", + left: condition, + right: alternative + }); + } + // if (foo) exp = something; else exp = something_else; + // | + // v + // exp = foo ? something : something_else; + if ( + consequent instanceof AST_Assign + && alternative instanceof AST_Assign + && consequent.operator === alternative.operator + && consequent.logical === alternative.logical + && consequent.left.equivalent_to(alternative.left) + && (!self.condition.has_side_effects(compressor) + || consequent.operator == "=" + && !consequent.left.has_side_effects(compressor)) + ) { + return make_node(AST_Assign, self, { + operator: consequent.operator, + left: consequent.left, + logical: consequent.logical, + right: make_node(AST_Conditional, self, { + condition: self.condition, + consequent: consequent.right, + alternative: alternative.right + }) + }); + } + // x ? y(a) : y(b) --> y(x ? a : b) + var arg_index; + if (consequent instanceof AST_Call + && alternative.TYPE === consequent.TYPE + && consequent.args.length > 0 + && consequent.args.length == alternative.args.length + && consequent.expression.equivalent_to(alternative.expression) + && !self.condition.has_side_effects(compressor) + && !consequent.expression.has_side_effects(compressor) + && typeof (arg_index = single_arg_diff()) == "number") { + var node = consequent.clone(); + node.args[arg_index] = make_node(AST_Conditional, self, { + condition: self.condition, + consequent: consequent.args[arg_index], + alternative: alternative.args[arg_index] + }); + return node; + } + // a ? b : c ? b : d --> (a || c) ? b : d + if (alternative instanceof AST_Conditional + && consequent.equivalent_to(alternative.consequent)) { + return make_node(AST_Conditional, self, { + condition: make_node(AST_Binary, self, { + operator: "||", + left: condition, + right: alternative.condition + }), + consequent: consequent, + alternative: alternative.alternative + }).optimize(compressor); + } + + // a == null ? b : a -> a ?? b + if ( + compressor.option("ecma") >= 2020 && + is_nullish_check(condition, alternative, compressor) + ) { + return make_node(AST_Binary, self, { + operator: "??", + left: alternative, + right: consequent + }).optimize(compressor); + } + + // a ? b : (c, b) --> (a || c), b + if (alternative instanceof AST_Sequence + && consequent.equivalent_to(alternative.expressions[alternative.expressions.length - 1])) { + return make_sequence(self, [ + make_node(AST_Binary, self, { + operator: "||", + left: condition, + right: make_sequence(self, alternative.expressions.slice(0, -1)) + }), + consequent + ]).optimize(compressor); + } + // a ? b : (c && b) --> (a || c) && b + if (alternative instanceof AST_Binary + && alternative.operator == "&&" + && consequent.equivalent_to(alternative.right)) { + return make_node(AST_Binary, self, { + operator: "&&", + left: make_node(AST_Binary, self, { + operator: "||", + left: condition, + right: alternative.left + }), + right: consequent + }).optimize(compressor); + } + // x?y?z:a:a --> x&&y?z:a + if (consequent instanceof AST_Conditional + && consequent.alternative.equivalent_to(alternative)) { + return make_node(AST_Conditional, self, { + condition: make_node(AST_Binary, self, { + left: self.condition, + operator: "&&", + right: consequent.condition + }), + consequent: consequent.consequent, + alternative: alternative + }); + } + // x ? y : y --> x, y + if (consequent.equivalent_to(alternative)) { + return make_sequence(self, [ + self.condition, + consequent + ]).optimize(compressor); + } + // x ? y || z : z --> x && y || z + if (consequent instanceof AST_Binary + && consequent.operator == "||" + && consequent.right.equivalent_to(alternative)) { + return make_node(AST_Binary, self, { + operator: "||", + left: make_node(AST_Binary, self, { + operator: "&&", + left: self.condition, + right: consequent.left + }), + right: alternative + }).optimize(compressor); + } + + const in_bool = compressor.in_boolean_context(); + if (is_true(self.consequent)) { + if (is_false(self.alternative)) { + // c ? true : false ---> !!c + return booleanize(self.condition); + } + // c ? true : x ---> !!c || x + return make_node(AST_Binary, self, { + operator: "||", + left: booleanize(self.condition), + right: self.alternative + }); + } + if (is_false(self.consequent)) { + if (is_true(self.alternative)) { + // c ? false : true ---> !c + return booleanize(self.condition.negate(compressor)); + } + // c ? false : x ---> !c && x + return make_node(AST_Binary, self, { + operator: "&&", + left: booleanize(self.condition.negate(compressor)), + right: self.alternative + }); + } + if (is_true(self.alternative)) { + // c ? x : true ---> !c || x + return make_node(AST_Binary, self, { + operator: "||", + left: booleanize(self.condition.negate(compressor)), + right: self.consequent + }); + } + if (is_false(self.alternative)) { + // c ? x : false ---> !!c && x + return make_node(AST_Binary, self, { + operator: "&&", + left: booleanize(self.condition), + right: self.consequent + }); + } + + return self; + + function booleanize(node) { + if (node.is_boolean()) return node; + // !!expression + return make_node(AST_UnaryPrefix, node, { + operator: "!", + expression: node.negate(compressor) + }); + } + + // AST_True or !0 + function is_true(node) { + return node instanceof AST_True + || in_bool + && node instanceof AST_Constant + && node.getValue() + || (node instanceof AST_UnaryPrefix + && node.operator == "!" + && node.expression instanceof AST_Constant + && !node.expression.getValue()); + } + // AST_False or !1 + function is_false(node) { + return node instanceof AST_False + || in_bool + && node instanceof AST_Constant + && !node.getValue() + || (node instanceof AST_UnaryPrefix + && node.operator == "!" + && node.expression instanceof AST_Constant + && node.expression.getValue()); + } + + function single_arg_diff() { + var a = consequent.args; + var b = alternative.args; + for (var i = 0, len = a.length; i < len; i++) { + if (a[i] instanceof AST_Expansion) return; + if (!a[i].equivalent_to(b[i])) { + if (b[i] instanceof AST_Expansion) return; + for (var j = i + 1; j < len; j++) { + if (a[j] instanceof AST_Expansion) return; + if (!a[j].equivalent_to(b[j])) return; + } + return i; + } + } + } +}); + +def_optimize(AST_Boolean, function(self, compressor) { + if (compressor.in_boolean_context()) return make_node(AST_Number, self, { + value: +self.value + }); + var p = compressor.parent(); + if (compressor.option("booleans_as_integers")) { + if (p instanceof AST_Binary && (p.operator == "===" || p.operator == "!==")) { + p.operator = p.operator.replace(/=$/, ""); + } + return make_node(AST_Number, self, { + value: +self.value + }); + } + if (compressor.option("booleans")) { + if (p instanceof AST_Binary && (p.operator == "==" + || p.operator == "!=")) { + return make_node(AST_Number, self, { + value: +self.value + }); + } + return make_node(AST_UnaryPrefix, self, { + operator: "!", + expression: make_node(AST_Number, self, { + value: 1 - self.value + }) + }); + } + return self; +}); + +function safe_to_flatten(value, compressor) { + if (value instanceof AST_SymbolRef) { + value = value.fixed_value(); + } + if (!value) return false; + if (!(value instanceof AST_Lambda || value instanceof AST_Class)) return true; + if (!(value instanceof AST_Lambda && value.contains_this())) return true; + return compressor.parent() instanceof AST_New; +} + +AST_PropAccess.DEFMETHOD("flatten_object", function(key, compressor) { + if (!compressor.option("properties")) return; + if (key === "__proto__") return; + + var arrows = compressor.option("unsafe_arrows") && compressor.option("ecma") >= 2015; + var expr = this.expression; + if (expr instanceof AST_Object) { + var props = expr.properties; + + for (var i = props.length; --i >= 0;) { + var prop = props[i]; + + if ("" + (prop instanceof AST_ConciseMethod ? prop.key.name : prop.key) == key) { + const all_props_flattenable = props.every((p) => + (p instanceof AST_ObjectKeyVal + || arrows && p instanceof AST_ConciseMethod && !p.is_generator + ) + && !p.computed_key() + ); + + if (!all_props_flattenable) return; + if (!safe_to_flatten(prop.value, compressor)) return; + + return make_node(AST_Sub, this, { + expression: make_node(AST_Array, expr, { + elements: props.map(function(prop) { + var v = prop.value; + if (v instanceof AST_Accessor) { + v = make_node(AST_Function, v, v); + } + + var k = prop.key; + if (k instanceof AST_Node && !(k instanceof AST_SymbolMethod)) { + return make_sequence(prop, [ k, v ]); + } + + return v; + }) + }), + property: make_node(AST_Number, this, { + value: i + }) + }); + } + } + } +}); + +def_optimize(AST_Sub, function(self, compressor) { + var expr = self.expression; + var prop = self.property; + if (compressor.option("properties")) { + var key = prop.evaluate(compressor); + if (key !== prop) { + if (typeof key == "string") { + if (key == "undefined") { + key = undefined; + } else { + var value = parseFloat(key); + if (value.toString() == key) { + key = value; + } + } + } + prop = self.property = best_of_expression( + prop, + make_node_from_constant(key, prop).transform(compressor) + ); + var property = "" + key; + if (is_basic_identifier_string(property) + && property.length <= prop.size() + 1) { + return make_node(AST_Dot, self, { + expression: expr, + optional: self.optional, + property: property, + quote: prop.quote, + }).optimize(compressor); + } + } + } + var fn; + OPT_ARGUMENTS: if (compressor.option("arguments") + && expr instanceof AST_SymbolRef + && expr.name == "arguments" + && expr.definition().orig.length == 1 + && (fn = expr.scope) instanceof AST_Lambda + && fn.uses_arguments + && !(fn instanceof AST_Arrow) + && prop instanceof AST_Number) { + var index = prop.getValue(); + var params = new Set(); + var argnames = fn.argnames; + for (var n = 0; n < argnames.length; n++) { + if (!(argnames[n] instanceof AST_SymbolFunarg)) { + break OPT_ARGUMENTS; // destructuring parameter - bail + } + var param = argnames[n].name; + if (params.has(param)) { + break OPT_ARGUMENTS; // duplicate parameter - bail + } + params.add(param); + } + var argname = fn.argnames[index]; + if (argname && compressor.has_directive("use strict")) { + var def = argname.definition(); + if (!compressor.option("reduce_vars") || def.assignments || def.orig.length > 1) { + argname = null; + } + } else if (!argname && !compressor.option("keep_fargs") && index < fn.argnames.length + 5) { + while (index >= fn.argnames.length) { + argname = fn.create_symbol(AST_SymbolFunarg, { + source: fn, + scope: fn, + tentative_name: "argument_" + fn.argnames.length, + }); + fn.argnames.push(argname); + } + } + if (argname) { + var sym = make_node(AST_SymbolRef, self, argname); + sym.reference({}); + clear_flag(argname, UNUSED); + return sym; + } + } + if (compressor.is_lhs()) return self; + if (key !== prop) { + var sub = self.flatten_object(property, compressor); + if (sub) { + expr = self.expression = sub.expression; + prop = self.property = sub.property; + } + } + if (compressor.option("properties") && compressor.option("side_effects") + && prop instanceof AST_Number && expr instanceof AST_Array) { + var index = prop.getValue(); + var elements = expr.elements; + var retValue = elements[index]; + FLATTEN: if (safe_to_flatten(retValue, compressor)) { + var flatten = true; + var values = []; + for (var i = elements.length; --i > index;) { + var value = elements[i].drop_side_effect_free(compressor); + if (value) { + values.unshift(value); + if (flatten && value.has_side_effects(compressor)) flatten = false; + } + } + if (retValue instanceof AST_Expansion) break FLATTEN; + retValue = retValue instanceof AST_Hole ? make_node(AST_Undefined, retValue) : retValue; + if (!flatten) values.unshift(retValue); + while (--i >= 0) { + var value = elements[i]; + if (value instanceof AST_Expansion) break FLATTEN; + value = value.drop_side_effect_free(compressor); + if (value) values.unshift(value); + else index--; + } + if (flatten) { + values.push(retValue); + return make_sequence(self, values).optimize(compressor); + } else return make_node(AST_Sub, self, { + expression: make_node(AST_Array, expr, { + elements: values + }), + property: make_node(AST_Number, prop, { + value: index + }) + }); + } + } + var ev = self.evaluate(compressor); + if (ev !== self) { + ev = make_node_from_constant(ev, self).optimize(compressor); + return best_of(compressor, ev, self); + } + return self; +}); + +def_optimize(AST_Chain, function (self, compressor) { + if (is_nullish(self.expression, compressor)) { + let parent = compressor.parent(); + // It's valid to delete a nullish optional chain, but if we optimized + // this to `delete undefined` then it would appear to be a syntax error + // when we try to optimize the delete. Thankfully, `delete 0` is fine. + if (parent instanceof AST_UnaryPrefix && parent.operator === "delete") { + return make_node_from_constant(0, self); + } + return make_node(AST_Undefined, self); + } + return self; +}); + +def_optimize(AST_Dot, function(self, compressor) { + const parent = compressor.parent(); + if (compressor.is_lhs()) return self; + if (compressor.option("unsafe_proto") + && self.expression instanceof AST_Dot + && self.expression.property == "prototype") { + var exp = self.expression.expression; + if (is_undeclared_ref(exp)) switch (exp.name) { + case "Array": + self.expression = make_node(AST_Array, self.expression, { + elements: [] + }); + break; + case "Function": + self.expression = make_node(AST_Function, self.expression, { + argnames: [], + body: [] + }); + break; + case "Number": + self.expression = make_node(AST_Number, self.expression, { + value: 0 + }); + break; + case "Object": + self.expression = make_node(AST_Object, self.expression, { + properties: [] + }); + break; + case "RegExp": + self.expression = make_node(AST_RegExp, self.expression, { + value: { source: "t", flags: "" } + }); + break; + case "String": + self.expression = make_node(AST_String, self.expression, { + value: "" + }); + break; + } + } + if (!(parent instanceof AST_Call) || !has_annotation(parent, _NOINLINE)) { + const sub = self.flatten_object(self.property, compressor); + if (sub) return sub.optimize(compressor); + } + + if (self.expression instanceof AST_PropAccess + && parent instanceof AST_PropAccess) { + return self; + } + + let ev = self.evaluate(compressor); + if (ev !== self) { + ev = make_node_from_constant(ev, self).optimize(compressor); + return best_of(compressor, ev, self); + } + return self; +}); + +function literals_in_boolean_context(self, compressor) { + if (compressor.in_boolean_context()) { + return best_of(compressor, self, make_sequence(self, [ + self, + make_node(AST_True, self) + ]).optimize(compressor)); + } + return self; +} + +function inline_array_like_spread(elements) { + for (var i = 0; i < elements.length; i++) { + var el = elements[i]; + if (el instanceof AST_Expansion) { + var expr = el.expression; + if ( + expr instanceof AST_Array + && !expr.elements.some(elm => elm instanceof AST_Hole) + ) { + elements.splice(i, 1, ...expr.elements); + // Step back one, as the element at i is now new. + i--; + } + // In array-like spread, spreading a non-iterable value is TypeError. + // We therefore can’t optimize anything else, unlike with object spread. + } + } +} + +def_optimize(AST_Array, function(self, compressor) { + var optimized = literals_in_boolean_context(self, compressor); + if (optimized !== self) { + return optimized; + } + inline_array_like_spread(self.elements); + return self; +}); + +function inline_object_prop_spread(props, compressor) { + for (var i = 0; i < props.length; i++) { + var prop = props[i]; + if (prop instanceof AST_Expansion) { + const expr = prop.expression; + if ( + expr instanceof AST_Object + && expr.properties.every(prop => prop instanceof AST_ObjectKeyVal) + ) { + props.splice(i, 1, ...expr.properties); + // Step back one, as the property at i is now new. + i--; + } else if (expr instanceof AST_Constant + && !(expr instanceof AST_String)) { + // Unlike array-like spread, in object spread, spreading a + // non-iterable value silently does nothing; it is thus safe + // to remove. AST_String is the only iterable AST_Constant. + props.splice(i, 1); + i--; + } else if (is_nullish(expr, compressor)) { + // Likewise, null and undefined can be silently removed. + props.splice(i, 1); + i--; + } + } + } +} + +def_optimize(AST_Object, function(self, compressor) { + var optimized = literals_in_boolean_context(self, compressor); + if (optimized !== self) { + return optimized; + } + inline_object_prop_spread(self.properties, compressor); + return self; +}); + +def_optimize(AST_RegExp, literals_in_boolean_context); + +def_optimize(AST_Return, function(self, compressor) { + if (self.value && is_undefined(self.value, compressor)) { + self.value = null; + } + return self; +}); + +def_optimize(AST_Arrow, opt_AST_Lambda); + +def_optimize(AST_Function, function(self, compressor) { + self = opt_AST_Lambda(self, compressor); + if (compressor.option("unsafe_arrows") + && compressor.option("ecma") >= 2015 + && !self.name + && !self.is_generator + && !self.uses_arguments + && !self.pinned()) { + const uses_this = walk(self, node => { + if (node instanceof AST_This) return walk_abort; + }); + if (!uses_this) return make_node(AST_Arrow, self, self).optimize(compressor); + } + return self; +}); + +def_optimize(AST_Class, function(self) { + // HACK to avoid compress failure. + // AST_Class is not really an AST_Scope/AST_Block as it lacks a body. + return self; +}); + +def_optimize(AST_ClassStaticBlock, function(self, compressor) { + tighten_body(self.body, compressor); + return self; +}); + +def_optimize(AST_Yield, function(self, compressor) { + if (self.expression && !self.is_star && is_undefined(self.expression, compressor)) { + self.expression = null; + } + return self; +}); + +def_optimize(AST_TemplateString, function(self, compressor) { + if ( + !compressor.option("evaluate") + || compressor.parent() instanceof AST_PrefixedTemplateString + ) { + return self; + } + + var segments = []; + for (var i = 0; i < self.segments.length; i++) { + var segment = self.segments[i]; + if (segment instanceof AST_Node) { + var result = segment.evaluate(compressor); + // Evaluate to constant value + // Constant value shorter than ${segment} + if (result !== segment && (result + "").length <= segment.size() + "${}".length) { + // There should always be a previous and next segment if segment is a node + segments[segments.length - 1].value = segments[segments.length - 1].value + result + self.segments[++i].value; + continue; + } + // `before ${`innerBefore ${any} innerAfter`} after` => `before innerBefore ${any} innerAfter after` + // TODO: + // `before ${'test' + foo} after` => `before innerBefore ${any} innerAfter after` + // `before ${foo + 'test} after` => `before innerBefore ${any} innerAfter after` + if (segment instanceof AST_TemplateString) { + var inners = segment.segments; + segments[segments.length - 1].value += inners[0].value; + for (var j = 1; j < inners.length; j++) { + segment = inners[j]; + segments.push(segment); + } + continue; + } + } + segments.push(segment); + } + self.segments = segments; + + // `foo` => "foo" + if (segments.length == 1) { + return make_node(AST_String, self, segments[0]); + } + + if ( + segments.length === 3 + && segments[1] instanceof AST_Node + && ( + segments[1].is_string(compressor) + || segments[1].is_number(compressor) + || is_nullish(segments[1], compressor) + || compressor.option("unsafe") + ) + ) { + // `foo${bar}` => "foo" + bar + if (segments[2].value === "") { + return make_node(AST_Binary, self, { + operator: "+", + left: make_node(AST_String, self, { + value: segments[0].value, + }), + right: segments[1], + }); + } + // `${bar}baz` => bar + "baz" + if (segments[0].value === "") { + return make_node(AST_Binary, self, { + operator: "+", + left: segments[1], + right: make_node(AST_String, self, { + value: segments[2].value, + }), + }); + } + } + return self; +}); + +def_optimize(AST_PrefixedTemplateString, function(self) { + return self; +}); + +// ["p"]:1 ---> p:1 +// [42]:1 ---> 42:1 +function lift_key(self, compressor) { + if (!compressor.option("computed_props")) return self; + // save a comparison in the typical case + if (!(self.key instanceof AST_Constant)) return self; + // allow certain acceptable props as not all AST_Constants are true constants + if (self.key instanceof AST_String || self.key instanceof AST_Number) { + if (self.key.value === "__proto__") return self; + if (self.key.value == "constructor" + && compressor.parent() instanceof AST_Class) return self; + if (self instanceof AST_ObjectKeyVal) { + self.quote = self.key.quote; + self.key = self.key.value; + } else if (self instanceof AST_ClassProperty) { + self.quote = self.key.quote; + self.key = make_node(AST_SymbolClassProperty, self.key, { + name: self.key.value + }); + } else { + self.quote = self.key.quote; + self.key = make_node(AST_SymbolMethod, self.key, { + name: self.key.value + }); + } + } + return self; +} + +def_optimize(AST_ObjectProperty, lift_key); + +def_optimize(AST_ConciseMethod, function(self, compressor) { + lift_key(self, compressor); + // p(){return x;} ---> p:()=>x + if (compressor.option("arrows") + && compressor.parent() instanceof AST_Object + && !self.is_generator + && !self.value.uses_arguments + && !self.value.pinned() + && self.value.body.length == 1 + && self.value.body[0] instanceof AST_Return + && self.value.body[0].value + && !self.value.contains_this()) { + var arrow = make_node(AST_Arrow, self.value, self.value); + arrow.async = self.async; + arrow.is_generator = self.is_generator; + return make_node(AST_ObjectKeyVal, self, { + key: self.key instanceof AST_SymbolMethod ? self.key.name : self.key, + value: arrow, + quote: self.quote, + }); + } + return self; +}); + +def_optimize(AST_ObjectKeyVal, function(self, compressor) { + lift_key(self, compressor); + // p:function(){} ---> p(){} + // p:function*(){} ---> *p(){} + // p:async function(){} ---> async p(){} + // p:()=>{} ---> p(){} + // p:async()=>{} ---> async p(){} + var unsafe_methods = compressor.option("unsafe_methods"); + if (unsafe_methods + && compressor.option("ecma") >= 2015 + && (!(unsafe_methods instanceof RegExp) || unsafe_methods.test(self.key + ""))) { + var key = self.key; + var value = self.value; + var is_arrow_with_block = value instanceof AST_Arrow + && Array.isArray(value.body) + && !value.contains_this(); + if ((is_arrow_with_block || value instanceof AST_Function) && !value.name) { + return make_node(AST_ConciseMethod, self, { + async: value.async, + is_generator: value.is_generator, + key: key instanceof AST_Node ? key : make_node(AST_SymbolMethod, self, { + name: key, + }), + value: make_node(AST_Accessor, value, value), + quote: self.quote, + }); + } + } + return self; +}); + +def_optimize(AST_Destructuring, function(self, compressor) { + if (compressor.option("pure_getters") == true + && compressor.option("unused") + && !self.is_array + && Array.isArray(self.names) + && !is_destructuring_export_decl(compressor) + && !(self.names[self.names.length - 1] instanceof AST_Expansion)) { + var keep = []; + for (var i = 0; i < self.names.length; i++) { + var elem = self.names[i]; + if (!(elem instanceof AST_ObjectKeyVal + && typeof elem.key == "string" + && elem.value instanceof AST_SymbolDeclaration + && !should_retain(compressor, elem.value.definition()))) { + keep.push(elem); + } + } + if (keep.length != self.names.length) { + self.names = keep; + } + } + return self; + + function is_destructuring_export_decl(compressor) { + var ancestors = [/^VarDef$/, /^(Const|Let|Var)$/, /^Export$/]; + for (var a = 0, p = 0, len = ancestors.length; a < len; p++) { + var parent = compressor.parent(p); + if (!parent) return false; + if (a === 0 && parent.TYPE == "Destructuring") continue; + if (!ancestors[a].test(parent.TYPE)) { + return false; + } + a++; + } + return true; + } + + function should_retain(compressor, def) { + if (def.references.length) return true; + if (!def.global) return false; + if (compressor.toplevel.vars) { + if (compressor.top_retain) { + return compressor.top_retain(def); + } + return false; + } + return true; + } +}); + +/*********************************************************************** + + A JavaScript tokenizer / parser / beautifier / compressor. + https://github.com/mishoo/UglifyJS2 + + -------------------------------- (C) --------------------------------- + + Author: Mihai Bazon + + http://mihai.bazon.net/blog + + Distributed under the BSD license: + + Copyright 2012 (c) Mihai Bazon + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + ***********************************************************************/ + +// a small wrapper around source-map and @jridgewell/source-map +async function SourceMap(options) { + options = defaults(options, { + file : null, + root : null, + orig : null, + files: {}, + }); + + var orig_map; + var generator = new sourceMap.SourceMapGenerator({ + file : options.file, + sourceRoot : options.root + }); + + let sourcesContent = {__proto__: null}; + let files = options.files; + for (var name in files) if (HOP(files, name)) { + sourcesContent[name] = files[name]; + } + if (options.orig) { + // We support both @jridgewell/source-map (which has a sync + // SourceMapConsumer) and source-map (which has an async + // SourceMapConsumer). + orig_map = await new sourceMap.SourceMapConsumer(options.orig); + if (orig_map.sourcesContent) { + orig_map.sources.forEach(function(source, i) { + var content = orig_map.sourcesContent[i]; + if (content) { + sourcesContent[source] = content; + } + }); + } + } + + function add(source, gen_line, gen_col, orig_line, orig_col, name) { + let generatedPos = { line: gen_line, column: gen_col }; + + if (orig_map) { + var info = orig_map.originalPositionFor({ + line: orig_line, + column: orig_col + }); + if (info.source === null) { + generator.addMapping({ + generated: generatedPos, + original: null, + source: null, + name: null + }); + return; + } + source = info.source; + orig_line = info.line; + orig_col = info.column; + name = info.name || name; + } + generator.addMapping({ + generated : generatedPos, + original : { line: orig_line, column: orig_col }, + source : source, + name : name + }); + generator.setSourceContent(source, sourcesContent[source]); + } + + function clean(map) { + const allNull = map.sourcesContent && map.sourcesContent.every(c => c == null); + if (allNull) delete map.sourcesContent; + if (map.file === undefined) delete map.file; + if (map.sourceRoot === undefined) delete map.sourceRoot; + return map; + } + + function getDecoded() { + if (!generator.toDecodedMap) return null; + return clean(generator.toDecodedMap()); + } + + function getEncoded() { + return clean(generator.toJSON()); + } + + function destroy() { + // @jridgewell/source-map's SourceMapConsumer does not need to be + // manually freed. + if (orig_map && orig_map.destroy) orig_map.destroy(); + } + + return { + add, + getDecoded, + getEncoded, + destroy, + }; +} + +var domprops = [ + "$&", + "$'", + "$*", + "$+", + "$1", + "$2", + "$3", + "$4", + "$5", + "$6", + "$7", + "$8", + "$9", + "$_", + "$`", + "$input", + "-moz-animation", + "-moz-animation-delay", + "-moz-animation-direction", + "-moz-animation-duration", + "-moz-animation-fill-mode", + "-moz-animation-iteration-count", + "-moz-animation-name", + "-moz-animation-play-state", + "-moz-animation-timing-function", + "-moz-appearance", + "-moz-backface-visibility", + "-moz-border-end", + "-moz-border-end-color", + "-moz-border-end-style", + "-moz-border-end-width", + "-moz-border-image", + "-moz-border-start", + "-moz-border-start-color", + "-moz-border-start-style", + "-moz-border-start-width", + "-moz-box-align", + "-moz-box-direction", + "-moz-box-flex", + "-moz-box-ordinal-group", + "-moz-box-orient", + "-moz-box-pack", + "-moz-box-sizing", + "-moz-float-edge", + "-moz-font-feature-settings", + "-moz-font-language-override", + "-moz-force-broken-image-icon", + "-moz-hyphens", + "-moz-image-region", + "-moz-margin-end", + "-moz-margin-start", + "-moz-orient", + "-moz-osx-font-smoothing", + "-moz-outline-radius", + "-moz-outline-radius-bottomleft", + "-moz-outline-radius-bottomright", + "-moz-outline-radius-topleft", + "-moz-outline-radius-topright", + "-moz-padding-end", + "-moz-padding-start", + "-moz-perspective", + "-moz-perspective-origin", + "-moz-tab-size", + "-moz-text-size-adjust", + "-moz-transform", + "-moz-transform-origin", + "-moz-transform-style", + "-moz-transition", + "-moz-transition-delay", + "-moz-transition-duration", + "-moz-transition-property", + "-moz-transition-timing-function", + "-moz-user-focus", + "-moz-user-input", + "-moz-user-modify", + "-moz-user-select", + "-moz-window-dragging", + "-webkit-align-content", + "-webkit-align-items", + "-webkit-align-self", + "-webkit-animation", + "-webkit-animation-delay", + "-webkit-animation-direction", + "-webkit-animation-duration", + "-webkit-animation-fill-mode", + "-webkit-animation-iteration-count", + "-webkit-animation-name", + "-webkit-animation-play-state", + "-webkit-animation-timing-function", + "-webkit-appearance", + "-webkit-backface-visibility", + "-webkit-background-clip", + "-webkit-background-origin", + "-webkit-background-size", + "-webkit-border-bottom-left-radius", + "-webkit-border-bottom-right-radius", + "-webkit-border-image", + "-webkit-border-radius", + "-webkit-border-top-left-radius", + "-webkit-border-top-right-radius", + "-webkit-box-align", + "-webkit-box-direction", + "-webkit-box-flex", + "-webkit-box-ordinal-group", + "-webkit-box-orient", + "-webkit-box-pack", + "-webkit-box-shadow", + "-webkit-box-sizing", + "-webkit-filter", + "-webkit-flex", + "-webkit-flex-basis", + "-webkit-flex-direction", + "-webkit-flex-flow", + "-webkit-flex-grow", + "-webkit-flex-shrink", + "-webkit-flex-wrap", + "-webkit-justify-content", + "-webkit-line-clamp", + "-webkit-mask", + "-webkit-mask-clip", + "-webkit-mask-composite", + "-webkit-mask-image", + "-webkit-mask-origin", + "-webkit-mask-position", + "-webkit-mask-position-x", + "-webkit-mask-position-y", + "-webkit-mask-repeat", + "-webkit-mask-size", + "-webkit-order", + "-webkit-perspective", + "-webkit-perspective-origin", + "-webkit-text-fill-color", + "-webkit-text-size-adjust", + "-webkit-text-stroke", + "-webkit-text-stroke-color", + "-webkit-text-stroke-width", + "-webkit-transform", + "-webkit-transform-origin", + "-webkit-transform-style", + "-webkit-transition", + "-webkit-transition-delay", + "-webkit-transition-duration", + "-webkit-transition-property", + "-webkit-transition-timing-function", + "-webkit-user-select", + "0", + "1", + "10", + "11", + "12", + "13", + "14", + "15", + "16", + "17", + "18", + "19", + "2", + "20", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "@@iterator", + "ABORT_ERR", + "ACTIVE", + "ACTIVE_ATTRIBUTES", + "ACTIVE_TEXTURE", + "ACTIVE_UNIFORMS", + "ACTIVE_UNIFORM_BLOCKS", + "ADDITION", + "ALIASED_LINE_WIDTH_RANGE", + "ALIASED_POINT_SIZE_RANGE", + "ALLOW_KEYBOARD_INPUT", + "ALLPASS", + "ALPHA", + "ALPHA_BITS", + "ALREADY_SIGNALED", + "ALT_MASK", + "ALWAYS", + "ANY_SAMPLES_PASSED", + "ANY_SAMPLES_PASSED_CONSERVATIVE", + "ANY_TYPE", + "ANY_UNORDERED_NODE_TYPE", + "ARRAY_BUFFER", + "ARRAY_BUFFER_BINDING", + "ATTACHED_SHADERS", + "ATTRIBUTE_NODE", + "AT_TARGET", + "AbortController", + "AbortSignal", + "AbsoluteOrientationSensor", + "AbstractRange", + "Accelerometer", + "AddSearchProvider", + "AggregateError", + "AnalyserNode", + "Animation", + "AnimationEffect", + "AnimationEvent", + "AnimationPlaybackEvent", + "AnimationTimeline", + "AnonXMLHttpRequest", + "Any", + "ApplicationCache", + "ApplicationCacheErrorEvent", + "Array", + "ArrayBuffer", + "ArrayType", + "Atomics", + "Attr", + "Audio", + "AudioBuffer", + "AudioBufferSourceNode", + "AudioContext", + "AudioDestinationNode", + "AudioListener", + "AudioNode", + "AudioParam", + "AudioParamMap", + "AudioProcessingEvent", + "AudioScheduledSourceNode", + "AudioStreamTrack", + "AudioWorklet", + "AudioWorkletNode", + "AuthenticatorAssertionResponse", + "AuthenticatorAttestationResponse", + "AuthenticatorResponse", + "AutocompleteErrorEvent", + "BACK", + "BAD_BOUNDARYPOINTS_ERR", + "BAD_REQUEST", + "BANDPASS", + "BLEND", + "BLEND_COLOR", + "BLEND_DST_ALPHA", + "BLEND_DST_RGB", + "BLEND_EQUATION", + "BLEND_EQUATION_ALPHA", + "BLEND_EQUATION_RGB", + "BLEND_SRC_ALPHA", + "BLEND_SRC_RGB", + "BLUE_BITS", + "BLUR", + "BOOL", + "BOOLEAN_TYPE", + "BOOL_VEC2", + "BOOL_VEC3", + "BOOL_VEC4", + "BOTH", + "BROWSER_DEFAULT_WEBGL", + "BUBBLING_PHASE", + "BUFFER_SIZE", + "BUFFER_USAGE", + "BYTE", + "BYTES_PER_ELEMENT", + "BackgroundFetchManager", + "BackgroundFetchRecord", + "BackgroundFetchRegistration", + "BarProp", + "BarcodeDetector", + "BaseAudioContext", + "BaseHref", + "BatteryManager", + "BeforeInstallPromptEvent", + "BeforeLoadEvent", + "BeforeUnloadEvent", + "BigInt", + "BigInt64Array", + "BigUint64Array", + "BiquadFilterNode", + "Blob", + "BlobEvent", + "Bluetooth", + "BluetoothCharacteristicProperties", + "BluetoothDevice", + "BluetoothRemoteGATTCharacteristic", + "BluetoothRemoteGATTDescriptor", + "BluetoothRemoteGATTServer", + "BluetoothRemoteGATTService", + "BluetoothUUID", + "Boolean", + "BroadcastChannel", + "ByteLengthQueuingStrategy", + "CAPTURING_PHASE", + "CCW", + "CDATASection", + "CDATA_SECTION_NODE", + "CHANGE", + "CHARSET_RULE", + "CHECKING", + "CLAMP_TO_EDGE", + "CLICK", + "CLOSED", + "CLOSING", + "COLOR", + "COLOR_ATTACHMENT0", + "COLOR_ATTACHMENT1", + "COLOR_ATTACHMENT10", + "COLOR_ATTACHMENT11", + "COLOR_ATTACHMENT12", + "COLOR_ATTACHMENT13", + "COLOR_ATTACHMENT14", + "COLOR_ATTACHMENT15", + "COLOR_ATTACHMENT2", + "COLOR_ATTACHMENT3", + "COLOR_ATTACHMENT4", + "COLOR_ATTACHMENT5", + "COLOR_ATTACHMENT6", + "COLOR_ATTACHMENT7", + "COLOR_ATTACHMENT8", + "COLOR_ATTACHMENT9", + "COLOR_BUFFER_BIT", + "COLOR_CLEAR_VALUE", + "COLOR_WRITEMASK", + "COMMENT_NODE", + "COMPARE_REF_TO_TEXTURE", + "COMPILE_STATUS", + "COMPLETION_STATUS_KHR", + "COMPRESSED_RGBA_S3TC_DXT1_EXT", + "COMPRESSED_RGBA_S3TC_DXT3_EXT", + "COMPRESSED_RGBA_S3TC_DXT5_EXT", + "COMPRESSED_RGB_S3TC_DXT1_EXT", + "COMPRESSED_TEXTURE_FORMATS", + "CONDITION_SATISFIED", + "CONFIGURATION_UNSUPPORTED", + "CONNECTING", + "CONSTANT_ALPHA", + "CONSTANT_COLOR", + "CONSTRAINT_ERR", + "CONTEXT_LOST_WEBGL", + "CONTROL_MASK", + "COPY_READ_BUFFER", + "COPY_READ_BUFFER_BINDING", + "COPY_WRITE_BUFFER", + "COPY_WRITE_BUFFER_BINDING", + "COUNTER_STYLE_RULE", + "CSS", + "CSS2Properties", + "CSSAnimation", + "CSSCharsetRule", + "CSSConditionRule", + "CSSCounterStyleRule", + "CSSFontFaceRule", + "CSSFontFeatureValuesRule", + "CSSGroupingRule", + "CSSImageValue", + "CSSImportRule", + "CSSKeyframeRule", + "CSSKeyframesRule", + "CSSKeywordValue", + "CSSMathInvert", + "CSSMathMax", + "CSSMathMin", + "CSSMathNegate", + "CSSMathProduct", + "CSSMathSum", + "CSSMathValue", + "CSSMatrixComponent", + "CSSMediaRule", + "CSSMozDocumentRule", + "CSSNameSpaceRule", + "CSSNamespaceRule", + "CSSNumericArray", + "CSSNumericValue", + "CSSPageRule", + "CSSPerspective", + "CSSPositionValue", + "CSSPrimitiveValue", + "CSSRotate", + "CSSRule", + "CSSRuleList", + "CSSScale", + "CSSSkew", + "CSSSkewX", + "CSSSkewY", + "CSSStyleDeclaration", + "CSSStyleRule", + "CSSStyleSheet", + "CSSStyleValue", + "CSSSupportsRule", + "CSSTransformComponent", + "CSSTransformValue", + "CSSTransition", + "CSSTranslate", + "CSSUnitValue", + "CSSUnknownRule", + "CSSUnparsedValue", + "CSSValue", + "CSSValueList", + "CSSVariableReferenceValue", + "CSSVariablesDeclaration", + "CSSVariablesRule", + "CSSViewportRule", + "CSS_ATTR", + "CSS_CM", + "CSS_COUNTER", + "CSS_CUSTOM", + "CSS_DEG", + "CSS_DIMENSION", + "CSS_EMS", + "CSS_EXS", + "CSS_FILTER_BLUR", + "CSS_FILTER_BRIGHTNESS", + "CSS_FILTER_CONTRAST", + "CSS_FILTER_CUSTOM", + "CSS_FILTER_DROP_SHADOW", + "CSS_FILTER_GRAYSCALE", + "CSS_FILTER_HUE_ROTATE", + "CSS_FILTER_INVERT", + "CSS_FILTER_OPACITY", + "CSS_FILTER_REFERENCE", + "CSS_FILTER_SATURATE", + "CSS_FILTER_SEPIA", + "CSS_GRAD", + "CSS_HZ", + "CSS_IDENT", + "CSS_IN", + "CSS_INHERIT", + "CSS_KHZ", + "CSS_MATRIX", + "CSS_MATRIX3D", + "CSS_MM", + "CSS_MS", + "CSS_NUMBER", + "CSS_PC", + "CSS_PERCENTAGE", + "CSS_PERSPECTIVE", + "CSS_PRIMITIVE_VALUE", + "CSS_PT", + "CSS_PX", + "CSS_RAD", + "CSS_RECT", + "CSS_RGBCOLOR", + "CSS_ROTATE", + "CSS_ROTATE3D", + "CSS_ROTATEX", + "CSS_ROTATEY", + "CSS_ROTATEZ", + "CSS_S", + "CSS_SCALE", + "CSS_SCALE3D", + "CSS_SCALEX", + "CSS_SCALEY", + "CSS_SCALEZ", + "CSS_SKEW", + "CSS_SKEWX", + "CSS_SKEWY", + "CSS_STRING", + "CSS_TRANSLATE", + "CSS_TRANSLATE3D", + "CSS_TRANSLATEX", + "CSS_TRANSLATEY", + "CSS_TRANSLATEZ", + "CSS_UNKNOWN", + "CSS_URI", + "CSS_VALUE_LIST", + "CSS_VH", + "CSS_VMAX", + "CSS_VMIN", + "CSS_VW", + "CULL_FACE", + "CULL_FACE_MODE", + "CURRENT_PROGRAM", + "CURRENT_QUERY", + "CURRENT_VERTEX_ATTRIB", + "CUSTOM", + "CW", + "Cache", + "CacheStorage", + "CanvasCaptureMediaStream", + "CanvasCaptureMediaStreamTrack", + "CanvasGradient", + "CanvasPattern", + "CanvasRenderingContext2D", + "CaretPosition", + "ChannelMergerNode", + "ChannelSplitterNode", + "CharacterData", + "ClientRect", + "ClientRectList", + "Clipboard", + "ClipboardEvent", + "ClipboardItem", + "CloseEvent", + "Collator", + "CommandEvent", + "Comment", + "CompileError", + "CompositionEvent", + "CompressionStream", + "Console", + "ConstantSourceNode", + "Controllers", + "ConvolverNode", + "CountQueuingStrategy", + "Counter", + "Credential", + "CredentialsContainer", + "Crypto", + "CryptoKey", + "CustomElementRegistry", + "CustomEvent", + "DATABASE_ERR", + "DATA_CLONE_ERR", + "DATA_ERR", + "DBLCLICK", + "DECR", + "DECR_WRAP", + "DELETE_STATUS", + "DEPTH", + "DEPTH24_STENCIL8", + "DEPTH32F_STENCIL8", + "DEPTH_ATTACHMENT", + "DEPTH_BITS", + "DEPTH_BUFFER_BIT", + "DEPTH_CLEAR_VALUE", + "DEPTH_COMPONENT", + "DEPTH_COMPONENT16", + "DEPTH_COMPONENT24", + "DEPTH_COMPONENT32F", + "DEPTH_FUNC", + "DEPTH_RANGE", + "DEPTH_STENCIL", + "DEPTH_STENCIL_ATTACHMENT", + "DEPTH_TEST", + "DEPTH_WRITEMASK", + "DEVICE_INELIGIBLE", + "DIRECTION_DOWN", + "DIRECTION_LEFT", + "DIRECTION_RIGHT", + "DIRECTION_UP", + "DISABLED", + "DISPATCH_REQUEST_ERR", + "DITHER", + "DOCUMENT_FRAGMENT_NODE", + "DOCUMENT_NODE", + "DOCUMENT_POSITION_CONTAINED_BY", + "DOCUMENT_POSITION_CONTAINS", + "DOCUMENT_POSITION_DISCONNECTED", + "DOCUMENT_POSITION_FOLLOWING", + "DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC", + "DOCUMENT_POSITION_PRECEDING", + "DOCUMENT_TYPE_NODE", + "DOMCursor", + "DOMError", + "DOMException", + "DOMImplementation", + "DOMImplementationLS", + "DOMMatrix", + "DOMMatrixReadOnly", + "DOMParser", + "DOMPoint", + "DOMPointReadOnly", + "DOMQuad", + "DOMRect", + "DOMRectList", + "DOMRectReadOnly", + "DOMRequest", + "DOMSTRING_SIZE_ERR", + "DOMSettableTokenList", + "DOMStringList", + "DOMStringMap", + "DOMTokenList", + "DOMTransactionEvent", + "DOM_DELTA_LINE", + "DOM_DELTA_PAGE", + "DOM_DELTA_PIXEL", + "DOM_INPUT_METHOD_DROP", + "DOM_INPUT_METHOD_HANDWRITING", + "DOM_INPUT_METHOD_IME", + "DOM_INPUT_METHOD_KEYBOARD", + "DOM_INPUT_METHOD_MULTIMODAL", + "DOM_INPUT_METHOD_OPTION", + "DOM_INPUT_METHOD_PASTE", + "DOM_INPUT_METHOD_SCRIPT", + "DOM_INPUT_METHOD_UNKNOWN", + "DOM_INPUT_METHOD_VOICE", + "DOM_KEY_LOCATION_JOYSTICK", + "DOM_KEY_LOCATION_LEFT", + "DOM_KEY_LOCATION_MOBILE", + "DOM_KEY_LOCATION_NUMPAD", + "DOM_KEY_LOCATION_RIGHT", + "DOM_KEY_LOCATION_STANDARD", + "DOM_VK_0", + "DOM_VK_1", + "DOM_VK_2", + "DOM_VK_3", + "DOM_VK_4", + "DOM_VK_5", + "DOM_VK_6", + "DOM_VK_7", + "DOM_VK_8", + "DOM_VK_9", + "DOM_VK_A", + "DOM_VK_ACCEPT", + "DOM_VK_ADD", + "DOM_VK_ALT", + "DOM_VK_ALTGR", + "DOM_VK_AMPERSAND", + "DOM_VK_ASTERISK", + "DOM_VK_AT", + "DOM_VK_ATTN", + "DOM_VK_B", + "DOM_VK_BACKSPACE", + "DOM_VK_BACK_QUOTE", + "DOM_VK_BACK_SLASH", + "DOM_VK_BACK_SPACE", + "DOM_VK_C", + "DOM_VK_CANCEL", + "DOM_VK_CAPS_LOCK", + "DOM_VK_CIRCUMFLEX", + "DOM_VK_CLEAR", + "DOM_VK_CLOSE_BRACKET", + "DOM_VK_CLOSE_CURLY_BRACKET", + "DOM_VK_CLOSE_PAREN", + "DOM_VK_COLON", + "DOM_VK_COMMA", + "DOM_VK_CONTEXT_MENU", + "DOM_VK_CONTROL", + "DOM_VK_CONVERT", + "DOM_VK_CRSEL", + "DOM_VK_CTRL", + "DOM_VK_D", + "DOM_VK_DECIMAL", + "DOM_VK_DELETE", + "DOM_VK_DIVIDE", + "DOM_VK_DOLLAR", + "DOM_VK_DOUBLE_QUOTE", + "DOM_VK_DOWN", + "DOM_VK_E", + "DOM_VK_EISU", + "DOM_VK_END", + "DOM_VK_ENTER", + "DOM_VK_EQUALS", + "DOM_VK_EREOF", + "DOM_VK_ESCAPE", + "DOM_VK_EXCLAMATION", + "DOM_VK_EXECUTE", + "DOM_VK_EXSEL", + "DOM_VK_F", + "DOM_VK_F1", + "DOM_VK_F10", + "DOM_VK_F11", + "DOM_VK_F12", + "DOM_VK_F13", + "DOM_VK_F14", + "DOM_VK_F15", + "DOM_VK_F16", + "DOM_VK_F17", + "DOM_VK_F18", + "DOM_VK_F19", + "DOM_VK_F2", + "DOM_VK_F20", + "DOM_VK_F21", + "DOM_VK_F22", + "DOM_VK_F23", + "DOM_VK_F24", + "DOM_VK_F25", + "DOM_VK_F26", + "DOM_VK_F27", + "DOM_VK_F28", + "DOM_VK_F29", + "DOM_VK_F3", + "DOM_VK_F30", + "DOM_VK_F31", + "DOM_VK_F32", + "DOM_VK_F33", + "DOM_VK_F34", + "DOM_VK_F35", + "DOM_VK_F36", + "DOM_VK_F4", + "DOM_VK_F5", + "DOM_VK_F6", + "DOM_VK_F7", + "DOM_VK_F8", + "DOM_VK_F9", + "DOM_VK_FINAL", + "DOM_VK_FRONT", + "DOM_VK_G", + "DOM_VK_GREATER_THAN", + "DOM_VK_H", + "DOM_VK_HANGUL", + "DOM_VK_HANJA", + "DOM_VK_HASH", + "DOM_VK_HELP", + "DOM_VK_HK_TOGGLE", + "DOM_VK_HOME", + "DOM_VK_HYPHEN_MINUS", + "DOM_VK_I", + "DOM_VK_INSERT", + "DOM_VK_J", + "DOM_VK_JUNJA", + "DOM_VK_K", + "DOM_VK_KANA", + "DOM_VK_KANJI", + "DOM_VK_L", + "DOM_VK_LEFT", + "DOM_VK_LEFT_TAB", + "DOM_VK_LESS_THAN", + "DOM_VK_M", + "DOM_VK_META", + "DOM_VK_MODECHANGE", + "DOM_VK_MULTIPLY", + "DOM_VK_N", + "DOM_VK_NONCONVERT", + "DOM_VK_NUMPAD0", + "DOM_VK_NUMPAD1", + "DOM_VK_NUMPAD2", + "DOM_VK_NUMPAD3", + "DOM_VK_NUMPAD4", + "DOM_VK_NUMPAD5", + "DOM_VK_NUMPAD6", + "DOM_VK_NUMPAD7", + "DOM_VK_NUMPAD8", + "DOM_VK_NUMPAD9", + "DOM_VK_NUM_LOCK", + "DOM_VK_O", + "DOM_VK_OEM_1", + "DOM_VK_OEM_102", + "DOM_VK_OEM_2", + "DOM_VK_OEM_3", + "DOM_VK_OEM_4", + "DOM_VK_OEM_5", + "DOM_VK_OEM_6", + "DOM_VK_OEM_7", + "DOM_VK_OEM_8", + "DOM_VK_OEM_COMMA", + "DOM_VK_OEM_MINUS", + "DOM_VK_OEM_PERIOD", + "DOM_VK_OEM_PLUS", + "DOM_VK_OPEN_BRACKET", + "DOM_VK_OPEN_CURLY_BRACKET", + "DOM_VK_OPEN_PAREN", + "DOM_VK_P", + "DOM_VK_PA1", + "DOM_VK_PAGEDOWN", + "DOM_VK_PAGEUP", + "DOM_VK_PAGE_DOWN", + "DOM_VK_PAGE_UP", + "DOM_VK_PAUSE", + "DOM_VK_PERCENT", + "DOM_VK_PERIOD", + "DOM_VK_PIPE", + "DOM_VK_PLAY", + "DOM_VK_PLUS", + "DOM_VK_PRINT", + "DOM_VK_PRINTSCREEN", + "DOM_VK_PROCESSKEY", + "DOM_VK_PROPERITES", + "DOM_VK_Q", + "DOM_VK_QUESTION_MARK", + "DOM_VK_QUOTE", + "DOM_VK_R", + "DOM_VK_REDO", + "DOM_VK_RETURN", + "DOM_VK_RIGHT", + "DOM_VK_S", + "DOM_VK_SCROLL_LOCK", + "DOM_VK_SELECT", + "DOM_VK_SEMICOLON", + "DOM_VK_SEPARATOR", + "DOM_VK_SHIFT", + "DOM_VK_SLASH", + "DOM_VK_SLEEP", + "DOM_VK_SPACE", + "DOM_VK_SUBTRACT", + "DOM_VK_T", + "DOM_VK_TAB", + "DOM_VK_TILDE", + "DOM_VK_U", + "DOM_VK_UNDERSCORE", + "DOM_VK_UNDO", + "DOM_VK_UNICODE", + "DOM_VK_UP", + "DOM_VK_V", + "DOM_VK_VOLUME_DOWN", + "DOM_VK_VOLUME_MUTE", + "DOM_VK_VOLUME_UP", + "DOM_VK_W", + "DOM_VK_WIN", + "DOM_VK_WINDOW", + "DOM_VK_WIN_ICO_00", + "DOM_VK_WIN_ICO_CLEAR", + "DOM_VK_WIN_ICO_HELP", + "DOM_VK_WIN_OEM_ATTN", + "DOM_VK_WIN_OEM_AUTO", + "DOM_VK_WIN_OEM_BACKTAB", + "DOM_VK_WIN_OEM_CLEAR", + "DOM_VK_WIN_OEM_COPY", + "DOM_VK_WIN_OEM_CUSEL", + "DOM_VK_WIN_OEM_ENLW", + "DOM_VK_WIN_OEM_FINISH", + "DOM_VK_WIN_OEM_FJ_JISHO", + "DOM_VK_WIN_OEM_FJ_LOYA", + "DOM_VK_WIN_OEM_FJ_MASSHOU", + "DOM_VK_WIN_OEM_FJ_ROYA", + "DOM_VK_WIN_OEM_FJ_TOUROKU", + "DOM_VK_WIN_OEM_JUMP", + "DOM_VK_WIN_OEM_PA1", + "DOM_VK_WIN_OEM_PA2", + "DOM_VK_WIN_OEM_PA3", + "DOM_VK_WIN_OEM_RESET", + "DOM_VK_WIN_OEM_WSCTRL", + "DOM_VK_X", + "DOM_VK_XF86XK_ADD_FAVORITE", + "DOM_VK_XF86XK_APPLICATION_LEFT", + "DOM_VK_XF86XK_APPLICATION_RIGHT", + "DOM_VK_XF86XK_AUDIO_CYCLE_TRACK", + "DOM_VK_XF86XK_AUDIO_FORWARD", + "DOM_VK_XF86XK_AUDIO_LOWER_VOLUME", + "DOM_VK_XF86XK_AUDIO_MEDIA", + "DOM_VK_XF86XK_AUDIO_MUTE", + "DOM_VK_XF86XK_AUDIO_NEXT", + "DOM_VK_XF86XK_AUDIO_PAUSE", + "DOM_VK_XF86XK_AUDIO_PLAY", + "DOM_VK_XF86XK_AUDIO_PREV", + "DOM_VK_XF86XK_AUDIO_RAISE_VOLUME", + "DOM_VK_XF86XK_AUDIO_RANDOM_PLAY", + "DOM_VK_XF86XK_AUDIO_RECORD", + "DOM_VK_XF86XK_AUDIO_REPEAT", + "DOM_VK_XF86XK_AUDIO_REWIND", + "DOM_VK_XF86XK_AUDIO_STOP", + "DOM_VK_XF86XK_AWAY", + "DOM_VK_XF86XK_BACK", + "DOM_VK_XF86XK_BACK_FORWARD", + "DOM_VK_XF86XK_BATTERY", + "DOM_VK_XF86XK_BLUE", + "DOM_VK_XF86XK_BLUETOOTH", + "DOM_VK_XF86XK_BOOK", + "DOM_VK_XF86XK_BRIGHTNESS_ADJUST", + "DOM_VK_XF86XK_CALCULATOR", + "DOM_VK_XF86XK_CALENDAR", + "DOM_VK_XF86XK_CD", + "DOM_VK_XF86XK_CLOSE", + "DOM_VK_XF86XK_COMMUNITY", + "DOM_VK_XF86XK_CONTRAST_ADJUST", + "DOM_VK_XF86XK_COPY", + "DOM_VK_XF86XK_CUT", + "DOM_VK_XF86XK_CYCLE_ANGLE", + "DOM_VK_XF86XK_DISPLAY", + "DOM_VK_XF86XK_DOCUMENTS", + "DOM_VK_XF86XK_DOS", + "DOM_VK_XF86XK_EJECT", + "DOM_VK_XF86XK_EXCEL", + "DOM_VK_XF86XK_EXPLORER", + "DOM_VK_XF86XK_FAVORITES", + "DOM_VK_XF86XK_FINANCE", + "DOM_VK_XF86XK_FORWARD", + "DOM_VK_XF86XK_FRAME_BACK", + "DOM_VK_XF86XK_FRAME_FORWARD", + "DOM_VK_XF86XK_GAME", + "DOM_VK_XF86XK_GO", + "DOM_VK_XF86XK_GREEN", + "DOM_VK_XF86XK_HIBERNATE", + "DOM_VK_XF86XK_HISTORY", + "DOM_VK_XF86XK_HOME_PAGE", + "DOM_VK_XF86XK_HOT_LINKS", + "DOM_VK_XF86XK_I_TOUCH", + "DOM_VK_XF86XK_KBD_BRIGHTNESS_DOWN", + "DOM_VK_XF86XK_KBD_BRIGHTNESS_UP", + "DOM_VK_XF86XK_KBD_LIGHT_ON_OFF", + "DOM_VK_XF86XK_LAUNCH0", + "DOM_VK_XF86XK_LAUNCH1", + "DOM_VK_XF86XK_LAUNCH2", + "DOM_VK_XF86XK_LAUNCH3", + "DOM_VK_XF86XK_LAUNCH4", + "DOM_VK_XF86XK_LAUNCH5", + "DOM_VK_XF86XK_LAUNCH6", + "DOM_VK_XF86XK_LAUNCH7", + "DOM_VK_XF86XK_LAUNCH8", + "DOM_VK_XF86XK_LAUNCH9", + "DOM_VK_XF86XK_LAUNCH_A", + "DOM_VK_XF86XK_LAUNCH_B", + "DOM_VK_XF86XK_LAUNCH_C", + "DOM_VK_XF86XK_LAUNCH_D", + "DOM_VK_XF86XK_LAUNCH_E", + "DOM_VK_XF86XK_LAUNCH_F", + "DOM_VK_XF86XK_LIGHT_BULB", + "DOM_VK_XF86XK_LOG_OFF", + "DOM_VK_XF86XK_MAIL", + "DOM_VK_XF86XK_MAIL_FORWARD", + "DOM_VK_XF86XK_MARKET", + "DOM_VK_XF86XK_MEETING", + "DOM_VK_XF86XK_MEMO", + "DOM_VK_XF86XK_MENU_KB", + "DOM_VK_XF86XK_MENU_PB", + "DOM_VK_XF86XK_MESSENGER", + "DOM_VK_XF86XK_MON_BRIGHTNESS_DOWN", + "DOM_VK_XF86XK_MON_BRIGHTNESS_UP", + "DOM_VK_XF86XK_MUSIC", + "DOM_VK_XF86XK_MY_COMPUTER", + "DOM_VK_XF86XK_MY_SITES", + "DOM_VK_XF86XK_NEW", + "DOM_VK_XF86XK_NEWS", + "DOM_VK_XF86XK_OFFICE_HOME", + "DOM_VK_XF86XK_OPEN", + "DOM_VK_XF86XK_OPEN_URL", + "DOM_VK_XF86XK_OPTION", + "DOM_VK_XF86XK_PASTE", + "DOM_VK_XF86XK_PHONE", + "DOM_VK_XF86XK_PICTURES", + "DOM_VK_XF86XK_POWER_DOWN", + "DOM_VK_XF86XK_POWER_OFF", + "DOM_VK_XF86XK_RED", + "DOM_VK_XF86XK_REFRESH", + "DOM_VK_XF86XK_RELOAD", + "DOM_VK_XF86XK_REPLY", + "DOM_VK_XF86XK_ROCKER_DOWN", + "DOM_VK_XF86XK_ROCKER_ENTER", + "DOM_VK_XF86XK_ROCKER_UP", + "DOM_VK_XF86XK_ROTATE_WINDOWS", + "DOM_VK_XF86XK_ROTATION_KB", + "DOM_VK_XF86XK_ROTATION_PB", + "DOM_VK_XF86XK_SAVE", + "DOM_VK_XF86XK_SCREEN_SAVER", + "DOM_VK_XF86XK_SCROLL_CLICK", + "DOM_VK_XF86XK_SCROLL_DOWN", + "DOM_VK_XF86XK_SCROLL_UP", + "DOM_VK_XF86XK_SEARCH", + "DOM_VK_XF86XK_SEND", + "DOM_VK_XF86XK_SHOP", + "DOM_VK_XF86XK_SPELL", + "DOM_VK_XF86XK_SPLIT_SCREEN", + "DOM_VK_XF86XK_STANDBY", + "DOM_VK_XF86XK_START", + "DOM_VK_XF86XK_STOP", + "DOM_VK_XF86XK_SUBTITLE", + "DOM_VK_XF86XK_SUPPORT", + "DOM_VK_XF86XK_SUSPEND", + "DOM_VK_XF86XK_TASK_PANE", + "DOM_VK_XF86XK_TERMINAL", + "DOM_VK_XF86XK_TIME", + "DOM_VK_XF86XK_TOOLS", + "DOM_VK_XF86XK_TOP_MENU", + "DOM_VK_XF86XK_TO_DO_LIST", + "DOM_VK_XF86XK_TRAVEL", + "DOM_VK_XF86XK_USER1KB", + "DOM_VK_XF86XK_USER2KB", + "DOM_VK_XF86XK_USER_PB", + "DOM_VK_XF86XK_UWB", + "DOM_VK_XF86XK_VENDOR_HOME", + "DOM_VK_XF86XK_VIDEO", + "DOM_VK_XF86XK_VIEW", + "DOM_VK_XF86XK_WAKE_UP", + "DOM_VK_XF86XK_WEB_CAM", + "DOM_VK_XF86XK_WHEEL_BUTTON", + "DOM_VK_XF86XK_WLAN", + "DOM_VK_XF86XK_WORD", + "DOM_VK_XF86XK_WWW", + "DOM_VK_XF86XK_XFER", + "DOM_VK_XF86XK_YELLOW", + "DOM_VK_XF86XK_ZOOM_IN", + "DOM_VK_XF86XK_ZOOM_OUT", + "DOM_VK_Y", + "DOM_VK_Z", + "DOM_VK_ZOOM", + "DONE", + "DONT_CARE", + "DOWNLOADING", + "DRAGDROP", + "DRAW_BUFFER0", + "DRAW_BUFFER1", + "DRAW_BUFFER10", + "DRAW_BUFFER11", + "DRAW_BUFFER12", + "DRAW_BUFFER13", + "DRAW_BUFFER14", + "DRAW_BUFFER15", + "DRAW_BUFFER2", + "DRAW_BUFFER3", + "DRAW_BUFFER4", + "DRAW_BUFFER5", + "DRAW_BUFFER6", + "DRAW_BUFFER7", + "DRAW_BUFFER8", + "DRAW_BUFFER9", + "DRAW_FRAMEBUFFER", + "DRAW_FRAMEBUFFER_BINDING", + "DST_ALPHA", + "DST_COLOR", + "DYNAMIC_COPY", + "DYNAMIC_DRAW", + "DYNAMIC_READ", + "DataChannel", + "DataTransfer", + "DataTransferItem", + "DataTransferItemList", + "DataView", + "Date", + "DateTimeFormat", + "DecompressionStream", + "DelayNode", + "DeprecationReportBody", + "DesktopNotification", + "DesktopNotificationCenter", + "DeviceLightEvent", + "DeviceMotionEvent", + "DeviceMotionEventAcceleration", + "DeviceMotionEventRotationRate", + "DeviceOrientationEvent", + "DeviceProximityEvent", + "DeviceStorage", + "DeviceStorageChangeEvent", + "Directory", + "DisplayNames", + "Document", + "DocumentFragment", + "DocumentTimeline", + "DocumentType", + "DragEvent", + "DynamicsCompressorNode", + "E", + "ELEMENT_ARRAY_BUFFER", + "ELEMENT_ARRAY_BUFFER_BINDING", + "ELEMENT_NODE", + "EMPTY", + "ENCODING_ERR", + "ENDED", + "END_TO_END", + "END_TO_START", + "ENTITY_NODE", + "ENTITY_REFERENCE_NODE", + "EPSILON", + "EQUAL", + "EQUALPOWER", + "ERROR", + "EXPONENTIAL_DISTANCE", + "Element", + "ElementInternals", + "ElementQuery", + "EnterPictureInPictureEvent", + "Entity", + "EntityReference", + "Error", + "ErrorEvent", + "EvalError", + "Event", + "EventException", + "EventSource", + "EventTarget", + "External", + "FASTEST", + "FIDOSDK", + "FILTER_ACCEPT", + "FILTER_INTERRUPT", + "FILTER_REJECT", + "FILTER_SKIP", + "FINISHED_STATE", + "FIRST_ORDERED_NODE_TYPE", + "FLOAT", + "FLOAT_32_UNSIGNED_INT_24_8_REV", + "FLOAT_MAT2", + "FLOAT_MAT2x3", + "FLOAT_MAT2x4", + "FLOAT_MAT3", + "FLOAT_MAT3x2", + "FLOAT_MAT3x4", + "FLOAT_MAT4", + "FLOAT_MAT4x2", + "FLOAT_MAT4x3", + "FLOAT_VEC2", + "FLOAT_VEC3", + "FLOAT_VEC4", + "FOCUS", + "FONT_FACE_RULE", + "FONT_FEATURE_VALUES_RULE", + "FRAGMENT_SHADER", + "FRAGMENT_SHADER_DERIVATIVE_HINT", + "FRAGMENT_SHADER_DERIVATIVE_HINT_OES", + "FRAMEBUFFER", + "FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE", + "FRAMEBUFFER_ATTACHMENT_BLUE_SIZE", + "FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING", + "FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE", + "FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE", + "FRAMEBUFFER_ATTACHMENT_GREEN_SIZE", + "FRAMEBUFFER_ATTACHMENT_OBJECT_NAME", + "FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE", + "FRAMEBUFFER_ATTACHMENT_RED_SIZE", + "FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE", + "FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE", + "FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER", + "FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL", + "FRAMEBUFFER_BINDING", + "FRAMEBUFFER_COMPLETE", + "FRAMEBUFFER_DEFAULT", + "FRAMEBUFFER_INCOMPLETE_ATTACHMENT", + "FRAMEBUFFER_INCOMPLETE_DIMENSIONS", + "FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT", + "FRAMEBUFFER_INCOMPLETE_MULTISAMPLE", + "FRAMEBUFFER_UNSUPPORTED", + "FRONT", + "FRONT_AND_BACK", + "FRONT_FACE", + "FUNC_ADD", + "FUNC_REVERSE_SUBTRACT", + "FUNC_SUBTRACT", + "FeaturePolicy", + "FeaturePolicyViolationReportBody", + "FederatedCredential", + "Feed", + "FeedEntry", + "File", + "FileError", + "FileList", + "FileReader", + "FileSystem", + "FileSystemDirectoryEntry", + "FileSystemDirectoryReader", + "FileSystemEntry", + "FileSystemFileEntry", + "FinalizationRegistry", + "FindInPage", + "Float32Array", + "Float64Array", + "FocusEvent", + "FontFace", + "FontFaceSet", + "FontFaceSetLoadEvent", + "FormData", + "FormDataEvent", + "FragmentDirective", + "Function", + "GENERATE_MIPMAP_HINT", + "GEQUAL", + "GREATER", + "GREEN_BITS", + "GainNode", + "Gamepad", + "GamepadAxisMoveEvent", + "GamepadButton", + "GamepadButtonEvent", + "GamepadEvent", + "GamepadHapticActuator", + "GamepadPose", + "Geolocation", + "GeolocationCoordinates", + "GeolocationPosition", + "GeolocationPositionError", + "GestureEvent", + "Global", + "Gyroscope", + "HALF_FLOAT", + "HAVE_CURRENT_DATA", + "HAVE_ENOUGH_DATA", + "HAVE_FUTURE_DATA", + "HAVE_METADATA", + "HAVE_NOTHING", + "HEADERS_RECEIVED", + "HIDDEN", + "HIERARCHY_REQUEST_ERR", + "HIGHPASS", + "HIGHSHELF", + "HIGH_FLOAT", + "HIGH_INT", + "HORIZONTAL", + "HORIZONTAL_AXIS", + "HRTF", + "HTMLAllCollection", + "HTMLAnchorElement", + "HTMLAppletElement", + "HTMLAreaElement", + "HTMLAudioElement", + "HTMLBRElement", + "HTMLBaseElement", + "HTMLBaseFontElement", + "HTMLBlockquoteElement", + "HTMLBodyElement", + "HTMLButtonElement", + "HTMLCanvasElement", + "HTMLCollection", + "HTMLCommandElement", + "HTMLContentElement", + "HTMLDListElement", + "HTMLDataElement", + "HTMLDataListElement", + "HTMLDetailsElement", + "HTMLDialogElement", + "HTMLDirectoryElement", + "HTMLDivElement", + "HTMLDocument", + "HTMLElement", + "HTMLEmbedElement", + "HTMLFieldSetElement", + "HTMLFontElement", + "HTMLFormControlsCollection", + "HTMLFormElement", + "HTMLFrameElement", + "HTMLFrameSetElement", + "HTMLHRElement", + "HTMLHeadElement", + "HTMLHeadingElement", + "HTMLHtmlElement", + "HTMLIFrameElement", + "HTMLImageElement", + "HTMLInputElement", + "HTMLIsIndexElement", + "HTMLKeygenElement", + "HTMLLIElement", + "HTMLLabelElement", + "HTMLLegendElement", + "HTMLLinkElement", + "HTMLMapElement", + "HTMLMarqueeElement", + "HTMLMediaElement", + "HTMLMenuElement", + "HTMLMenuItemElement", + "HTMLMetaElement", + "HTMLMeterElement", + "HTMLModElement", + "HTMLOListElement", + "HTMLObjectElement", + "HTMLOptGroupElement", + "HTMLOptionElement", + "HTMLOptionsCollection", + "HTMLOutputElement", + "HTMLParagraphElement", + "HTMLParamElement", + "HTMLPictureElement", + "HTMLPreElement", + "HTMLProgressElement", + "HTMLPropertiesCollection", + "HTMLQuoteElement", + "HTMLScriptElement", + "HTMLSelectElement", + "HTMLShadowElement", + "HTMLSlotElement", + "HTMLSourceElement", + "HTMLSpanElement", + "HTMLStyleElement", + "HTMLTableCaptionElement", + "HTMLTableCellElement", + "HTMLTableColElement", + "HTMLTableElement", + "HTMLTableRowElement", + "HTMLTableSectionElement", + "HTMLTemplateElement", + "HTMLTextAreaElement", + "HTMLTimeElement", + "HTMLTitleElement", + "HTMLTrackElement", + "HTMLUListElement", + "HTMLUnknownElement", + "HTMLVideoElement", + "HashChangeEvent", + "Headers", + "History", + "Hz", + "ICE_CHECKING", + "ICE_CLOSED", + "ICE_COMPLETED", + "ICE_CONNECTED", + "ICE_FAILED", + "ICE_GATHERING", + "ICE_WAITING", + "IDBCursor", + "IDBCursorWithValue", + "IDBDatabase", + "IDBDatabaseException", + "IDBFactory", + "IDBFileHandle", + "IDBFileRequest", + "IDBIndex", + "IDBKeyRange", + "IDBMutableFile", + "IDBObjectStore", + "IDBOpenDBRequest", + "IDBRequest", + "IDBTransaction", + "IDBVersionChangeEvent", + "IDLE", + "IIRFilterNode", + "IMPLEMENTATION_COLOR_READ_FORMAT", + "IMPLEMENTATION_COLOR_READ_TYPE", + "IMPORT_RULE", + "INCR", + "INCR_WRAP", + "INDEX_SIZE_ERR", + "INT", + "INTERLEAVED_ATTRIBS", + "INT_2_10_10_10_REV", + "INT_SAMPLER_2D", + "INT_SAMPLER_2D_ARRAY", + "INT_SAMPLER_3D", + "INT_SAMPLER_CUBE", + "INT_VEC2", + "INT_VEC3", + "INT_VEC4", + "INUSE_ATTRIBUTE_ERR", + "INVALID_ACCESS_ERR", + "INVALID_CHARACTER_ERR", + "INVALID_ENUM", + "INVALID_EXPRESSION_ERR", + "INVALID_FRAMEBUFFER_OPERATION", + "INVALID_INDEX", + "INVALID_MODIFICATION_ERR", + "INVALID_NODE_TYPE_ERR", + "INVALID_OPERATION", + "INVALID_STATE_ERR", + "INVALID_VALUE", + "INVERSE_DISTANCE", + "INVERT", + "IceCandidate", + "IdleDeadline", + "Image", + "ImageBitmap", + "ImageBitmapRenderingContext", + "ImageCapture", + "ImageData", + "Infinity", + "InputDeviceCapabilities", + "InputDeviceInfo", + "InputEvent", + "InputMethodContext", + "InstallTrigger", + "InstallTriggerImpl", + "Instance", + "Int16Array", + "Int32Array", + "Int8Array", + "Intent", + "InternalError", + "IntersectionObserver", + "IntersectionObserverEntry", + "Intl", + "IsSearchProviderInstalled", + "Iterator", + "JSON", + "KEEP", + "KEYDOWN", + "KEYFRAMES_RULE", + "KEYFRAME_RULE", + "KEYPRESS", + "KEYUP", + "KeyEvent", + "Keyboard", + "KeyboardEvent", + "KeyboardLayoutMap", + "KeyframeEffect", + "LENGTHADJUST_SPACING", + "LENGTHADJUST_SPACINGANDGLYPHS", + "LENGTHADJUST_UNKNOWN", + "LEQUAL", + "LESS", + "LINEAR", + "LINEAR_DISTANCE", + "LINEAR_MIPMAP_LINEAR", + "LINEAR_MIPMAP_NEAREST", + "LINES", + "LINE_LOOP", + "LINE_STRIP", + "LINE_WIDTH", + "LINK_STATUS", + "LIVE", + "LN10", + "LN2", + "LOADED", + "LOADING", + "LOG10E", + "LOG2E", + "LOWPASS", + "LOWSHELF", + "LOW_FLOAT", + "LOW_INT", + "LSException", + "LSParserFilter", + "LUMINANCE", + "LUMINANCE_ALPHA", + "LargestContentfulPaint", + "LayoutShift", + "LayoutShiftAttribution", + "LinearAccelerationSensor", + "LinkError", + "ListFormat", + "LocalMediaStream", + "Locale", + "Location", + "Lock", + "LockManager", + "MAX", + "MAX_3D_TEXTURE_SIZE", + "MAX_ARRAY_TEXTURE_LAYERS", + "MAX_CLIENT_WAIT_TIMEOUT_WEBGL", + "MAX_COLOR_ATTACHMENTS", + "MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS", + "MAX_COMBINED_TEXTURE_IMAGE_UNITS", + "MAX_COMBINED_UNIFORM_BLOCKS", + "MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS", + "MAX_CUBE_MAP_TEXTURE_SIZE", + "MAX_DRAW_BUFFERS", + "MAX_ELEMENTS_INDICES", + "MAX_ELEMENTS_VERTICES", + "MAX_ELEMENT_INDEX", + "MAX_FRAGMENT_INPUT_COMPONENTS", + "MAX_FRAGMENT_UNIFORM_BLOCKS", + "MAX_FRAGMENT_UNIFORM_COMPONENTS", + "MAX_FRAGMENT_UNIFORM_VECTORS", + "MAX_PROGRAM_TEXEL_OFFSET", + "MAX_RENDERBUFFER_SIZE", + "MAX_SAFE_INTEGER", + "MAX_SAMPLES", + "MAX_SERVER_WAIT_TIMEOUT", + "MAX_TEXTURE_IMAGE_UNITS", + "MAX_TEXTURE_LOD_BIAS", + "MAX_TEXTURE_MAX_ANISOTROPY_EXT", + "MAX_TEXTURE_SIZE", + "MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS", + "MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS", + "MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS", + "MAX_UNIFORM_BLOCK_SIZE", + "MAX_UNIFORM_BUFFER_BINDINGS", + "MAX_VALUE", + "MAX_VARYING_COMPONENTS", + "MAX_VARYING_VECTORS", + "MAX_VERTEX_ATTRIBS", + "MAX_VERTEX_OUTPUT_COMPONENTS", + "MAX_VERTEX_TEXTURE_IMAGE_UNITS", + "MAX_VERTEX_UNIFORM_BLOCKS", + "MAX_VERTEX_UNIFORM_COMPONENTS", + "MAX_VERTEX_UNIFORM_VECTORS", + "MAX_VIEWPORT_DIMS", + "MEDIA_ERR_ABORTED", + "MEDIA_ERR_DECODE", + "MEDIA_ERR_ENCRYPTED", + "MEDIA_ERR_NETWORK", + "MEDIA_ERR_SRC_NOT_SUPPORTED", + "MEDIA_KEYERR_CLIENT", + "MEDIA_KEYERR_DOMAIN", + "MEDIA_KEYERR_HARDWARECHANGE", + "MEDIA_KEYERR_OUTPUT", + "MEDIA_KEYERR_SERVICE", + "MEDIA_KEYERR_UNKNOWN", + "MEDIA_RULE", + "MEDIUM_FLOAT", + "MEDIUM_INT", + "META_MASK", + "MIDIAccess", + "MIDIConnectionEvent", + "MIDIInput", + "MIDIInputMap", + "MIDIMessageEvent", + "MIDIOutput", + "MIDIOutputMap", + "MIDIPort", + "MIN", + "MIN_PROGRAM_TEXEL_OFFSET", + "MIN_SAFE_INTEGER", + "MIN_VALUE", + "MIRRORED_REPEAT", + "MODE_ASYNCHRONOUS", + "MODE_SYNCHRONOUS", + "MODIFICATION", + "MOUSEDOWN", + "MOUSEDRAG", + "MOUSEMOVE", + "MOUSEOUT", + "MOUSEOVER", + "MOUSEUP", + "MOZ_KEYFRAMES_RULE", + "MOZ_KEYFRAME_RULE", + "MOZ_SOURCE_CURSOR", + "MOZ_SOURCE_ERASER", + "MOZ_SOURCE_KEYBOARD", + "MOZ_SOURCE_MOUSE", + "MOZ_SOURCE_PEN", + "MOZ_SOURCE_TOUCH", + "MOZ_SOURCE_UNKNOWN", + "MSGESTURE_FLAG_BEGIN", + "MSGESTURE_FLAG_CANCEL", + "MSGESTURE_FLAG_END", + "MSGESTURE_FLAG_INERTIA", + "MSGESTURE_FLAG_NONE", + "MSPOINTER_TYPE_MOUSE", + "MSPOINTER_TYPE_PEN", + "MSPOINTER_TYPE_TOUCH", + "MS_ASYNC_CALLBACK_STATUS_ASSIGN_DELEGATE", + "MS_ASYNC_CALLBACK_STATUS_CANCEL", + "MS_ASYNC_CALLBACK_STATUS_CHOOSEANY", + "MS_ASYNC_CALLBACK_STATUS_ERROR", + "MS_ASYNC_CALLBACK_STATUS_JOIN", + "MS_ASYNC_OP_STATUS_CANCELED", + "MS_ASYNC_OP_STATUS_ERROR", + "MS_ASYNC_OP_STATUS_SUCCESS", + "MS_MANIPULATION_STATE_ACTIVE", + "MS_MANIPULATION_STATE_CANCELLED", + "MS_MANIPULATION_STATE_COMMITTED", + "MS_MANIPULATION_STATE_DRAGGING", + "MS_MANIPULATION_STATE_INERTIA", + "MS_MANIPULATION_STATE_PRESELECT", + "MS_MANIPULATION_STATE_SELECTING", + "MS_MANIPULATION_STATE_STOPPED", + "MS_MEDIA_ERR_ENCRYPTED", + "MS_MEDIA_KEYERR_CLIENT", + "MS_MEDIA_KEYERR_DOMAIN", + "MS_MEDIA_KEYERR_HARDWARECHANGE", + "MS_MEDIA_KEYERR_OUTPUT", + "MS_MEDIA_KEYERR_SERVICE", + "MS_MEDIA_KEYERR_UNKNOWN", + "Map", + "Math", + "MathMLElement", + "MediaCapabilities", + "MediaCapabilitiesInfo", + "MediaController", + "MediaDeviceInfo", + "MediaDevices", + "MediaElementAudioSourceNode", + "MediaEncryptedEvent", + "MediaError", + "MediaKeyError", + "MediaKeyEvent", + "MediaKeyMessageEvent", + "MediaKeyNeededEvent", + "MediaKeySession", + "MediaKeyStatusMap", + "MediaKeySystemAccess", + "MediaKeys", + "MediaList", + "MediaMetadata", + "MediaQueryList", + "MediaQueryListEvent", + "MediaRecorder", + "MediaRecorderErrorEvent", + "MediaSession", + "MediaSettingsRange", + "MediaSource", + "MediaStream", + "MediaStreamAudioDestinationNode", + "MediaStreamAudioSourceNode", + "MediaStreamEvent", + "MediaStreamTrack", + "MediaStreamTrackAudioSourceNode", + "MediaStreamTrackEvent", + "Memory", + "MessageChannel", + "MessageEvent", + "MessagePort", + "Methods", + "MimeType", + "MimeTypeArray", + "Module", + "MouseEvent", + "MouseScrollEvent", + "MozAnimation", + "MozAnimationDelay", + "MozAnimationDirection", + "MozAnimationDuration", + "MozAnimationFillMode", + "MozAnimationIterationCount", + "MozAnimationName", + "MozAnimationPlayState", + "MozAnimationTimingFunction", + "MozAppearance", + "MozBackfaceVisibility", + "MozBinding", + "MozBorderBottomColors", + "MozBorderEnd", + "MozBorderEndColor", + "MozBorderEndStyle", + "MozBorderEndWidth", + "MozBorderImage", + "MozBorderLeftColors", + "MozBorderRightColors", + "MozBorderStart", + "MozBorderStartColor", + "MozBorderStartStyle", + "MozBorderStartWidth", + "MozBorderTopColors", + "MozBoxAlign", + "MozBoxDirection", + "MozBoxFlex", + "MozBoxOrdinalGroup", + "MozBoxOrient", + "MozBoxPack", + "MozBoxSizing", + "MozCSSKeyframeRule", + "MozCSSKeyframesRule", + "MozColumnCount", + "MozColumnFill", + "MozColumnGap", + "MozColumnRule", + "MozColumnRuleColor", + "MozColumnRuleStyle", + "MozColumnRuleWidth", + "MozColumnWidth", + "MozColumns", + "MozContactChangeEvent", + "MozFloatEdge", + "MozFontFeatureSettings", + "MozFontLanguageOverride", + "MozForceBrokenImageIcon", + "MozHyphens", + "MozImageRegion", + "MozMarginEnd", + "MozMarginStart", + "MozMmsEvent", + "MozMmsMessage", + "MozMobileMessageThread", + "MozOSXFontSmoothing", + "MozOrient", + "MozOsxFontSmoothing", + "MozOutlineRadius", + "MozOutlineRadiusBottomleft", + "MozOutlineRadiusBottomright", + "MozOutlineRadiusTopleft", + "MozOutlineRadiusTopright", + "MozPaddingEnd", + "MozPaddingStart", + "MozPerspective", + "MozPerspectiveOrigin", + "MozPowerManager", + "MozSettingsEvent", + "MozSmsEvent", + "MozSmsMessage", + "MozStackSizing", + "MozTabSize", + "MozTextAlignLast", + "MozTextDecorationColor", + "MozTextDecorationLine", + "MozTextDecorationStyle", + "MozTextSizeAdjust", + "MozTransform", + "MozTransformOrigin", + "MozTransformStyle", + "MozTransition", + "MozTransitionDelay", + "MozTransitionDuration", + "MozTransitionProperty", + "MozTransitionTimingFunction", + "MozUserFocus", + "MozUserInput", + "MozUserModify", + "MozUserSelect", + "MozWindowDragging", + "MozWindowShadow", + "MutationEvent", + "MutationObserver", + "MutationRecord", + "NAMESPACE_ERR", + "NAMESPACE_RULE", + "NEAREST", + "NEAREST_MIPMAP_LINEAR", + "NEAREST_MIPMAP_NEAREST", + "NEGATIVE_INFINITY", + "NETWORK_EMPTY", + "NETWORK_ERR", + "NETWORK_IDLE", + "NETWORK_LOADED", + "NETWORK_LOADING", + "NETWORK_NO_SOURCE", + "NEVER", + "NEW", + "NEXT", + "NEXT_NO_DUPLICATE", + "NICEST", + "NODE_AFTER", + "NODE_BEFORE", + "NODE_BEFORE_AND_AFTER", + "NODE_INSIDE", + "NONE", + "NON_TRANSIENT_ERR", + "NOTATION_NODE", + "NOTCH", + "NOTEQUAL", + "NOT_ALLOWED_ERR", + "NOT_FOUND_ERR", + "NOT_READABLE_ERR", + "NOT_SUPPORTED_ERR", + "NO_DATA_ALLOWED_ERR", + "NO_ERR", + "NO_ERROR", + "NO_MODIFICATION_ALLOWED_ERR", + "NUMBER_TYPE", + "NUM_COMPRESSED_TEXTURE_FORMATS", + "NaN", + "NamedNodeMap", + "NavigationPreloadManager", + "Navigator", + "NearbyLinks", + "NetworkInformation", + "Node", + "NodeFilter", + "NodeIterator", + "NodeList", + "Notation", + "Notification", + "NotifyPaintEvent", + "Number", + "NumberFormat", + "OBJECT_TYPE", + "OBSOLETE", + "OK", + "ONE", + "ONE_MINUS_CONSTANT_ALPHA", + "ONE_MINUS_CONSTANT_COLOR", + "ONE_MINUS_DST_ALPHA", + "ONE_MINUS_DST_COLOR", + "ONE_MINUS_SRC_ALPHA", + "ONE_MINUS_SRC_COLOR", + "OPEN", + "OPENED", + "OPENING", + "ORDERED_NODE_ITERATOR_TYPE", + "ORDERED_NODE_SNAPSHOT_TYPE", + "OTHER_ERROR", + "OUT_OF_MEMORY", + "Object", + "OfflineAudioCompletionEvent", + "OfflineAudioContext", + "OfflineResourceList", + "OffscreenCanvas", + "OffscreenCanvasRenderingContext2D", + "Option", + "OrientationSensor", + "OscillatorNode", + "OverconstrainedError", + "OverflowEvent", + "PACK_ALIGNMENT", + "PACK_ROW_LENGTH", + "PACK_SKIP_PIXELS", + "PACK_SKIP_ROWS", + "PAGE_RULE", + "PARSE_ERR", + "PATHSEG_ARC_ABS", + "PATHSEG_ARC_REL", + "PATHSEG_CLOSEPATH", + "PATHSEG_CURVETO_CUBIC_ABS", + "PATHSEG_CURVETO_CUBIC_REL", + "PATHSEG_CURVETO_CUBIC_SMOOTH_ABS", + "PATHSEG_CURVETO_CUBIC_SMOOTH_REL", + "PATHSEG_CURVETO_QUADRATIC_ABS", + "PATHSEG_CURVETO_QUADRATIC_REL", + "PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS", + "PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL", + "PATHSEG_LINETO_ABS", + "PATHSEG_LINETO_HORIZONTAL_ABS", + "PATHSEG_LINETO_HORIZONTAL_REL", + "PATHSEG_LINETO_REL", + "PATHSEG_LINETO_VERTICAL_ABS", + "PATHSEG_LINETO_VERTICAL_REL", + "PATHSEG_MOVETO_ABS", + "PATHSEG_MOVETO_REL", + "PATHSEG_UNKNOWN", + "PATH_EXISTS_ERR", + "PEAKING", + "PERMISSION_DENIED", + "PERSISTENT", + "PI", + "PIXEL_PACK_BUFFER", + "PIXEL_PACK_BUFFER_BINDING", + "PIXEL_UNPACK_BUFFER", + "PIXEL_UNPACK_BUFFER_BINDING", + "PLAYING_STATE", + "POINTS", + "POLYGON_OFFSET_FACTOR", + "POLYGON_OFFSET_FILL", + "POLYGON_OFFSET_UNITS", + "POSITION_UNAVAILABLE", + "POSITIVE_INFINITY", + "PREV", + "PREV_NO_DUPLICATE", + "PROCESSING_INSTRUCTION_NODE", + "PageChangeEvent", + "PageTransitionEvent", + "PaintRequest", + "PaintRequestList", + "PannerNode", + "PasswordCredential", + "Path2D", + "PaymentAddress", + "PaymentInstruments", + "PaymentManager", + "PaymentMethodChangeEvent", + "PaymentRequest", + "PaymentRequestUpdateEvent", + "PaymentResponse", + "Performance", + "PerformanceElementTiming", + "PerformanceEntry", + "PerformanceEventTiming", + "PerformanceLongTaskTiming", + "PerformanceMark", + "PerformanceMeasure", + "PerformanceNavigation", + "PerformanceNavigationTiming", + "PerformanceObserver", + "PerformanceObserverEntryList", + "PerformancePaintTiming", + "PerformanceResourceTiming", + "PerformanceServerTiming", + "PerformanceTiming", + "PeriodicSyncManager", + "PeriodicWave", + "PermissionStatus", + "Permissions", + "PhotoCapabilities", + "PictureInPictureWindow", + "Plugin", + "PluginArray", + "PluralRules", + "PointerEvent", + "PopStateEvent", + "PopupBlockedEvent", + "Presentation", + "PresentationAvailability", + "PresentationConnection", + "PresentationConnectionAvailableEvent", + "PresentationConnectionCloseEvent", + "PresentationConnectionList", + "PresentationReceiver", + "PresentationRequest", + "ProcessingInstruction", + "ProgressEvent", + "Promise", + "PromiseRejectionEvent", + "PropertyNodeList", + "Proxy", + "PublicKeyCredential", + "PushManager", + "PushSubscription", + "PushSubscriptionOptions", + "Q", + "QUERY_RESULT", + "QUERY_RESULT_AVAILABLE", + "QUOTA_ERR", + "QUOTA_EXCEEDED_ERR", + "QueryInterface", + "R11F_G11F_B10F", + "R16F", + "R16I", + "R16UI", + "R32F", + "R32I", + "R32UI", + "R8", + "R8I", + "R8UI", + "R8_SNORM", + "RASTERIZER_DISCARD", + "READ_BUFFER", + "READ_FRAMEBUFFER", + "READ_FRAMEBUFFER_BINDING", + "READ_ONLY", + "READ_ONLY_ERR", + "READ_WRITE", + "RED", + "RED_BITS", + "RED_INTEGER", + "REMOVAL", + "RENDERBUFFER", + "RENDERBUFFER_ALPHA_SIZE", + "RENDERBUFFER_BINDING", + "RENDERBUFFER_BLUE_SIZE", + "RENDERBUFFER_DEPTH_SIZE", + "RENDERBUFFER_GREEN_SIZE", + "RENDERBUFFER_HEIGHT", + "RENDERBUFFER_INTERNAL_FORMAT", + "RENDERBUFFER_RED_SIZE", + "RENDERBUFFER_SAMPLES", + "RENDERBUFFER_STENCIL_SIZE", + "RENDERBUFFER_WIDTH", + "RENDERER", + "RENDERING_INTENT_ABSOLUTE_COLORIMETRIC", + "RENDERING_INTENT_AUTO", + "RENDERING_INTENT_PERCEPTUAL", + "RENDERING_INTENT_RELATIVE_COLORIMETRIC", + "RENDERING_INTENT_SATURATION", + "RENDERING_INTENT_UNKNOWN", + "REPEAT", + "REPLACE", + "RG", + "RG16F", + "RG16I", + "RG16UI", + "RG32F", + "RG32I", + "RG32UI", + "RG8", + "RG8I", + "RG8UI", + "RG8_SNORM", + "RGB", + "RGB10_A2", + "RGB10_A2UI", + "RGB16F", + "RGB16I", + "RGB16UI", + "RGB32F", + "RGB32I", + "RGB32UI", + "RGB565", + "RGB5_A1", + "RGB8", + "RGB8I", + "RGB8UI", + "RGB8_SNORM", + "RGB9_E5", + "RGBA", + "RGBA16F", + "RGBA16I", + "RGBA16UI", + "RGBA32F", + "RGBA32I", + "RGBA32UI", + "RGBA4", + "RGBA8", + "RGBA8I", + "RGBA8UI", + "RGBA8_SNORM", + "RGBA_INTEGER", + "RGBColor", + "RGB_INTEGER", + "RG_INTEGER", + "ROTATION_CLOCKWISE", + "ROTATION_COUNTERCLOCKWISE", + "RTCCertificate", + "RTCDTMFSender", + "RTCDTMFToneChangeEvent", + "RTCDataChannel", + "RTCDataChannelEvent", + "RTCDtlsTransport", + "RTCError", + "RTCErrorEvent", + "RTCIceCandidate", + "RTCIceTransport", + "RTCPeerConnection", + "RTCPeerConnectionIceErrorEvent", + "RTCPeerConnectionIceEvent", + "RTCRtpReceiver", + "RTCRtpSender", + "RTCRtpTransceiver", + "RTCSctpTransport", + "RTCSessionDescription", + "RTCStatsReport", + "RTCTrackEvent", + "RadioNodeList", + "Range", + "RangeError", + "RangeException", + "ReadableStream", + "ReadableStreamDefaultReader", + "RecordErrorEvent", + "Rect", + "ReferenceError", + "Reflect", + "RegExp", + "RelativeOrientationSensor", + "RelativeTimeFormat", + "RemotePlayback", + "Report", + "ReportBody", + "ReportingObserver", + "Request", + "ResizeObserver", + "ResizeObserverEntry", + "ResizeObserverSize", + "Response", + "RuntimeError", + "SAMPLER_2D", + "SAMPLER_2D_ARRAY", + "SAMPLER_2D_ARRAY_SHADOW", + "SAMPLER_2D_SHADOW", + "SAMPLER_3D", + "SAMPLER_BINDING", + "SAMPLER_CUBE", + "SAMPLER_CUBE_SHADOW", + "SAMPLES", + "SAMPLE_ALPHA_TO_COVERAGE", + "SAMPLE_BUFFERS", + "SAMPLE_COVERAGE", + "SAMPLE_COVERAGE_INVERT", + "SAMPLE_COVERAGE_VALUE", + "SAWTOOTH", + "SCHEDULED_STATE", + "SCISSOR_BOX", + "SCISSOR_TEST", + "SCROLL_PAGE_DOWN", + "SCROLL_PAGE_UP", + "SDP_ANSWER", + "SDP_OFFER", + "SDP_PRANSWER", + "SECURITY_ERR", + "SELECT", + "SEPARATE_ATTRIBS", + "SERIALIZE_ERR", + "SEVERITY_ERROR", + "SEVERITY_FATAL_ERROR", + "SEVERITY_WARNING", + "SHADER_COMPILER", + "SHADER_TYPE", + "SHADING_LANGUAGE_VERSION", + "SHIFT_MASK", + "SHORT", + "SHOWING", + "SHOW_ALL", + "SHOW_ATTRIBUTE", + "SHOW_CDATA_SECTION", + "SHOW_COMMENT", + "SHOW_DOCUMENT", + "SHOW_DOCUMENT_FRAGMENT", + "SHOW_DOCUMENT_TYPE", + "SHOW_ELEMENT", + "SHOW_ENTITY", + "SHOW_ENTITY_REFERENCE", + "SHOW_NOTATION", + "SHOW_PROCESSING_INSTRUCTION", + "SHOW_TEXT", + "SIGNALED", + "SIGNED_NORMALIZED", + "SINE", + "SOUNDFIELD", + "SQLException", + "SQRT1_2", + "SQRT2", + "SQUARE", + "SRC_ALPHA", + "SRC_ALPHA_SATURATE", + "SRC_COLOR", + "SRGB", + "SRGB8", + "SRGB8_ALPHA8", + "START_TO_END", + "START_TO_START", + "STATIC_COPY", + "STATIC_DRAW", + "STATIC_READ", + "STENCIL", + "STENCIL_ATTACHMENT", + "STENCIL_BACK_FAIL", + "STENCIL_BACK_FUNC", + "STENCIL_BACK_PASS_DEPTH_FAIL", + "STENCIL_BACK_PASS_DEPTH_PASS", + "STENCIL_BACK_REF", + "STENCIL_BACK_VALUE_MASK", + "STENCIL_BACK_WRITEMASK", + "STENCIL_BITS", + "STENCIL_BUFFER_BIT", + "STENCIL_CLEAR_VALUE", + "STENCIL_FAIL", + "STENCIL_FUNC", + "STENCIL_INDEX", + "STENCIL_INDEX8", + "STENCIL_PASS_DEPTH_FAIL", + "STENCIL_PASS_DEPTH_PASS", + "STENCIL_REF", + "STENCIL_TEST", + "STENCIL_VALUE_MASK", + "STENCIL_WRITEMASK", + "STREAM_COPY", + "STREAM_DRAW", + "STREAM_READ", + "STRING_TYPE", + "STYLE_RULE", + "SUBPIXEL_BITS", + "SUPPORTS_RULE", + "SVGAElement", + "SVGAltGlyphDefElement", + "SVGAltGlyphElement", + "SVGAltGlyphItemElement", + "SVGAngle", + "SVGAnimateColorElement", + "SVGAnimateElement", + "SVGAnimateMotionElement", + "SVGAnimateTransformElement", + "SVGAnimatedAngle", + "SVGAnimatedBoolean", + "SVGAnimatedEnumeration", + "SVGAnimatedInteger", + "SVGAnimatedLength", + "SVGAnimatedLengthList", + "SVGAnimatedNumber", + "SVGAnimatedNumberList", + "SVGAnimatedPreserveAspectRatio", + "SVGAnimatedRect", + "SVGAnimatedString", + "SVGAnimatedTransformList", + "SVGAnimationElement", + "SVGCircleElement", + "SVGClipPathElement", + "SVGColor", + "SVGComponentTransferFunctionElement", + "SVGCursorElement", + "SVGDefsElement", + "SVGDescElement", + "SVGDiscardElement", + "SVGDocument", + "SVGElement", + "SVGElementInstance", + "SVGElementInstanceList", + "SVGEllipseElement", + "SVGException", + "SVGFEBlendElement", + "SVGFEColorMatrixElement", + "SVGFEComponentTransferElement", + "SVGFECompositeElement", + "SVGFEConvolveMatrixElement", + "SVGFEDiffuseLightingElement", + "SVGFEDisplacementMapElement", + "SVGFEDistantLightElement", + "SVGFEDropShadowElement", + "SVGFEFloodElement", + "SVGFEFuncAElement", + "SVGFEFuncBElement", + "SVGFEFuncGElement", + "SVGFEFuncRElement", + "SVGFEGaussianBlurElement", + "SVGFEImageElement", + "SVGFEMergeElement", + "SVGFEMergeNodeElement", + "SVGFEMorphologyElement", + "SVGFEOffsetElement", + "SVGFEPointLightElement", + "SVGFESpecularLightingElement", + "SVGFESpotLightElement", + "SVGFETileElement", + "SVGFETurbulenceElement", + "SVGFilterElement", + "SVGFontElement", + "SVGFontFaceElement", + "SVGFontFaceFormatElement", + "SVGFontFaceNameElement", + "SVGFontFaceSrcElement", + "SVGFontFaceUriElement", + "SVGForeignObjectElement", + "SVGGElement", + "SVGGeometryElement", + "SVGGlyphElement", + "SVGGlyphRefElement", + "SVGGradientElement", + "SVGGraphicsElement", + "SVGHKernElement", + "SVGImageElement", + "SVGLength", + "SVGLengthList", + "SVGLineElement", + "SVGLinearGradientElement", + "SVGMPathElement", + "SVGMarkerElement", + "SVGMaskElement", + "SVGMatrix", + "SVGMetadataElement", + "SVGMissingGlyphElement", + "SVGNumber", + "SVGNumberList", + "SVGPaint", + "SVGPathElement", + "SVGPathSeg", + "SVGPathSegArcAbs", + "SVGPathSegArcRel", + "SVGPathSegClosePath", + "SVGPathSegCurvetoCubicAbs", + "SVGPathSegCurvetoCubicRel", + "SVGPathSegCurvetoCubicSmoothAbs", + "SVGPathSegCurvetoCubicSmoothRel", + "SVGPathSegCurvetoQuadraticAbs", + "SVGPathSegCurvetoQuadraticRel", + "SVGPathSegCurvetoQuadraticSmoothAbs", + "SVGPathSegCurvetoQuadraticSmoothRel", + "SVGPathSegLinetoAbs", + "SVGPathSegLinetoHorizontalAbs", + "SVGPathSegLinetoHorizontalRel", + "SVGPathSegLinetoRel", + "SVGPathSegLinetoVerticalAbs", + "SVGPathSegLinetoVerticalRel", + "SVGPathSegList", + "SVGPathSegMovetoAbs", + "SVGPathSegMovetoRel", + "SVGPatternElement", + "SVGPoint", + "SVGPointList", + "SVGPolygonElement", + "SVGPolylineElement", + "SVGPreserveAspectRatio", + "SVGRadialGradientElement", + "SVGRect", + "SVGRectElement", + "SVGRenderingIntent", + "SVGSVGElement", + "SVGScriptElement", + "SVGSetElement", + "SVGStopElement", + "SVGStringList", + "SVGStyleElement", + "SVGSwitchElement", + "SVGSymbolElement", + "SVGTRefElement", + "SVGTSpanElement", + "SVGTextContentElement", + "SVGTextElement", + "SVGTextPathElement", + "SVGTextPositioningElement", + "SVGTitleElement", + "SVGTransform", + "SVGTransformList", + "SVGUnitTypes", + "SVGUseElement", + "SVGVKernElement", + "SVGViewElement", + "SVGViewSpec", + "SVGZoomAndPan", + "SVGZoomEvent", + "SVG_ANGLETYPE_DEG", + "SVG_ANGLETYPE_GRAD", + "SVG_ANGLETYPE_RAD", + "SVG_ANGLETYPE_UNKNOWN", + "SVG_ANGLETYPE_UNSPECIFIED", + "SVG_CHANNEL_A", + "SVG_CHANNEL_B", + "SVG_CHANNEL_G", + "SVG_CHANNEL_R", + "SVG_CHANNEL_UNKNOWN", + "SVG_COLORTYPE_CURRENTCOLOR", + "SVG_COLORTYPE_RGBCOLOR", + "SVG_COLORTYPE_RGBCOLOR_ICCCOLOR", + "SVG_COLORTYPE_UNKNOWN", + "SVG_EDGEMODE_DUPLICATE", + "SVG_EDGEMODE_NONE", + "SVG_EDGEMODE_UNKNOWN", + "SVG_EDGEMODE_WRAP", + "SVG_FEBLEND_MODE_COLOR", + "SVG_FEBLEND_MODE_COLOR_BURN", + "SVG_FEBLEND_MODE_COLOR_DODGE", + "SVG_FEBLEND_MODE_DARKEN", + "SVG_FEBLEND_MODE_DIFFERENCE", + "SVG_FEBLEND_MODE_EXCLUSION", + "SVG_FEBLEND_MODE_HARD_LIGHT", + "SVG_FEBLEND_MODE_HUE", + "SVG_FEBLEND_MODE_LIGHTEN", + "SVG_FEBLEND_MODE_LUMINOSITY", + "SVG_FEBLEND_MODE_MULTIPLY", + "SVG_FEBLEND_MODE_NORMAL", + "SVG_FEBLEND_MODE_OVERLAY", + "SVG_FEBLEND_MODE_SATURATION", + "SVG_FEBLEND_MODE_SCREEN", + "SVG_FEBLEND_MODE_SOFT_LIGHT", + "SVG_FEBLEND_MODE_UNKNOWN", + "SVG_FECOLORMATRIX_TYPE_HUEROTATE", + "SVG_FECOLORMATRIX_TYPE_LUMINANCETOALPHA", + "SVG_FECOLORMATRIX_TYPE_MATRIX", + "SVG_FECOLORMATRIX_TYPE_SATURATE", + "SVG_FECOLORMATRIX_TYPE_UNKNOWN", + "SVG_FECOMPONENTTRANSFER_TYPE_DISCRETE", + "SVG_FECOMPONENTTRANSFER_TYPE_GAMMA", + "SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY", + "SVG_FECOMPONENTTRANSFER_TYPE_LINEAR", + "SVG_FECOMPONENTTRANSFER_TYPE_TABLE", + "SVG_FECOMPONENTTRANSFER_TYPE_UNKNOWN", + "SVG_FECOMPOSITE_OPERATOR_ARITHMETIC", + "SVG_FECOMPOSITE_OPERATOR_ATOP", + "SVG_FECOMPOSITE_OPERATOR_IN", + "SVG_FECOMPOSITE_OPERATOR_OUT", + "SVG_FECOMPOSITE_OPERATOR_OVER", + "SVG_FECOMPOSITE_OPERATOR_UNKNOWN", + "SVG_FECOMPOSITE_OPERATOR_XOR", + "SVG_INVALID_VALUE_ERR", + "SVG_LENGTHTYPE_CM", + "SVG_LENGTHTYPE_EMS", + "SVG_LENGTHTYPE_EXS", + "SVG_LENGTHTYPE_IN", + "SVG_LENGTHTYPE_MM", + "SVG_LENGTHTYPE_NUMBER", + "SVG_LENGTHTYPE_PC", + "SVG_LENGTHTYPE_PERCENTAGE", + "SVG_LENGTHTYPE_PT", + "SVG_LENGTHTYPE_PX", + "SVG_LENGTHTYPE_UNKNOWN", + "SVG_MARKERUNITS_STROKEWIDTH", + "SVG_MARKERUNITS_UNKNOWN", + "SVG_MARKERUNITS_USERSPACEONUSE", + "SVG_MARKER_ORIENT_ANGLE", + "SVG_MARKER_ORIENT_AUTO", + "SVG_MARKER_ORIENT_UNKNOWN", + "SVG_MASKTYPE_ALPHA", + "SVG_MASKTYPE_LUMINANCE", + "SVG_MATRIX_NOT_INVERTABLE", + "SVG_MEETORSLICE_MEET", + "SVG_MEETORSLICE_SLICE", + "SVG_MEETORSLICE_UNKNOWN", + "SVG_MORPHOLOGY_OPERATOR_DILATE", + "SVG_MORPHOLOGY_OPERATOR_ERODE", + "SVG_MORPHOLOGY_OPERATOR_UNKNOWN", + "SVG_PAINTTYPE_CURRENTCOLOR", + "SVG_PAINTTYPE_NONE", + "SVG_PAINTTYPE_RGBCOLOR", + "SVG_PAINTTYPE_RGBCOLOR_ICCCOLOR", + "SVG_PAINTTYPE_UNKNOWN", + "SVG_PAINTTYPE_URI", + "SVG_PAINTTYPE_URI_CURRENTCOLOR", + "SVG_PAINTTYPE_URI_NONE", + "SVG_PAINTTYPE_URI_RGBCOLOR", + "SVG_PAINTTYPE_URI_RGBCOLOR_ICCCOLOR", + "SVG_PRESERVEASPECTRATIO_NONE", + "SVG_PRESERVEASPECTRATIO_UNKNOWN", + "SVG_PRESERVEASPECTRATIO_XMAXYMAX", + "SVG_PRESERVEASPECTRATIO_XMAXYMID", + "SVG_PRESERVEASPECTRATIO_XMAXYMIN", + "SVG_PRESERVEASPECTRATIO_XMIDYMAX", + "SVG_PRESERVEASPECTRATIO_XMIDYMID", + "SVG_PRESERVEASPECTRATIO_XMIDYMIN", + "SVG_PRESERVEASPECTRATIO_XMINYMAX", + "SVG_PRESERVEASPECTRATIO_XMINYMID", + "SVG_PRESERVEASPECTRATIO_XMINYMIN", + "SVG_SPREADMETHOD_PAD", + "SVG_SPREADMETHOD_REFLECT", + "SVG_SPREADMETHOD_REPEAT", + "SVG_SPREADMETHOD_UNKNOWN", + "SVG_STITCHTYPE_NOSTITCH", + "SVG_STITCHTYPE_STITCH", + "SVG_STITCHTYPE_UNKNOWN", + "SVG_TRANSFORM_MATRIX", + "SVG_TRANSFORM_ROTATE", + "SVG_TRANSFORM_SCALE", + "SVG_TRANSFORM_SKEWX", + "SVG_TRANSFORM_SKEWY", + "SVG_TRANSFORM_TRANSLATE", + "SVG_TRANSFORM_UNKNOWN", + "SVG_TURBULENCE_TYPE_FRACTALNOISE", + "SVG_TURBULENCE_TYPE_TURBULENCE", + "SVG_TURBULENCE_TYPE_UNKNOWN", + "SVG_UNIT_TYPE_OBJECTBOUNDINGBOX", + "SVG_UNIT_TYPE_UNKNOWN", + "SVG_UNIT_TYPE_USERSPACEONUSE", + "SVG_WRONG_TYPE_ERR", + "SVG_ZOOMANDPAN_DISABLE", + "SVG_ZOOMANDPAN_MAGNIFY", + "SVG_ZOOMANDPAN_UNKNOWN", + "SYNC_CONDITION", + "SYNC_FENCE", + "SYNC_FLAGS", + "SYNC_FLUSH_COMMANDS_BIT", + "SYNC_GPU_COMMANDS_COMPLETE", + "SYNC_STATUS", + "SYNTAX_ERR", + "SavedPages", + "Screen", + "ScreenOrientation", + "Script", + "ScriptProcessorNode", + "ScrollAreaEvent", + "SecurityPolicyViolationEvent", + "Selection", + "Sensor", + "SensorErrorEvent", + "ServiceWorker", + "ServiceWorkerContainer", + "ServiceWorkerRegistration", + "SessionDescription", + "Set", + "ShadowRoot", + "SharedArrayBuffer", + "SharedWorker", + "SimpleGestureEvent", + "SourceBuffer", + "SourceBufferList", + "SpeechSynthesis", + "SpeechSynthesisErrorEvent", + "SpeechSynthesisEvent", + "SpeechSynthesisUtterance", + "SpeechSynthesisVoice", + "StaticRange", + "StereoPannerNode", + "StopIteration", + "Storage", + "StorageEvent", + "StorageManager", + "String", + "StructType", + "StylePropertyMap", + "StylePropertyMapReadOnly", + "StyleSheet", + "StyleSheetList", + "SubmitEvent", + "SubtleCrypto", + "Symbol", + "SyncManager", + "SyntaxError", + "TEMPORARY", + "TEXTPATH_METHODTYPE_ALIGN", + "TEXTPATH_METHODTYPE_STRETCH", + "TEXTPATH_METHODTYPE_UNKNOWN", + "TEXTPATH_SPACINGTYPE_AUTO", + "TEXTPATH_SPACINGTYPE_EXACT", + "TEXTPATH_SPACINGTYPE_UNKNOWN", + "TEXTURE", + "TEXTURE0", + "TEXTURE1", + "TEXTURE10", + "TEXTURE11", + "TEXTURE12", + "TEXTURE13", + "TEXTURE14", + "TEXTURE15", + "TEXTURE16", + "TEXTURE17", + "TEXTURE18", + "TEXTURE19", + "TEXTURE2", + "TEXTURE20", + "TEXTURE21", + "TEXTURE22", + "TEXTURE23", + "TEXTURE24", + "TEXTURE25", + "TEXTURE26", + "TEXTURE27", + "TEXTURE28", + "TEXTURE29", + "TEXTURE3", + "TEXTURE30", + "TEXTURE31", + "TEXTURE4", + "TEXTURE5", + "TEXTURE6", + "TEXTURE7", + "TEXTURE8", + "TEXTURE9", + "TEXTURE_2D", + "TEXTURE_2D_ARRAY", + "TEXTURE_3D", + "TEXTURE_BASE_LEVEL", + "TEXTURE_BINDING_2D", + "TEXTURE_BINDING_2D_ARRAY", + "TEXTURE_BINDING_3D", + "TEXTURE_BINDING_CUBE_MAP", + "TEXTURE_COMPARE_FUNC", + "TEXTURE_COMPARE_MODE", + "TEXTURE_CUBE_MAP", + "TEXTURE_CUBE_MAP_NEGATIVE_X", + "TEXTURE_CUBE_MAP_NEGATIVE_Y", + "TEXTURE_CUBE_MAP_NEGATIVE_Z", + "TEXTURE_CUBE_MAP_POSITIVE_X", + "TEXTURE_CUBE_MAP_POSITIVE_Y", + "TEXTURE_CUBE_MAP_POSITIVE_Z", + "TEXTURE_IMMUTABLE_FORMAT", + "TEXTURE_IMMUTABLE_LEVELS", + "TEXTURE_MAG_FILTER", + "TEXTURE_MAX_ANISOTROPY_EXT", + "TEXTURE_MAX_LEVEL", + "TEXTURE_MAX_LOD", + "TEXTURE_MIN_FILTER", + "TEXTURE_MIN_LOD", + "TEXTURE_WRAP_R", + "TEXTURE_WRAP_S", + "TEXTURE_WRAP_T", + "TEXT_NODE", + "TIMEOUT", + "TIMEOUT_ERR", + "TIMEOUT_EXPIRED", + "TIMEOUT_IGNORED", + "TOO_LARGE_ERR", + "TRANSACTION_INACTIVE_ERR", + "TRANSFORM_FEEDBACK", + "TRANSFORM_FEEDBACK_ACTIVE", + "TRANSFORM_FEEDBACK_BINDING", + "TRANSFORM_FEEDBACK_BUFFER", + "TRANSFORM_FEEDBACK_BUFFER_BINDING", + "TRANSFORM_FEEDBACK_BUFFER_MODE", + "TRANSFORM_FEEDBACK_BUFFER_SIZE", + "TRANSFORM_FEEDBACK_BUFFER_START", + "TRANSFORM_FEEDBACK_PAUSED", + "TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN", + "TRANSFORM_FEEDBACK_VARYINGS", + "TRIANGLE", + "TRIANGLES", + "TRIANGLE_FAN", + "TRIANGLE_STRIP", + "TYPE_BACK_FORWARD", + "TYPE_ERR", + "TYPE_MISMATCH_ERR", + "TYPE_NAVIGATE", + "TYPE_RELOAD", + "TYPE_RESERVED", + "Table", + "TaskAttributionTiming", + "Text", + "TextDecoder", + "TextDecoderStream", + "TextEncoder", + "TextEncoderStream", + "TextEvent", + "TextMetrics", + "TextTrack", + "TextTrackCue", + "TextTrackCueList", + "TextTrackList", + "TimeEvent", + "TimeRanges", + "Touch", + "TouchEvent", + "TouchList", + "TrackEvent", + "TransformStream", + "TransitionEvent", + "TreeWalker", + "TrustedHTML", + "TrustedScript", + "TrustedScriptURL", + "TrustedTypePolicy", + "TrustedTypePolicyFactory", + "TypeError", + "TypedObject", + "U2F", + "UIEvent", + "UNCACHED", + "UNIFORM_ARRAY_STRIDE", + "UNIFORM_BLOCK_ACTIVE_UNIFORMS", + "UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES", + "UNIFORM_BLOCK_BINDING", + "UNIFORM_BLOCK_DATA_SIZE", + "UNIFORM_BLOCK_INDEX", + "UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER", + "UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER", + "UNIFORM_BUFFER", + "UNIFORM_BUFFER_BINDING", + "UNIFORM_BUFFER_OFFSET_ALIGNMENT", + "UNIFORM_BUFFER_SIZE", + "UNIFORM_BUFFER_START", + "UNIFORM_IS_ROW_MAJOR", + "UNIFORM_MATRIX_STRIDE", + "UNIFORM_OFFSET", + "UNIFORM_SIZE", + "UNIFORM_TYPE", + "UNKNOWN_ERR", + "UNKNOWN_RULE", + "UNMASKED_RENDERER_WEBGL", + "UNMASKED_VENDOR_WEBGL", + "UNORDERED_NODE_ITERATOR_TYPE", + "UNORDERED_NODE_SNAPSHOT_TYPE", + "UNPACK_ALIGNMENT", + "UNPACK_COLORSPACE_CONVERSION_WEBGL", + "UNPACK_FLIP_Y_WEBGL", + "UNPACK_IMAGE_HEIGHT", + "UNPACK_PREMULTIPLY_ALPHA_WEBGL", + "UNPACK_ROW_LENGTH", + "UNPACK_SKIP_IMAGES", + "UNPACK_SKIP_PIXELS", + "UNPACK_SKIP_ROWS", + "UNSCHEDULED_STATE", + "UNSENT", + "UNSIGNALED", + "UNSIGNED_BYTE", + "UNSIGNED_INT", + "UNSIGNED_INT_10F_11F_11F_REV", + "UNSIGNED_INT_24_8", + "UNSIGNED_INT_2_10_10_10_REV", + "UNSIGNED_INT_5_9_9_9_REV", + "UNSIGNED_INT_SAMPLER_2D", + "UNSIGNED_INT_SAMPLER_2D_ARRAY", + "UNSIGNED_INT_SAMPLER_3D", + "UNSIGNED_INT_SAMPLER_CUBE", + "UNSIGNED_INT_VEC2", + "UNSIGNED_INT_VEC3", + "UNSIGNED_INT_VEC4", + "UNSIGNED_NORMALIZED", + "UNSIGNED_SHORT", + "UNSIGNED_SHORT_4_4_4_4", + "UNSIGNED_SHORT_5_5_5_1", + "UNSIGNED_SHORT_5_6_5", + "UNSPECIFIED_EVENT_TYPE_ERR", + "UPDATEREADY", + "URIError", + "URL", + "URLSearchParams", + "URLUnencoded", + "URL_MISMATCH_ERR", + "USB", + "USBAlternateInterface", + "USBConfiguration", + "USBConnectionEvent", + "USBDevice", + "USBEndpoint", + "USBInTransferResult", + "USBInterface", + "USBIsochronousInTransferPacket", + "USBIsochronousInTransferResult", + "USBIsochronousOutTransferPacket", + "USBIsochronousOutTransferResult", + "USBOutTransferResult", + "UTC", + "Uint16Array", + "Uint32Array", + "Uint8Array", + "Uint8ClampedArray", + "UserActivation", + "UserMessageHandler", + "UserMessageHandlersNamespace", + "UserProximityEvent", + "VALIDATE_STATUS", + "VALIDATION_ERR", + "VARIABLES_RULE", + "VENDOR", + "VERSION", + "VERSION_CHANGE", + "VERSION_ERR", + "VERTEX_ARRAY_BINDING", + "VERTEX_ATTRIB_ARRAY_BUFFER_BINDING", + "VERTEX_ATTRIB_ARRAY_DIVISOR", + "VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE", + "VERTEX_ATTRIB_ARRAY_ENABLED", + "VERTEX_ATTRIB_ARRAY_INTEGER", + "VERTEX_ATTRIB_ARRAY_NORMALIZED", + "VERTEX_ATTRIB_ARRAY_POINTER", + "VERTEX_ATTRIB_ARRAY_SIZE", + "VERTEX_ATTRIB_ARRAY_STRIDE", + "VERTEX_ATTRIB_ARRAY_TYPE", + "VERTEX_SHADER", + "VERTICAL", + "VERTICAL_AXIS", + "VER_ERR", + "VIEWPORT", + "VIEWPORT_RULE", + "VRDisplay", + "VRDisplayCapabilities", + "VRDisplayEvent", + "VREyeParameters", + "VRFieldOfView", + "VRFrameData", + "VRPose", + "VRStageParameters", + "VTTCue", + "VTTRegion", + "ValidityState", + "VideoPlaybackQuality", + "VideoStreamTrack", + "VisualViewport", + "WAIT_FAILED", + "WEBKIT_FILTER_RULE", + "WEBKIT_KEYFRAMES_RULE", + "WEBKIT_KEYFRAME_RULE", + "WEBKIT_REGION_RULE", + "WRONG_DOCUMENT_ERR", + "WakeLock", + "WakeLockSentinel", + "WasmAnyRef", + "WaveShaperNode", + "WeakMap", + "WeakRef", + "WeakSet", + "WebAssembly", + "WebGL2RenderingContext", + "WebGLActiveInfo", + "WebGLBuffer", + "WebGLContextEvent", + "WebGLFramebuffer", + "WebGLProgram", + "WebGLQuery", + "WebGLRenderbuffer", + "WebGLRenderingContext", + "WebGLSampler", + "WebGLShader", + "WebGLShaderPrecisionFormat", + "WebGLSync", + "WebGLTexture", + "WebGLTransformFeedback", + "WebGLUniformLocation", + "WebGLVertexArray", + "WebGLVertexArrayObject", + "WebKitAnimationEvent", + "WebKitBlobBuilder", + "WebKitCSSFilterRule", + "WebKitCSSFilterValue", + "WebKitCSSKeyframeRule", + "WebKitCSSKeyframesRule", + "WebKitCSSMatrix", + "WebKitCSSRegionRule", + "WebKitCSSTransformValue", + "WebKitDataCue", + "WebKitGamepad", + "WebKitMediaKeyError", + "WebKitMediaKeyMessageEvent", + "WebKitMediaKeySession", + "WebKitMediaKeys", + "WebKitMediaSource", + "WebKitMutationObserver", + "WebKitNamespace", + "WebKitPlaybackTargetAvailabilityEvent", + "WebKitPoint", + "WebKitShadowRoot", + "WebKitSourceBuffer", + "WebKitSourceBufferList", + "WebKitTransitionEvent", + "WebSocket", + "WebkitAlignContent", + "WebkitAlignItems", + "WebkitAlignSelf", + "WebkitAnimation", + "WebkitAnimationDelay", + "WebkitAnimationDirection", + "WebkitAnimationDuration", + "WebkitAnimationFillMode", + "WebkitAnimationIterationCount", + "WebkitAnimationName", + "WebkitAnimationPlayState", + "WebkitAnimationTimingFunction", + "WebkitAppearance", + "WebkitBackfaceVisibility", + "WebkitBackgroundClip", + "WebkitBackgroundOrigin", + "WebkitBackgroundSize", + "WebkitBorderBottomLeftRadius", + "WebkitBorderBottomRightRadius", + "WebkitBorderImage", + "WebkitBorderRadius", + "WebkitBorderTopLeftRadius", + "WebkitBorderTopRightRadius", + "WebkitBoxAlign", + "WebkitBoxDirection", + "WebkitBoxFlex", + "WebkitBoxOrdinalGroup", + "WebkitBoxOrient", + "WebkitBoxPack", + "WebkitBoxShadow", + "WebkitBoxSizing", + "WebkitFilter", + "WebkitFlex", + "WebkitFlexBasis", + "WebkitFlexDirection", + "WebkitFlexFlow", + "WebkitFlexGrow", + "WebkitFlexShrink", + "WebkitFlexWrap", + "WebkitJustifyContent", + "WebkitLineClamp", + "WebkitMask", + "WebkitMaskClip", + "WebkitMaskComposite", + "WebkitMaskImage", + "WebkitMaskOrigin", + "WebkitMaskPosition", + "WebkitMaskPositionX", + "WebkitMaskPositionY", + "WebkitMaskRepeat", + "WebkitMaskSize", + "WebkitOrder", + "WebkitPerspective", + "WebkitPerspectiveOrigin", + "WebkitTextFillColor", + "WebkitTextSizeAdjust", + "WebkitTextStroke", + "WebkitTextStrokeColor", + "WebkitTextStrokeWidth", + "WebkitTransform", + "WebkitTransformOrigin", + "WebkitTransformStyle", + "WebkitTransition", + "WebkitTransitionDelay", + "WebkitTransitionDuration", + "WebkitTransitionProperty", + "WebkitTransitionTimingFunction", + "WebkitUserSelect", + "WheelEvent", + "Window", + "Worker", + "Worklet", + "WritableStream", + "WritableStreamDefaultWriter", + "XMLDocument", + "XMLHttpRequest", + "XMLHttpRequestEventTarget", + "XMLHttpRequestException", + "XMLHttpRequestProgressEvent", + "XMLHttpRequestUpload", + "XMLSerializer", + "XMLStylesheetProcessingInstruction", + "XPathEvaluator", + "XPathException", + "XPathExpression", + "XPathNSResolver", + "XPathResult", + "XRBoundedReferenceSpace", + "XRDOMOverlayState", + "XRFrame", + "XRHitTestResult", + "XRHitTestSource", + "XRInputSource", + "XRInputSourceArray", + "XRInputSourceEvent", + "XRInputSourcesChangeEvent", + "XRLayer", + "XRPose", + "XRRay", + "XRReferenceSpace", + "XRReferenceSpaceEvent", + "XRRenderState", + "XRRigidTransform", + "XRSession", + "XRSessionEvent", + "XRSpace", + "XRSystem", + "XRTransientInputHitTestResult", + "XRTransientInputHitTestSource", + "XRView", + "XRViewerPose", + "XRViewport", + "XRWebGLLayer", + "XSLTProcessor", + "ZERO", + "_XD0M_", + "_YD0M_", + "__defineGetter__", + "__defineSetter__", + "__lookupGetter__", + "__lookupSetter__", + "__opera", + "__proto__", + "_browserjsran", + "a", + "aLink", + "abbr", + "abort", + "aborted", + "abs", + "absolute", + "acceleration", + "accelerationIncludingGravity", + "accelerator", + "accept", + "acceptCharset", + "acceptNode", + "accessKey", + "accessKeyLabel", + "accuracy", + "acos", + "acosh", + "action", + "actionURL", + "actions", + "activated", + "active", + "activeCues", + "activeElement", + "activeSourceBuffers", + "activeSourceCount", + "activeTexture", + "activeVRDisplays", + "actualBoundingBoxAscent", + "actualBoundingBoxDescent", + "actualBoundingBoxLeft", + "actualBoundingBoxRight", + "add", + "addAll", + "addBehavior", + "addCandidate", + "addColorStop", + "addCue", + "addElement", + "addEventListener", + "addFilter", + "addFromString", + "addFromUri", + "addIceCandidate", + "addImport", + "addListener", + "addModule", + "addNamed", + "addPageRule", + "addPath", + "addPointer", + "addRange", + "addRegion", + "addRule", + "addSearchEngine", + "addSourceBuffer", + "addStream", + "addTextTrack", + "addTrack", + "addTransceiver", + "addWakeLockListener", + "added", + "addedNodes", + "additionalName", + "additiveSymbols", + "addons", + "address", + "addressLine", + "adoptNode", + "adoptedStyleSheets", + "adr", + "advance", + "after", + "album", + "alert", + "algorithm", + "align", + "align-content", + "align-items", + "align-self", + "alignContent", + "alignItems", + "alignSelf", + "alignmentBaseline", + "alinkColor", + "all", + "allSettled", + "allow", + "allowFullscreen", + "allowPaymentRequest", + "allowedDirections", + "allowedFeatures", + "allowedToPlay", + "allowsFeature", + "alpha", + "alt", + "altGraphKey", + "altHtml", + "altKey", + "altLeft", + "alternate", + "alternateSetting", + "alternates", + "altitude", + "altitudeAccuracy", + "amplitude", + "ancestorOrigins", + "anchor", + "anchorNode", + "anchorOffset", + "anchors", + "and", + "angle", + "angularAcceleration", + "angularVelocity", + "animVal", + "animate", + "animatedInstanceRoot", + "animatedNormalizedPathSegList", + "animatedPathSegList", + "animatedPoints", + "animation", + "animation-delay", + "animation-direction", + "animation-duration", + "animation-fill-mode", + "animation-iteration-count", + "animation-name", + "animation-play-state", + "animation-timing-function", + "animationDelay", + "animationDirection", + "animationDuration", + "animationFillMode", + "animationIterationCount", + "animationName", + "animationPlayState", + "animationStartTime", + "animationTimingFunction", + "animationsPaused", + "anniversary", + "antialias", + "anticipatedRemoval", + "any", + "app", + "appCodeName", + "appMinorVersion", + "appName", + "appNotifications", + "appVersion", + "appearance", + "append", + "appendBuffer", + "appendChild", + "appendData", + "appendItem", + "appendMedium", + "appendNamed", + "appendRule", + "appendStream", + "appendWindowEnd", + "appendWindowStart", + "applets", + "applicationCache", + "applicationServerKey", + "apply", + "applyConstraints", + "applyElement", + "arc", + "arcTo", + "architecture", + "archive", + "areas", + "arguments", + "ariaAtomic", + "ariaAutoComplete", + "ariaBusy", + "ariaChecked", + "ariaColCount", + "ariaColIndex", + "ariaColSpan", + "ariaCurrent", + "ariaDescription", + "ariaDisabled", + "ariaExpanded", + "ariaHasPopup", + "ariaHidden", + "ariaKeyShortcuts", + "ariaLabel", + "ariaLevel", + "ariaLive", + "ariaModal", + "ariaMultiLine", + "ariaMultiSelectable", + "ariaOrientation", + "ariaPlaceholder", + "ariaPosInSet", + "ariaPressed", + "ariaReadOnly", + "ariaRelevant", + "ariaRequired", + "ariaRoleDescription", + "ariaRowCount", + "ariaRowIndex", + "ariaRowSpan", + "ariaSelected", + "ariaSetSize", + "ariaSort", + "ariaValueMax", + "ariaValueMin", + "ariaValueNow", + "ariaValueText", + "arrayBuffer", + "artist", + "artwork", + "as", + "asIntN", + "asUintN", + "asin", + "asinh", + "assert", + "assign", + "assignedElements", + "assignedNodes", + "assignedSlot", + "async", + "asyncIterator", + "atEnd", + "atan", + "atan2", + "atanh", + "atob", + "attachEvent", + "attachInternals", + "attachShader", + "attachShadow", + "attachments", + "attack", + "attestationObject", + "attrChange", + "attrName", + "attributeFilter", + "attributeName", + "attributeNamespace", + "attributeOldValue", + "attributeStyleMap", + "attributes", + "attribution", + "audioBitsPerSecond", + "audioTracks", + "audioWorklet", + "authenticatedSignedWrites", + "authenticatorData", + "autoIncrement", + "autobuffer", + "autocapitalize", + "autocomplete", + "autocorrect", + "autofocus", + "automationRate", + "autoplay", + "availHeight", + "availLeft", + "availTop", + "availWidth", + "availability", + "available", + "aversion", + "ax", + "axes", + "axis", + "ay", + "azimuth", + "b", + "back", + "backface-visibility", + "backfaceVisibility", + "background", + "background-attachment", + "background-blend-mode", + "background-clip", + "background-color", + "background-image", + "background-origin", + "background-position", + "background-position-x", + "background-position-y", + "background-repeat", + "background-size", + "backgroundAttachment", + "backgroundBlendMode", + "backgroundClip", + "backgroundColor", + "backgroundFetch", + "backgroundImage", + "backgroundOrigin", + "backgroundPosition", + "backgroundPositionX", + "backgroundPositionY", + "backgroundRepeat", + "backgroundSize", + "badInput", + "badge", + "balance", + "baseFrequencyX", + "baseFrequencyY", + "baseLatency", + "baseLayer", + "baseNode", + "baseOffset", + "baseURI", + "baseVal", + "baselineShift", + "battery", + "bday", + "before", + "beginElement", + "beginElementAt", + "beginPath", + "beginQuery", + "beginTransformFeedback", + "behavior", + "behaviorCookie", + "behaviorPart", + "behaviorUrns", + "beta", + "bezierCurveTo", + "bgColor", + "bgProperties", + "bias", + "big", + "bigint64", + "biguint64", + "binaryType", + "bind", + "bindAttribLocation", + "bindBuffer", + "bindBufferBase", + "bindBufferRange", + "bindFramebuffer", + "bindRenderbuffer", + "bindSampler", + "bindTexture", + "bindTransformFeedback", + "bindVertexArray", + "bitness", + "blendColor", + "blendEquation", + "blendEquationSeparate", + "blendFunc", + "blendFuncSeparate", + "blink", + "blitFramebuffer", + "blob", + "block-size", + "blockDirection", + "blockSize", + "blockedURI", + "blue", + "bluetooth", + "blur", + "body", + "bodyUsed", + "bold", + "bookmarks", + "booleanValue", + "border", + "border-block", + "border-block-color", + "border-block-end", + "border-block-end-color", + "border-block-end-style", + "border-block-end-width", + "border-block-start", + "border-block-start-color", + "border-block-start-style", + "border-block-start-width", + "border-block-style", + "border-block-width", + "border-bottom", + "border-bottom-color", + "border-bottom-left-radius", + "border-bottom-right-radius", + "border-bottom-style", + "border-bottom-width", + "border-collapse", + "border-color", + "border-end-end-radius", + "border-end-start-radius", + "border-image", + "border-image-outset", + "border-image-repeat", + "border-image-slice", + "border-image-source", + "border-image-width", + "border-inline", + "border-inline-color", + "border-inline-end", + "border-inline-end-color", + "border-inline-end-style", + "border-inline-end-width", + "border-inline-start", + "border-inline-start-color", + "border-inline-start-style", + "border-inline-start-width", + "border-inline-style", + "border-inline-width", + "border-left", + "border-left-color", + "border-left-style", + "border-left-width", + "border-radius", + "border-right", + "border-right-color", + "border-right-style", + "border-right-width", + "border-spacing", + "border-start-end-radius", + "border-start-start-radius", + "border-style", + "border-top", + "border-top-color", + "border-top-left-radius", + "border-top-right-radius", + "border-top-style", + "border-top-width", + "border-width", + "borderBlock", + "borderBlockColor", + "borderBlockEnd", + "borderBlockEndColor", + "borderBlockEndStyle", + "borderBlockEndWidth", + "borderBlockStart", + "borderBlockStartColor", + "borderBlockStartStyle", + "borderBlockStartWidth", + "borderBlockStyle", + "borderBlockWidth", + "borderBottom", + "borderBottomColor", + "borderBottomLeftRadius", + "borderBottomRightRadius", + "borderBottomStyle", + "borderBottomWidth", + "borderBoxSize", + "borderCollapse", + "borderColor", + "borderColorDark", + "borderColorLight", + "borderEndEndRadius", + "borderEndStartRadius", + "borderImage", + "borderImageOutset", + "borderImageRepeat", + "borderImageSlice", + "borderImageSource", + "borderImageWidth", + "borderInline", + "borderInlineColor", + "borderInlineEnd", + "borderInlineEndColor", + "borderInlineEndStyle", + "borderInlineEndWidth", + "borderInlineStart", + "borderInlineStartColor", + "borderInlineStartStyle", + "borderInlineStartWidth", + "borderInlineStyle", + "borderInlineWidth", + "borderLeft", + "borderLeftColor", + "borderLeftStyle", + "borderLeftWidth", + "borderRadius", + "borderRight", + "borderRightColor", + "borderRightStyle", + "borderRightWidth", + "borderSpacing", + "borderStartEndRadius", + "borderStartStartRadius", + "borderStyle", + "borderTop", + "borderTopColor", + "borderTopLeftRadius", + "borderTopRightRadius", + "borderTopStyle", + "borderTopWidth", + "borderWidth", + "bottom", + "bottomMargin", + "bound", + "boundElements", + "boundingClientRect", + "boundingHeight", + "boundingLeft", + "boundingTop", + "boundingWidth", + "bounds", + "boundsGeometry", + "box-decoration-break", + "box-shadow", + "box-sizing", + "boxDecorationBreak", + "boxShadow", + "boxSizing", + "brand", + "brands", + "break-after", + "break-before", + "break-inside", + "breakAfter", + "breakBefore", + "breakInside", + "broadcast", + "browserLanguage", + "btoa", + "bubbles", + "buffer", + "bufferData", + "bufferDepth", + "bufferSize", + "bufferSubData", + "buffered", + "bufferedAmount", + "bufferedAmountLowThreshold", + "buildID", + "buildNumber", + "button", + "buttonID", + "buttons", + "byteLength", + "byteOffset", + "bytesWritten", + "c", + "cache", + "caches", + "call", + "caller", + "canBeFormatted", + "canBeMounted", + "canBeShared", + "canHaveChildren", + "canHaveHTML", + "canInsertDTMF", + "canMakePayment", + "canPlayType", + "canPresent", + "canTrickleIceCandidates", + "cancel", + "cancelAndHoldAtTime", + "cancelAnimationFrame", + "cancelBubble", + "cancelIdleCallback", + "cancelScheduledValues", + "cancelVideoFrameCallback", + "cancelWatchAvailability", + "cancelable", + "candidate", + "canonicalUUID", + "canvas", + "capabilities", + "caption", + "caption-side", + "captionSide", + "capture", + "captureEvents", + "captureStackTrace", + "captureStream", + "caret-color", + "caretBidiLevel", + "caretColor", + "caretPositionFromPoint", + "caretRangeFromPoint", + "cast", + "catch", + "category", + "cbrt", + "cd", + "ceil", + "cellIndex", + "cellPadding", + "cellSpacing", + "cells", + "ch", + "chOff", + "chain", + "challenge", + "changeType", + "changedTouches", + "channel", + "channelCount", + "channelCountMode", + "channelInterpretation", + "char", + "charAt", + "charCode", + "charCodeAt", + "charIndex", + "charLength", + "characterData", + "characterDataOldValue", + "characterSet", + "characteristic", + "charging", + "chargingTime", + "charset", + "check", + "checkEnclosure", + "checkFramebufferStatus", + "checkIntersection", + "checkValidity", + "checked", + "childElementCount", + "childList", + "childNodes", + "children", + "chrome", + "ciphertext", + "cite", + "city", + "claimInterface", + "claimed", + "classList", + "className", + "classid", + "clear", + "clearAppBadge", + "clearAttributes", + "clearBufferfi", + "clearBufferfv", + "clearBufferiv", + "clearBufferuiv", + "clearColor", + "clearData", + "clearDepth", + "clearHalt", + "clearImmediate", + "clearInterval", + "clearLiveSeekableRange", + "clearMarks", + "clearMaxGCPauseAccumulator", + "clearMeasures", + "clearParameters", + "clearRect", + "clearResourceTimings", + "clearShadow", + "clearStencil", + "clearTimeout", + "clearWatch", + "click", + "clickCount", + "clientDataJSON", + "clientHeight", + "clientInformation", + "clientLeft", + "clientRect", + "clientRects", + "clientTop", + "clientWaitSync", + "clientWidth", + "clientX", + "clientY", + "clip", + "clip-path", + "clip-rule", + "clipBottom", + "clipLeft", + "clipPath", + "clipPathUnits", + "clipRight", + "clipRule", + "clipTop", + "clipboard", + "clipboardData", + "clone", + "cloneContents", + "cloneNode", + "cloneRange", + "close", + "closePath", + "closed", + "closest", + "clz", + "clz32", + "cm", + "cmp", + "code", + "codeBase", + "codePointAt", + "codeType", + "colSpan", + "collapse", + "collapseToEnd", + "collapseToStart", + "collapsed", + "collect", + "colno", + "color", + "color-adjust", + "color-interpolation", + "color-interpolation-filters", + "colorAdjust", + "colorDepth", + "colorInterpolation", + "colorInterpolationFilters", + "colorMask", + "colorType", + "cols", + "column-count", + "column-fill", + "column-gap", + "column-rule", + "column-rule-color", + "column-rule-style", + "column-rule-width", + "column-span", + "column-width", + "columnCount", + "columnFill", + "columnGap", + "columnNumber", + "columnRule", + "columnRuleColor", + "columnRuleStyle", + "columnRuleWidth", + "columnSpan", + "columnWidth", + "columns", + "command", + "commit", + "commitPreferences", + "commitStyles", + "commonAncestorContainer", + "compact", + "compareBoundaryPoints", + "compareDocumentPosition", + "compareEndPoints", + "compareExchange", + "compareNode", + "comparePoint", + "compatMode", + "compatible", + "compile", + "compileShader", + "compileStreaming", + "complete", + "component", + "componentFromPoint", + "composed", + "composedPath", + "composite", + "compositionEndOffset", + "compositionStartOffset", + "compressedTexImage2D", + "compressedTexImage3D", + "compressedTexSubImage2D", + "compressedTexSubImage3D", + "computedStyleMap", + "concat", + "conditionText", + "coneInnerAngle", + "coneOuterAngle", + "coneOuterGain", + "configurable", + "configuration", + "configurationName", + "configurationValue", + "configurations", + "confirm", + "confirmComposition", + "confirmSiteSpecificTrackingException", + "confirmWebWideTrackingException", + "connect", + "connectEnd", + "connectShark", + "connectStart", + "connected", + "connection", + "connectionList", + "connectionSpeed", + "connectionState", + "connections", + "console", + "consolidate", + "constraint", + "constrictionActive", + "construct", + "constructor", + "contactID", + "contain", + "containerId", + "containerName", + "containerSrc", + "containerType", + "contains", + "containsNode", + "content", + "contentBoxSize", + "contentDocument", + "contentEditable", + "contentHint", + "contentOverflow", + "contentRect", + "contentScriptType", + "contentStyleType", + "contentType", + "contentWindow", + "context", + "contextMenu", + "contextmenu", + "continue", + "continuePrimaryKey", + "continuous", + "control", + "controlTransferIn", + "controlTransferOut", + "controller", + "controls", + "controlsList", + "convertPointFromNode", + "convertQuadFromNode", + "convertRectFromNode", + "convertToBlob", + "convertToSpecifiedUnits", + "cookie", + "cookieEnabled", + "coords", + "copyBufferSubData", + "copyFromChannel", + "copyTexImage2D", + "copyTexSubImage2D", + "copyTexSubImage3D", + "copyToChannel", + "copyWithin", + "correspondingElement", + "correspondingUseElement", + "corruptedVideoFrames", + "cos", + "cosh", + "count", + "countReset", + "counter-increment", + "counter-reset", + "counter-set", + "counterIncrement", + "counterReset", + "counterSet", + "country", + "cpuClass", + "cpuSleepAllowed", + "create", + "createAnalyser", + "createAnswer", + "createAttribute", + "createAttributeNS", + "createBiquadFilter", + "createBuffer", + "createBufferSource", + "createCDATASection", + "createCSSStyleSheet", + "createCaption", + "createChannelMerger", + "createChannelSplitter", + "createComment", + "createConstantSource", + "createContextualFragment", + "createControlRange", + "createConvolver", + "createDTMFSender", + "createDataChannel", + "createDelay", + "createDelayNode", + "createDocument", + "createDocumentFragment", + "createDocumentType", + "createDynamicsCompressor", + "createElement", + "createElementNS", + "createEntityReference", + "createEvent", + "createEventObject", + "createExpression", + "createFramebuffer", + "createFunction", + "createGain", + "createGainNode", + "createHTML", + "createHTMLDocument", + "createIIRFilter", + "createImageBitmap", + "createImageData", + "createIndex", + "createJavaScriptNode", + "createLinearGradient", + "createMediaElementSource", + "createMediaKeys", + "createMediaStreamDestination", + "createMediaStreamSource", + "createMediaStreamTrackSource", + "createMutableFile", + "createNSResolver", + "createNodeIterator", + "createNotification", + "createObjectStore", + "createObjectURL", + "createOffer", + "createOscillator", + "createPanner", + "createPattern", + "createPeriodicWave", + "createPolicy", + "createPopup", + "createProcessingInstruction", + "createProgram", + "createQuery", + "createRadialGradient", + "createRange", + "createRangeCollection", + "createReader", + "createRenderbuffer", + "createSVGAngle", + "createSVGLength", + "createSVGMatrix", + "createSVGNumber", + "createSVGPathSegArcAbs", + "createSVGPathSegArcRel", + "createSVGPathSegClosePath", + "createSVGPathSegCurvetoCubicAbs", + "createSVGPathSegCurvetoCubicRel", + "createSVGPathSegCurvetoCubicSmoothAbs", + "createSVGPathSegCurvetoCubicSmoothRel", + "createSVGPathSegCurvetoQuadraticAbs", + "createSVGPathSegCurvetoQuadraticRel", + "createSVGPathSegCurvetoQuadraticSmoothAbs", + "createSVGPathSegCurvetoQuadraticSmoothRel", + "createSVGPathSegLinetoAbs", + "createSVGPathSegLinetoHorizontalAbs", + "createSVGPathSegLinetoHorizontalRel", + "createSVGPathSegLinetoRel", + "createSVGPathSegLinetoVerticalAbs", + "createSVGPathSegLinetoVerticalRel", + "createSVGPathSegMovetoAbs", + "createSVGPathSegMovetoRel", + "createSVGPoint", + "createSVGRect", + "createSVGTransform", + "createSVGTransformFromMatrix", + "createSampler", + "createScript", + "createScriptProcessor", + "createScriptURL", + "createSession", + "createShader", + "createShadowRoot", + "createStereoPanner", + "createStyleSheet", + "createTBody", + "createTFoot", + "createTHead", + "createTextNode", + "createTextRange", + "createTexture", + "createTouch", + "createTouchList", + "createTransformFeedback", + "createTreeWalker", + "createVertexArray", + "createWaveShaper", + "creationTime", + "credentials", + "crossOrigin", + "crossOriginIsolated", + "crypto", + "csi", + "csp", + "cssFloat", + "cssRules", + "cssText", + "cssValueType", + "ctrlKey", + "ctrlLeft", + "cues", + "cullFace", + "currentDirection", + "currentLocalDescription", + "currentNode", + "currentPage", + "currentRect", + "currentRemoteDescription", + "currentScale", + "currentScript", + "currentSrc", + "currentState", + "currentStyle", + "currentTarget", + "currentTime", + "currentTranslate", + "currentView", + "cursor", + "curve", + "customElements", + "customError", + "cx", + "cy", + "d", + "data", + "dataFld", + "dataFormatAs", + "dataLoss", + "dataLossMessage", + "dataPageSize", + "dataSrc", + "dataTransfer", + "database", + "databases", + "dataset", + "dateTime", + "db", + "debug", + "debuggerEnabled", + "declare", + "decode", + "decodeAudioData", + "decodeURI", + "decodeURIComponent", + "decodedBodySize", + "decoding", + "decodingInfo", + "decrypt", + "default", + "defaultCharset", + "defaultChecked", + "defaultMuted", + "defaultPlaybackRate", + "defaultPolicy", + "defaultPrevented", + "defaultRequest", + "defaultSelected", + "defaultStatus", + "defaultURL", + "defaultValue", + "defaultView", + "defaultstatus", + "defer", + "define", + "defineMagicFunction", + "defineMagicVariable", + "defineProperties", + "defineProperty", + "deg", + "delay", + "delayTime", + "delegatesFocus", + "delete", + "deleteBuffer", + "deleteCaption", + "deleteCell", + "deleteContents", + "deleteData", + "deleteDatabase", + "deleteFramebuffer", + "deleteFromDocument", + "deleteIndex", + "deleteMedium", + "deleteObjectStore", + "deleteProgram", + "deleteProperty", + "deleteQuery", + "deleteRenderbuffer", + "deleteRow", + "deleteRule", + "deleteSampler", + "deleteShader", + "deleteSync", + "deleteTFoot", + "deleteTHead", + "deleteTexture", + "deleteTransformFeedback", + "deleteVertexArray", + "deliverChangeRecords", + "delivery", + "deliveryInfo", + "deliveryStatus", + "deliveryTimestamp", + "delta", + "deltaMode", + "deltaX", + "deltaY", + "deltaZ", + "dependentLocality", + "depthFar", + "depthFunc", + "depthMask", + "depthNear", + "depthRange", + "deref", + "deriveBits", + "deriveKey", + "description", + "deselectAll", + "designMode", + "desiredSize", + "destination", + "destinationURL", + "detach", + "detachEvent", + "detachShader", + "detail", + "details", + "detect", + "detune", + "device", + "deviceClass", + "deviceId", + "deviceMemory", + "devicePixelContentBoxSize", + "devicePixelRatio", + "deviceProtocol", + "deviceSubclass", + "deviceVersionMajor", + "deviceVersionMinor", + "deviceVersionSubminor", + "deviceXDPI", + "deviceYDPI", + "didTimeout", + "diffuseConstant", + "digest", + "dimensions", + "dir", + "dirName", + "direction", + "dirxml", + "disable", + "disablePictureInPicture", + "disableRemotePlayback", + "disableVertexAttribArray", + "disabled", + "dischargingTime", + "disconnect", + "disconnectShark", + "dispatchEvent", + "display", + "displayId", + "displayName", + "disposition", + "distanceModel", + "div", + "divisor", + "djsapi", + "djsproxy", + "doImport", + "doNotTrack", + "doScroll", + "doctype", + "document", + "documentElement", + "documentMode", + "documentURI", + "dolphin", + "dolphinGameCenter", + "dolphininfo", + "dolphinmeta", + "domComplete", + "domContentLoadedEventEnd", + "domContentLoadedEventStart", + "domInteractive", + "domLoading", + "domOverlayState", + "domain", + "domainLookupEnd", + "domainLookupStart", + "dominant-baseline", + "dominantBaseline", + "done", + "dopplerFactor", + "dotAll", + "downDegrees", + "downlink", + "download", + "downloadTotal", + "downloaded", + "dpcm", + "dpi", + "dppx", + "dragDrop", + "draggable", + "drawArrays", + "drawArraysInstanced", + "drawArraysInstancedANGLE", + "drawBuffers", + "drawCustomFocusRing", + "drawElements", + "drawElementsInstanced", + "drawElementsInstancedANGLE", + "drawFocusIfNeeded", + "drawImage", + "drawImageFromRect", + "drawRangeElements", + "drawSystemFocusRing", + "drawingBufferHeight", + "drawingBufferWidth", + "dropEffect", + "droppedVideoFrames", + "dropzone", + "dtmf", + "dump", + "dumpProfile", + "duplicate", + "durability", + "duration", + "dvname", + "dvnum", + "dx", + "dy", + "dynsrc", + "e", + "edgeMode", + "effect", + "effectAllowed", + "effectiveDirective", + "effectiveType", + "elapsedTime", + "element", + "elementFromPoint", + "elementTiming", + "elements", + "elementsFromPoint", + "elevation", + "ellipse", + "em", + "email", + "embeds", + "emma", + "empty", + "empty-cells", + "emptyCells", + "emptyHTML", + "emptyScript", + "emulatedPosition", + "enable", + "enableBackground", + "enableDelegations", + "enableStyleSheetsForSet", + "enableVertexAttribArray", + "enabled", + "enabledPlugin", + "encode", + "encodeInto", + "encodeURI", + "encodeURIComponent", + "encodedBodySize", + "encoding", + "encodingInfo", + "encrypt", + "enctype", + "end", + "endContainer", + "endElement", + "endElementAt", + "endOfStream", + "endOffset", + "endQuery", + "endTime", + "endTransformFeedback", + "ended", + "endpoint", + "endpointNumber", + "endpoints", + "endsWith", + "enterKeyHint", + "entities", + "entries", + "entryType", + "enumerable", + "enumerate", + "enumerateDevices", + "enumerateEditable", + "environmentBlendMode", + "equals", + "error", + "errorCode", + "errorDetail", + "errorText", + "escape", + "estimate", + "eval", + "evaluate", + "event", + "eventPhase", + "every", + "ex", + "exception", + "exchange", + "exec", + "execCommand", + "execCommandShowHelp", + "execScript", + "exitFullscreen", + "exitPictureInPicture", + "exitPointerLock", + "exitPresent", + "exp", + "expand", + "expandEntityReferences", + "expando", + "expansion", + "expiration", + "expirationTime", + "expires", + "expiryDate", + "explicitOriginalTarget", + "expm1", + "exponent", + "exponentialRampToValueAtTime", + "exportKey", + "exports", + "extend", + "extensions", + "extentNode", + "extentOffset", + "external", + "externalResourcesRequired", + "extractContents", + "extractable", + "eye", + "f", + "face", + "factoryReset", + "failureReason", + "fallback", + "family", + "familyName", + "farthestViewportElement", + "fastSeek", + "fatal", + "featureId", + "featurePolicy", + "featureSettings", + "features", + "fenceSync", + "fetch", + "fetchStart", + "fftSize", + "fgColor", + "fieldOfView", + "file", + "fileCreatedDate", + "fileHandle", + "fileModifiedDate", + "fileName", + "fileSize", + "fileUpdatedDate", + "filename", + "files", + "filesystem", + "fill", + "fill-opacity", + "fill-rule", + "fillLightMode", + "fillOpacity", + "fillRect", + "fillRule", + "fillStyle", + "fillText", + "filter", + "filterResX", + "filterResY", + "filterUnits", + "filters", + "finally", + "find", + "findIndex", + "findRule", + "findText", + "finish", + "finished", + "fireEvent", + "firesTouchEvents", + "firstChild", + "firstElementChild", + "firstPage", + "fixed", + "flags", + "flat", + "flatMap", + "flex", + "flex-basis", + "flex-direction", + "flex-flow", + "flex-grow", + "flex-shrink", + "flex-wrap", + "flexBasis", + "flexDirection", + "flexFlow", + "flexGrow", + "flexShrink", + "flexWrap", + "flipX", + "flipY", + "float", + "float32", + "float64", + "flood-color", + "flood-opacity", + "floodColor", + "floodOpacity", + "floor", + "flush", + "focus", + "focusNode", + "focusOffset", + "font", + "font-family", + "font-feature-settings", + "font-kerning", + "font-language-override", + "font-optical-sizing", + "font-size", + "font-size-adjust", + "font-stretch", + "font-style", + "font-synthesis", + "font-variant", + "font-variant-alternates", + "font-variant-caps", + "font-variant-east-asian", + "font-variant-ligatures", + "font-variant-numeric", + "font-variant-position", + "font-variation-settings", + "font-weight", + "fontFamily", + "fontFeatureSettings", + "fontKerning", + "fontLanguageOverride", + "fontOpticalSizing", + "fontSize", + "fontSizeAdjust", + "fontSmoothingEnabled", + "fontStretch", + "fontStyle", + "fontSynthesis", + "fontVariant", + "fontVariantAlternates", + "fontVariantCaps", + "fontVariantEastAsian", + "fontVariantLigatures", + "fontVariantNumeric", + "fontVariantPosition", + "fontVariationSettings", + "fontWeight", + "fontcolor", + "fontfaces", + "fonts", + "fontsize", + "for", + "forEach", + "force", + "forceRedraw", + "form", + "formAction", + "formData", + "formEnctype", + "formMethod", + "formNoValidate", + "formTarget", + "format", + "formatToParts", + "forms", + "forward", + "forwardX", + "forwardY", + "forwardZ", + "foundation", + "fr", + "fragmentDirective", + "frame", + "frameBorder", + "frameElement", + "frameSpacing", + "framebuffer", + "framebufferHeight", + "framebufferRenderbuffer", + "framebufferTexture2D", + "framebufferTextureLayer", + "framebufferWidth", + "frames", + "freeSpace", + "freeze", + "frequency", + "frequencyBinCount", + "from", + "fromCharCode", + "fromCodePoint", + "fromElement", + "fromEntries", + "fromFloat32Array", + "fromFloat64Array", + "fromMatrix", + "fromPoint", + "fromQuad", + "fromRect", + "frontFace", + "fround", + "fullPath", + "fullScreen", + "fullVersionList", + "fullscreen", + "fullscreenElement", + "fullscreenEnabled", + "fx", + "fy", + "gain", + "gamepad", + "gamma", + "gap", + "gatheringState", + "gatt", + "genderIdentity", + "generateCertificate", + "generateKey", + "generateMipmap", + "generateRequest", + "geolocation", + "gestureObject", + "get", + "getActiveAttrib", + "getActiveUniform", + "getActiveUniformBlockName", + "getActiveUniformBlockParameter", + "getActiveUniforms", + "getAdjacentText", + "getAll", + "getAllKeys", + "getAllResponseHeaders", + "getAllowlistForFeature", + "getAnimations", + "getAsFile", + "getAsString", + "getAttachedShaders", + "getAttribLocation", + "getAttribute", + "getAttributeNS", + "getAttributeNames", + "getAttributeNode", + "getAttributeNodeNS", + "getAttributeType", + "getAudioTracks", + "getAvailability", + "getBBox", + "getBattery", + "getBigInt64", + "getBigUint64", + "getBlob", + "getBookmark", + "getBoundingClientRect", + "getBounds", + "getBoxQuads", + "getBufferParameter", + "getBufferSubData", + "getByteFrequencyData", + "getByteTimeDomainData", + "getCSSCanvasContext", + "getCTM", + "getCandidateWindowClientRect", + "getCanonicalLocales", + "getCapabilities", + "getChannelData", + "getCharNumAtPosition", + "getCharacteristic", + "getCharacteristics", + "getClientExtensionResults", + "getClientRect", + "getClientRects", + "getCoalescedEvents", + "getCompositionAlternatives", + "getComputedStyle", + "getComputedTextLength", + "getComputedTiming", + "getConfiguration", + "getConstraints", + "getContext", + "getContextAttributes", + "getContributingSources", + "getCounterValue", + "getCueAsHTML", + "getCueById", + "getCurrentPosition", + "getCurrentTime", + "getData", + "getDatabaseNames", + "getDate", + "getDay", + "getDefaultComputedStyle", + "getDescriptor", + "getDescriptors", + "getDestinationInsertionPoints", + "getDevices", + "getDirectory", + "getDisplayMedia", + "getDistributedNodes", + "getEditable", + "getElementById", + "getElementsByClassName", + "getElementsByName", + "getElementsByTagName", + "getElementsByTagNameNS", + "getEnclosureList", + "getEndPositionOfChar", + "getEntries", + "getEntriesByName", + "getEntriesByType", + "getError", + "getExtension", + "getExtentOfChar", + "getEyeParameters", + "getFeature", + "getFile", + "getFiles", + "getFilesAndDirectories", + "getFingerprints", + "getFloat32", + "getFloat64", + "getFloatFrequencyData", + "getFloatTimeDomainData", + "getFloatValue", + "getFragDataLocation", + "getFrameData", + "getFramebufferAttachmentParameter", + "getFrequencyResponse", + "getFullYear", + "getGamepads", + "getHighEntropyValues", + "getHitTestResults", + "getHitTestResultsForTransientInput", + "getHours", + "getIdentityAssertion", + "getIds", + "getImageData", + "getIndexedParameter", + "getInstalledRelatedApps", + "getInt16", + "getInt32", + "getInt8", + "getInternalformatParameter", + "getIntersectionList", + "getItem", + "getItems", + "getKey", + "getKeyframes", + "getLayers", + "getLayoutMap", + "getLineDash", + "getLocalCandidates", + "getLocalParameters", + "getLocalStreams", + "getMarks", + "getMatchedCSSRules", + "getMaxGCPauseSinceClear", + "getMeasures", + "getMetadata", + "getMilliseconds", + "getMinutes", + "getModifierState", + "getMonth", + "getNamedItem", + "getNamedItemNS", + "getNativeFramebufferScaleFactor", + "getNotifications", + "getNotifier", + "getNumberOfChars", + "getOffsetReferenceSpace", + "getOutputTimestamp", + "getOverrideHistoryNavigationMode", + "getOverrideStyle", + "getOwnPropertyDescriptor", + "getOwnPropertyDescriptors", + "getOwnPropertyNames", + "getOwnPropertySymbols", + "getParameter", + "getParameters", + "getParent", + "getPathSegAtLength", + "getPhotoCapabilities", + "getPhotoSettings", + "getPointAtLength", + "getPose", + "getPredictedEvents", + "getPreference", + "getPreferenceDefault", + "getPresentationAttribute", + "getPreventDefault", + "getPrimaryService", + "getPrimaryServices", + "getProgramInfoLog", + "getProgramParameter", + "getPropertyCSSValue", + "getPropertyPriority", + "getPropertyShorthand", + "getPropertyType", + "getPropertyValue", + "getPrototypeOf", + "getQuery", + "getQueryParameter", + "getRGBColorValue", + "getRandomValues", + "getRangeAt", + "getReader", + "getReceivers", + "getRectValue", + "getRegistration", + "getRegistrations", + "getRemoteCandidates", + "getRemoteCertificates", + "getRemoteParameters", + "getRemoteStreams", + "getRenderbufferParameter", + "getResponseHeader", + "getRoot", + "getRootNode", + "getRotationOfChar", + "getSVGDocument", + "getSamplerParameter", + "getScreenCTM", + "getSeconds", + "getSelectedCandidatePair", + "getSelection", + "getSenders", + "getService", + "getSettings", + "getShaderInfoLog", + "getShaderParameter", + "getShaderPrecisionFormat", + "getShaderSource", + "getSimpleDuration", + "getSiteIcons", + "getSources", + "getSpeculativeParserUrls", + "getStartPositionOfChar", + "getStartTime", + "getState", + "getStats", + "getStatusForPolicy", + "getStorageUpdates", + "getStreamById", + "getStringValue", + "getSubStringLength", + "getSubscription", + "getSupportedConstraints", + "getSupportedExtensions", + "getSupportedFormats", + "getSyncParameter", + "getSynchronizationSources", + "getTags", + "getTargetRanges", + "getTexParameter", + "getTime", + "getTimezoneOffset", + "getTiming", + "getTotalLength", + "getTrackById", + "getTracks", + "getTransceivers", + "getTransform", + "getTransformFeedbackVarying", + "getTransformToElement", + "getTransports", + "getType", + "getTypeMapping", + "getUTCDate", + "getUTCDay", + "getUTCFullYear", + "getUTCHours", + "getUTCMilliseconds", + "getUTCMinutes", + "getUTCMonth", + "getUTCSeconds", + "getUint16", + "getUint32", + "getUint8", + "getUniform", + "getUniformBlockIndex", + "getUniformIndices", + "getUniformLocation", + "getUserMedia", + "getVRDisplays", + "getValues", + "getVarDate", + "getVariableValue", + "getVertexAttrib", + "getVertexAttribOffset", + "getVideoPlaybackQuality", + "getVideoTracks", + "getViewerPose", + "getViewport", + "getVoices", + "getWakeLockState", + "getWriter", + "getYear", + "givenName", + "global", + "globalAlpha", + "globalCompositeOperation", + "globalThis", + "glyphOrientationHorizontal", + "glyphOrientationVertical", + "glyphRef", + "go", + "grabFrame", + "grad", + "gradientTransform", + "gradientUnits", + "grammars", + "green", + "grid", + "grid-area", + "grid-auto-columns", + "grid-auto-flow", + "grid-auto-rows", + "grid-column", + "grid-column-end", + "grid-column-gap", + "grid-column-start", + "grid-gap", + "grid-row", + "grid-row-end", + "grid-row-gap", + "grid-row-start", + "grid-template", + "grid-template-areas", + "grid-template-columns", + "grid-template-rows", + "gridArea", + "gridAutoColumns", + "gridAutoFlow", + "gridAutoRows", + "gridColumn", + "gridColumnEnd", + "gridColumnGap", + "gridColumnStart", + "gridGap", + "gridRow", + "gridRowEnd", + "gridRowGap", + "gridRowStart", + "gridTemplate", + "gridTemplateAreas", + "gridTemplateColumns", + "gridTemplateRows", + "gripSpace", + "group", + "groupCollapsed", + "groupEnd", + "groupId", + "hadRecentInput", + "hand", + "handedness", + "hapticActuators", + "hardwareConcurrency", + "has", + "hasAttribute", + "hasAttributeNS", + "hasAttributes", + "hasBeenActive", + "hasChildNodes", + "hasComposition", + "hasEnrolledInstrument", + "hasExtension", + "hasExternalDisplay", + "hasFeature", + "hasFocus", + "hasInstance", + "hasLayout", + "hasOrientation", + "hasOwnProperty", + "hasPointerCapture", + "hasPosition", + "hasReading", + "hasStorageAccess", + "hash", + "head", + "headers", + "heading", + "height", + "hidden", + "hide", + "hideFocus", + "high", + "highWaterMark", + "hint", + "history", + "honorificPrefix", + "honorificSuffix", + "horizontalOverflow", + "host", + "hostCandidate", + "hostname", + "href", + "hrefTranslate", + "hreflang", + "hspace", + "html5TagCheckInerface", + "htmlFor", + "htmlText", + "httpEquiv", + "httpRequestStatusCode", + "hwTimestamp", + "hyphens", + "hypot", + "iccId", + "iceConnectionState", + "iceGatheringState", + "iceTransport", + "icon", + "iconURL", + "id", + "identifier", + "identity", + "idpLoginUrl", + "ignoreBOM", + "ignoreCase", + "ignoreDepthValues", + "image-orientation", + "image-rendering", + "imageHeight", + "imageOrientation", + "imageRendering", + "imageSizes", + "imageSmoothingEnabled", + "imageSmoothingQuality", + "imageSrcset", + "imageWidth", + "images", + "ime-mode", + "imeMode", + "implementation", + "importKey", + "importNode", + "importStylesheet", + "imports", + "impp", + "imul", + "in", + "in1", + "in2", + "inBandMetadataTrackDispatchType", + "inRange", + "includes", + "incremental", + "indeterminate", + "index", + "indexNames", + "indexOf", + "indexedDB", + "indicate", + "inert", + "inertiaDestinationX", + "inertiaDestinationY", + "info", + "init", + "initAnimationEvent", + "initBeforeLoadEvent", + "initClipboardEvent", + "initCloseEvent", + "initCommandEvent", + "initCompositionEvent", + "initCustomEvent", + "initData", + "initDataType", + "initDeviceMotionEvent", + "initDeviceOrientationEvent", + "initDragEvent", + "initErrorEvent", + "initEvent", + "initFocusEvent", + "initGestureEvent", + "initHashChangeEvent", + "initKeyEvent", + "initKeyboardEvent", + "initMSManipulationEvent", + "initMessageEvent", + "initMouseEvent", + "initMouseScrollEvent", + "initMouseWheelEvent", + "initMutationEvent", + "initNSMouseEvent", + "initOverflowEvent", + "initPageEvent", + "initPageTransitionEvent", + "initPointerEvent", + "initPopStateEvent", + "initProgressEvent", + "initScrollAreaEvent", + "initSimpleGestureEvent", + "initStorageEvent", + "initTextEvent", + "initTimeEvent", + "initTouchEvent", + "initTransitionEvent", + "initUIEvent", + "initWebKitAnimationEvent", + "initWebKitTransitionEvent", + "initWebKitWheelEvent", + "initWheelEvent", + "initialTime", + "initialize", + "initiatorType", + "inline-size", + "inlineSize", + "inlineVerticalFieldOfView", + "inner", + "innerHTML", + "innerHeight", + "innerText", + "innerWidth", + "input", + "inputBuffer", + "inputEncoding", + "inputMethod", + "inputMode", + "inputSource", + "inputSources", + "inputType", + "inputs", + "insertAdjacentElement", + "insertAdjacentHTML", + "insertAdjacentText", + "insertBefore", + "insertCell", + "insertDTMF", + "insertData", + "insertItemBefore", + "insertNode", + "insertRow", + "insertRule", + "inset", + "inset-block", + "inset-block-end", + "inset-block-start", + "inset-inline", + "inset-inline-end", + "inset-inline-start", + "insetBlock", + "insetBlockEnd", + "insetBlockStart", + "insetInline", + "insetInlineEnd", + "insetInlineStart", + "installing", + "instanceRoot", + "instantiate", + "instantiateStreaming", + "instruments", + "int16", + "int32", + "int8", + "integrity", + "interactionMode", + "intercept", + "interfaceClass", + "interfaceName", + "interfaceNumber", + "interfaceProtocol", + "interfaceSubclass", + "interfaces", + "interimResults", + "internalSubset", + "interpretation", + "intersectionRatio", + "intersectionRect", + "intersectsNode", + "interval", + "invalidIteratorState", + "invalidateFramebuffer", + "invalidateSubFramebuffer", + "inverse", + "invertSelf", + "is", + "is2D", + "isActive", + "isAlternate", + "isArray", + "isBingCurrentSearchDefault", + "isBuffer", + "isCandidateWindowVisible", + "isChar", + "isCollapsed", + "isComposing", + "isConcatSpreadable", + "isConnected", + "isContentEditable", + "isContentHandlerRegistered", + "isContextLost", + "isDefaultNamespace", + "isDirectory", + "isDisabled", + "isEnabled", + "isEqual", + "isEqualNode", + "isExtensible", + "isExternalCTAP2SecurityKeySupported", + "isFile", + "isFinite", + "isFramebuffer", + "isFrozen", + "isGenerator", + "isHTML", + "isHistoryNavigation", + "isId", + "isIdentity", + "isInjected", + "isInteger", + "isIntersecting", + "isLockFree", + "isMap", + "isMultiLine", + "isNaN", + "isOpen", + "isPointInFill", + "isPointInPath", + "isPointInRange", + "isPointInStroke", + "isPrefAlternate", + "isPresenting", + "isPrimary", + "isProgram", + "isPropertyImplicit", + "isProtocolHandlerRegistered", + "isPrototypeOf", + "isQuery", + "isRenderbuffer", + "isSafeInteger", + "isSameNode", + "isSampler", + "isScript", + "isScriptURL", + "isSealed", + "isSecureContext", + "isSessionSupported", + "isShader", + "isSupported", + "isSync", + "isTextEdit", + "isTexture", + "isTransformFeedback", + "isTrusted", + "isTypeSupported", + "isUserVerifyingPlatformAuthenticatorAvailable", + "isVertexArray", + "isView", + "isVisible", + "isochronousTransferIn", + "isochronousTransferOut", + "isolation", + "italics", + "item", + "itemId", + "itemProp", + "itemRef", + "itemScope", + "itemType", + "itemValue", + "items", + "iterateNext", + "iterationComposite", + "iterator", + "javaEnabled", + "jobTitle", + "join", + "json", + "justify-content", + "justify-items", + "justify-self", + "justifyContent", + "justifyItems", + "justifySelf", + "k1", + "k2", + "k3", + "k4", + "kHz", + "keepalive", + "kernelMatrix", + "kernelUnitLengthX", + "kernelUnitLengthY", + "kerning", + "key", + "keyCode", + "keyFor", + "keyIdentifier", + "keyLightEnabled", + "keyLocation", + "keyPath", + "keyStatuses", + "keySystem", + "keyText", + "keyUsage", + "keyboard", + "keys", + "keytype", + "kind", + "knee", + "label", + "labels", + "lang", + "language", + "languages", + "largeArcFlag", + "lastChild", + "lastElementChild", + "lastEventId", + "lastIndex", + "lastIndexOf", + "lastInputTime", + "lastMatch", + "lastMessageSubject", + "lastMessageType", + "lastModified", + "lastModifiedDate", + "lastPage", + "lastParen", + "lastState", + "lastStyleSheetSet", + "latitude", + "layerX", + "layerY", + "layoutFlow", + "layoutGrid", + "layoutGridChar", + "layoutGridLine", + "layoutGridMode", + "layoutGridType", + "lbound", + "left", + "leftContext", + "leftDegrees", + "leftMargin", + "leftProjectionMatrix", + "leftViewMatrix", + "length", + "lengthAdjust", + "lengthComputable", + "letter-spacing", + "letterSpacing", + "level", + "lighting-color", + "lightingColor", + "limitingConeAngle", + "line", + "line-break", + "line-height", + "lineAlign", + "lineBreak", + "lineCap", + "lineDashOffset", + "lineHeight", + "lineJoin", + "lineNumber", + "lineTo", + "lineWidth", + "linearAcceleration", + "linearRampToValueAtTime", + "linearVelocity", + "lineno", + "lines", + "link", + "linkColor", + "linkProgram", + "links", + "list", + "list-style", + "list-style-image", + "list-style-position", + "list-style-type", + "listStyle", + "listStyleImage", + "listStylePosition", + "listStyleType", + "listener", + "load", + "loadEventEnd", + "loadEventStart", + "loadTime", + "loadTimes", + "loaded", + "loading", + "localDescription", + "localName", + "localService", + "localStorage", + "locale", + "localeCompare", + "location", + "locationbar", + "lock", + "locked", + "lockedFile", + "locks", + "log", + "log10", + "log1p", + "log2", + "logicalXDPI", + "logicalYDPI", + "longDesc", + "longitude", + "lookupNamespaceURI", + "lookupPrefix", + "loop", + "loopEnd", + "loopStart", + "looping", + "low", + "lower", + "lowerBound", + "lowerOpen", + "lowsrc", + "m11", + "m12", + "m13", + "m14", + "m21", + "m22", + "m23", + "m24", + "m31", + "m32", + "m33", + "m34", + "m41", + "m42", + "m43", + "m44", + "makeXRCompatible", + "manifest", + "manufacturer", + "manufacturerName", + "map", + "mapping", + "margin", + "margin-block", + "margin-block-end", + "margin-block-start", + "margin-bottom", + "margin-inline", + "margin-inline-end", + "margin-inline-start", + "margin-left", + "margin-right", + "margin-top", + "marginBlock", + "marginBlockEnd", + "marginBlockStart", + "marginBottom", + "marginHeight", + "marginInline", + "marginInlineEnd", + "marginInlineStart", + "marginLeft", + "marginRight", + "marginTop", + "marginWidth", + "mark", + "marker", + "marker-end", + "marker-mid", + "marker-offset", + "marker-start", + "markerEnd", + "markerHeight", + "markerMid", + "markerOffset", + "markerStart", + "markerUnits", + "markerWidth", + "marks", + "mask", + "mask-clip", + "mask-composite", + "mask-image", + "mask-mode", + "mask-origin", + "mask-position", + "mask-position-x", + "mask-position-y", + "mask-repeat", + "mask-size", + "mask-type", + "maskClip", + "maskComposite", + "maskContentUnits", + "maskImage", + "maskMode", + "maskOrigin", + "maskPosition", + "maskPositionX", + "maskPositionY", + "maskRepeat", + "maskSize", + "maskType", + "maskUnits", + "match", + "matchAll", + "matchMedia", + "matchMedium", + "matches", + "matrix", + "matrixTransform", + "max", + "max-block-size", + "max-height", + "max-inline-size", + "max-width", + "maxActions", + "maxAlternatives", + "maxBlockSize", + "maxChannelCount", + "maxChannels", + "maxConnectionsPerServer", + "maxDecibels", + "maxDistance", + "maxHeight", + "maxInlineSize", + "maxLayers", + "maxLength", + "maxMessageSize", + "maxPacketLifeTime", + "maxRetransmits", + "maxTouchPoints", + "maxValue", + "maxWidth", + "measure", + "measureText", + "media", + "mediaCapabilities", + "mediaDevices", + "mediaElement", + "mediaGroup", + "mediaKeys", + "mediaSession", + "mediaStream", + "mediaText", + "meetOrSlice", + "memory", + "menubar", + "mergeAttributes", + "message", + "messageClass", + "messageHandlers", + "messageType", + "metaKey", + "metadata", + "method", + "methodDetails", + "methodName", + "mid", + "mimeType", + "mimeTypes", + "min", + "min-block-size", + "min-height", + "min-inline-size", + "min-width", + "minBlockSize", + "minDecibels", + "minHeight", + "minInlineSize", + "minLength", + "minValue", + "minWidth", + "miterLimit", + "mix-blend-mode", + "mixBlendMode", + "mm", + "mobile", + "mode", + "model", + "modify", + "mount", + "move", + "moveBy", + "moveEnd", + "moveFirst", + "moveFocusDown", + "moveFocusLeft", + "moveFocusRight", + "moveFocusUp", + "moveNext", + "moveRow", + "moveStart", + "moveTo", + "moveToBookmark", + "moveToElementText", + "moveToPoint", + "movementX", + "movementY", + "mozAdd", + "mozAnimationStartTime", + "mozAnon", + "mozApps", + "mozAudioCaptured", + "mozAudioChannelType", + "mozAutoplayEnabled", + "mozCancelAnimationFrame", + "mozCancelFullScreen", + "mozCancelRequestAnimationFrame", + "mozCaptureStream", + "mozCaptureStreamUntilEnded", + "mozClearDataAt", + "mozContact", + "mozContacts", + "mozCreateFileHandle", + "mozCurrentTransform", + "mozCurrentTransformInverse", + "mozCursor", + "mozDash", + "mozDashOffset", + "mozDecodedFrames", + "mozExitPointerLock", + "mozFillRule", + "mozFragmentEnd", + "mozFrameDelay", + "mozFullScreen", + "mozFullScreenElement", + "mozFullScreenEnabled", + "mozGetAll", + "mozGetAllKeys", + "mozGetAsFile", + "mozGetDataAt", + "mozGetMetadata", + "mozGetUserMedia", + "mozHasAudio", + "mozHasItem", + "mozHidden", + "mozImageSmoothingEnabled", + "mozIndexedDB", + "mozInnerScreenX", + "mozInnerScreenY", + "mozInputSource", + "mozIsTextField", + "mozItem", + "mozItemCount", + "mozItems", + "mozLength", + "mozLockOrientation", + "mozMatchesSelector", + "mozMovementX", + "mozMovementY", + "mozOpaque", + "mozOrientation", + "mozPaintCount", + "mozPaintedFrames", + "mozParsedFrames", + "mozPay", + "mozPointerLockElement", + "mozPresentedFrames", + "mozPreservesPitch", + "mozPressure", + "mozPrintCallback", + "mozRTCIceCandidate", + "mozRTCPeerConnection", + "mozRTCSessionDescription", + "mozRemove", + "mozRequestAnimationFrame", + "mozRequestFullScreen", + "mozRequestPointerLock", + "mozSetDataAt", + "mozSetImageElement", + "mozSourceNode", + "mozSrcObject", + "mozSystem", + "mozTCPSocket", + "mozTextStyle", + "mozTypesAt", + "mozUnlockOrientation", + "mozUserCancelled", + "mozVisibilityState", + "ms", + "msAnimation", + "msAnimationDelay", + "msAnimationDirection", + "msAnimationDuration", + "msAnimationFillMode", + "msAnimationIterationCount", + "msAnimationName", + "msAnimationPlayState", + "msAnimationStartTime", + "msAnimationTimingFunction", + "msBackfaceVisibility", + "msBlockProgression", + "msCSSOMElementFloatMetrics", + "msCaching", + "msCachingEnabled", + "msCancelRequestAnimationFrame", + "msCapsLockWarningOff", + "msClearImmediate", + "msClose", + "msContentZoomChaining", + "msContentZoomFactor", + "msContentZoomLimit", + "msContentZoomLimitMax", + "msContentZoomLimitMin", + "msContentZoomSnap", + "msContentZoomSnapPoints", + "msContentZoomSnapType", + "msContentZooming", + "msConvertURL", + "msCrypto", + "msDoNotTrack", + "msElementsFromPoint", + "msElementsFromRect", + "msExitFullscreen", + "msExtendedCode", + "msFillRule", + "msFirstPaint", + "msFlex", + "msFlexAlign", + "msFlexDirection", + "msFlexFlow", + "msFlexItemAlign", + "msFlexLinePack", + "msFlexNegative", + "msFlexOrder", + "msFlexPack", + "msFlexPositive", + "msFlexPreferredSize", + "msFlexWrap", + "msFlowFrom", + "msFlowInto", + "msFontFeatureSettings", + "msFullscreenElement", + "msFullscreenEnabled", + "msGetInputContext", + "msGetRegionContent", + "msGetUntransformedBounds", + "msGraphicsTrustStatus", + "msGridColumn", + "msGridColumnAlign", + "msGridColumnSpan", + "msGridColumns", + "msGridRow", + "msGridRowAlign", + "msGridRowSpan", + "msGridRows", + "msHidden", + "msHighContrastAdjust", + "msHyphenateLimitChars", + "msHyphenateLimitLines", + "msHyphenateLimitZone", + "msHyphens", + "msImageSmoothingEnabled", + "msImeAlign", + "msIndexedDB", + "msInterpolationMode", + "msIsStaticHTML", + "msKeySystem", + "msKeys", + "msLaunchUri", + "msLockOrientation", + "msManipulationViewsEnabled", + "msMatchMedia", + "msMatchesSelector", + "msMaxTouchPoints", + "msOrientation", + "msOverflowStyle", + "msPerspective", + "msPerspectiveOrigin", + "msPlayToDisabled", + "msPlayToPreferredSourceUri", + "msPlayToPrimary", + "msPointerEnabled", + "msRegionOverflow", + "msReleasePointerCapture", + "msRequestAnimationFrame", + "msRequestFullscreen", + "msSaveBlob", + "msSaveOrOpenBlob", + "msScrollChaining", + "msScrollLimit", + "msScrollLimitXMax", + "msScrollLimitXMin", + "msScrollLimitYMax", + "msScrollLimitYMin", + "msScrollRails", + "msScrollSnapPointsX", + "msScrollSnapPointsY", + "msScrollSnapType", + "msScrollSnapX", + "msScrollSnapY", + "msScrollTranslation", + "msSetImmediate", + "msSetMediaKeys", + "msSetPointerCapture", + "msTextCombineHorizontal", + "msTextSizeAdjust", + "msToBlob", + "msTouchAction", + "msTouchSelect", + "msTraceAsyncCallbackCompleted", + "msTraceAsyncCallbackStarting", + "msTraceAsyncOperationCompleted", + "msTraceAsyncOperationStarting", + "msTransform", + "msTransformOrigin", + "msTransformStyle", + "msTransition", + "msTransitionDelay", + "msTransitionDuration", + "msTransitionProperty", + "msTransitionTimingFunction", + "msUnlockOrientation", + "msUpdateAsyncCallbackRelation", + "msUserSelect", + "msVisibilityState", + "msWrapFlow", + "msWrapMargin", + "msWrapThrough", + "msWriteProfilerMark", + "msZoom", + "msZoomTo", + "mt", + "mul", + "multiEntry", + "multiSelectionObj", + "multiline", + "multiple", + "multiply", + "multiplySelf", + "mutableFile", + "muted", + "n", + "name", + "nameProp", + "namedItem", + "namedRecordset", + "names", + "namespaceURI", + "namespaces", + "naturalHeight", + "naturalWidth", + "navigate", + "navigation", + "navigationMode", + "navigationPreload", + "navigationStart", + "navigator", + "near", + "nearestViewportElement", + "negative", + "negotiated", + "netscape", + "networkState", + "newScale", + "newTranslate", + "newURL", + "newValue", + "newValueSpecifiedUnits", + "newVersion", + "newhome", + "next", + "nextElementSibling", + "nextHopProtocol", + "nextNode", + "nextPage", + "nextSibling", + "nickname", + "noHref", + "noModule", + "noResize", + "noShade", + "noValidate", + "noWrap", + "node", + "nodeName", + "nodeType", + "nodeValue", + "nonce", + "normalize", + "normalizedPathSegList", + "notationName", + "notations", + "note", + "noteGrainOn", + "noteOff", + "noteOn", + "notify", + "now", + "numOctaves", + "number", + "numberOfChannels", + "numberOfInputs", + "numberOfItems", + "numberOfOutputs", + "numberValue", + "oMatchesSelector", + "object", + "object-fit", + "object-position", + "objectFit", + "objectPosition", + "objectStore", + "objectStoreNames", + "objectType", + "observe", + "of", + "offscreenBuffering", + "offset", + "offset-anchor", + "offset-distance", + "offset-path", + "offset-rotate", + "offsetAnchor", + "offsetDistance", + "offsetHeight", + "offsetLeft", + "offsetNode", + "offsetParent", + "offsetPath", + "offsetRotate", + "offsetTop", + "offsetWidth", + "offsetX", + "offsetY", + "ok", + "oldURL", + "oldValue", + "oldVersion", + "olderShadowRoot", + "onLine", + "onabort", + "onabsolutedeviceorientation", + "onactivate", + "onactive", + "onaddsourcebuffer", + "onaddstream", + "onaddtrack", + "onafterprint", + "onafterscriptexecute", + "onafterupdate", + "onanimationcancel", + "onanimationend", + "onanimationiteration", + "onanimationstart", + "onappinstalled", + "onaudioend", + "onaudioprocess", + "onaudiostart", + "onautocomplete", + "onautocompleteerror", + "onauxclick", + "onbeforeactivate", + "onbeforecopy", + "onbeforecut", + "onbeforedeactivate", + "onbeforeeditfocus", + "onbeforeinstallprompt", + "onbeforepaste", + "onbeforeprint", + "onbeforescriptexecute", + "onbeforeunload", + "onbeforeupdate", + "onbeforexrselect", + "onbegin", + "onblocked", + "onblur", + "onbounce", + "onboundary", + "onbufferedamountlow", + "oncached", + "oncancel", + "oncandidatewindowhide", + "oncandidatewindowshow", + "oncandidatewindowupdate", + "oncanplay", + "oncanplaythrough", + "once", + "oncellchange", + "onchange", + "oncharacteristicvaluechanged", + "onchargingchange", + "onchargingtimechange", + "onchecking", + "onclick", + "onclose", + "onclosing", + "oncompassneedscalibration", + "oncomplete", + "onconnect", + "onconnecting", + "onconnectionavailable", + "onconnectionstatechange", + "oncontextmenu", + "oncontrollerchange", + "oncontrolselect", + "oncopy", + "oncuechange", + "oncut", + "ondataavailable", + "ondatachannel", + "ondatasetchanged", + "ondatasetcomplete", + "ondblclick", + "ondeactivate", + "ondevicechange", + "ondevicelight", + "ondevicemotion", + "ondeviceorientation", + "ondeviceorientationabsolute", + "ondeviceproximity", + "ondischargingtimechange", + "ondisconnect", + "ondisplay", + "ondownloading", + "ondrag", + "ondragend", + "ondragenter", + "ondragexit", + "ondragleave", + "ondragover", + "ondragstart", + "ondrop", + "ondurationchange", + "onemptied", + "onencrypted", + "onend", + "onended", + "onenter", + "onenterpictureinpicture", + "onerror", + "onerrorupdate", + "onexit", + "onfilterchange", + "onfinish", + "onfocus", + "onfocusin", + "onfocusout", + "onformdata", + "onfreeze", + "onfullscreenchange", + "onfullscreenerror", + "ongatheringstatechange", + "ongattserverdisconnected", + "ongesturechange", + "ongestureend", + "ongesturestart", + "ongotpointercapture", + "onhashchange", + "onhelp", + "onicecandidate", + "onicecandidateerror", + "oniceconnectionstatechange", + "onicegatheringstatechange", + "oninactive", + "oninput", + "oninputsourceschange", + "oninvalid", + "onkeydown", + "onkeypress", + "onkeystatuseschange", + "onkeyup", + "onlanguagechange", + "onlayoutcomplete", + "onleavepictureinpicture", + "onlevelchange", + "onload", + "onloadeddata", + "onloadedmetadata", + "onloadend", + "onloading", + "onloadingdone", + "onloadingerror", + "onloadstart", + "onlosecapture", + "onlostpointercapture", + "only", + "onmark", + "onmessage", + "onmessageerror", + "onmidimessage", + "onmousedown", + "onmouseenter", + "onmouseleave", + "onmousemove", + "onmouseout", + "onmouseover", + "onmouseup", + "onmousewheel", + "onmove", + "onmoveend", + "onmovestart", + "onmozfullscreenchange", + "onmozfullscreenerror", + "onmozorientationchange", + "onmozpointerlockchange", + "onmozpointerlockerror", + "onmscontentzoom", + "onmsfullscreenchange", + "onmsfullscreenerror", + "onmsgesturechange", + "onmsgesturedoubletap", + "onmsgestureend", + "onmsgesturehold", + "onmsgesturestart", + "onmsgesturetap", + "onmsgotpointercapture", + "onmsinertiastart", + "onmslostpointercapture", + "onmsmanipulationstatechanged", + "onmsneedkey", + "onmsorientationchange", + "onmspointercancel", + "onmspointerdown", + "onmspointerenter", + "onmspointerhover", + "onmspointerleave", + "onmspointermove", + "onmspointerout", + "onmspointerover", + "onmspointerup", + "onmssitemodejumplistitemremoved", + "onmsthumbnailclick", + "onmute", + "onnegotiationneeded", + "onnomatch", + "onnoupdate", + "onobsolete", + "onoffline", + "ononline", + "onopen", + "onorientationchange", + "onpagechange", + "onpagehide", + "onpageshow", + "onpaste", + "onpause", + "onpayerdetailchange", + "onpaymentmethodchange", + "onplay", + "onplaying", + "onpluginstreamstart", + "onpointercancel", + "onpointerdown", + "onpointerenter", + "onpointerleave", + "onpointerlockchange", + "onpointerlockerror", + "onpointermove", + "onpointerout", + "onpointerover", + "onpointerrawupdate", + "onpointerup", + "onpopstate", + "onprocessorerror", + "onprogress", + "onpropertychange", + "onratechange", + "onreading", + "onreadystatechange", + "onrejectionhandled", + "onrelease", + "onremove", + "onremovesourcebuffer", + "onremovestream", + "onremovetrack", + "onrepeat", + "onreset", + "onresize", + "onresizeend", + "onresizestart", + "onresourcetimingbufferfull", + "onresult", + "onresume", + "onrowenter", + "onrowexit", + "onrowsdelete", + "onrowsinserted", + "onscroll", + "onsearch", + "onsecuritypolicyviolation", + "onseeked", + "onseeking", + "onselect", + "onselectedcandidatepairchange", + "onselectend", + "onselectionchange", + "onselectstart", + "onshippingaddresschange", + "onshippingoptionchange", + "onshow", + "onsignalingstatechange", + "onsoundend", + "onsoundstart", + "onsourceclose", + "onsourceclosed", + "onsourceended", + "onsourceopen", + "onspeechend", + "onspeechstart", + "onsqueeze", + "onsqueezeend", + "onsqueezestart", + "onstalled", + "onstart", + "onstatechange", + "onstop", + "onstorage", + "onstoragecommit", + "onsubmit", + "onsuccess", + "onsuspend", + "onterminate", + "ontextinput", + "ontimeout", + "ontimeupdate", + "ontoggle", + "ontonechange", + "ontouchcancel", + "ontouchend", + "ontouchmove", + "ontouchstart", + "ontrack", + "ontransitioncancel", + "ontransitionend", + "ontransitionrun", + "ontransitionstart", + "onunhandledrejection", + "onunload", + "onunmute", + "onupdate", + "onupdateend", + "onupdatefound", + "onupdateready", + "onupdatestart", + "onupgradeneeded", + "onuserproximity", + "onversionchange", + "onvisibilitychange", + "onvoiceschanged", + "onvolumechange", + "onvrdisplayactivate", + "onvrdisplayconnect", + "onvrdisplaydeactivate", + "onvrdisplaydisconnect", + "onvrdisplaypresentchange", + "onwaiting", + "onwaitingforkey", + "onwarning", + "onwebkitanimationend", + "onwebkitanimationiteration", + "onwebkitanimationstart", + "onwebkitcurrentplaybacktargetiswirelesschanged", + "onwebkitfullscreenchange", + "onwebkitfullscreenerror", + "onwebkitkeyadded", + "onwebkitkeyerror", + "onwebkitkeymessage", + "onwebkitneedkey", + "onwebkitorientationchange", + "onwebkitplaybacktargetavailabilitychanged", + "onwebkitpointerlockchange", + "onwebkitpointerlockerror", + "onwebkitresourcetimingbufferfull", + "onwebkittransitionend", + "onwheel", + "onzoom", + "opacity", + "open", + "openCursor", + "openDatabase", + "openKeyCursor", + "opened", + "opener", + "opera", + "operationType", + "operator", + "opr", + "optimum", + "options", + "or", + "order", + "orderX", + "orderY", + "ordered", + "org", + "organization", + "orient", + "orientAngle", + "orientType", + "orientation", + "orientationX", + "orientationY", + "orientationZ", + "origin", + "originalPolicy", + "originalTarget", + "orphans", + "oscpu", + "outerHTML", + "outerHeight", + "outerText", + "outerWidth", + "outline", + "outline-color", + "outline-offset", + "outline-style", + "outline-width", + "outlineColor", + "outlineOffset", + "outlineStyle", + "outlineWidth", + "outputBuffer", + "outputChannelCount", + "outputLatency", + "outputs", + "overflow", + "overflow-anchor", + "overflow-block", + "overflow-inline", + "overflow-wrap", + "overflow-x", + "overflow-y", + "overflowAnchor", + "overflowBlock", + "overflowInline", + "overflowWrap", + "overflowX", + "overflowY", + "overrideMimeType", + "oversample", + "overscroll-behavior", + "overscroll-behavior-block", + "overscroll-behavior-inline", + "overscroll-behavior-x", + "overscroll-behavior-y", + "overscrollBehavior", + "overscrollBehaviorBlock", + "overscrollBehaviorInline", + "overscrollBehaviorX", + "overscrollBehaviorY", + "ownKeys", + "ownerDocument", + "ownerElement", + "ownerNode", + "ownerRule", + "ownerSVGElement", + "owningElement", + "p1", + "p2", + "p3", + "p4", + "packetSize", + "packets", + "pad", + "padEnd", + "padStart", + "padding", + "padding-block", + "padding-block-end", + "padding-block-start", + "padding-bottom", + "padding-inline", + "padding-inline-end", + "padding-inline-start", + "padding-left", + "padding-right", + "padding-top", + "paddingBlock", + "paddingBlockEnd", + "paddingBlockStart", + "paddingBottom", + "paddingInline", + "paddingInlineEnd", + "paddingInlineStart", + "paddingLeft", + "paddingRight", + "paddingTop", + "page", + "page-break-after", + "page-break-before", + "page-break-inside", + "pageBreakAfter", + "pageBreakBefore", + "pageBreakInside", + "pageCount", + "pageLeft", + "pageTop", + "pageX", + "pageXOffset", + "pageY", + "pageYOffset", + "pages", + "paint-order", + "paintOrder", + "paintRequests", + "paintType", + "paintWorklet", + "palette", + "pan", + "panningModel", + "parameterData", + "parameters", + "parent", + "parentElement", + "parentNode", + "parentRule", + "parentStyleSheet", + "parentTextEdit", + "parentWindow", + "parse", + "parseAll", + "parseFloat", + "parseFromString", + "parseInt", + "part", + "participants", + "passive", + "password", + "pasteHTML", + "path", + "pathLength", + "pathSegList", + "pathSegType", + "pathSegTypeAsLetter", + "pathname", + "pattern", + "patternContentUnits", + "patternMismatch", + "patternTransform", + "patternUnits", + "pause", + "pauseAnimations", + "pauseOnExit", + "pauseProfilers", + "pauseTransformFeedback", + "paused", + "payerEmail", + "payerName", + "payerPhone", + "paymentManager", + "pc", + "peerIdentity", + "pending", + "pendingLocalDescription", + "pendingRemoteDescription", + "percent", + "performance", + "periodicSync", + "permission", + "permissionState", + "permissions", + "persist", + "persisted", + "personalbar", + "perspective", + "perspective-origin", + "perspectiveOrigin", + "phone", + "phoneticFamilyName", + "phoneticGivenName", + "photo", + "pictureInPictureElement", + "pictureInPictureEnabled", + "pictureInPictureWindow", + "ping", + "pipeThrough", + "pipeTo", + "pitch", + "pixelBottom", + "pixelDepth", + "pixelHeight", + "pixelLeft", + "pixelRight", + "pixelStorei", + "pixelTop", + "pixelUnitToMillimeterX", + "pixelUnitToMillimeterY", + "pixelWidth", + "place-content", + "place-items", + "place-self", + "placeContent", + "placeItems", + "placeSelf", + "placeholder", + "platformVersion", + "platform", + "platforms", + "play", + "playEffect", + "playState", + "playbackRate", + "playbackState", + "playbackTime", + "played", + "playoutDelayHint", + "playsInline", + "plugins", + "pluginspage", + "pname", + "pointer-events", + "pointerBeforeReferenceNode", + "pointerEnabled", + "pointerEvents", + "pointerId", + "pointerLockElement", + "pointerType", + "points", + "pointsAtX", + "pointsAtY", + "pointsAtZ", + "polygonOffset", + "pop", + "populateMatrix", + "popupWindowFeatures", + "popupWindowName", + "popupWindowURI", + "port", + "port1", + "port2", + "ports", + "posBottom", + "posHeight", + "posLeft", + "posRight", + "posTop", + "posWidth", + "pose", + "position", + "positionAlign", + "positionX", + "positionY", + "positionZ", + "postError", + "postMessage", + "postalCode", + "poster", + "pow", + "powerEfficient", + "powerOff", + "preMultiplySelf", + "precision", + "preferredStyleSheetSet", + "preferredStylesheetSet", + "prefix", + "preload", + "prepend", + "presentation", + "preserveAlpha", + "preserveAspectRatio", + "preserveAspectRatioString", + "pressed", + "pressure", + "prevValue", + "preventDefault", + "preventExtensions", + "preventSilentAccess", + "previousElementSibling", + "previousNode", + "previousPage", + "previousRect", + "previousScale", + "previousSibling", + "previousTranslate", + "primaryKey", + "primitiveType", + "primitiveUnits", + "principals", + "print", + "priority", + "privateKey", + "probablySupportsContext", + "process", + "processIceMessage", + "processingEnd", + "processingStart", + "processorOptions", + "product", + "productId", + "productName", + "productSub", + "profile", + "profileEnd", + "profiles", + "projectionMatrix", + "promise", + "prompt", + "properties", + "propertyIsEnumerable", + "propertyName", + "protocol", + "protocolLong", + "prototype", + "provider", + "pseudoClass", + "pseudoElement", + "pt", + "publicId", + "publicKey", + "published", + "pulse", + "push", + "pushManager", + "pushNotification", + "pushState", + "put", + "putImageData", + "px", + "quadraticCurveTo", + "qualifier", + "quaternion", + "query", + "queryCommandEnabled", + "queryCommandIndeterm", + "queryCommandState", + "queryCommandSupported", + "queryCommandText", + "queryCommandValue", + "querySelector", + "querySelectorAll", + "queueMicrotask", + "quote", + "quotes", + "r", + "r1", + "r2", + "race", + "rad", + "radiogroup", + "radiusX", + "radiusY", + "random", + "range", + "rangeCount", + "rangeMax", + "rangeMin", + "rangeOffset", + "rangeOverflow", + "rangeParent", + "rangeUnderflow", + "rate", + "ratio", + "raw", + "rawId", + "read", + "readAsArrayBuffer", + "readAsBinaryString", + "readAsBlob", + "readAsDataURL", + "readAsText", + "readBuffer", + "readEntries", + "readOnly", + "readPixels", + "readReportRequested", + "readText", + "readValue", + "readable", + "ready", + "readyState", + "reason", + "reboot", + "receivedAlert", + "receiver", + "receivers", + "recipient", + "reconnect", + "recordNumber", + "recordsAvailable", + "recordset", + "rect", + "red", + "redEyeReduction", + "redirect", + "redirectCount", + "redirectEnd", + "redirectStart", + "redirected", + "reduce", + "reduceRight", + "reduction", + "refDistance", + "refX", + "refY", + "referenceNode", + "referenceSpace", + "referrer", + "referrerPolicy", + "refresh", + "region", + "regionAnchorX", + "regionAnchorY", + "regionId", + "regions", + "register", + "registerContentHandler", + "registerElement", + "registerProperty", + "registerProtocolHandler", + "reject", + "rel", + "relList", + "relatedAddress", + "relatedNode", + "relatedPort", + "relatedTarget", + "release", + "releaseCapture", + "releaseEvents", + "releaseInterface", + "releaseLock", + "releasePointerCapture", + "releaseShaderCompiler", + "reliable", + "reliableWrite", + "reload", + "rem", + "remainingSpace", + "remote", + "remoteDescription", + "remove", + "removeAllRanges", + "removeAttribute", + "removeAttributeNS", + "removeAttributeNode", + "removeBehavior", + "removeChild", + "removeCue", + "removeEventListener", + "removeFilter", + "removeImport", + "removeItem", + "removeListener", + "removeNamedItem", + "removeNamedItemNS", + "removeNode", + "removeParameter", + "removeProperty", + "removeRange", + "removeRegion", + "removeRule", + "removeSiteSpecificTrackingException", + "removeSourceBuffer", + "removeStream", + "removeTrack", + "removeVariable", + "removeWakeLockListener", + "removeWebWideTrackingException", + "removed", + "removedNodes", + "renderHeight", + "renderState", + "renderTime", + "renderWidth", + "renderbufferStorage", + "renderbufferStorageMultisample", + "renderedBuffer", + "renderingMode", + "renotify", + "repeat", + "replace", + "replaceAdjacentText", + "replaceAll", + "replaceChild", + "replaceChildren", + "replaceData", + "replaceId", + "replaceItem", + "replaceNode", + "replaceState", + "replaceSync", + "replaceTrack", + "replaceWholeText", + "replaceWith", + "reportValidity", + "request", + "requestAnimationFrame", + "requestAutocomplete", + "requestData", + "requestDevice", + "requestFrame", + "requestFullscreen", + "requestHitTestSource", + "requestHitTestSourceForTransientInput", + "requestId", + "requestIdleCallback", + "requestMIDIAccess", + "requestMediaKeySystemAccess", + "requestPermission", + "requestPictureInPicture", + "requestPointerLock", + "requestPresent", + "requestReferenceSpace", + "requestSession", + "requestStart", + "requestStorageAccess", + "requestSubmit", + "requestVideoFrameCallback", + "requestingWindow", + "requireInteraction", + "required", + "requiredExtensions", + "requiredFeatures", + "reset", + "resetPose", + "resetTransform", + "resize", + "resizeBy", + "resizeTo", + "resolve", + "response", + "responseBody", + "responseEnd", + "responseReady", + "responseStart", + "responseText", + "responseType", + "responseURL", + "responseXML", + "restartIce", + "restore", + "result", + "resultIndex", + "resultType", + "results", + "resume", + "resumeProfilers", + "resumeTransformFeedback", + "retry", + "returnValue", + "rev", + "reverse", + "reversed", + "revocable", + "revokeObjectURL", + "rgbColor", + "right", + "rightContext", + "rightDegrees", + "rightMargin", + "rightProjectionMatrix", + "rightViewMatrix", + "role", + "rolloffFactor", + "root", + "rootBounds", + "rootElement", + "rootMargin", + "rotate", + "rotateAxisAngle", + "rotateAxisAngleSelf", + "rotateFromVector", + "rotateFromVectorSelf", + "rotateSelf", + "rotation", + "rotationAngle", + "rotationRate", + "round", + "row-gap", + "rowGap", + "rowIndex", + "rowSpan", + "rows", + "rtcpTransport", + "rtt", + "ruby-align", + "ruby-position", + "rubyAlign", + "rubyOverhang", + "rubyPosition", + "rules", + "runtime", + "runtimeStyle", + "rx", + "ry", + "s", + "safari", + "sample", + "sampleCoverage", + "sampleRate", + "samplerParameterf", + "samplerParameteri", + "sandbox", + "save", + "saveData", + "scale", + "scale3d", + "scale3dSelf", + "scaleNonUniform", + "scaleNonUniformSelf", + "scaleSelf", + "scheme", + "scissor", + "scope", + "scopeName", + "scoped", + "screen", + "screenBrightness", + "screenEnabled", + "screenLeft", + "screenPixelToMillimeterX", + "screenPixelToMillimeterY", + "screenTop", + "screenX", + "screenY", + "scriptURL", + "scripts", + "scroll", + "scroll-behavior", + "scroll-margin", + "scroll-margin-block", + "scroll-margin-block-end", + "scroll-margin-block-start", + "scroll-margin-bottom", + "scroll-margin-inline", + "scroll-margin-inline-end", + "scroll-margin-inline-start", + "scroll-margin-left", + "scroll-margin-right", + "scroll-margin-top", + "scroll-padding", + "scroll-padding-block", + "scroll-padding-block-end", + "scroll-padding-block-start", + "scroll-padding-bottom", + "scroll-padding-inline", + "scroll-padding-inline-end", + "scroll-padding-inline-start", + "scroll-padding-left", + "scroll-padding-right", + "scroll-padding-top", + "scroll-snap-align", + "scroll-snap-type", + "scrollAmount", + "scrollBehavior", + "scrollBy", + "scrollByLines", + "scrollByPages", + "scrollDelay", + "scrollHeight", + "scrollIntoView", + "scrollIntoViewIfNeeded", + "scrollLeft", + "scrollLeftMax", + "scrollMargin", + "scrollMarginBlock", + "scrollMarginBlockEnd", + "scrollMarginBlockStart", + "scrollMarginBottom", + "scrollMarginInline", + "scrollMarginInlineEnd", + "scrollMarginInlineStart", + "scrollMarginLeft", + "scrollMarginRight", + "scrollMarginTop", + "scrollMaxX", + "scrollMaxY", + "scrollPadding", + "scrollPaddingBlock", + "scrollPaddingBlockEnd", + "scrollPaddingBlockStart", + "scrollPaddingBottom", + "scrollPaddingInline", + "scrollPaddingInlineEnd", + "scrollPaddingInlineStart", + "scrollPaddingLeft", + "scrollPaddingRight", + "scrollPaddingTop", + "scrollRestoration", + "scrollSnapAlign", + "scrollSnapType", + "scrollTo", + "scrollTop", + "scrollTopMax", + "scrollWidth", + "scrollX", + "scrollY", + "scrollbar-color", + "scrollbar-width", + "scrollbar3dLightColor", + "scrollbarArrowColor", + "scrollbarBaseColor", + "scrollbarColor", + "scrollbarDarkShadowColor", + "scrollbarFaceColor", + "scrollbarHighlightColor", + "scrollbarShadowColor", + "scrollbarTrackColor", + "scrollbarWidth", + "scrollbars", + "scrolling", + "scrollingElement", + "sctp", + "sctpCauseCode", + "sdp", + "sdpLineNumber", + "sdpMLineIndex", + "sdpMid", + "seal", + "search", + "searchBox", + "searchBoxJavaBridge_", + "searchParams", + "sectionRowIndex", + "secureConnectionStart", + "security", + "seed", + "seekToNextFrame", + "seekable", + "seeking", + "select", + "selectAllChildren", + "selectAlternateInterface", + "selectConfiguration", + "selectNode", + "selectNodeContents", + "selectNodes", + "selectSingleNode", + "selectSubString", + "selected", + "selectedIndex", + "selectedOptions", + "selectedStyleSheetSet", + "selectedStylesheetSet", + "selection", + "selectionDirection", + "selectionEnd", + "selectionStart", + "selector", + "selectorText", + "self", + "send", + "sendAsBinary", + "sendBeacon", + "sender", + "sentAlert", + "sentTimestamp", + "separator", + "serialNumber", + "serializeToString", + "serverTiming", + "service", + "serviceWorker", + "session", + "sessionId", + "sessionStorage", + "set", + "setActionHandler", + "setActive", + "setAlpha", + "setAppBadge", + "setAttribute", + "setAttributeNS", + "setAttributeNode", + "setAttributeNodeNS", + "setBaseAndExtent", + "setBigInt64", + "setBigUint64", + "setBingCurrentSearchDefault", + "setCapture", + "setCodecPreferences", + "setColor", + "setCompositeOperation", + "setConfiguration", + "setCurrentTime", + "setCustomValidity", + "setData", + "setDate", + "setDragImage", + "setEnd", + "setEndAfter", + "setEndBefore", + "setEndPoint", + "setFillColor", + "setFilterRes", + "setFloat32", + "setFloat64", + "setFloatValue", + "setFormValue", + "setFullYear", + "setHeaderValue", + "setHours", + "setIdentityProvider", + "setImmediate", + "setInt16", + "setInt32", + "setInt8", + "setInterval", + "setItem", + "setKeyframes", + "setLineCap", + "setLineDash", + "setLineJoin", + "setLineWidth", + "setLiveSeekableRange", + "setLocalDescription", + "setMatrix", + "setMatrixValue", + "setMediaKeys", + "setMilliseconds", + "setMinutes", + "setMiterLimit", + "setMonth", + "setNamedItem", + "setNamedItemNS", + "setNonUserCodeExceptions", + "setOrientToAngle", + "setOrientToAuto", + "setOrientation", + "setOverrideHistoryNavigationMode", + "setPaint", + "setParameter", + "setParameters", + "setPeriodicWave", + "setPointerCapture", + "setPosition", + "setPositionState", + "setPreference", + "setProperty", + "setPrototypeOf", + "setRGBColor", + "setRGBColorICCColor", + "setRadius", + "setRangeText", + "setRemoteDescription", + "setRequestHeader", + "setResizable", + "setResourceTimingBufferSize", + "setRotate", + "setScale", + "setSeconds", + "setSelectionRange", + "setServerCertificate", + "setShadow", + "setSinkId", + "setSkewX", + "setSkewY", + "setStart", + "setStartAfter", + "setStartBefore", + "setStdDeviation", + "setStreams", + "setStringValue", + "setStrokeColor", + "setSuggestResult", + "setTargetAtTime", + "setTargetValueAtTime", + "setTime", + "setTimeout", + "setTransform", + "setTranslate", + "setUTCDate", + "setUTCFullYear", + "setUTCHours", + "setUTCMilliseconds", + "setUTCMinutes", + "setUTCMonth", + "setUTCSeconds", + "setUint16", + "setUint32", + "setUint8", + "setUri", + "setValidity", + "setValueAtTime", + "setValueCurveAtTime", + "setVariable", + "setVelocity", + "setVersion", + "setYear", + "settingName", + "settingValue", + "sex", + "shaderSource", + "shadowBlur", + "shadowColor", + "shadowOffsetX", + "shadowOffsetY", + "shadowRoot", + "shape", + "shape-image-threshold", + "shape-margin", + "shape-outside", + "shape-rendering", + "shapeImageThreshold", + "shapeMargin", + "shapeOutside", + "shapeRendering", + "sheet", + "shift", + "shiftKey", + "shiftLeft", + "shippingAddress", + "shippingOption", + "shippingType", + "show", + "showHelp", + "showModal", + "showModalDialog", + "showModelessDialog", + "showNotification", + "sidebar", + "sign", + "signal", + "signalingState", + "signature", + "silent", + "sin", + "singleNodeValue", + "sinh", + "sinkId", + "sittingToStandingTransform", + "size", + "sizeToContent", + "sizeX", + "sizeZ", + "sizes", + "skewX", + "skewXSelf", + "skewY", + "skewYSelf", + "slice", + "slope", + "slot", + "small", + "smil", + "smooth", + "smoothingTimeConstant", + "snapToLines", + "snapshotItem", + "snapshotLength", + "some", + "sort", + "sortingCode", + "source", + "sourceBuffer", + "sourceBuffers", + "sourceCapabilities", + "sourceFile", + "sourceIndex", + "sources", + "spacing", + "span", + "speak", + "speakAs", + "speaking", + "species", + "specified", + "specularConstant", + "specularExponent", + "speechSynthesis", + "speed", + "speedOfSound", + "spellcheck", + "splice", + "split", + "splitText", + "spreadMethod", + "sqrt", + "src", + "srcElement", + "srcFilter", + "srcObject", + "srcUrn", + "srcdoc", + "srclang", + "srcset", + "stack", + "stackTraceLimit", + "stacktrace", + "stageParameters", + "standalone", + "standby", + "start", + "startContainer", + "startIce", + "startMessages", + "startNotifications", + "startOffset", + "startProfiling", + "startRendering", + "startShark", + "startTime", + "startsWith", + "state", + "status", + "statusCode", + "statusMessage", + "statusText", + "statusbar", + "stdDeviationX", + "stdDeviationY", + "stencilFunc", + "stencilFuncSeparate", + "stencilMask", + "stencilMaskSeparate", + "stencilOp", + "stencilOpSeparate", + "step", + "stepDown", + "stepMismatch", + "stepUp", + "sticky", + "stitchTiles", + "stop", + "stop-color", + "stop-opacity", + "stopColor", + "stopImmediatePropagation", + "stopNotifications", + "stopOpacity", + "stopProfiling", + "stopPropagation", + "stopShark", + "stopped", + "storage", + "storageArea", + "storageName", + "storageStatus", + "store", + "storeSiteSpecificTrackingException", + "storeWebWideTrackingException", + "stpVersion", + "stream", + "streams", + "stretch", + "strike", + "string", + "stringValue", + "stringify", + "stroke", + "stroke-dasharray", + "stroke-dashoffset", + "stroke-linecap", + "stroke-linejoin", + "stroke-miterlimit", + "stroke-opacity", + "stroke-width", + "strokeDasharray", + "strokeDashoffset", + "strokeLinecap", + "strokeLinejoin", + "strokeMiterlimit", + "strokeOpacity", + "strokeRect", + "strokeStyle", + "strokeText", + "strokeWidth", + "style", + "styleFloat", + "styleMap", + "styleMedia", + "styleSheet", + "styleSheetSets", + "styleSheets", + "sub", + "subarray", + "subject", + "submit", + "submitFrame", + "submitter", + "subscribe", + "substr", + "substring", + "substringData", + "subtle", + "subtree", + "suffix", + "suffixes", + "summary", + "sup", + "supported", + "supportedContentEncodings", + "supportedEntryTypes", + "supports", + "supportsSession", + "surfaceScale", + "surroundContents", + "suspend", + "suspendRedraw", + "swapCache", + "swapNode", + "sweepFlag", + "symbols", + "sync", + "sysexEnabled", + "system", + "systemCode", + "systemId", + "systemLanguage", + "systemXDPI", + "systemYDPI", + "tBodies", + "tFoot", + "tHead", + "tabIndex", + "table", + "table-layout", + "tableLayout", + "tableValues", + "tag", + "tagName", + "tagUrn", + "tags", + "taintEnabled", + "takePhoto", + "takeRecords", + "tan", + "tangentialPressure", + "tanh", + "target", + "targetElement", + "targetRayMode", + "targetRaySpace", + "targetTouches", + "targetX", + "targetY", + "tcpType", + "tee", + "tel", + "terminate", + "test", + "texImage2D", + "texImage3D", + "texParameterf", + "texParameteri", + "texStorage2D", + "texStorage3D", + "texSubImage2D", + "texSubImage3D", + "text", + "text-align", + "text-align-last", + "text-anchor", + "text-combine-upright", + "text-decoration", + "text-decoration-color", + "text-decoration-line", + "text-decoration-skip-ink", + "text-decoration-style", + "text-decoration-thickness", + "text-emphasis", + "text-emphasis-color", + "text-emphasis-position", + "text-emphasis-style", + "text-indent", + "text-justify", + "text-orientation", + "text-overflow", + "text-rendering", + "text-shadow", + "text-transform", + "text-underline-offset", + "text-underline-position", + "textAlign", + "textAlignLast", + "textAnchor", + "textAutospace", + "textBaseline", + "textCombineUpright", + "textContent", + "textDecoration", + "textDecorationBlink", + "textDecorationColor", + "textDecorationLine", + "textDecorationLineThrough", + "textDecorationNone", + "textDecorationOverline", + "textDecorationSkipInk", + "textDecorationStyle", + "textDecorationThickness", + "textDecorationUnderline", + "textEmphasis", + "textEmphasisColor", + "textEmphasisPosition", + "textEmphasisStyle", + "textIndent", + "textJustify", + "textJustifyTrim", + "textKashida", + "textKashidaSpace", + "textLength", + "textOrientation", + "textOverflow", + "textRendering", + "textShadow", + "textTracks", + "textTransform", + "textUnderlineOffset", + "textUnderlinePosition", + "then", + "threadId", + "threshold", + "thresholds", + "tiltX", + "tiltY", + "time", + "timeEnd", + "timeLog", + "timeOrigin", + "timeRemaining", + "timeStamp", + "timecode", + "timeline", + "timelineTime", + "timeout", + "timestamp", + "timestampOffset", + "timing", + "title", + "to", + "toArray", + "toBlob", + "toDataURL", + "toDateString", + "toElement", + "toExponential", + "toFixed", + "toFloat32Array", + "toFloat64Array", + "toGMTString", + "toISOString", + "toJSON", + "toLocaleDateString", + "toLocaleFormat", + "toLocaleLowerCase", + "toLocaleString", + "toLocaleTimeString", + "toLocaleUpperCase", + "toLowerCase", + "toMatrix", + "toMethod", + "toPrecision", + "toPrimitive", + "toSdp", + "toSource", + "toStaticHTML", + "toString", + "toStringTag", + "toSum", + "toTimeString", + "toUTCString", + "toUpperCase", + "toggle", + "toggleAttribute", + "toggleLongPressEnabled", + "tone", + "toneBuffer", + "tooLong", + "tooShort", + "toolbar", + "top", + "topMargin", + "total", + "totalFrameDelay", + "totalVideoFrames", + "touch-action", + "touchAction", + "touched", + "touches", + "trace", + "track", + "trackVisibility", + "transaction", + "transactions", + "transceiver", + "transferControlToOffscreen", + "transferFromImageBitmap", + "transferImageBitmap", + "transferIn", + "transferOut", + "transferSize", + "transferToImageBitmap", + "transform", + "transform-box", + "transform-origin", + "transform-style", + "transformBox", + "transformFeedbackVaryings", + "transformOrigin", + "transformPoint", + "transformString", + "transformStyle", + "transformToDocument", + "transformToFragment", + "transition", + "transition-delay", + "transition-duration", + "transition-property", + "transition-timing-function", + "transitionDelay", + "transitionDuration", + "transitionProperty", + "transitionTimingFunction", + "translate", + "translateSelf", + "translationX", + "translationY", + "transport", + "trim", + "trimEnd", + "trimLeft", + "trimRight", + "trimStart", + "trueSpeed", + "trunc", + "truncate", + "trustedTypes", + "turn", + "twist", + "type", + "typeDetail", + "typeMismatch", + "typeMustMatch", + "types", + "u2f", + "ubound", + "uint16", + "uint32", + "uint8", + "uint8Clamped", + "undefined", + "unescape", + "uneval", + "unicode", + "unicode-bidi", + "unicodeBidi", + "unicodeRange", + "uniform1f", + "uniform1fv", + "uniform1i", + "uniform1iv", + "uniform1ui", + "uniform1uiv", + "uniform2f", + "uniform2fv", + "uniform2i", + "uniform2iv", + "uniform2ui", + "uniform2uiv", + "uniform3f", + "uniform3fv", + "uniform3i", + "uniform3iv", + "uniform3ui", + "uniform3uiv", + "uniform4f", + "uniform4fv", + "uniform4i", + "uniform4iv", + "uniform4ui", + "uniform4uiv", + "uniformBlockBinding", + "uniformMatrix2fv", + "uniformMatrix2x3fv", + "uniformMatrix2x4fv", + "uniformMatrix3fv", + "uniformMatrix3x2fv", + "uniformMatrix3x4fv", + "uniformMatrix4fv", + "uniformMatrix4x2fv", + "uniformMatrix4x3fv", + "unique", + "uniqueID", + "uniqueNumber", + "unit", + "unitType", + "units", + "unloadEventEnd", + "unloadEventStart", + "unlock", + "unmount", + "unobserve", + "unpause", + "unpauseAnimations", + "unreadCount", + "unregister", + "unregisterContentHandler", + "unregisterProtocolHandler", + "unscopables", + "unselectable", + "unshift", + "unsubscribe", + "unsuspendRedraw", + "unsuspendRedrawAll", + "unwatch", + "unwrapKey", + "upDegrees", + "upX", + "upY", + "upZ", + "update", + "updateCommands", + "updateIce", + "updateInterval", + "updatePlaybackRate", + "updateRenderState", + "updateSettings", + "updateTiming", + "updateViaCache", + "updateWith", + "updated", + "updating", + "upgrade", + "upload", + "uploadTotal", + "uploaded", + "upper", + "upperBound", + "upperOpen", + "uri", + "url", + "urn", + "urns", + "usages", + "usb", + "usbVersionMajor", + "usbVersionMinor", + "usbVersionSubminor", + "useCurrentView", + "useMap", + "useProgram", + "usedSpace", + "user-select", + "userActivation", + "userAgent", + "userAgentData", + "userChoice", + "userHandle", + "userHint", + "userLanguage", + "userSelect", + "userVisibleOnly", + "username", + "usernameFragment", + "utterance", + "uuid", + "v8BreakIterator", + "vAlign", + "vLink", + "valid", + "validate", + "validateProgram", + "validationMessage", + "validity", + "value", + "valueAsDate", + "valueAsNumber", + "valueAsString", + "valueInSpecifiedUnits", + "valueMissing", + "valueOf", + "valueText", + "valueType", + "values", + "variable", + "variant", + "variationSettings", + "vector-effect", + "vectorEffect", + "velocityAngular", + "velocityExpansion", + "velocityX", + "velocityY", + "vendor", + "vendorId", + "vendorSub", + "verify", + "version", + "vertexAttrib1f", + "vertexAttrib1fv", + "vertexAttrib2f", + "vertexAttrib2fv", + "vertexAttrib3f", + "vertexAttrib3fv", + "vertexAttrib4f", + "vertexAttrib4fv", + "vertexAttribDivisor", + "vertexAttribDivisorANGLE", + "vertexAttribI4i", + "vertexAttribI4iv", + "vertexAttribI4ui", + "vertexAttribI4uiv", + "vertexAttribIPointer", + "vertexAttribPointer", + "vertical", + "vertical-align", + "verticalAlign", + "verticalOverflow", + "vh", + "vibrate", + "vibrationActuator", + "videoBitsPerSecond", + "videoHeight", + "videoTracks", + "videoWidth", + "view", + "viewBox", + "viewBoxString", + "viewTarget", + "viewTargetString", + "viewport", + "viewportAnchorX", + "viewportAnchorY", + "viewportElement", + "views", + "violatedDirective", + "visibility", + "visibilityState", + "visible", + "visualViewport", + "vlinkColor", + "vmax", + "vmin", + "voice", + "voiceURI", + "volume", + "vrml", + "vspace", + "vw", + "w", + "wait", + "waitSync", + "waiting", + "wake", + "wakeLock", + "wand", + "warn", + "wasClean", + "wasDiscarded", + "watch", + "watchAvailability", + "watchPosition", + "webdriver", + "webkitAddKey", + "webkitAlignContent", + "webkitAlignItems", + "webkitAlignSelf", + "webkitAnimation", + "webkitAnimationDelay", + "webkitAnimationDirection", + "webkitAnimationDuration", + "webkitAnimationFillMode", + "webkitAnimationIterationCount", + "webkitAnimationName", + "webkitAnimationPlayState", + "webkitAnimationTimingFunction", + "webkitAppearance", + "webkitAudioContext", + "webkitAudioDecodedByteCount", + "webkitAudioPannerNode", + "webkitBackfaceVisibility", + "webkitBackground", + "webkitBackgroundAttachment", + "webkitBackgroundClip", + "webkitBackgroundColor", + "webkitBackgroundImage", + "webkitBackgroundOrigin", + "webkitBackgroundPosition", + "webkitBackgroundPositionX", + "webkitBackgroundPositionY", + "webkitBackgroundRepeat", + "webkitBackgroundSize", + "webkitBackingStorePixelRatio", + "webkitBorderBottomLeftRadius", + "webkitBorderBottomRightRadius", + "webkitBorderImage", + "webkitBorderImageOutset", + "webkitBorderImageRepeat", + "webkitBorderImageSlice", + "webkitBorderImageSource", + "webkitBorderImageWidth", + "webkitBorderRadius", + "webkitBorderTopLeftRadius", + "webkitBorderTopRightRadius", + "webkitBoxAlign", + "webkitBoxDirection", + "webkitBoxFlex", + "webkitBoxOrdinalGroup", + "webkitBoxOrient", + "webkitBoxPack", + "webkitBoxShadow", + "webkitBoxSizing", + "webkitCancelAnimationFrame", + "webkitCancelFullScreen", + "webkitCancelKeyRequest", + "webkitCancelRequestAnimationFrame", + "webkitClearResourceTimings", + "webkitClosedCaptionsVisible", + "webkitConvertPointFromNodeToPage", + "webkitConvertPointFromPageToNode", + "webkitCreateShadowRoot", + "webkitCurrentFullScreenElement", + "webkitCurrentPlaybackTargetIsWireless", + "webkitDecodedFrameCount", + "webkitDirectionInvertedFromDevice", + "webkitDisplayingFullscreen", + "webkitDroppedFrameCount", + "webkitEnterFullScreen", + "webkitEnterFullscreen", + "webkitEntries", + "webkitExitFullScreen", + "webkitExitFullscreen", + "webkitExitPointerLock", + "webkitFilter", + "webkitFlex", + "webkitFlexBasis", + "webkitFlexDirection", + "webkitFlexFlow", + "webkitFlexGrow", + "webkitFlexShrink", + "webkitFlexWrap", + "webkitFullScreenKeyboardInputAllowed", + "webkitFullscreenElement", + "webkitFullscreenEnabled", + "webkitGenerateKeyRequest", + "webkitGetAsEntry", + "webkitGetDatabaseNames", + "webkitGetEntries", + "webkitGetEntriesByName", + "webkitGetEntriesByType", + "webkitGetFlowByName", + "webkitGetGamepads", + "webkitGetImageDataHD", + "webkitGetNamedFlows", + "webkitGetRegionFlowRanges", + "webkitGetUserMedia", + "webkitHasClosedCaptions", + "webkitHidden", + "webkitIDBCursor", + "webkitIDBDatabase", + "webkitIDBDatabaseError", + "webkitIDBDatabaseException", + "webkitIDBFactory", + "webkitIDBIndex", + "webkitIDBKeyRange", + "webkitIDBObjectStore", + "webkitIDBRequest", + "webkitIDBTransaction", + "webkitImageSmoothingEnabled", + "webkitIndexedDB", + "webkitInitMessageEvent", + "webkitIsFullScreen", + "webkitJustifyContent", + "webkitKeys", + "webkitLineClamp", + "webkitLineDashOffset", + "webkitLockOrientation", + "webkitMask", + "webkitMaskClip", + "webkitMaskComposite", + "webkitMaskImage", + "webkitMaskOrigin", + "webkitMaskPosition", + "webkitMaskPositionX", + "webkitMaskPositionY", + "webkitMaskRepeat", + "webkitMaskSize", + "webkitMatchesSelector", + "webkitMediaStream", + "webkitNotifications", + "webkitOfflineAudioContext", + "webkitOrder", + "webkitOrientation", + "webkitPeerConnection00", + "webkitPersistentStorage", + "webkitPerspective", + "webkitPerspectiveOrigin", + "webkitPointerLockElement", + "webkitPostMessage", + "webkitPreservesPitch", + "webkitPutImageDataHD", + "webkitRTCPeerConnection", + "webkitRegionOverset", + "webkitRelativePath", + "webkitRequestAnimationFrame", + "webkitRequestFileSystem", + "webkitRequestFullScreen", + "webkitRequestFullscreen", + "webkitRequestPointerLock", + "webkitResolveLocalFileSystemURL", + "webkitSetMediaKeys", + "webkitSetResourceTimingBufferSize", + "webkitShadowRoot", + "webkitShowPlaybackTargetPicker", + "webkitSlice", + "webkitSpeechGrammar", + "webkitSpeechGrammarList", + "webkitSpeechRecognition", + "webkitSpeechRecognitionError", + "webkitSpeechRecognitionEvent", + "webkitStorageInfo", + "webkitSupportsFullscreen", + "webkitTemporaryStorage", + "webkitTextFillColor", + "webkitTextSizeAdjust", + "webkitTextStroke", + "webkitTextStrokeColor", + "webkitTextStrokeWidth", + "webkitTransform", + "webkitTransformOrigin", + "webkitTransformStyle", + "webkitTransition", + "webkitTransitionDelay", + "webkitTransitionDuration", + "webkitTransitionProperty", + "webkitTransitionTimingFunction", + "webkitURL", + "webkitUnlockOrientation", + "webkitUserSelect", + "webkitVideoDecodedByteCount", + "webkitVisibilityState", + "webkitWirelessVideoPlaybackDisabled", + "webkitdirectory", + "webkitdropzone", + "webstore", + "weight", + "whatToShow", + "wheelDelta", + "wheelDeltaX", + "wheelDeltaY", + "whenDefined", + "which", + "white-space", + "whiteSpace", + "wholeText", + "widows", + "width", + "will-change", + "willChange", + "willValidate", + "window", + "withCredentials", + "word-break", + "word-spacing", + "word-wrap", + "wordBreak", + "wordSpacing", + "wordWrap", + "workerStart", + "wow64", + "wrap", + "wrapKey", + "writable", + "writableAuxiliaries", + "write", + "writeText", + "writeValue", + "writeWithoutResponse", + "writeln", + "writing-mode", + "writingMode", + "x", + "x1", + "x2", + "xChannelSelector", + "xmlEncoding", + "xmlStandalone", + "xmlVersion", + "xmlbase", + "xmllang", + "xmlspace", + "xor", + "xr", + "y", + "y1", + "y2", + "yChannelSelector", + "yandex", + "z", + "z-index", + "zIndex", + "zoom", + "zoomAndPan", + "zoomRectScreen", +]; + +/*********************************************************************** + + A JavaScript tokenizer / parser / beautifier / compressor. + https://github.com/mishoo/UglifyJS2 + + -------------------------------- (C) --------------------------------- + + Author: Mihai Bazon + + http://mihai.bazon.net/blog + + Distributed under the BSD license: + + Copyright 2012 (c) Mihai Bazon + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the following + disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + ***********************************************************************/ + +function find_builtins(reserved) { + domprops.forEach(add); + + // Compatibility fix for some standard defined globals not defined on every js environment + var new_globals = ["Symbol", "Map", "Promise", "Proxy", "Reflect", "Set", "WeakMap", "WeakSet"]; + var objects = {}; + var global_ref = typeof global === "object" ? global : self; + + new_globals.forEach(function (new_global) { + objects[new_global] = global_ref[new_global] || function() {}; + }); + + [ + "null", + "true", + "false", + "NaN", + "Infinity", + "-Infinity", + "undefined", + ].forEach(add); + [ Object, Array, Function, Number, + String, Boolean, Error, Math, + Date, RegExp, objects.Symbol, ArrayBuffer, + DataView, decodeURI, decodeURIComponent, + encodeURI, encodeURIComponent, eval, EvalError, + Float32Array, Float64Array, Int8Array, Int16Array, + Int32Array, isFinite, isNaN, JSON, objects.Map, parseFloat, + parseInt, objects.Promise, objects.Proxy, RangeError, ReferenceError, + objects.Reflect, objects.Set, SyntaxError, TypeError, Uint8Array, + Uint8ClampedArray, Uint16Array, Uint32Array, URIError, + objects.WeakMap, objects.WeakSet + ].forEach(function(ctor) { + Object.getOwnPropertyNames(ctor).map(add); + if (ctor.prototype) { + Object.getOwnPropertyNames(ctor.prototype).map(add); + } + }); + function add(name) { + reserved.add(name); + } +} + +function reserve_quoted_keys(ast, reserved) { + function add(name) { + push_uniq(reserved, name); + } + + ast.walk(new TreeWalker(function(node) { + if (node instanceof AST_ObjectKeyVal && node.quote) { + add(node.key); + } else if (node instanceof AST_ObjectProperty && node.quote) { + add(node.key.name); + } else if (node instanceof AST_Sub) { + addStrings(node.property, add); + } + })); +} + +function addStrings(node, add) { + node.walk(new TreeWalker(function(node) { + if (node instanceof AST_Sequence) { + addStrings(node.tail_node(), add); + } else if (node instanceof AST_String) { + add(node.value); + } else if (node instanceof AST_Conditional) { + addStrings(node.consequent, add); + addStrings(node.alternative, add); + } + return true; + })); +} + +function mangle_private_properties(ast, options) { + var cprivate = -1; + var private_cache = new Map(); + var nth_identifier = options.nth_identifier || base54; + + ast = ast.transform(new TreeTransformer(function(node) { + if ( + node instanceof AST_ClassPrivateProperty + || node instanceof AST_PrivateMethod + || node instanceof AST_PrivateGetter + || node instanceof AST_PrivateSetter + || node instanceof AST_PrivateIn + ) { + node.key.name = mangle_private(node.key.name); + } else if (node instanceof AST_DotHash) { + node.property = mangle_private(node.property); + } + })); + return ast; + + function mangle_private(name) { + let mangled = private_cache.get(name); + if (!mangled) { + mangled = nth_identifier.get(++cprivate); + private_cache.set(name, mangled); + } + + return mangled; + } +} + +function mangle_properties(ast, options) { + options = defaults(options, { + builtins: false, + cache: null, + debug: false, + keep_quoted: false, + nth_identifier: base54, + only_cache: false, + regex: null, + reserved: null, + undeclared: false, + only_annotated: false, + }, true); + + var nth_identifier = options.nth_identifier; + + var reserved_option = options.reserved; + if (!Array.isArray(reserved_option)) reserved_option = [reserved_option]; + var reserved = new Set(reserved_option); + if (!options.builtins) find_builtins(reserved); + + var cname = -1; + + var cache; + if (options.cache) { + cache = options.cache.props; + } else { + cache = new Map(); + } + + var only_annotated = options.only_annotated; + var regex = options.regex && new RegExp(options.regex); + + // note debug is either false (disabled), or a string of the debug suffix to use (enabled). + // note debug may be enabled as an empty string, which is falsey. Also treat passing 'true' + // the same as passing an empty string. + var debug = options.debug !== false; + var debug_name_suffix; + if (debug) { + debug_name_suffix = (options.debug === true ? "" : options.debug); + } + + var annotated_names = new Set(); + var names_to_mangle = new Set(); + var unmangleable = new Set(); + // Track each already-mangled name to prevent nth_identifier from generating + // the same name. + cache.forEach((mangled_name) => unmangleable.add(mangled_name)); + + var keep_quoted = !!options.keep_quoted; + + // Step 1: Find all annotated /*@__MANGLEPROP__*/ + walk(ast, node => { + if ( + node instanceof AST_ClassPrivateProperty + || node instanceof AST_PrivateMethod + || node instanceof AST_PrivateGetter + || node instanceof AST_PrivateSetter + || node instanceof AST_DotHash + ) ; else if (node instanceof AST_ObjectKeyVal) { + if ( + typeof node.key == "string" + && has_annotation(node, _MANGLEPROP) + && can_mangle(node.key) + ) { + annotated_names.add(node.key); + clear_annotation(node, _MANGLEPROP); + } + } else if (node instanceof AST_ObjectProperty) { + // setter or getter, since KeyVal is handled above + if ( + has_annotation(node, _MANGLEPROP) + && can_mangle(node.key.name) + ) { + annotated_names.add(node.key.name); + clear_annotation(node, _MANGLEPROP); + } + } + }); + + // step 2: find candidates to mangle + ast.walk(new TreeWalker(function(node) { + if ( + node instanceof AST_ClassPrivateProperty + || node instanceof AST_PrivateMethod + || node instanceof AST_PrivateGetter + || node instanceof AST_PrivateSetter + || node instanceof AST_DotHash + ) ; else if (node instanceof AST_ObjectKeyVal) { + if (typeof node.key == "string" && (!keep_quoted || !node.quote)) { + add(node.key); + } + } else if (node instanceof AST_ObjectProperty) { + // setter or getter, since KeyVal is handled above + if (!keep_quoted || !node.quote) { + add(node.key.name); + } + } else if (node instanceof AST_Dot) { + var declared = !!options.undeclared; + if (!declared) { + var root = node; + while (root.expression) { + root = root.expression; + } + declared = !(root.thedef && root.thedef.undeclared); + } + if (declared && + (!keep_quoted || !node.quote)) { + add(node.property); + } + } else if (node instanceof AST_Sub) { + if (!keep_quoted) { + addStrings(node.property, add); + } + } else if (node instanceof AST_Call + && node.expression.print_to_string() == "Object.defineProperty") { + addStrings(node.args[1], add); + } else if (node instanceof AST_Binary && node.operator === "in") { + addStrings(node.left, add); + } else if (node instanceof AST_String && has_annotation(node, _KEY)) { + add(node.value); + } + })); + + // step 2: transform the tree, renaming properties + return ast.transform(new TreeTransformer(function(node) { + if ( + node instanceof AST_ClassPrivateProperty + || node instanceof AST_PrivateMethod + || node instanceof AST_PrivateGetter + || node instanceof AST_PrivateSetter + || node instanceof AST_DotHash + ) ; else if (node instanceof AST_ObjectKeyVal) { + if (typeof node.key == "string" && (!keep_quoted || !node.quote)) { + node.key = mangle(node.key); + } + } else if (node instanceof AST_ObjectProperty) { + // setter, getter, method or class field + if (!keep_quoted || !node.quote) { + node.key.name = mangle(node.key.name); + } + } else if (node instanceof AST_Dot) { + if (!keep_quoted || !node.quote) { + node.property = mangle(node.property); + } + } else if (!keep_quoted && node instanceof AST_Sub) { + node.property = mangleStrings(node.property); + } else if (node instanceof AST_Call + && node.expression.print_to_string() == "Object.defineProperty") { + node.args[1] = mangleStrings(node.args[1]); + } else if (node instanceof AST_Binary && node.operator === "in") { + node.left = mangleStrings(node.left); + } else if (node instanceof AST_String && has_annotation(node, _KEY)) { + // Clear _KEY annotation to prevent double mangling + clear_annotation(node, _KEY); + node.value = mangle(node.value); + } + })); + + // only function declarations after this line + + function can_mangle(name) { + if (unmangleable.has(name)) return false; + if (reserved.has(name)) return false; + if (options.only_cache) { + return cache.has(name); + } + if (/^-?[0-9]+(\.[0-9]+)?(e[+-][0-9]+)?$/.test(name)) return false; + return true; + } + + function should_mangle(name) { + if (only_annotated && !annotated_names.has(name)) return false; + if (regex && !regex.test(name)) { + return annotated_names.has(name); + } + if (reserved.has(name)) return false; + return cache.has(name) + || names_to_mangle.has(name); + } + + function add(name) { + if (can_mangle(name)) { + names_to_mangle.add(name); + } + + if (!should_mangle(name)) { + unmangleable.add(name); + } + } + + function mangle(name) { + if (!should_mangle(name)) { + return name; + } + + var mangled = cache.get(name); + if (!mangled) { + if (debug) { + // debug mode: use a prefix and suffix to preserve readability, e.g. o.foo -> o._$foo$NNN_. + var debug_mangled = "_$" + name + "$" + debug_name_suffix + "_"; + + if (can_mangle(debug_mangled)) { + mangled = debug_mangled; + } + } + + // either debug mode is off, or it is on and we could not use the mangled name + if (!mangled) { + do { + mangled = nth_identifier.get(++cname); + } while (!can_mangle(mangled)); + } + + cache.set(name, mangled); + } + return mangled; + } + + function mangleStrings(node) { + return node.transform(new TreeTransformer(function(node) { + if (node instanceof AST_Sequence) { + var last = node.expressions.length - 1; + node.expressions[last] = mangleStrings(node.expressions[last]); + } else if (node instanceof AST_String) { + // Clear _KEY annotation to prevent double mangling + clear_annotation(node, _KEY); + node.value = mangle(node.value); + } else if (node instanceof AST_Conditional) { + node.consequent = mangleStrings(node.consequent); + node.alternative = mangleStrings(node.alternative); + } + return node; + })); + } +} + +// to/from base64 functions +// Prefer built-in Buffer, if available, then use hack +// https://developer.mozilla.org/en-US/docs/Glossary/Base64#The_Unicode_Problem +var to_ascii = typeof Buffer !== "undefined" + ? (b64) => Buffer.from(b64, "base64").toString() + : (b64) => decodeURIComponent(escape(atob(b64))); +var to_base64 = typeof Buffer !== "undefined" + ? (str) => Buffer.from(str).toString("base64") + : (str) => btoa(unescape(encodeURIComponent(str))); + +function read_source_map(code) { + var match = /(?:^|[^.])\/\/# sourceMappingURL=data:application\/json(;[\w=-]*)?;base64,([+/0-9A-Za-z]*=*)\s*$/.exec(code); + if (!match) { + console.warn("inline source map not found"); + return null; + } + return to_ascii(match[2]); +} + +function set_shorthand(name, options, keys) { + if (options[name]) { + keys.forEach(function(key) { + if (options[key]) { + if (typeof options[key] != "object") options[key] = {}; + if (!(name in options[key])) options[key][name] = options[name]; + } + }); + } +} + +function init_cache(cache) { + if (!cache) return; + if (!("props" in cache)) { + cache.props = new Map(); + } else if (!(cache.props instanceof Map)) { + cache.props = map_from_object(cache.props); + } +} + +function cache_to_json(cache) { + return { + props: map_to_object(cache.props) + }; +} + +function log_input(files, options, fs, debug_folder) { + if (!(fs && fs.writeFileSync && fs.mkdirSync)) { + return; + } + + try { + fs.mkdirSync(debug_folder); + } catch (e) { + if (e.code !== "EEXIST") throw e; + } + + const log_path = `${debug_folder}/terser-debug-${(Math.random() * 9999999) | 0}.log`; + + options = options || {}; + + const options_str = JSON.stringify(options, (_key, thing) => { + if (typeof thing === "function") return "[Function " + thing.toString() + "]"; + if (thing instanceof RegExp) return "[RegExp " + thing.toString() + "]"; + return thing; + }, 4); + + const files_str = (file) => { + if (typeof file === "object" && options.parse && options.parse.spidermonkey) { + return JSON.stringify(file, null, 2); + } else if (typeof file === "object") { + return Object.keys(file) + .map((key) => key + ": " + files_str(file[key])) + .join("\n\n"); + } else if (typeof file === "string") { + return "```\n" + file + "\n```"; + } else { + return file; // What do? + } + }; + + fs.writeFileSync(log_path, "Options: \n" + options_str + "\n\nInput files:\n\n" + files_str(files) + "\n"); +} + +async function minify(files, options, _fs_module) { + if ( + _fs_module + && typeof process === "object" + && process.env + && typeof process.env.TERSER_DEBUG_DIR === "string" + ) { + log_input(files, options, _fs_module, process.env.TERSER_DEBUG_DIR); + } + + options = defaults(options, { + compress: {}, + ecma: undefined, + enclose: false, + ie8: false, + keep_classnames: undefined, + keep_fnames: false, + mangle: {}, + module: false, + nameCache: null, + output: null, + format: null, + parse: {}, + rename: undefined, + safari10: false, + sourceMap: false, + spidermonkey: false, + timings: false, + toplevel: false, + warnings: false, + wrap: false, + }, true); + + var timings = options.timings && { + start: Date.now() + }; + if (options.keep_classnames === undefined) { + options.keep_classnames = options.keep_fnames; + } + if (options.rename === undefined) { + options.rename = options.compress && options.mangle; + } + if (options.output && options.format) { + throw new Error("Please only specify either output or format option, preferrably format."); + } + options.format = options.format || options.output || {}; + set_shorthand("ecma", options, [ "parse", "compress", "format" ]); + set_shorthand("ie8", options, [ "compress", "mangle", "format" ]); + set_shorthand("keep_classnames", options, [ "compress", "mangle" ]); + set_shorthand("keep_fnames", options, [ "compress", "mangle" ]); + set_shorthand("module", options, [ "parse", "compress", "mangle" ]); + set_shorthand("safari10", options, [ "mangle", "format" ]); + set_shorthand("toplevel", options, [ "compress", "mangle" ]); + set_shorthand("warnings", options, [ "compress" ]); // legacy + var quoted_props; + if (options.mangle) { + options.mangle = defaults(options.mangle, { + cache: options.nameCache && (options.nameCache.vars || {}), + eval: false, + ie8: false, + keep_classnames: false, + keep_fnames: false, + module: false, + nth_identifier: base54, + properties: false, + reserved: [], + safari10: false, + toplevel: false, + }, true); + if (options.mangle.properties) { + if (typeof options.mangle.properties != "object") { + options.mangle.properties = {}; + } + if (options.mangle.properties.keep_quoted) { + quoted_props = options.mangle.properties.reserved; + if (!Array.isArray(quoted_props)) quoted_props = []; + options.mangle.properties.reserved = quoted_props; + } + if (options.nameCache && !("cache" in options.mangle.properties)) { + options.mangle.properties.cache = options.nameCache.props || {}; + } + } + init_cache(options.mangle.cache); + init_cache(options.mangle.properties.cache); + } + if (options.sourceMap) { + options.sourceMap = defaults(options.sourceMap, { + asObject: false, + content: null, + filename: null, + includeSources: false, + root: null, + url: null, + }, true); + } + + // -- Parse phase -- + if (timings) timings.parse = Date.now(); + var toplevel; + if (files instanceof AST_Toplevel) { + toplevel = files; + } else { + if (typeof files == "string" || (options.parse.spidermonkey && !Array.isArray(files))) { + files = [ files ]; + } + options.parse = options.parse || {}; + options.parse.toplevel = null; + + if (options.parse.spidermonkey) { + options.parse.toplevel = AST_Node.from_mozilla_ast(Object.keys(files).reduce(function(toplevel, name) { + if (!toplevel) return files[name]; + toplevel.body = toplevel.body.concat(files[name].body); + return toplevel; + }, null)); + } else { + delete options.parse.spidermonkey; + + for (var name in files) if (HOP(files, name)) { + options.parse.filename = name; + options.parse.toplevel = parse(files[name], options.parse); + if (options.sourceMap && options.sourceMap.content == "inline") { + if (Object.keys(files).length > 1) + throw new Error("inline source map only works with singular input"); + options.sourceMap.content = read_source_map(files[name]); + } + } + } + + toplevel = options.parse.toplevel; + } + if (quoted_props && options.mangle.properties.keep_quoted !== "strict") { + reserve_quoted_keys(toplevel, quoted_props); + } + if (options.wrap) { + toplevel = toplevel.wrap_commonjs(options.wrap); + } + if (options.enclose) { + toplevel = toplevel.wrap_enclose(options.enclose); + } + if (timings) timings.rename = Date.now(); + + // -- Compress phase -- + if (timings) timings.compress = Date.now(); + if (options.compress) { + toplevel = new Compressor(options.compress, { + mangle_options: options.mangle + }).compress(toplevel); + } + + // -- Mangle phase -- + if (timings) timings.scope = Date.now(); + if (options.mangle) toplevel.figure_out_scope(options.mangle); + if (timings) timings.mangle = Date.now(); + if (options.mangle) { + toplevel.compute_char_frequency(options.mangle); + toplevel.mangle_names(options.mangle); + toplevel = mangle_private_properties(toplevel, options.mangle); + } + if (timings) timings.properties = Date.now(); + if (options.mangle && options.mangle.properties) { + toplevel = mangle_properties(toplevel, options.mangle.properties); + } + + // Format phase + if (timings) timings.format = Date.now(); + var result = {}; + if (options.format.ast) { + result.ast = toplevel; + } + if (options.format.spidermonkey) { + result.ast = toplevel.to_mozilla_ast(); + } + let format_options; + if (!HOP(options.format, "code") || options.format.code) { + // Make a shallow copy so that we can modify without mutating the user's input. + format_options = {...options.format}; + if (!format_options.ast) { + // Destroy stuff to save RAM. (unless the deprecated `ast` option is on) + format_options._destroy_ast = true; + + walk(toplevel, node => { + if (node instanceof AST_Scope) { + node.variables = undefined; + node.enclosed = undefined; + node.parent_scope = undefined; + } + if (node.block_scope) { + node.block_scope.variables = undefined; + node.block_scope.enclosed = undefined; + node.parent_scope = undefined; + } + }); + } + + if (options.sourceMap) { + if (options.sourceMap.includeSources && files instanceof AST_Toplevel) { + throw new Error("original source content unavailable"); + } + format_options.source_map = await SourceMap({ + file: options.sourceMap.filename, + orig: options.sourceMap.content, + root: options.sourceMap.root, + files: options.sourceMap.includeSources ? files : null, + }); + } + delete format_options.ast; + delete format_options.code; + delete format_options.spidermonkey; + var stream = OutputStream(format_options); + toplevel.print(stream); + result.code = stream.get(); + if (options.sourceMap) { + Object.defineProperty(result, "map", { + configurable: true, + enumerable: true, + get() { + const map = format_options.source_map.getEncoded(); + return (result.map = options.sourceMap.asObject ? map : JSON.stringify(map)); + }, + set(value) { + Object.defineProperty(result, "map", { + value, + writable: true, + }); + } + }); + result.decoded_map = format_options.source_map.getDecoded(); + if (options.sourceMap.url == "inline") { + var sourceMap = typeof result.map === "object" ? JSON.stringify(result.map) : result.map; + result.code += "\n//# sourceMappingURL=data:application/json;charset=utf-8;base64," + to_base64(sourceMap); + } else if (options.sourceMap.url) { + result.code += "\n//# sourceMappingURL=" + options.sourceMap.url; + } + } + } + if (options.nameCache && options.mangle) { + if (options.mangle.cache) options.nameCache.vars = cache_to_json(options.mangle.cache); + if (options.mangle.properties && options.mangle.properties.cache) { + options.nameCache.props = cache_to_json(options.mangle.properties.cache); + } + } + if (format_options && format_options.source_map) { + format_options.source_map.destroy(); + } + if (timings) { + timings.end = Date.now(); + result.timings = { + parse: 1e-3 * (timings.rename - timings.parse), + rename: 1e-3 * (timings.compress - timings.rename), + compress: 1e-3 * (timings.scope - timings.compress), + scope: 1e-3 * (timings.mangle - timings.scope), + mangle: 1e-3 * (timings.properties - timings.mangle), + properties: 1e-3 * (timings.format - timings.properties), + format: 1e-3 * (timings.end - timings.format), + total: 1e-3 * (timings.end - timings.start) + }; + } + return result; +} + +async function run_cli({ program, packageJson, fs, path }) { + const skip_keys = new Set([ "cname", "parent_scope", "scope", "uses_eval", "uses_with" ]); + var files = {}; + var options = { + compress: false, + mangle: false + }; + const default_options = await _default_options(); + program.version(packageJson.name + " " + packageJson.version); + program.parseArgv = program.parse; + program.parse = undefined; + + if (process.argv.includes("ast")) program.helpInformation = describe_ast; + else if (process.argv.includes("options")) program.helpInformation = function() { + var text = []; + for (var option in default_options) { + text.push("--" + (option === "sourceMap" ? "source-map" : option) + " options:"); + text.push(format_object(default_options[option])); + text.push(""); + } + return text.join("\n"); + }; + + program.option("-p, --parse ", "Specify parser options.", parse_js()); + program.option("-c, --compress [options]", "Enable compressor/specify compressor options.", parse_js()); + program.option("-m, --mangle [options]", "Mangle names/specify mangler options.", parse_js()); + program.option("--mangle-props [options]", "Mangle properties/specify mangler options.", parse_js()); + program.option("-f, --format [options]", "Format options.", parse_js()); + program.option("-b, --beautify [options]", "Alias for --format.", parse_js()); + program.option("-o, --output ", "Output file (default STDOUT)."); + program.option("--comments [filter]", "Preserve copyright comments in the output."); + program.option("--config-file ", "Read minify() options from JSON file."); + program.option("-d, --define [=value]", "Global definitions.", parse_js("define")); + program.option("--ecma ", "Specify ECMAScript release: 5, 2015, 2016 or 2017..."); + program.option("-e, --enclose [arg[,...][:value[,...]]]", "Embed output in a big function with configurable arguments and values."); + program.option("--ie8", "Support non-standard Internet Explorer 8."); + program.option("--keep-classnames", "Do not mangle/drop class names."); + program.option("--keep-fnames", "Do not mangle/drop function names. Useful for code relying on Function.prototype.name."); + program.option("--module", "Input is an ES6 module"); + program.option("--name-cache ", "File to hold mangled name mappings."); + program.option("--rename", "Force symbol expansion."); + program.option("--no-rename", "Disable symbol expansion."); + program.option("--safari10", "Support non-standard Safari 10."); + program.option("--source-map [options]", "Enable source map/specify source map options.", parse_js()); + program.option("--timings", "Display operations run time on STDERR."); + program.option("--toplevel", "Compress and/or mangle variables in toplevel scope."); + program.option("--wrap ", "Embed everything as a function with “exports” corresponding to “name” globally."); + program.arguments("[files...]").parseArgv(process.argv); + if (program.configFile) { + options = JSON.parse(read_file(program.configFile)); + } + if (!program.output && program.sourceMap && program.sourceMap.url != "inline") { + fatal("ERROR: cannot write source map to STDOUT"); + } + + [ + "compress", + "enclose", + "ie8", + "mangle", + "module", + "safari10", + "sourceMap", + "toplevel", + "wrap" + ].forEach(function(name) { + if (name in program) { + options[name] = program[name]; + } + }); + + if ("ecma" in program) { + if (program.ecma != (program.ecma | 0)) fatal("ERROR: ecma must be an integer"); + const ecma = program.ecma | 0; + if (ecma > 5 && ecma < 2015) + options.ecma = ecma + 2009; + else + options.ecma = ecma; + } + if (program.format || program.beautify) { + const chosenOption = program.format || program.beautify; + options.format = typeof chosenOption === "object" ? chosenOption : {}; + } + if (program.comments) { + if (typeof options.format != "object") options.format = {}; + options.format.comments = typeof program.comments == "string" ? (program.comments == "false" ? false : program.comments) : "some"; + } + if (program.define) { + if (typeof options.compress != "object") options.compress = {}; + if (typeof options.compress.global_defs != "object") options.compress.global_defs = {}; + for (var expr in program.define) { + options.compress.global_defs[expr] = program.define[expr]; + } + } + if (program.keepClassnames) { + options.keep_classnames = true; + } + if (program.keepFnames) { + options.keep_fnames = true; + } + if (program.mangleProps) { + if (program.mangleProps.domprops) { + delete program.mangleProps.domprops; + } else { + if (typeof program.mangleProps != "object") program.mangleProps = {}; + if (!Array.isArray(program.mangleProps.reserved)) program.mangleProps.reserved = []; + } + if (typeof options.mangle != "object") options.mangle = {}; + options.mangle.properties = program.mangleProps; + } + if (program.nameCache) { + options.nameCache = JSON.parse(read_file(program.nameCache, "{}")); + } + if (program.output == "ast") { + options.format = { + ast: true, + code: false + }; + } + if (program.parse) { + if (!program.parse.acorn && !program.parse.spidermonkey) { + options.parse = program.parse; + } else if (program.sourceMap && program.sourceMap.content == "inline") { + fatal("ERROR: inline source map only works with built-in parser"); + } + } + if (~program.rawArgs.indexOf("--rename")) { + options.rename = true; + } else if (!program.rename) { + options.rename = false; + } + + let convert_path = name => name; + if (typeof program.sourceMap == "object" && "base" in program.sourceMap) { + convert_path = function() { + var base = program.sourceMap.base; + delete options.sourceMap.base; + return function(name) { + return path.relative(base, name); + }; + }(); + } + + let filesList; + if (options.files && options.files.length) { + filesList = options.files; + + delete options.files; + } else if (program.args.length) { + filesList = program.args; + } + + if (filesList) { + simple_glob(filesList).forEach(function(name) { + files[convert_path(name)] = read_file(name); + }); + } else { + await new Promise((resolve) => { + var chunks = []; + process.stdin.setEncoding("utf8"); + process.stdin.on("data", function(chunk) { + chunks.push(chunk); + }).on("end", function() { + files = [ chunks.join("") ]; + resolve(); + }); + process.stdin.resume(); + }); + } + + await run_cli(); + + function convert_ast(fn) { + return AST_Node.from_mozilla_ast(Object.keys(files).reduce(fn, null)); + } + + async function run_cli() { + var content = program.sourceMap && program.sourceMap.content; + if (content && content !== "inline") { + options.sourceMap.content = read_file(content, content); + } + if (program.timings) options.timings = true; + + try { + if (program.parse) { + if (program.parse.acorn) { + files = convert_ast(function(toplevel, name) { + return require("acorn").parse(files[name], { + ecmaVersion: 2018, + locations: true, + program: toplevel, + sourceFile: name, + sourceType: options.module || program.parse.module ? "module" : "script" + }); + }); + } else if (program.parse.spidermonkey) { + files = convert_ast(function(toplevel, name) { + var obj = JSON.parse(files[name]); + if (!toplevel) return obj; + toplevel.body = toplevel.body.concat(obj.body); + return toplevel; + }); + } + } + } catch (ex) { + fatal(ex); + } + + let result; + try { + result = await minify(files, options, fs); + } catch (ex) { + if (ex.name == "SyntaxError") { + print_error("Parse error at " + ex.filename + ":" + ex.line + "," + ex.col); + var col = ex.col; + var lines = files[ex.filename].split(/\r?\n/); + var line = lines[ex.line - 1]; + if (!line && !col) { + line = lines[ex.line - 2]; + col = line.length; + } + if (line) { + var limit = 70; + if (col > limit) { + line = line.slice(col - limit); + col = limit; + } + print_error(line.slice(0, 80)); + print_error(line.slice(0, col).replace(/\S/g, " ") + "^"); + } + } + if (ex.defs) { + print_error("Supported options:"); + print_error(format_object(ex.defs)); + } + fatal(ex); + return; + } + + if (program.output == "ast") { + if (!options.compress && !options.mangle) { + result.ast.figure_out_scope({}); + } + console.log(JSON.stringify(result.ast, function(key, value) { + if (value) switch (key) { + case "thedef": + return symdef(value); + case "enclosed": + return value.length ? value.map(symdef) : undefined; + case "variables": + case "globals": + return value.size ? collect_from_map(value, symdef) : undefined; + } + if (skip_keys.has(key)) return; + if (value instanceof AST_Token) return; + if (value instanceof Map) return; + if (value instanceof AST_Node) { + var result = { + _class: "AST_" + value.TYPE + }; + if (value.block_scope) { + result.variables = value.block_scope.variables; + result.enclosed = value.block_scope.enclosed; + } + value.CTOR.PROPS.forEach(function(prop) { + if (prop !== "block_scope") { + result[prop] = value[prop]; + } + }); + return result; + } + return value; + }, 2)); + } else if (program.output == "spidermonkey") { + try { + const minified = await minify( + result.code, + { + compress: false, + mangle: false, + format: { + ast: true, + code: false + } + }, + fs + ); + console.log(JSON.stringify(minified.ast.to_mozilla_ast(), null, 2)); + } catch (ex) { + fatal(ex); + return; + } + } else if (program.output) { + fs.writeFileSync(program.output, result.code); + if (options.sourceMap && options.sourceMap.url !== "inline" && result.map) { + fs.writeFileSync(program.output + ".map", result.map); + } + } else { + console.log(result.code); + } + if (program.nameCache) { + fs.writeFileSync(program.nameCache, JSON.stringify(options.nameCache)); + } + if (result.timings) for (var phase in result.timings) { + print_error("- " + phase + ": " + result.timings[phase].toFixed(3) + "s"); + } + } + + function fatal(message) { + if (message instanceof Error) message = message.stack.replace(/^\S*?Error:/, "ERROR:"); + print_error(message); + process.exit(1); + } + + // A file glob function that only supports "*" and "?" wildcards in the basename. + // Example: "foo/bar/*baz??.*.js" + // Argument `glob` may be a string or an array of strings. + // Returns an array of strings. Garbage in, garbage out. + function simple_glob(glob) { + if (Array.isArray(glob)) { + return [].concat.apply([], glob.map(simple_glob)); + } + if (glob && glob.match(/[*?]/)) { + var dir = path.dirname(glob); + try { + var entries = fs.readdirSync(dir); + } catch (ex) {} + if (entries) { + var pattern = "^" + path.basename(glob) + .replace(/[.+^$[\]\\(){}]/g, "\\$&") + .replace(/\*/g, "[^/\\\\]*") + .replace(/\?/g, "[^/\\\\]") + "$"; + var mod = process.platform === "win32" ? "i" : ""; + var rx = new RegExp(pattern, mod); + var results = entries.filter(function(name) { + return rx.test(name); + }).map(function(name) { + return path.join(dir, name); + }); + if (results.length) return results; + } + } + return [ glob ]; + } + + function read_file(path, default_value) { + try { + return fs.readFileSync(path, "utf8"); + } catch (ex) { + if ((ex.code == "ENOENT" || ex.code == "ENAMETOOLONG") && default_value != null) return default_value; + fatal(ex); + } + } + + function parse_js(flag) { + return function(value, options) { + options = options || {}; + try { + walk(parse(value, { expression: true }), node => { + if (node instanceof AST_Assign) { + var name = node.left.print_to_string(); + var value = node.right; + if (flag) { + options[name] = value; + } else if (value instanceof AST_Array) { + options[name] = value.elements.map(to_string); + } else if (value instanceof AST_RegExp) { + value = value.value; + options[name] = new RegExp(value.source, value.flags); + } else { + options[name] = to_string(value); + } + return true; + } + if (node instanceof AST_Symbol || node instanceof AST_PropAccess) { + var name = node.print_to_string(); + options[name] = true; + return true; + } + if (!(node instanceof AST_Sequence)) throw node; + + function to_string(value) { + return value instanceof AST_Constant ? value.getValue() : value.print_to_string({ + quote_keys: true + }); + } + }); + } catch(ex) { + if (flag) { + fatal("Error parsing arguments for '" + flag + "': " + value); + } else { + options[value] = null; + } + } + return options; + }; + } + + function symdef(def) { + var ret = (1e6 + def.id) + " " + def.name; + if (def.mangled_name) ret += " " + def.mangled_name; + return ret; + } + + function collect_from_map(map, callback) { + var result = []; + map.forEach(function (def) { + result.push(callback(def)); + }); + return result; + } + + function format_object(obj) { + var lines = []; + var padding = ""; + Object.keys(obj).map(function(name) { + if (padding.length < name.length) padding = Array(name.length + 1).join(" "); + return [ name, JSON.stringify(obj[name]) ]; + }).forEach(function(tokens) { + lines.push(" " + tokens[0] + padding.slice(tokens[0].length - 2) + tokens[1]); + }); + return lines.join("\n"); + } + + function print_error(msg) { + process.stderr.write(msg); + process.stderr.write("\n"); + } + + function describe_ast() { + var out = OutputStream({ beautify: true }); + function doitem(ctor) { + out.print("AST_" + ctor.TYPE); + const props = ctor.SELF_PROPS.filter(prop => !/^\$/.test(prop)); + + if (props.length > 0) { + out.space(); + out.with_parens(function() { + props.forEach(function(prop, i) { + if (i) out.space(); + out.print(prop); + }); + }); + } + + if (ctor.documentation) { + out.space(); + out.print_string(ctor.documentation); + } + + if (ctor.SUBCLASSES.length > 0) { + out.space(); + out.with_block(function() { + ctor.SUBCLASSES.forEach(function(ctor) { + out.indent(); + doitem(ctor); + out.newline(); + }); + }); + } + } + doitem(AST_Node); + return out + "\n"; + } +} + +async function _default_options() { + const defs = {}; + + Object.keys(infer_options({ 0: 0 })).forEach((component) => { + const options = infer_options({ + [component]: {0: 0} + }); + + if (options) defs[component] = options; + }); + return defs; +} + +async function infer_options(options) { + try { + await minify("", options); + } catch (error) { + return error.defs; + } +} + +exports.AST_Node = AST_Node; +exports.AST_Token = AST_Token; +exports._default_options = _default_options; +exports._run_cli = run_cli; +exports.minify = minify; }))); -//# sourceMappingURL=bundle.js.map diff --git a/tools/acorn-optimizer.js b/tools/acorn-optimizer.js index 6c5ce3e0ee5e5..e466a6212d53c 100755 --- a/tools/acorn-optimizer.js +++ b/tools/acorn-optimizer.js @@ -1945,24 +1945,16 @@ function reattachComments(ast, comments) { symbols[j].start.comments_before = []; } symbols[j].start.comments_before.push( - new terser.AST_Token({ - end: undefined, - quote: undefined, - raw: undefined, - file: '0', - comments_after: undefined, - comments_before: undefined, - nlb: false, - endpos: undefined, - endcol: undefined, - endline: undefined, - pos: undefined, - col: undefined, - line: undefined, - value: comments[i].value, - type: comments[i].type == 'Line' ? 'comment' : 'comment2', - flags: 0, - }) + new terser.AST_Token( + comments[i].type == 'Line' ? 'comment' : 'comment2', + comments[i].value, + undefined, + undefined, + false, + undefined, + undefined, + '0' + ) ); } } diff --git a/tools/unsafe_optimizations.js b/tools/unsafe_optimizations.js index 0463f92f7fa41..9ff7a5ef648b6 100644 --- a/tools/unsafe_optimizations.js +++ b/tools/unsafe_optimizations.js @@ -223,7 +223,7 @@ function optPassMergeVarInitializationAssignments(ast) { } function runOnJsText(js, pretty = false) { - const ast = acorn.parse(js, {ecmaVersion: 6}); + const ast = acorn.parse(js, {ecmaVersion: 2020}); optPassSimplifyModuleInitialization(ast); optPassRemoveRedundantOperatorNews(ast); @@ -255,7 +255,7 @@ let numTestFailures = 0; function test(input, expected) { const observed = runOnJsText(input); if (observed != expected) { - console.error(`Input: ${input}\nobserved: ${observed}\nexpected: ${expected}\n`); + console.error(`ERROR: Input: ${input}\nobserved: ${observed}\nexpected: ${expected}\n`); ++numTestFailures; } else { console.log(`OK: ${input} -> ${expected}`); @@ -279,7 +279,7 @@ function runTests() { test("new function(a) {new TextDecoder(a);}('utf8');", ''); test( 'WebAssembly.instantiate(c.wasm,{}).then((a) => {new Int8Array(b);});', - 'WebAssembly.instantiate(c.wasm,{}).then(a=>{});' + 'WebAssembly.instantiate(c.wasm,{}).then((a=>{}));' ); test('let x=new Uint16Array(a);', 'let x=new Uint16Array(a);'); @@ -305,6 +305,9 @@ function runTests() { // Test that arrays containing nulls don't cause issues test('[,];', '[,];'); + // Test optional chaining operator + test('console?.log("");', 'console?.log("");'); + process.exit(numTestFailures); } From d7470049c0514d3c5418d606271359b76baf522d Mon Sep 17 00:00:00 2001 From: Brendan Dahl Date: Fri, 7 Jul 2023 15:19:55 -0700 Subject: [PATCH 0529/1523] JSPI - Enable cubescript test. (#19802) Test is already working no changes needed. --- .circleci/config.yml | 3 ++- test/test_core.py | 10 +++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 60b6131c75d27..2500e05b55439 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -657,7 +657,8 @@ jobs: core2.test_hello_world core0.test_pthread_join_and_asyncify core0.test_async_ccall_promise_jspi - core0.test_async_ccall_promise_exit_runtime_jspi" + core0.test_async_ccall_promise_exit_runtime_jspi + core0.test_cubescript_jspi" # Run some basic tests with the minimum version of node that we currently # support. - install-node-version: diff --git a/test/test_core.py b/test/test_core.py index e1d96f71b470b..7acfb7927d27f 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -6637,8 +6637,9 @@ def test_mmap_anon_pthreads(self): @no_lsan('Test code contains memory leaks') @parameterized({ - '': (False,), - '_asyncify': (True,) + '': (0,), + 'asyncify': (1,), + 'jspi': (2,), }) def test_cubescript(self, asyncify): # uses register keyword @@ -6652,7 +6653,10 @@ def test_cubescript(self, asyncify): if asyncify: if self.is_wasm64(): self.skipTest('TODO: asyncify for wasm64') - self.set_setting('ASYNCIFY') + self.set_setting('ASYNCIFY', asyncify) + if asyncify == 2: + self.require_jspi() + self.emcc_args += ['-Wno-experimental'] src = test_file('third_party/cubescript/command.cpp') self.do_runf(src, '*\nTemp is 33\n9\n5\nhello, everyone\n*') From 61e6b14d980f5904362638ad1b2ea9fb40a2bc3f Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 7 Jul 2023 15:24:13 -0700 Subject: [PATCH 0530/1523] Be consistent with single quotes in generated code. NFC (#19811) --- emscripten.py | 8 ++++---- src/jsifier.js | 2 +- src/library_async.js | 2 +- src/library_exports.js | 2 +- src/modules.js | 2 +- test/test_other.py | 8 ++++---- tools/acorn-optimizer.js | 8 ++++---- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/emscripten.py b/emscripten.py index cf778bd8f41bd..bda7604280c4b 100644 --- a/emscripten.py +++ b/emscripten.py @@ -755,7 +755,7 @@ def install_wrapper(sym): # TODO(sbc): Can we avoid exporting the dynCall_ functions on the module. should_export = settings.EXPORT_KEEPALIVE and mangled in settings.EXPORTED_FUNCTIONS if name.startswith('dynCall_') or should_export: - exported = 'Module["%s"] = ' % mangled + exported = "Module['%s'] = " % mangled else: exported = '' wrapper += exported @@ -771,7 +771,7 @@ def install_wrapper(sym): # With assertions disabled the wrapper will replace the global var and Module var on # first use. wrapper += f'''function() {{ - return ({mangled} = {exported}Module["asm"]["{name}"]).apply(null, arguments); + return ({mangled} = {exported}Module['asm']['{name}']).apply(null, arguments); }}; ''' else: @@ -797,7 +797,7 @@ def create_receiving(exports): # In Wasm exports are assigned inside a function to variables # existing in top level JS scope, i.e. # var _main; - # WebAssembly.instantiate(Module["wasm"], imports).then((output) => { + # WebAssembly.instantiate(Module['wasm'], imports).then((output) => { # var asm = output.instance.exports; # _main = asm["_main"]; generate_dyncall_assignment = settings.DYNCALLS and '$dynCall' in settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE @@ -809,7 +809,7 @@ def create_receiving(exports): should_export = settings.EXPORT_ALL or (settings.EXPORT_KEEPALIVE and mangled in settings.EXPORTED_FUNCTIONS) export_assignment = '' if settings.MODULARIZE and should_export: - export_assignment = f'Module["{mangled}"] = ' + export_assignment = f"Module['{mangled}'] = " receiving += [f'{export_assignment}{dynCallAssignment}{mangled} = asm["{s}"]'] else: receiving += make_export_wrappers(exports, delay_assignment) diff --git a/src/jsifier.js b/src/jsifier.js index 6fbcd00cae356..edb6a5fa11edc 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -507,7 +507,7 @@ function(${args}) { // asm module exports are done in emscripten.py, after the asm module is ready. Here // we also export library methods as necessary. if ((EXPORT_ALL || EXPORTED_FUNCTIONS.has(mangled)) && !isStub) { - contentText += `\nModule["${mangled}"] = ${mangled};`; + contentText += `\nModule['${mangled}'] = ${mangled};`; } // Relocatable code needs signatures to create proper wrappers. Stack // switching needs signatures so we can create a proper diff --git a/src/library_async.js b/src/library_async.js index 52be05df3cd6b..776a084a97ac6 100644 --- a/src/library_async.js +++ b/src/library_async.js @@ -269,7 +269,7 @@ mergeInto(LibraryManager.library, { var name = Asyncify.callStackIdToName[id]; var func = Module['asm'][name]; #if RELOCATABLE - // Exported functions in side modules are not listed in `Module["asm"]`, + // Exported functions in side modules are not listed in `Module['asm']`, // So we should use `resolveGlobalSymbol` helper function, which is defined in `library_dylink.js`. if (!func) { func = resolveGlobalSymbol(name, false).sym; diff --git a/src/library_exports.js b/src/library_exports.js index 59a1ba4fcdd53..b04839b7e2ae1 100644 --- a/src/library_exports.js +++ b/src/library_exports.js @@ -16,7 +16,7 @@ mergeInto(LibraryManager.library, { var exportedFunc = asm[name]; #else // In regular runtime, exports are available on the Module object. - var exportedFunc = Module["asm"][name]; + var exportedFunc = Module['asm'][name]; #endif if (exportedFunc) { // Record the created function pointer to each function object, diff --git a/src/modules.js b/src/modules.js index bbaf317e2d235..20200c5fd4192 100644 --- a/src/modules.js +++ b/src/modules.js @@ -355,7 +355,7 @@ function exportRuntime() { } else if (legacyRuntimeElements.has(exported)) { exported = legacyRuntimeElements.get(exported); } - return `Module["${name}"] = ${exported};`; + return `Module['${name}'] = ${exported};`; } } diff --git a/test/test_other.py b/test/test_other.py index 60d25f526f56a..b27f4dcbc73e2 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -5756,10 +5756,10 @@ def test(opts, has, not_has): self.assertContained(has, src) self.assertNotContained(not_has, src) - test([], 'Module["', 'Module["waka') - test(['-sEXPORTED_RUNTIME_METHODS=[]'], '', 'Module["addRunDependency') - test(['-sEXPORTED_RUNTIME_METHODS=addRunDependency'], 'Module["addRunDependency', 'Module["waka') - test(['-sEXPORTED_RUNTIME_METHODS=[]', '-sEXPORTED_RUNTIME_METHODS=addRunDependency'], 'Module["addRunDependency', 'Module["waka') + test([], "Module['", "Module['waka") + test(['-sEXPORTED_RUNTIME_METHODS=[]'], '', "Module['addRunDependency") + test(['-sEXPORTED_RUNTIME_METHODS=addRunDependency'], "Module['addRunDependency", "Module['waka") + test(['-sEXPORTED_RUNTIME_METHODS=[]', '-sEXPORTED_RUNTIME_METHODS=addRunDependency'], "Module['addRunDependency", "Module['waka") def test_stat_fail_alongtheway(self): create_file('src.c', r''' diff --git a/tools/acorn-optimizer.js b/tools/acorn-optimizer.js index e466a6212d53c..53f8e1bc08cfc 100755 --- a/tools/acorn-optimizer.js +++ b/tools/acorn-optimizer.js @@ -665,16 +665,16 @@ function emitDCEGraph(ast) { // The exports are trickier, as they have a different form whether or not // async compilation is enabled. It can be either: // - // var _malloc = Module["_malloc"] = asm["_malloc"]; + // var _malloc = Module['_malloc'] = asm['_malloc']; // // or // - // var _malloc = asm["_malloc"]; + // var _malloc = asm['_malloc']; // // or // - // var _malloc = Module["_malloc"] = (function() { - // return Module["asm"]["_malloc"].apply(null, arguments); + // var _malloc = Module['_malloc'] = (function() { + // return Module['asm']['_malloc'].apply(null, arguments); // }); // // or, in the minimal runtime, it looks like From 3a3329d8e1358b1fd7ac127edfe5186ba5873fcd Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Fri, 7 Jul 2023 20:13:09 -0700 Subject: [PATCH 0531/1523] [docs] Fix docs about getExceptionMessage() (#19814) #19764 pointed out that the docs on `getExceptionMessage` was outdated. We don't need to implement a custom `getExceptionMessage` anymore. --- site/source/docs/porting/Debugging.rst | 53 +------------------------ site/source/docs/porting/exceptions.rst | 50 ++++++++++++++++++++--- test/test_core.py | 1 + 3 files changed, 48 insertions(+), 56 deletions(-) diff --git a/site/source/docs/porting/Debugging.rst b/site/source/docs/porting/Debugging.rst index 773c2148ce566..a4b872aec8829 100644 --- a/site/source/docs/porting/Debugging.rst +++ b/site/source/docs/porting/Debugging.rst @@ -157,60 +157,11 @@ See `Debugging WebAssembly with modern tools `_ for the details. -.. _handling-c-exceptions-from-javascript: - -Handling C++ exceptions from JavaScript +Handling C++ Exceptions from JavaScript ======================================= -C++ exceptions are thrown from WebAssembly using exception pointers, which means -that try/catch/finally blocks in JavaScript will only receive a number, which -represents a pointer into linear memory. In order to get the exception message, -the user will need to create some WASM code which will extract the meaning from -the exception. In the example code below we created a function that receives the -address of a ``std::exception``, and by casting the pointer -returns the ``what`` function call result. - -.. code-block:: cpp - - #include - - std::string getExceptionMessage(intptr_t exceptionPtr) { - return std::string(reinterpret_cast(exceptionPtr)->what()); - } - - EMSCRIPTEN_BINDINGS(Bindings) { - emscripten::function("getExceptionMessage", &getExceptionMessage); - }; - -This requires using the linker flags ``-lembind -sEXPORT_EXCEPTION_HANDLING_HELPERS``. -Once such a function has been created, exception handling code in javascript -can call it when receiving an exception from WASM. Here the function is used -in order to log the thrown exception. +See :ref:`handling-c-exceptions-from-javascript`. -.. code-block:: javascript - - try { - ... // some code that calls WebAssembly - } catch (exception) { - console.error(Module.getExceptionMessage(exception)); - } finally { - ... - } - -It's important to notice that this example code will work only for thrown -statically allocated exceptions. If your code throws other objects, such as -strings or dynamically allocated exceptions, the handling code will need to -take that into account. For example, if your code needs to handle both native -C++ exceptions and JavaScript exceptions you could use the following code to -distinguish between them: - -.. code-block:: javascript - - function getExceptionMessage(exception) { - return typeof exception === 'number' - ? Module.getExceptionMessage(exception) - : exception; - } .. _debugging-emscripten-specific-issues: diff --git a/site/source/docs/porting/exceptions.rst b/site/source/docs/porting/exceptions.rst index 5cb606e26c6ae..168336875eadf 100644 --- a/site/source/docs/porting/exceptions.rst +++ b/site/source/docs/porting/exceptions.rst @@ -35,8 +35,8 @@ If you want to opt-in, you have two following options. .. _javascript-based-exception-support: -JavaScript-based Exception Support -================================== +Emscripten (JavaScript-based) Exception Support +=============================================== First, you can enable exceptions via Emscripten's JavaScript-based support. To enable it, pass ``-fexceptions`` at both compile time and link time. @@ -113,11 +113,51 @@ property. For example: Stack traces within Wasm code are not supported in :ref:`JavaScipt-based exceptions `. -Exception Messages ------------------- + +.. _handling-c-exceptions-from-javascript: + +Handling C++ Exceptions from JavaScript +--------------------------------------- You can also catch and examine the type and the message of C++ exceptions from -JavaScript. See :ref:`handling-c-exceptions-from-javascript`. +JavaScript, in case they inherit from ``std::exception`` and thus have ``what`` +method. + +``getExceptionMessage`` returns a list of two strings: ``[type, message]``. the +``message`` is the result of calling ``what`` method in case the exception is a +subclass of ``std::exception``. Otherwise it will be just an empty string. + +.. code-block:: javascript + + try { + ... // some code that calls WebAssembly + } catch (e) { + console.log(getExceptionMessage(e).toString()); + } finally { + ... + } + +In case the thrown value is an integer 3, this will print ``int,``, because the +message part is empty. If the thrown value is an instance of ``MyException`` +that is a subclass of ``std::exception`` and its ``what`` message is ``My +exception thrown``, this code will print ``MyException,My exception thrown``. + +To use this function, you need to pass ``-sEXPORT_EXCEPTION_HANDLING_HELPERS`` +to the options. You need to enable either of Emscripten EH or Wasm EH to use +this option. + +.. note:: If you catch a Wasm exception and do not rethrow it, you need to free + the storage associated with the exception in JS using + ``decrementExceptionRefcount`` method because the exception + catching code in Wasm does not have a chance to free it. But currently due to + an implementation issue that Wasm EH and Emscripten (JS-based) EH, you need + to call incrementExceptionRefcount additionally in case of Emscripten EH. See + https://github.com/emscripten-core/emscripten/issues/17115 for details and a + code example. + +.. todo:: Fix the above-mentinoed `inconsistency + `_ between Wasm + EH and Emscripten EH, on the reference counting. Using Exceptions and setjmp-longjmp Together diff --git a/test/test_core.py b/test/test_core.py index 7acfb7927d27f..930ca09f6cb0d 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -1598,6 +1598,7 @@ class myexception : public exception { // Emscripten EH sets the refcount to 0 when throwing, and // increase it in __cxa_begin_catch, and decrease it in // __cxa_end_catch. Fix this inconsistency later. + // https://github.com/emscripten-core/emscripten/issues/17115 incrementExceptionRefcount(p); #endif console.log(getExceptionMessage(p).toString()); From a6b8143cf3c1171db911750359456b15a8deece7 Mon Sep 17 00:00:00 2001 From: Kassy <78169097+Kassy2048@users.noreply.github.com> Date: Sun, 9 Jul 2023 08:29:58 +0200 Subject: [PATCH 0532/1523] Use dedicated API to know if fullscreen/pointerlock can be requested (#19758) Fullscreen can be requested during transient activation not just while handling an input event, so check for that on browsers that support it. --- src/library_html5.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/library_html5.js b/src/library_html5.js index 71e521ecc2a87..8e6837acd8c30 100644 --- a/src/library_html5.js +++ b/src/library_html5.js @@ -112,6 +112,14 @@ var LibraryHTML5 = { }, canPerformEventHandlerRequests: function() { + if (navigator.userActivation) { + // Verify against transient activation status from UserActivation API + // whether it is possible to perform a request here without needing to defer. See + // https://developer.mozilla.org/en-US/docs/Web/Security/User_activation#transient_activation + // and https://caniuse.com/mdn-api_useractivation + // At the time of writing, Firefox does not support this API: https://bugzilla.mozilla.org/show_bug.cgi?id=1791079 + return navigator.userActivation.isActive; + } return JSEvents.inEventHandler && JSEvents.currentEventHandler.allowsDeferredCalls; }, From 34dff27cb0254b0269dea4d9ca4970a66c1580b2 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 10 Jul 2023 11:21:34 -0700 Subject: [PATCH 0533/1523] Automatically convert pointer args for wasmfs funcs. NFC (#19823) We really should find a way for folks to attach this metadata to native functions in the source code. --- emscripten.py | 2 ++ src/library_wasmfs.js | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/emscripten.py b/emscripten.py index bda7604280c4b..6f41722177e19 100644 --- a/emscripten.py +++ b/emscripten.py @@ -903,6 +903,8 @@ def create_pointer_conversion_wrappers(metadata): '_emscripten_proxy_dlsync_async': '_pp', '_wasmfs_rmdir': '_p', '_wasmfs_unlink': '_p', + '_wasmfs_mkdir': '_p_', + '_wasmfs_open': '_p__', 'emscripten_wasm_worker_initialize': '_p_', } diff --git a/src/library_wasmfs.js b/src/library_wasmfs.js index a961456026bea..f8f3ab2c65104 100644 --- a/src/library_wasmfs.js +++ b/src/library_wasmfs.js @@ -148,7 +148,7 @@ FS.createPreloadedFile = FS_createPreloadedFile; mkdir: (path, mode) => FS.handleError(withStackSave(() => { mode = mode !== undefined ? mode : 511 /* 0777 */; var buffer = stringToUTF8OnStack(path); - return __wasmfs_mkdir({{{ to64('buffer') }}}, mode); + return __wasmfs_mkdir(buffer, mode); })), mkdirTree: (path, mode) => { var dirs = path.split('/'); @@ -170,7 +170,7 @@ FS.createPreloadedFile = FS_createPreloadedFile; flags = typeof flags == 'string' ? FS_modeStringToFlags(flags) : flags; mode = typeof mode == 'undefined' ? 438 /* 0666 */ : mode; var buffer = stringToUTF8OnStack(path); - var fd = FS.handleError(__wasmfs_open({{{ to64('buffer') }}}, flags, mode)); + var fd = FS.handleError(__wasmfs_open(buffer, flags, mode)); return { fd : fd }; }), create: (path, mode) => { From ed35cb952d17807b321c42d3d2aeb7d27e184ff0 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 10 Jul 2023 13:36:18 -0700 Subject: [PATCH 0534/1523] Mark 3.1.43 as released (#19826) --- ChangeLog.md | 5 ++++- emscripten-version.txt | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 118bb43b1ea91..b25577dfc3ed5 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -18,8 +18,11 @@ to browse the changes between the tags. See docs/process.md for more on how version tagging works. -3.1.43 (in development) +3.1.44 (in development) ----------------------- + +3.1.43 - 07/10/23 +----------------- - Handling i64 arguments and return values in JS functions is now much simpler with the new `__i53abi` decorator. When this is set to true, i64 values are automatically converted to JS numbers (i53) at the JS boundary. Parameters diff --git a/emscripten-version.txt b/emscripten-version.txt index e4bc9e9f5be44..c4a4f68771378 100644 --- a/emscripten-version.txt +++ b/emscripten-version.txt @@ -1 +1 @@ -3.1.43-git +3.1.44-git From 502bc378f07483faf444428aa84322412a1087d8 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 10 Jul 2023 13:39:11 -0700 Subject: [PATCH 0535/1523] Fix extra braces added during terser update. NFC (#19813) See https://github.com/terser/terser/issues/839 See #19805 --- test/optimizer/applyImportAndExportNameChanges2-output.js | 4 ++-- .../minimal-runtime-applyDCEGraphRemovals-output.js | 4 ++-- tools/acorn-optimizer.js | 1 + tools/unsafe_optimizations.js | 8 ++++++-- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/test/optimizer/applyImportAndExportNameChanges2-output.js b/test/optimizer/applyImportAndExportNameChanges2-output.js index a2d41cf3f95ab..03d3dfdbb746e 100644 --- a/test/optimizer/applyImportAndExportNameChanges2-output.js +++ b/test/optimizer/applyImportAndExportNameChanges2-output.js @@ -264,7 +264,7 @@ var imports = { var ___errno_location, _llvm_bswap_i32, _main, _memcpy, _memset, dynCall_ii, dynCall_iiii; -WebAssembly.instantiate(Module["wasm"], imports).then((output => { +WebAssembly.instantiate(Module["wasm"], imports).then(output => { var asm = output.instance.exports; ___errno_location = asm["j"]; _llvm_bswap_i32 = asm["k"]; @@ -275,4 +275,4 @@ WebAssembly.instantiate(Module["wasm"], imports).then((output => { dynCall_iiii = asm["p"]; initRuntime(asm); ready(); -})); +}); diff --git a/test/optimizer/minimal-runtime-applyDCEGraphRemovals-output.js b/test/optimizer/minimal-runtime-applyDCEGraphRemovals-output.js index 7607038014f8c..465ce4410ab35 100644 --- a/test/optimizer/minimal-runtime-applyDCEGraphRemovals-output.js +++ b/test/optimizer/minimal-runtime-applyDCEGraphRemovals-output.js @@ -5,14 +5,14 @@ var wasmImports = { save2: 2 }; -WebAssembly.instantiate(Module["wasm"], imports).then((output => { +WebAssembly.instantiate(Module["wasm"], imports).then(output => { asm = output.instance.exports; expD1 = asm["expD1"]; expD2 = asm["expD2"]; expD3 = asm["expD3"]; initRuntime(asm); ready(); -})); +}); expD1; diff --git a/tools/acorn-optimizer.js b/tools/acorn-optimizer.js index 53f8e1bc08cfc..d5b54c452f40e 100755 --- a/tools/acorn-optimizer.js +++ b/tools/acorn-optimizer.js @@ -2067,6 +2067,7 @@ if (!noPrint) { beautify: !minifyWhitespace, indent_level: minifyWhitespace ? 0 : 1, keep_quoted_props: true, // for closure + wrap_func_args: false, // don't add extra braces comments: true, // for closure as well }); diff --git a/tools/unsafe_optimizations.js b/tools/unsafe_optimizations.js index 9ff7a5ef648b6..df2b9485d191d 100644 --- a/tools/unsafe_optimizations.js +++ b/tools/unsafe_optimizations.js @@ -238,7 +238,11 @@ function runOnJsText(js, pretty = false) { optPassSimplifyModularizeFunction(ast); const terserAst = terser.AST_Node.from_mozilla_ast(ast); - const output = terserAst.print_to_string({beautify: pretty, indent_level: pretty ? 1 : 0}); + const output = terserAst.print_to_string({ + wrap_func_args: false, + beautify: pretty, + indent_level: pretty ? 1 : 0, + }); return output; } @@ -279,7 +283,7 @@ function runTests() { test("new function(a) {new TextDecoder(a);}('utf8');", ''); test( 'WebAssembly.instantiate(c.wasm,{}).then((a) => {new Int8Array(b);});', - 'WebAssembly.instantiate(c.wasm,{}).then((a=>{}));' + 'WebAssembly.instantiate(c.wasm,{}).then(a=>{});' ); test('let x=new Uint16Array(a);', 'let x=new Uint16Array(a);'); From 7fa9b693c3f85f604cf44ecaeca545df539f10c4 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 10 Jul 2023 13:46:59 -0700 Subject: [PATCH 0536/1523] Remove unnecessary updateExport macro in library_glemu.js. NFC (#19824) This macro was implement in order to support dynamic linking, but recent changes to the way symbol are resolved in the dynamic linker make this no longer needed. We have test for this behaviour in the `browser.test_dynamic_link_glemu`. --- src/library_glemu.js | 43 ------------------------------------------- 1 file changed, 43 deletions(-) diff --git a/src/library_glemu.js b/src/library_glemu.js index f25307386ede6..c7e2c753763de 100644 --- a/src/library_glemu.js +++ b/src/library_glemu.js @@ -178,19 +178,6 @@ var LibraryGLEmulation = { 0x80A0: 1 // GL_SAMPLE_COVERAGE }; -#if RELOCATABLE -{{{ -(updateExport = (name) => { - var name = `_${name}`; - var exported = `Module["${name}"]`; - // make sure we write to an existing export, and are not repeating ourselves - return `assert(${exported} !== ${name}); ${exported} = ${name};`; -}, '') -}}} -#else -{{{ (updateExport = () => '', '') }}} -#endif - var glEnable = _glEnable; _glEnable = _emscripten_glEnable = (cap) => { // Clean up the renderer on any change to the rendering state. The optimization of @@ -241,7 +228,6 @@ var LibraryGLEmulation = { } glEnable(cap); }; - {{{ updateExport('glEnable') }}} var glDisable = _glDisable; _glDisable = _emscripten_glDisable = (cap) => { @@ -291,7 +277,6 @@ var LibraryGLEmulation = { } glDisable(cap); }; - {{{ updateExport('glDisable') }}} _glIsEnabled = _emscripten_glIsEnabled = (cap) => { if (cap == 0xB60 /* GL_FOG */) { @@ -311,7 +296,6 @@ var LibraryGLEmulation = { } return GLctx.isEnabled(cap); }; - {{{ updateExport('glIsEnabled') }}} var glGetBooleanv = _glGetBooleanv; _glGetBooleanv = _emscripten_glGetBooleanv = (pname, p) => { @@ -323,7 +307,6 @@ var LibraryGLEmulation = { } glGetBooleanv(pname, p); }; - {{{ updateExport('glGetBooleanv') }}} var glGetIntegerv = _glGetIntegerv; _glGetIntegerv = _emscripten_glGetIntegerv = (pname, params) => { @@ -405,7 +388,6 @@ var LibraryGLEmulation = { } glGetIntegerv(pname, params); }; - {{{ updateExport('glGetIntegerv') }}} var glGetString = _glGetString; _glGetString = _emscripten_glGetString = (name_) => { @@ -421,7 +403,6 @@ var LibraryGLEmulation = { } return glGetString(name_); }; - {{{ updateExport('glGetString') }}} // Do some automatic rewriting to work around GLSL differences. Note that this must be done in // tandem with the rest of the program, by itself it cannot suffice. @@ -440,7 +421,6 @@ var LibraryGLEmulation = { }; return id; }; - {{{ updateExport('glCreateShader') }}} function ensurePrecision(source) { if (!/precision +(low|medium|high)p +float *;/.test(source)) { @@ -561,7 +541,6 @@ var LibraryGLEmulation = { #endif GLctx.shaderSource(GL.shaders[shader], source); }; - {{{ updateExport('glShaderSource') }}} var glCompileShader = _glCompileShader; _glCompileShader = _emscripten_glCompileShader = (shader) => { @@ -576,7 +555,6 @@ var LibraryGLEmulation = { } #endif }; - {{{ updateExport('glCompileShader') }}} GL.programShaders = {}; var glAttachShader = _glAttachShader; @@ -585,7 +563,6 @@ var LibraryGLEmulation = { GL.programShaders[program].push(shader); glAttachShader(program, shader); }; - {{{ updateExport('glAttachShader') }}} var glDetachShader = _glDetachShader; _glDetachShader = _emscripten_glDetachShader = (program, shader) => { @@ -598,7 +575,6 @@ var LibraryGLEmulation = { programShader.splice(index, 1); glDetachShader(program, shader); }; - {{{ updateExport('glDetachShader') }}} var glUseProgram = _glUseProgram; _glUseProgram = _emscripten_glUseProgram = (program) => { @@ -620,7 +596,6 @@ var LibraryGLEmulation = { glUseProgram(program); } } - {{{ updateExport('glUseProgram') }}} var glDeleteProgram = _glDeleteProgram; _glDeleteProgram = _emscripten_glDeleteProgram = (program) => { @@ -630,7 +605,6 @@ var LibraryGLEmulation = { GL.currProgram = 0; } }; - {{{ updateExport('glDeleteProgram') }}} // If attribute 0 was not bound, bind it to 0 for WebGL performance reasons. Track if 0 is free for that. var zeroUsedPrograms = {}; @@ -639,7 +613,6 @@ var LibraryGLEmulation = { if (index == 0) zeroUsedPrograms[program] = true; glBindAttribLocation(program, index, name); }; - {{{ updateExport('glBindAttribLocation') }}} var glLinkProgram = _glLinkProgram; _glLinkProgram = _emscripten_glLinkProgram = (program) => { @@ -648,7 +621,6 @@ var LibraryGLEmulation = { } glLinkProgram(program); }; - {{{ updateExport('glLinkProgram') }}} var glBindBuffer = _glBindBuffer; _glBindBuffer = _emscripten_glBindBuffer = (target, buffer) => { @@ -664,7 +636,6 @@ var LibraryGLEmulation = { if (GLEmulation.currentVao) GLEmulation.currentVao.elementArrayBuffer = buffer; } }; - {{{ updateExport('glBindBuffer') }}} var glGetFloatv = _glGetFloatv; _glGetFloatv = _emscripten_glGetFloatv = (pname, params) => { @@ -695,7 +666,6 @@ var LibraryGLEmulation = { glGetFloatv(pname, params); } }; - {{{ updateExport('glGetFloatv') }}} var glHint = _glHint; _glHint = _emscripten_glHint = (target, mode) => { @@ -704,7 +674,6 @@ var LibraryGLEmulation = { } glHint(target, mode); }; - {{{ updateExport('glHint') }}} var glEnableVertexAttribArray = _glEnableVertexAttribArray; _glEnableVertexAttribArray = _emscripten_glEnableVertexAttribArray = (index) => { @@ -712,7 +681,6 @@ var LibraryGLEmulation = { GLEmulation.enabledVertexAttribArrays[index] = 1; if (GLEmulation.currentVao) GLEmulation.currentVao.enabledVertexAttribArrays[index] = 1; }; - {{{ updateExport('glEnableVertexAttribArray') }}} var glDisableVertexAttribArray = _glDisableVertexAttribArray; _glDisableVertexAttribArray = _emscripten_glDisableVertexAttribArray = (index) => { @@ -720,7 +688,6 @@ var LibraryGLEmulation = { delete GLEmulation.enabledVertexAttribArrays[index]; if (GLEmulation.currentVao) delete GLEmulation.currentVao.enabledVertexAttribArrays[index]; }; - {{{ updateExport('glDisableVertexAttribArray') }}} var glVertexAttribPointer = _glVertexAttribPointer; _glVertexAttribPointer = _emscripten_glVertexAttribPointer = (index, size, type, normalized, stride, pointer) => { @@ -729,7 +696,6 @@ var LibraryGLEmulation = { GLEmulation.currentVao.vertexAttribPointers[index] = [index, size, type, normalized, stride, pointer]; } }; - {{{ updateExport('glVertexAttribPointer') }}} }, getAttributeFromCapability: function(cap) { @@ -2793,21 +2759,18 @@ var LibraryGLEmulation = { GLImmediate.TexEnvJIT.hook_activeTexture(texture); glActiveTexture(texture); }; - {{{ updateExport('glActiveTexture') }}} var glEnable = _glEnable; _glEnable = _emscripten_glEnable = (cap) => { GLImmediate.TexEnvJIT.hook_enable(cap); glEnable(cap); }; - {{{ updateExport('glEnable') }}} var glDisable = _glDisable; _glDisable = _emscripten_glDisable = (cap) => { GLImmediate.TexEnvJIT.hook_disable(cap); glDisable(cap); }; - {{{ updateExport('glDisable') }}} var glTexEnvf = (typeof _glTexEnvf != 'undefined') ? _glTexEnvf : () => {}; /** @suppress {checkTypes} */ @@ -2816,7 +2779,6 @@ var LibraryGLEmulation = { // Don't call old func, since we are the implementor. //glTexEnvf(target, pname, param); }; - {{{ updateExport('glTexEnvf') }}} var glTexEnvi = (typeof _glTexEnvi != 'undefined') ? _glTexEnvi : () => {}; /** @suppress {checkTypes} */ @@ -2825,7 +2787,6 @@ var LibraryGLEmulation = { // Don't call old func, since we are the implementor. //glTexEnvi(target, pname, param); }; - {{{ updateExport('glTexEnvi') }}} var glTexEnvfv = (typeof _glTexEnvfv != 'undefined') ? _glTexEnvfv : () => {}; /** @suppress {checkTypes} */ @@ -2834,17 +2795,14 @@ var LibraryGLEmulation = { // Don't call old func, since we are the implementor. //glTexEnvfv(target, pname, param); }; - {{{ updateExport('glTexEnvfv') }}} _glGetTexEnviv = (target, pname, param) => { GLImmediate.TexEnvJIT.hook_getTexEnviv(target, pname, param); }; - {{{ updateExport('glGetTexEnviv') }}} _glGetTexEnvfv = (target, pname, param) => { GLImmediate.TexEnvJIT.hook_getTexEnvfv(target, pname, param); }; - {{{ updateExport('glGetTexEnvfv') }}} var glGetIntegerv = _glGetIntegerv; _glGetIntegerv = _emscripten_glGetIntegerv = (pname, params) => { @@ -2862,7 +2820,6 @@ var LibraryGLEmulation = { } glGetIntegerv(pname, params); }; - {{{ updateExport('glGetIntegerv') }}} }, // Main functions From b3c5344129f3e199be8a02854b72a15391eedfc1 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 10 Jul 2023 13:49:02 -0700 Subject: [PATCH 0537/1523] Remove reference to old `asm` pass in js_optimizer.py. NFC (#19815) --- tools/building.py | 2 +- tools/js_optimizer.py | 31 +++++++++++++------------------ 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/tools/building.py b/tools/building.py index f25f778849290..cbbfd0a453f20 100644 --- a/tools/building.py +++ b/tools/building.py @@ -320,7 +320,7 @@ def opt_level_to_str(opt_level, shrink_level=0): def js_optimizer(filename, passes): from . import js_optimizer try: - return js_optimizer.run(filename, passes) + return js_optimizer.run_on_js(filename, passes) except subprocess.CalledProcessError as e: exit_with_error("'%s' failed (%d)", ' '.join(e.cmd), e.returncode) diff --git a/tools/js_optimizer.py b/tools/js_optimizer.py index aeb4f7118d038..d5dd1ed852b12 100755 --- a/tools/js_optimizer.py +++ b/tools/js_optimizer.py @@ -139,6 +139,7 @@ def chunkify(funcs, chunk_size): return [''.join(func[1] for func in chunk) for chunk in chunks] # remove function names +@ToolchainProfiler.profile_block('js_optimizer.run_on_js') def run_on_js(filename, passes, extra_info=None): with ToolchainProfiler.profile_block('js_optimizer.split_markers'): if not isinstance(passes, list): @@ -175,18 +176,17 @@ def run_on_js(filename, passes, extra_info=None): pre = js[:start_funcs + len(start_funcs_marker)] post = js[end_funcs + len(end_funcs_marker):] js = js[start_funcs + len(start_funcs_marker):end_funcs] - if 'asm' not in passes: - # can have Module[..] and inlining prevention code, push those to post - finals = [] - - def process(line): - if line and (line.startswith(('Module[', 'if (globalScope)')) or line.endswith('["X"]=1;')): - finals.append(line) - return False - return True - - js = '\n'.join(line for line in js.split('\n') if process(line)) - post = '\n'.join(finals) + '\n' + post + # can have Module[..] and inlining prevention code, push those to post + finals = [] + + def process(line): + if line and (line.startswith(('Module[', 'if (globalScope)')) or line.endswith('["X"]=1;')): + finals.append(line) + return False + return True + + js = '\n'.join(line for line in js.split('\n') if process(line)) + post = '\n'.join(finals) + '\n' + post post = end_funcs_marker + post else: with ToolchainProfiler.profile_block('js_optimizer.minify_globals'): @@ -346,11 +346,6 @@ def write_chunk(chunk, i): return filename -@ToolchainProfiler.profile_block('js_optimizer.run_on_js') -def run(filename, passes, extra_info=None): - return run_on_js(filename, passes, extra_info=extra_info) - - def main(): last = sys.argv[-1] if '{' in last: @@ -358,7 +353,7 @@ def main(): sys.argv = sys.argv[:-1] else: extra_info = None - out = run(sys.argv[1], sys.argv[2:], extra_info=extra_info) + out = run_on_js(sys.argv[1], sys.argv[2:], extra_info=extra_info) shutil.copyfile(out, sys.argv[1] + '.jsopt.js') return 0 From 84e1d04bc33bdb1b8f913931e3eea80a6a528030 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 10 Jul 2023 13:54:15 -0700 Subject: [PATCH 0538/1523] Remove data URL handling from low level `read_`/`readAsync` functions. NFC (#19792) These functions are used by the higher level `getBinarySync` and `getBinaryPromise` APIs. `getBinary` already handles data URLs itself. This change adds data URL handling to `getBinaryPromise` and removes it from the various low level implementations, making them much simpler. --- ChangeLog.md | 3 ++ src/node_shell_read.js | 12 -------- src/preamble.js | 6 +++- src/shell.js | 19 ++----------- src/web_or_worker_shell_read.js | 49 ++++++--------------------------- 5 files changed, 19 insertions(+), 70 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index b25577dfc3ed5..0de5d4df68f9d 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -20,6 +20,9 @@ See docs/process.md for more on how version tagging works. 3.1.44 (in development) ----------------------- +- The internal `read_` and `readAsync` functions no longer handle date URIs. + This only effects builds that use `-sSINGLE_FILE` or `--memory-init-file`. + (#19792) 3.1.43 - 07/10/23 ----------------- diff --git a/src/node_shell_read.js b/src/node_shell_read.js index a0a8de24e4902..6714c642974ef 100644 --- a/src/node_shell_read.js +++ b/src/node_shell_read.js @@ -5,12 +5,6 @@ */ read_ = (filename, binary) => { -#if SUPPORT_BASE64_EMBEDDING - var ret = tryParseAsDataURI(filename); - if (ret) { - return binary ? ret : ret.toString(); - } -#endif // We need to re-wrap `file://` strings to URLs. Normalizing isn't // necessary in that case, the path should already be absolute. filename = isFileURI(filename) ? new URL(filename) : nodePath.normalize(filename); @@ -29,12 +23,6 @@ readBinary = (filename) => { }; readAsync = (filename, onload, onerror, binary = true) => { -#if SUPPORT_BASE64_EMBEDDING - var ret = tryParseAsDataURI(filename); - if (ret) { - onload(ret); - } -#endif // See the comment in the `read_` function. filename = isFileURI(filename) ? new URL(filename) : nodePath.normalize(filename); fs.readFile(filename, binary ? undefined : 'utf8', (err, data) => { diff --git a/src/preamble.js b/src/preamble.js index 4a2755fe2897f..859488257532c 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -667,7 +667,11 @@ function getBinaryPromise(binaryFile) { // See https://github.com/github/fetch/pull/92#issuecomment-140665932 // Cordova or Electron apps are typically loaded from a file:// url. // So use fetch if it is available and the url is not a file, otherwise fall back to XHR. - if (!wasmBinary && (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER)) { + if (!wasmBinary +#if SUPPORT_BASE64_EMBEDDING + && !isDataURI(binaryFile) +#endif + && (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER)) { if (typeof fetch == 'function' #if ENVIRONMENT_MAY_BE_WEBVIEW && !isFileURI(binaryFile) diff --git a/src/shell.js b/src/shell.js index 7c2e18e8fba03..a997e51d0c3ab 100644 --- a/src/shell.js +++ b/src/shell.js @@ -293,29 +293,14 @@ if (ENVIRONMENT_IS_SHELL) { #endif if (typeof read != 'undefined') { - read_ = (f) => { -#if SUPPORT_BASE64_EMBEDDING - const data = tryParseAsDataURI(f); - if (data) { - return intArrayToString(data); - } -#endif - return read(f); - }; + read_ = read; } readBinary = (f) => { - let data; -#if SUPPORT_BASE64_EMBEDDING - data = tryParseAsDataURI(f); - if (data) { - return data; - } -#endif if (typeof readbuffer == 'function') { return new Uint8Array(readbuffer(f)); } - data = read(f, 'binary'); + let data = read(f, 'binary'); assert(typeof data == 'object'); return data; }; diff --git a/src/web_or_worker_shell_read.js b/src/web_or_worker_shell_read.js index 91558272e9fdc..3ae5842e8f298 100644 --- a/src/web_or_worker_shell_read.js +++ b/src/web_or_worker_shell_read.js @@ -5,43 +5,19 @@ */ read_ = (url) => { -#if SUPPORT_BASE64_EMBEDDING - try { -#endif - var xhr = new XMLHttpRequest(); - xhr.open('GET', url, false); - xhr.send(null); - return xhr.responseText; -#if SUPPORT_BASE64_EMBEDDING - } catch (err) { - var data = tryParseAsDataURI(url); - if (data) { - return intArrayToString(data); - } - throw err; - } -#endif + var xhr = new XMLHttpRequest(); + xhr.open('GET', url, false); + xhr.send(null); + return xhr.responseText; } if (ENVIRONMENT_IS_WORKER) { readBinary = (url) => { -#if SUPPORT_BASE64_EMBEDDING - try { -#endif - var xhr = new XMLHttpRequest(); - xhr.open('GET', url, false); - xhr.responseType = 'arraybuffer'; - xhr.send(null); - return new Uint8Array(/** @type{!ArrayBuffer} */(xhr.response)); -#if SUPPORT_BASE64_EMBEDDING - } catch (err) { - var data = tryParseAsDataURI(url); - if (data) { - return data; - } - throw err; - } -#endif + var xhr = new XMLHttpRequest(); + xhr.open('GET', url, false); + xhr.responseType = 'arraybuffer'; + xhr.send(null); + return new Uint8Array(/** @type{!ArrayBuffer} */(xhr.response)); }; } @@ -54,13 +30,6 @@ onload(xhr.response); return; } -#if SUPPORT_BASE64_EMBEDDING - var data = tryParseAsDataURI(url); - if (data) { - onload(data.buffer); - return; - } -#endif onerror(); }; xhr.onerror = onerror; From 2e45d81eb02385d30834470b20cd8f575e4e261d Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 10 Jul 2023 14:40:17 -0700 Subject: [PATCH 0539/1523] Rebaseline codesize expectations. NFC --- test/other/metadce/test_metadce_cxx_ctors1.size | 2 +- test/other/metadce/test_metadce_cxx_ctors2.size | 2 +- test/other/metadce/test_metadce_cxx_except.size | 2 +- test/other/metadce/test_metadce_cxx_except_wasm.size | 2 +- test/other/metadce/test_metadce_cxx_mangle.size | 2 +- test/other/metadce/test_metadce_cxx_noexcept.size | 2 +- test/other/metadce/test_metadce_cxx_wasmfs.size | 2 +- test/other/metadce/test_metadce_files_wasmfs.size | 2 +- test/other/metadce/test_metadce_hello_O0.jssize | 2 +- test/other/metadce/test_metadce_minimal_O0.jssize | 2 +- test/other/metadce/test_metadce_minimal_pthreads.jssize | 2 +- test/other/test_unoptimized_code_size.js.size | 2 +- test/other/test_unoptimized_code_size_no_asserts.js.size | 2 +- test/other/test_unoptimized_code_size_strict.js.size | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/test/other/metadce/test_metadce_cxx_ctors1.size b/test/other/metadce/test_metadce_cxx_ctors1.size index 4443edf9cd5c0..89cb22ba96f60 100644 --- a/test/other/metadce/test_metadce_cxx_ctors1.size +++ b/test/other/metadce/test_metadce_cxx_ctors1.size @@ -1 +1 @@ -123581 +123583 diff --git a/test/other/metadce/test_metadce_cxx_ctors2.size b/test/other/metadce/test_metadce_cxx_ctors2.size index 36fb4f3004506..a2ee3fdaebe58 100644 --- a/test/other/metadce/test_metadce_cxx_ctors2.size +++ b/test/other/metadce/test_metadce_cxx_ctors2.size @@ -1 +1 @@ -123486 +123488 diff --git a/test/other/metadce/test_metadce_cxx_except.size b/test/other/metadce/test_metadce_cxx_except.size index 03cca2ca48dde..cd180f98728b2 100644 --- a/test/other/metadce/test_metadce_cxx_except.size +++ b/test/other/metadce/test_metadce_cxx_except.size @@ -1 +1 @@ -166416 +166418 diff --git a/test/other/metadce/test_metadce_cxx_except_wasm.size b/test/other/metadce/test_metadce_cxx_except_wasm.size index 4062adc879bbb..b8afba096689b 100644 --- a/test/other/metadce/test_metadce_cxx_except_wasm.size +++ b/test/other/metadce/test_metadce_cxx_except_wasm.size @@ -1 +1 @@ -137209 +137211 diff --git a/test/other/metadce/test_metadce_cxx_mangle.size b/test/other/metadce/test_metadce_cxx_mangle.size index 6f475dc73c711..464a54e303ebc 100644 --- a/test/other/metadce/test_metadce_cxx_mangle.size +++ b/test/other/metadce/test_metadce_cxx_mangle.size @@ -1 +1 @@ -221378 +221380 diff --git a/test/other/metadce/test_metadce_cxx_noexcept.size b/test/other/metadce/test_metadce_cxx_noexcept.size index 609d929760592..2827a22520f95 100644 --- a/test/other/metadce/test_metadce_cxx_noexcept.size +++ b/test/other/metadce/test_metadce_cxx_noexcept.size @@ -1 +1 @@ -126385 +126387 diff --git a/test/other/metadce/test_metadce_cxx_wasmfs.size b/test/other/metadce/test_metadce_cxx_wasmfs.size index 66d6176b9e607..662d7caaeaf39 100644 --- a/test/other/metadce/test_metadce_cxx_wasmfs.size +++ b/test/other/metadce/test_metadce_cxx_wasmfs.size @@ -1 +1 @@ -164530 +164526 diff --git a/test/other/metadce/test_metadce_files_wasmfs.size b/test/other/metadce/test_metadce_files_wasmfs.size index bf2df028f4931..86eeb43ae5b69 100644 --- a/test/other/metadce/test_metadce_files_wasmfs.size +++ b/test/other/metadce/test_metadce_files_wasmfs.size @@ -1 +1 @@ -52463 +52432 diff --git a/test/other/metadce/test_metadce_hello_O0.jssize b/test/other/metadce/test_metadce_hello_O0.jssize index 9a93fca8c9bbb..3b11232fb4988 100644 --- a/test/other/metadce/test_metadce_hello_O0.jssize +++ b/test/other/metadce/test_metadce_hello_O0.jssize @@ -1 +1 @@ -23740 +23732 diff --git a/test/other/metadce/test_metadce_minimal_O0.jssize b/test/other/metadce/test_metadce_minimal_O0.jssize index 0961a828ea334..d8f45b2f0ecc7 100644 --- a/test/other/metadce/test_metadce_minimal_O0.jssize +++ b/test/other/metadce/test_metadce_minimal_O0.jssize @@ -1 +1 @@ -20162 +20154 diff --git a/test/other/metadce/test_metadce_minimal_pthreads.jssize b/test/other/metadce/test_metadce_minimal_pthreads.jssize index b348f398ae4b1..157d7144163c0 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.jssize +++ b/test/other/metadce/test_metadce_minimal_pthreads.jssize @@ -1 +1 @@ -15052 +15050 diff --git a/test/other/test_unoptimized_code_size.js.size b/test/other/test_unoptimized_code_size.js.size index b65021da9a4c0..c8290f8e554e4 100644 --- a/test/other/test_unoptimized_code_size.js.size +++ b/test/other/test_unoptimized_code_size.js.size @@ -1 +1 @@ -59021 +58967 diff --git a/test/other/test_unoptimized_code_size_no_asserts.js.size b/test/other/test_unoptimized_code_size_no_asserts.js.size index ded36227e9536..9d0f802d763aa 100644 --- a/test/other/test_unoptimized_code_size_no_asserts.js.size +++ b/test/other/test_unoptimized_code_size_no_asserts.js.size @@ -1 +1 @@ -32444 +32432 diff --git a/test/other/test_unoptimized_code_size_strict.js.size b/test/other/test_unoptimized_code_size_strict.js.size index e0d0b82fafd55..c6ff60293936c 100644 --- a/test/other/test_unoptimized_code_size_strict.js.size +++ b/test/other/test_unoptimized_code_size_strict.js.size @@ -1 +1 @@ -57987 +57933 From 2bfe7cb4431d7b4679f5fe28dd161613a9361773 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 10 Jul 2023 15:13:21 -0700 Subject: [PATCH 0540/1523] create_release.py: Push resulting branch to origin (#19827) Also, set the upstream when creating the new branch. --- docs/process.md | 4 ++-- tools/maint/create_release.py | 8 +++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/docs/process.md b/docs/process.md index 136b0c309f2af..e802429b6c544 100644 --- a/docs/process.md +++ b/docs/process.md @@ -107,8 +107,8 @@ How: name release. Running this [`scripts/create_release.py`][create_release_emsdk] script will update [emscripten-releases-tags.json][emscripten_releases_tags], adding a new - version. The script will create a new git branch that can be uploaded as a - PR. An example of this PR is emscripten-core/emsdk#1071. + version. The script will create a new local git branch and push it up to + ``origin``. An example of this PR is emscripten-core/emsdk#1071. 1. [Tag][emsdk_tags] the `emsdk` repo with the new version number, on the commit that does the update, after it lands on main. 1. [Tag][emscripten_tags] the `emscripten` repo with the new version number, on diff --git a/tools/maint/create_release.py b/tools/maint/create_release.py index 4186373f34c43..5e3c00df54c01 100755 --- a/tools/maint/create_release.py +++ b/tools/maint/create_release.py @@ -59,15 +59,17 @@ def main(): branch_name = 'version_' + release_version # Create a new git branch - subprocess.check_call(['git', 'checkout', '-b', branch_name], cwd=root_dir) + subprocess.check_call(['git', 'checkout', '-b', branch_name, 'origin/main'], cwd=root_dir) # Create auto-generated changes to the new git branch subprocess.check_call(['git', 'add', '-u', '.'], cwd=root_dir) subprocess.check_call(['git', 'commit', '-m', f'Mark {release_version} as released'], cwd=root_dir) + print('New release created in branch: `%s`' % branch_name) - print('New relase created in branch: `%s`' % branch_name) + # Push new branch to origin + subprocess.check_call(['git', 'push', 'origin', branch_name], cwd=root_dir) - # TODO(sbc): Maybe create the tag too, and even push both to `origin`? + # TODO(sbc): Maybe create the tag too return 0 From 81c887b38bc58d8d2ad91f55585b6d2881f57465 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 10 Jul 2023 15:14:22 -0700 Subject: [PATCH 0541/1523] Deprecate `EM_LOG_FUNC_PARAMS` flag to emscripten_log/emscripten_get_callstack (#19820) Supporting this flag requires using `arguments.callee` which is deprecated, and won't work if any of functions on the callstack are in strict mode (or are arrow function, which implies strict mode). Why any frame in the calling stack is in strict mode this call will fail with: ``` TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them at traverseStack (emscripten_log.js:941:30) ``` This effects of these flag seem to not actually be tested, even though it is used in `test_emscripten_log`. --- ChangeLog.md | 3 + .../docs/api_reference/emscripten.h.rst | 4 -- src/generated_struct_info32.json | 2 - src/generated_struct_info64.json | 2 - src/library.js | 59 +------------------ src/struct_info.json | 2 - system/include/emscripten/emscripten.h | 4 +- test/test_browser.py | 2 +- test/test_core.py | 2 +- 9 files changed, 9 insertions(+), 71 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 0de5d4df68f9d..e4e9de3d2c8d4 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -20,6 +20,9 @@ See docs/process.md for more on how version tagging works. 3.1.44 (in development) ----------------------- +- The `EM_LOG_FUNC_PARAMS` flag to `emscripten_log`/`emscripten_get_callstack` + has been deprecated and no longer has any effect. It was based on a + long-deprecated JS API. (#19820) - The internal `read_` and `readAsync` functions no longer handle date URIs. This only effects builds that use `-sSINGLE_FILE` or `--memory-init-file`. (#19792) diff --git a/site/source/docs/api_reference/emscripten.h.rst b/site/source/docs/api_reference/emscripten.h.rst index 1fd9a6415be74..ed3f9cbeff0c2 100644 --- a/site/source/docs/api_reference/emscripten.h.rst +++ b/site/source/docs/api_reference/emscripten.h.rst @@ -1042,10 +1042,6 @@ Defines If specified, the pathnames of the file information in the call stack will be omitted. -.. c:macro:: EM_LOG_FUNC_PARAMS - - If specified, prints out the actual values of the parameters the functions were invoked with. - Functions --------- diff --git a/src/generated_struct_info32.json b/src/generated_struct_info32.json index 448b5d6d09357..899ec4b3047bc 100644 --- a/src/generated_struct_info32.json +++ b/src/generated_struct_info32.json @@ -220,9 +220,7 @@ "EM_LOG_CONSOLE": 1, "EM_LOG_C_STACK": 8, "EM_LOG_DEBUG": 256, - "EM_LOG_DEMANGLE": 32, "EM_LOG_ERROR": 4, - "EM_LOG_FUNC_PARAMS": 128, "EM_LOG_INFO": 512, "EM_LOG_JS_STACK": 16, "EM_LOG_NO_PATHS": 64, diff --git a/src/generated_struct_info64.json b/src/generated_struct_info64.json index 9c1c1657dec82..da24ad8bff70b 100644 --- a/src/generated_struct_info64.json +++ b/src/generated_struct_info64.json @@ -220,9 +220,7 @@ "EM_LOG_CONSOLE": 1, "EM_LOG_C_STACK": 8, "EM_LOG_DEBUG": 256, - "EM_LOG_DEMANGLE": 32, "EM_LOG_ERROR": 4, - "EM_LOG_FUNC_PARAMS": 128, "EM_LOG_INFO": 512, "EM_LOG_JS_STACK": 16, "EM_LOG_NO_PATHS": 64, diff --git a/src/library.js b/src/library.js index 5dee4eea59bf0..83820a17219fc 100644 --- a/src/library.js +++ b/src/library.js @@ -2410,37 +2410,7 @@ mergeInto(LibraryManager.library, { } }, - // Returns [parentFuncArguments, functionName, paramListName] - $traverseStack: (args) => { - if (!args || !args.callee || !args.callee.name) { - return [null, '', '']; - } - - var funstr = args.callee.toString(); - var funcname = args.callee.name; - var str = '('; - var first = true; - for (var i in args) { - var a = args[i]; - if (!first) { - str += ", "; - } - first = false; - if (typeof a == 'number' || typeof a == 'string') { - str += a; - } else { - str += `(${typeof a}})`; - } - } - str += ')'; - var caller = args.callee.caller; - args = caller ? caller.arguments : []; - if (first) - str = ''; - return [args, funcname, str]; - }, - - $getCallstack__deps: ['$traverseStack', '$jsStackTrace', '$warnOnce'], + $getCallstack__deps: ['$jsStackTrace', '$warnOnce'], $getCallstack__docs: '/** @param {number=} flags */', $getCallstack: function(flags) { var callstack = jsStackTrace(); @@ -2453,10 +2423,6 @@ mergeInto(LibraryManager.library, { var iNextLine = callstack.indexOf('\n', Math.max(iThisFunc, iThisFunc2))+1; callstack = callstack.slice(iNextLine); - if (flags & {{{ cDefs.EM_LOG_DEMANGLE }}}) { - warnOnce('EM_LOG_DEMANGLE is deprecated; ignoring'); - } - // If user requested to see the original source stack, but no source map // information is available, just fall back to showing the JS stack. if (flags & {{{ cDefs.EM_LOG_C_STACK }}} && typeof emscripten_source_map == 'undefined') { @@ -2465,15 +2431,6 @@ mergeInto(LibraryManager.library, { flags |= {{{ cDefs.EM_LOG_JS_STACK }}}; } - var stack_args = null; - if (flags & {{{ cDefs.EM_LOG_FUNC_PARAMS }}}) { - // To get the actual parameters to the functions, traverse the stack via - // the unfortunately deprecated 'arguments.callee' method, if it works: - stack_args = traverseStack(arguments); - while (stack_args[1].includes('_emscripten_')) - stack_args = traverseStack(stack_args[0]); - } - // Process all lines: var lines = callstack.split('\n'); callstack = ''; @@ -2537,16 +2494,6 @@ mergeInto(LibraryManager.library, { } callstack += (haveSourceMap ? (` = ${symbolName}`) : (` at ${symbolName}`)) + ` (${file}:${lineno}:${column})\n`; } - - // If we are still keeping track with the callstack by traversing via - // 'arguments.callee', print the function parameters as well. - if (flags & {{{ cDefs.EM_LOG_FUNC_PARAMS }}} && stack_args[0]) { - if (stack_args[1] == symbolName && stack_args[2].length > 0) { - callstack = callstack.replace(/\s+$/, ''); - callstack += ' with values: ' + stack_args[1] + stack_args[2] + '\n'; - } - stack_args = traverseStack(stack_args[0]); - } } // Trim extra whitespace at the end of the output. callstack = callstack.replace(/\s+$/, ''); @@ -2555,10 +2502,6 @@ mergeInto(LibraryManager.library, { emscripten_get_callstack__deps: ['$getCallstack', '$lengthBytesUTF8', '$stringToUTF8'], emscripten_get_callstack: function(flags, str, maxbytes) { - // Use explicit calls to from64 rather then using the __sig - // magic here. This is because the __sig wrapper uses arrow function - // notation which causes the inner call to traverseStack to fail. - {{{ from64('str') }}}; var callstack = getCallstack(flags); // User can query the required amount of bytes to hold the callstack. if (!str || maxbytes <= 0) { diff --git a/src/struct_info.json b/src/struct_info.json index 8b23a87324d25..4e8f474dc11e2 100644 --- a/src/struct_info.json +++ b/src/struct_info.json @@ -978,9 +978,7 @@ "EM_LOG_ERROR", "EM_LOG_C_STACK", "EM_LOG_JS_STACK", - "EM_LOG_DEMANGLE", "EM_LOG_NO_PATHS", - "EM_LOG_FUNC_PARAMS", "EM_LOG_DEBUG", "EM_LOG_INFO", "EM_TIMING_SETTIMEOUT", diff --git a/system/include/emscripten/emscripten.h b/system/include/emscripten/emscripten.h index f0331df8a479b..fe898165cd316 100644 --- a/system/include/emscripten/emscripten.h +++ b/system/include/emscripten/emscripten.h @@ -155,8 +155,10 @@ char *emscripten_get_preloaded_image_data_from_FILE(FILE *file, int *w, int *h); #define EM_LOG_C_STACK 8 #define EM_LOG_JS_STACK 16 #define EM_LOG_DEMANGLE 32 // deprecated +#pragma clang deprecated(EM_LOG_DEMANGLE) #define EM_LOG_NO_PATHS 64 -#define EM_LOG_FUNC_PARAMS 128 +#define EM_LOG_FUNC_PARAMS 128 // deprecated +#pragma clang deprecated(EM_LOG_FUNC_PARAMS) #define EM_LOG_DEBUG 256 #define EM_LOG_INFO 512 diff --git a/test/test_browser.py b/test/test_browser.py index 0d6743493e398..a2ef4d447738f 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -300,7 +300,7 @@ def test_zzz_html_source_map(self): def test_emscripten_log(self): self.btest_exit(test_file('emscripten_log/emscripten_log.cpp'), - args=['--pre-js', path_from_root('src/emscripten-source-map.min.js'), '-gsource-map']) + args=['-Wno-deprecated-pragma', '--pre-js', path_from_root('src/emscripten-source-map.min.js'), '-gsource-map']) @also_with_wasmfs def test_preload_file(self): diff --git a/test/test_core.py b/test/test_core.py index 930ca09f6cb0d..d01a41eed2b39 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -8035,7 +8035,7 @@ def test_emscripten_log(self): self.set_setting('DEMANGLE_SUPPORT') if '-g' not in self.emcc_args: self.emcc_args.append('-g') - self.emcc_args += ['-DRUN_FROM_JS_SHELL'] + self.emcc_args += ['-DRUN_FROM_JS_SHELL', '-Wno-deprecated-pragma'] self.do_run_in_out_file_test('emscripten_log/emscripten_log.cpp', interleaved_output=False) # test closure compiler as well if self.maybe_closure(): From 9c2f2dbf40aa67f661955126e3b5e185814b052b Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 10 Jul 2023 15:17:36 -0700 Subject: [PATCH 0542/1523] Rebaseline codesize expectations. NFC --- test/other/metadce/test_metadce_hello_O0.jssize | 2 +- test/other/metadce/test_metadce_minimal_O0.jssize | 2 +- test/other/test_unoptimized_code_size.js.size | 2 +- test/other/test_unoptimized_code_size_strict.js.size | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/other/metadce/test_metadce_hello_O0.jssize b/test/other/metadce/test_metadce_hello_O0.jssize index 3b11232fb4988..3af06f90a0351 100644 --- a/test/other/metadce/test_metadce_hello_O0.jssize +++ b/test/other/metadce/test_metadce_hello_O0.jssize @@ -1 +1 @@ -23732 +23718 diff --git a/test/other/metadce/test_metadce_minimal_O0.jssize b/test/other/metadce/test_metadce_minimal_O0.jssize index d8f45b2f0ecc7..26eba4efbe0ac 100644 --- a/test/other/metadce/test_metadce_minimal_O0.jssize +++ b/test/other/metadce/test_metadce_minimal_O0.jssize @@ -1 +1 @@ -20154 +20140 diff --git a/test/other/test_unoptimized_code_size.js.size b/test/other/test_unoptimized_code_size.js.size index c8290f8e554e4..423136b34609b 100644 --- a/test/other/test_unoptimized_code_size.js.size +++ b/test/other/test_unoptimized_code_size.js.size @@ -1 +1 @@ -58967 +58948 diff --git a/test/other/test_unoptimized_code_size_strict.js.size b/test/other/test_unoptimized_code_size_strict.js.size index c6ff60293936c..f600399c4ec4b 100644 --- a/test/other/test_unoptimized_code_size_strict.js.size +++ b/test/other/test_unoptimized_code_size_strict.js.size @@ -1 +1 @@ -57933 +57914 From f2ac81af61421c689ce18cbcb74c50edf8d959e0 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 10 Jul 2023 15:57:14 -0700 Subject: [PATCH 0543/1523] Use tabs in .gitmodules. NFC --- .gitmodules | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index 896f670b3caad..dae9c901f1a0b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -5,5 +5,5 @@ path = test/third_party/googletest url = https://github.com/google/googletest [submodule "test/third_party/wasi-test-suite"] - path = test/third_party/wasi-test-suite - url = https://github.com/khronosproject/wasi-test-suite + path = test/third_party/wasi-test-suite + url = https://github.com/khronosproject/wasi-test-suite From 8b5c8687226a27e856f0449db5a92684c4614571 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 10 Jul 2023 16:20:55 -0700 Subject: [PATCH 0544/1523] Simplify createExportWrapper. NFC (#19817) This functions is only used in debug builds (when ASSERTIONS are enabled), so we can just keep it simple. --- emscripten.py | 5 +---- src/preamble.js | 22 ++++++++----------- .../metadce/test_metadce_hello_O0.jssize | 2 +- .../metadce/test_metadce_minimal_O0.jssize | 2 +- test/other/test_unoptimized_code_size.js.size | 2 +- .../test_unoptimized_code_size_strict.js.size | 2 +- 6 files changed, 14 insertions(+), 21 deletions(-) diff --git a/emscripten.py b/emscripten.py index 6f41722177e19..ec6592a551bbe 100644 --- a/emscripten.py +++ b/emscripten.py @@ -763,10 +763,7 @@ def install_wrapper(sym): if settings.ASSERTIONS and install_wrapper(name): # With assertions enabled we create a wrapper that are calls get routed through, for # the lifetime of the program. - if delay_assignment: - wrapper += 'createExportWrapper("%s");' % name - else: - wrapper += 'createExportWrapper("%s", asm);' % name + wrapper += "createExportWrapper('%s');" % name elif delay_assignment: # With assertions disabled the wrapper will replace the global var and Module var on # first use. diff --git a/src/preamble.js b/src/preamble.js index 859488257532c..c89c522ef3abd 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -215,6 +215,9 @@ function preRun() { } function initRuntime() { +#if RUNTIME_DEBUG + dbg('initRuntime'); +#endif #if ASSERTIONS assert(!runtimeInitialized); #endif @@ -518,22 +521,15 @@ Module['FS_createPreloadedFile'] = FS.createPreloadedFile; #include "URIUtils.js" #if ASSERTIONS -/** @param {boolean=} fixedasm */ -function createExportWrapper(name, fixedasm) { +function createExportWrapper(name) { return function() { - var displayName = name; - var asm = fixedasm; - if (!fixedasm) { - asm = Module['asm']; - } - assert(runtimeInitialized, 'native function `' + displayName + '` called before runtime initialization'); + assert(runtimeInitialized, `native function \`${name}\` called before runtime initialization`); #if EXIT_RUNTIME - assert(!runtimeExited, 'native function `' + displayName + '` called after runtime exit (use NO_EXIT_RUNTIME to keep it alive after main() exits)'); + assert(!runtimeExited, `native function \`${name}\` called after runtime exit (use NO_EXIT_RUNTIME to keep it alive after main() exits)`); #endif - if (!asm[name]) { - assert(asm[name], 'exported native function `' + displayName + '` not found'); - } - return asm[name].apply(null, arguments); + var f = Module['asm'][name]; + assert(f, `exported native function \`${name}\` not found`); + return f.apply(null, arguments); }; } #endif diff --git a/test/other/metadce/test_metadce_hello_O0.jssize b/test/other/metadce/test_metadce_hello_O0.jssize index 3af06f90a0351..2906db3ee25dd 100644 --- a/test/other/metadce/test_metadce_hello_O0.jssize +++ b/test/other/metadce/test_metadce_hello_O0.jssize @@ -1 +1 @@ -23718 +23701 diff --git a/test/other/metadce/test_metadce_minimal_O0.jssize b/test/other/metadce/test_metadce_minimal_O0.jssize index 26eba4efbe0ac..c92cbadeec027 100644 --- a/test/other/metadce/test_metadce_minimal_O0.jssize +++ b/test/other/metadce/test_metadce_minimal_O0.jssize @@ -1 +1 @@ -20140 +20123 diff --git a/test/other/test_unoptimized_code_size.js.size b/test/other/test_unoptimized_code_size.js.size index 423136b34609b..a8124ba7c02fd 100644 --- a/test/other/test_unoptimized_code_size.js.size +++ b/test/other/test_unoptimized_code_size.js.size @@ -1 +1 @@ -58948 +58765 diff --git a/test/other/test_unoptimized_code_size_strict.js.size b/test/other/test_unoptimized_code_size_strict.js.size index f600399c4ec4b..331794ba20866 100644 --- a/test/other/test_unoptimized_code_size_strict.js.size +++ b/test/other/test_unoptimized_code_size_strict.js.size @@ -1 +1 @@ -57914 +57731 From 37629c054086d704bc85787edccfbb9ebe715764 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 10 Jul 2023 18:06:53 -0700 Subject: [PATCH 0545/1523] Update musl to v1.2.4 (#19812) --- ChangeLog.md | 1 + src/generated_struct_info32.json | 3 - src/generated_struct_info64.json | 3 - src/library_syscall.js | 8 +- src/struct_info.json | 3 - system/lib/libc/README.md | 2 +- system/lib/libc/musl/VERSION | 2 +- system/lib/libc/musl/WHATSNEW | 69 +++++++ system/lib/libc/musl/configure | 13 +- system/lib/libc/musl/include/arpa/nameser.h | 71 +++++++ system/lib/libc/musl/include/dirent.h | 2 +- system/lib/libc/musl/include/elf.h | 9 +- system/lib/libc/musl/include/fcntl.h | 2 +- system/lib/libc/musl/include/ftw.h | 2 +- system/lib/libc/musl/include/glob.h | 2 +- system/lib/libc/musl/include/netdb.h | 1 + system/lib/libc/musl/include/sched.h | 2 +- system/lib/libc/musl/include/stdio.h | 2 +- system/lib/libc/musl/include/stdlib.h | 4 +- system/lib/libc/musl/include/string.h | 2 +- system/lib/libc/musl/include/strings.h | 1 + system/lib/libc/musl/include/sys/mman.h | 2 +- system/lib/libc/musl/include/sys/resource.h | 2 +- system/lib/libc/musl/include/sys/stat.h | 2 +- system/lib/libc/musl/include/sys/statfs.h | 2 +- system/lib/libc/musl/include/sys/statvfs.h | 2 +- system/lib/libc/musl/include/sys/types.h | 2 +- system/lib/libc/musl/include/sys/uio.h | 2 +- system/lib/libc/musl/include/sys/wait.h | 2 +- system/lib/libc/musl/include/unistd.h | 6 +- system/lib/libc/musl/ldso/dlstart.c | 15 ++ system/lib/libc/musl/ldso/dynlink.c | 102 ++++++++-- system/lib/libc/musl/src/aio/aio.c | 32 ++- system/lib/libc/musl/src/aio/aio_suspend.c | 6 +- system/lib/libc/musl/src/aio/lio_listio.c | 2 - system/lib/libc/musl/src/conf/confstr.c | 2 +- system/lib/libc/musl/src/conf/sysconf.c | 15 ++ system/lib/libc/musl/src/dirent/alphasort.c | 2 - system/lib/libc/musl/src/dirent/readdir.c | 2 - system/lib/libc/musl/src/dirent/readdir_r.c | 2 - system/lib/libc/musl/src/dirent/scandir.c | 2 - system/lib/libc/musl/src/dirent/versionsort.c | 3 - system/lib/libc/musl/src/fcntl/creat.c | 2 - system/lib/libc/musl/src/fcntl/open.c | 2 - system/lib/libc/musl/src/fcntl/openat.c | 2 - .../lib/libc/musl/src/fcntl/posix_fadvise.c | 2 - .../lib/libc/musl/src/fcntl/posix_fallocate.c | 2 - system/lib/libc/musl/src/include/sys/stat.h | 9 + system/lib/libc/musl/src/internal/dynlink.h | 6 +- system/lib/libc/musl/src/internal/fork_impl.h | 2 +- .../lib/libc/musl/src/internal/ksigaction.h | 5 + system/lib/libc/musl/src/internal/syscall.h | 25 ++- system/lib/libc/musl/src/internal/version.h | 2 +- system/lib/libc/musl/src/ipc/semtimedop.c | 3 +- system/lib/libc/musl/src/ldso/dlerror.c | 34 ++-- system/lib/libc/musl/src/legacy/ftw.c | 2 - system/lib/libc/musl/src/linux/epoll.c | 1 + system/lib/libc/musl/src/linux/fallocate.c | 3 - system/lib/libc/musl/src/linux/getdents.c | 2 - system/lib/libc/musl/src/linux/membarrier.c | 2 +- system/lib/libc/musl/src/linux/prlimit.c | 3 - system/lib/libc/musl/src/linux/sendfile.c | 2 - system/lib/libc/musl/src/linux/wait4.c | 2 +- system/lib/libc/musl/src/math/logf.c | 2 +- system/lib/libc/musl/src/misc/getopt.c | 3 +- system/lib/libc/musl/src/misc/getrlimit.c | 8 +- system/lib/libc/musl/src/misc/lockf.c | 2 - system/lib/libc/musl/src/misc/mntent.c | 12 +- system/lib/libc/musl/src/misc/nftw.c | 6 +- system/lib/libc/musl/src/misc/setrlimit.c | 8 +- system/lib/libc/musl/src/mman/mmap.c | 2 - system/lib/libc/musl/src/mq/mq_notify.c | 47 +++-- system/lib/libc/musl/src/network/accept4.c | 4 + system/lib/libc/musl/src/network/dns_parse.c | 10 +- .../lib/libc/musl/src/network/gai_strerror.c | 2 +- .../lib/libc/musl/src/network/getaddrinfo.c | 7 +- .../lib/libc/musl/src/network/gethostbyaddr.c | 2 +- .../libc/musl/src/network/gethostbyaddr_r.c | 5 +- .../libc/musl/src/network/gethostbyname2.c | 2 +- .../libc/musl/src/network/gethostbyname2_r.c | 6 +- system/lib/libc/musl/src/network/getifaddrs.c | 14 +- .../lib/libc/musl/src/network/getnameinfo.c | 5 +- .../libc/musl/src/network/getservbyport_r.c | 4 +- system/lib/libc/musl/src/network/inet_pton.c | 1 + system/lib/libc/musl/src/network/lookup.h | 2 +- .../libc/musl/src/network/lookup_ipliteral.c | 4 +- .../lib/libc/musl/src/network/lookup_name.c | 50 +++-- system/lib/libc/musl/src/network/netlink.h | 2 +- .../lib/libc/musl/src/network/res_mkquery.c | 1 + system/lib/libc/musl/src/network/res_msend.c | 189 +++++++++++++++--- system/lib/libc/musl/src/network/res_send.c | 10 +- system/lib/libc/musl/src/network/sendmsg.c | 7 +- system/lib/libc/musl/src/process/_Fork.c | 3 +- system/lib/libc/musl/src/process/fork.c | 8 +- system/lib/libc/musl/src/regex/glob.c | 3 - system/lib/libc/musl/src/search/hsearch.c | 4 +- system/lib/libc/musl/src/select/poll.c | 9 +- system/lib/libc/musl/src/select/select.c | 1 + system/lib/libc/musl/src/signal/sigaction.c | 5 +- system/lib/libc/musl/src/stat/__xstat.c | 5 - system/lib/libc/musl/src/stat/fchmodat.c | 15 +- system/lib/libc/musl/src/stat/fstat.c | 8 +- system/lib/libc/musl/src/stat/fstatat.c | 16 +- system/lib/libc/musl/src/stat/lstat.c | 4 - system/lib/libc/musl/src/stat/stat.c | 4 - system/lib/libc/musl/src/stat/statvfs.c | 5 - system/lib/libc/musl/src/stdio/fgetpos.c | 2 - system/lib/libc/musl/src/stdio/fgets.c | 5 +- system/lib/libc/musl/src/stdio/fopen.c | 2 - system/lib/libc/musl/src/stdio/freopen.c | 4 +- system/lib/libc/musl/src/stdio/fseek.c | 2 - system/lib/libc/musl/src/stdio/fsetpos.c | 2 - system/lib/libc/musl/src/stdio/ftell.c | 2 - .../lib/libc/musl/src/stdio/open_wmemstream.c | 6 +- system/lib/libc/musl/src/stdio/tempnam.c | 8 +- system/lib/libc/musl/src/stdio/tmpfile.c | 2 - system/lib/libc/musl/src/stdio/tmpnam.c | 8 +- system/lib/libc/musl/src/stdio/vfprintf.c | 23 ++- system/lib/libc/musl/src/stdio/vfwprintf.c | 39 ++-- system/lib/libc/musl/src/stdio/vswprintf.c | 1 + system/lib/libc/musl/src/stdlib/qsort_nr.c | 2 +- system/lib/libc/musl/src/string/strverscmp.c | 6 +- system/lib/libc/musl/src/string/wcscmp.c | 2 +- system/lib/libc/musl/src/string/wcsncmp.c | 2 +- system/lib/libc/musl/src/string/wmemcmp.c | 2 +- system/lib/libc/musl/src/temp/__randname.c | 3 +- system/lib/libc/musl/src/temp/mkostemp.c | 2 - system/lib/libc/musl/src/temp/mkostemps.c | 1 - system/lib/libc/musl/src/temp/mkstemp.c | 2 - system/lib/libc/musl/src/temp/mkstemps.c | 2 - .../lib/libc/musl/src/thread/pthread_atfork.c | 8 +- .../lib/libc/musl/src/thread/pthread_cancel.c | 9 +- .../lib/libc/musl/src/thread/pthread_create.c | 16 +- .../lib/libc/musl/src/thread/pthread_detach.c | 13 +- .../lib/libc/musl/src/thread/pthread_join.c | 5 +- .../libc/musl/src/thread/pthread_key_create.c | 8 + .../lib/libc/musl/src/thread/sem_getvalue.c | 3 +- system/lib/libc/musl/src/thread/sem_post.c | 12 +- .../lib/libc/musl/src/thread/sem_timedwait.c | 10 +- system/lib/libc/musl/src/thread/sem_trywait.c | 6 +- system/lib/libc/musl/src/thread/synccall.c | 2 +- system/lib/libc/musl/src/time/__map_file.c | 5 +- .../libc/musl/src/time/clock_getcpuclockid.c | 1 + system/lib/libc/musl/src/time/clock_gettime.c | 7 + system/lib/libc/musl/src/time/timer_create.c | 6 +- system/lib/libc/musl/src/unistd/dup3.c | 6 +- system/lib/libc/musl/src/unistd/ftruncate.c | 2 - system/lib/libc/musl/src/unistd/lseek.c | 1 - system/lib/libc/musl/src/unistd/pipe2.c | 1 + system/lib/libc/musl/src/unistd/pread.c | 2 - system/lib/libc/musl/src/unistd/preadv.c | 2 - system/lib/libc/musl/src/unistd/pwrite.c | 2 - system/lib/libc/musl/src/unistd/pwritev.c | 2 - system/lib/libc/musl/src/unistd/truncate.c | 2 - system/lib/standalone/standalone.c | 8 + system/lib/wasmfs/syscalls.cpp | 2 + test/code_size/random_printf_wasm.json | 8 +- test/code_size/random_printf_wasm2js.json | 8 +- .../metadce/test_metadce_cxx_ctors1.size | 2 +- .../metadce/test_metadce_cxx_ctors2.size | 2 +- .../metadce/test_metadce_cxx_except.size | 2 +- .../metadce/test_metadce_cxx_except_wasm.size | 2 +- .../metadce/test_metadce_cxx_mangle.size | 2 +- .../metadce/test_metadce_cxx_noexcept.size | 2 +- .../metadce/test_metadce_cxx_wasmfs.size | 2 +- test/other/metadce/test_metadce_hello_O0.size | 2 +- .../test_unoptimized_code_size.wasm.size | 2 +- ...unoptimized_code_size_no_asserts.wasm.size | 2 +- ...est_unoptimized_code_size_strict.wasm.size | 2 +- test/sockets/test_getaddrinfo.c | 2 +- tools/system_libs.py | 1 + 171 files changed, 918 insertions(+), 425 deletions(-) create mode 100644 system/lib/libc/musl/src/include/sys/stat.h diff --git a/ChangeLog.md b/ChangeLog.md index e4e9de3d2c8d4..ba8f4442d6216 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -20,6 +20,7 @@ See docs/process.md for more on how version tagging works. 3.1.44 (in development) ----------------------- +- musl libc updated from v1.2.3 to v1.2.4. (#19812) - The `EM_LOG_FUNC_PARAMS` flag to `emscripten_log`/`emscripten_get_callstack` has been deprecated and no longer has any effect. It was based on a long-deprecated JS API. (#19820) diff --git a/src/generated_struct_info32.json b/src/generated_struct_info32.json index 899ec4b3047bc..37d021e8c86c7 100644 --- a/src/generated_struct_info32.json +++ b/src/generated_struct_info32.json @@ -302,15 +302,12 @@ "F_GETFD": 1, "F_GETFL": 3, "F_GETLK": 5, - "F_GETLK64": 5, "F_GETOWN": 9, "F_GETOWN_EX": 16, "F_SETFD": 2, "F_SETFL": 4, "F_SETLK": 6, - "F_SETLK64": 6, "F_SETLKW": 7, - "F_SETLKW64": 7, "F_SETOWN": 8, "F_UNLCK": 2, "File::DataFileKind": 1, diff --git a/src/generated_struct_info64.json b/src/generated_struct_info64.json index da24ad8bff70b..39d3d95da6f3b 100644 --- a/src/generated_struct_info64.json +++ b/src/generated_struct_info64.json @@ -302,15 +302,12 @@ "F_GETFD": 1, "F_GETFL": 3, "F_GETLK": 5, - "F_GETLK64": 5, "F_GETOWN": 9, "F_GETOWN_EX": 16, "F_SETFD": 2, "F_SETFL": 4, "F_SETLK": 6, - "F_SETLK64": 6, "F_SETLKW": 7, - "F_SETLKW64": 7, "F_SETOWN": 8, "F_UNLCK": 2, "File::DataFileKind": 1, diff --git a/src/library_syscall.js b/src/library_syscall.js index 05179c2bb1dee..fc2bd1d4b0a32 100644 --- a/src/library_syscall.js +++ b/src/library_syscall.js @@ -766,9 +766,7 @@ var SyscallsLibrary = { stream.flags |= arg; return 0; } - case {{{ cDefs.F_GETLK }}}: - /* case {{{ cDefs.F_GETLK64 }}}: Currently in musl F_GETLK64 has same value as F_GETLK, so omitted to avoid duplicate case blocks. If that changes, uncomment this */ { - {{{ assert(cDefs.F_GETLK === cDefs.F_GETLK64), '' }}} + case {{{ cDefs.F_GETLK }}}: { var arg = SYSCALLS.get(); var offset = {{{ C_STRUCTS.flock.l_type }}}; // We're always unlocked. @@ -777,10 +775,6 @@ var SyscallsLibrary = { } case {{{ cDefs.F_SETLK }}}: case {{{ cDefs.F_SETLKW }}}: - /* case {{{ cDefs.F_SETLK64 }}}: Currently in musl F_SETLK64 has same value as F_SETLK, so omitted to avoid duplicate case blocks. If that changes, uncomment this */ - /* case {{{ cDefs.F_SETLKW64 }}}: Currently in musl F_SETLKW64 has same value as F_SETLKW, so omitted to avoid duplicate case blocks. If that changes, uncomment this */ - {{{ assert(cDefs.F_SETLK64 === cDefs.F_SETLK), '' }}} - {{{ assert(cDefs.F_SETLKW64 === cDefs.F_SETLKW), '' }}} return 0; // Pretend that the locking is successful. case {{{ cDefs.F_GETOWN_EX }}}: case {{{ cDefs.F_SETOWN }}}: diff --git a/src/struct_info.json b/src/struct_info.json index 4e8f474dc11e2..4d6e67452e174 100644 --- a/src/struct_info.json +++ b/src/struct_info.json @@ -88,10 +88,7 @@ "F_UNLCK", "O_RDWR", "S_IRWXO", - "F_GETLK64", - "F_SETLKW64", "F_SETLKW", - "F_SETLK64", "F_GETLK", "S_ISVTX", "O_RDONLY", diff --git a/system/lib/libc/README.md b/system/lib/libc/README.md index c0c53c0152d60..4ad26207ca181 100644 --- a/system/lib/libc/README.md +++ b/system/lib/libc/README.md @@ -1,7 +1,7 @@ This folder contains the musl version of libc at `/musl`. The upstream version can be found at http://www.musl-libc.org/. -Most of the source comes from musl v1.2.2, with some exceptions listed below. +Most of the source comes from musl v1.2.4, with some exceptions listed below. We track these changes from upstream in https://github.com/emscripten-core/musl and use a script (`system/lib/update_musl.py`) to pull in updates. diff --git a/system/lib/libc/musl/VERSION b/system/lib/libc/musl/VERSION index 0495c4a88caed..e8ea05db81420 100644 --- a/system/lib/libc/musl/VERSION +++ b/system/lib/libc/musl/VERSION @@ -1 +1 @@ -1.2.3 +1.2.4 diff --git a/system/lib/libc/musl/WHATSNEW b/system/lib/libc/musl/WHATSNEW index f9bb248256005..c5c8c9f410314 100644 --- a/system/lib/libc/musl/WHATSNEW +++ b/system/lib/libc/musl/WHATSNEW @@ -2327,3 +2327,72 @@ bugs fixed: arch-specific bugs fixed: - powerpc (32-bit) struct shmid_ds layout was wrong for some fields - time64 struct layout was wrong in sound ioctl fallback (32-bit archs) + + + +1.2.4 release notes + +new features: +- large dns record lookups via tcp fallback +- new getaddrinfo EAI_NODATA result to distinguish NODATA/NxDomain +- support for new RELR compressed format for relative relocations +- sysconf keys for querying signal stack size requirements +- real vfork on riscv64 + +performance: +- mallocng no longer uses MADV_FREE (high performance cost, little gain) +- vdso clock_gettime is supported once again on 32-bit arm + +compatibility: +- gethostbyname family now distinguishes NO_DATA from HOST_NOT_FOUND +- res_send now works with caller-provided edns0 queries +- arpa/nameser.h RR types list is now up-to-date +- previously-missing POSIX confstr keys have been added +- mntent interfaces now accept missing fields +- alt signal stack, if any, is now used for internal signals +- the LFS64 macros are no longer exposed without _LARGEFILE64_SOURCE +- memmem (POSIX-future) is now exposed in default feature profile +- pthread_atfork now admits calls from an application-provided malloc +- debugger tracking of shared libraries now works on MIPS PIE binaries +- sendmsg now supports up to SCM_MAX_FD fds in SCM_RIGHTS messages + +bugs fixed: +- gethostbyname[2]_r wrongly returned nonzero (error) on negative result +- parallel v4/v6 address queries could fail on query id collisions +- spurious getaddrinfo/AI_ADDRCONFIG failures due to errno clobbering +- dns search domains ending in dot (including lone dot) broke lookups +- ipv6 servers in resolv.conf broke lookups on systems with v6 disabled +- systems with bindv6only failed to query both v4 and v6 nameservers +- res_mkquery mishandled consecutive final dots in name +- res_send could malfunction for very small answer buffer sizes +- resolver dns backend accepted answers with wrong (A vs AAAA) RR type +- getservbyport_r returned junk or ENOENT (vs ERANGE) on buffer size errors +- dns result parsing of malformed responses could process uninitialized data +- freopen didn't reset stream orientation (byte/wide) & encoding rule +- fwprintf didn't print most fields on open_wmemstream FILEs +- wide printf %lc ignored field width +- wide printf erroneously processed %n after encoding errors +- use of wide printf %9$ argument slot overflowed undersized buffer +- swprintf malfunctioned on nul character in output +- strverscmp ordered digit sequences vs nondigits incorrectly +- timer_create/SIGEV_THREAD failure leaked the thread +- semaphores were subject to missed-wake under certain usage patterns +- several possible rare deadlocks with lock handling at thread exit +- several possible rare deadlocks with aio and multithreaded fork +- dynamic linker relro processing was broken on archs w/variable pagesize +- async cancellation could run cancellation handlers in invalid context +- pthread_detach was wrongly a cancellation point in rare race code path +- use-after-close/double-close errors in mq_notify error paths +- mq_notify event thread wrongly ran with signals unmasked +- wcs{,n}cmp, wmemcmp returned wrong results when difference overflowed +- accept4, pipe2, and dup3 handled unknown flags wrong in fallback cases +- CPU_SETSIZE macro had wrong unit +- select fallback for pre-time64 kernels truncated timeout (vs clamping) + +arch-specific bugs fixed: +- x32 new socketcalls took fallback path due to pointer sign extension +- x32 wait4 didn't fill rusage structure (time64 regression) +- x32 semtimedop mismatched timespec ABI with kernel (time64 regression) +- sigaction signal mask was bogus on or1k, microblaze, mips, and riscv +- powerpc-sf longjmp asm clobbered value argument +- or1k poll function passed timeout to syscall in wrong form diff --git a/system/lib/libc/musl/configure b/system/lib/libc/musl/configure index 88962c24e40ec..2c9a32f6934c4 100755 --- a/system/lib/libc/musl/configure +++ b/system/lib/libc/musl/configure @@ -353,6 +353,14 @@ tryflag CFLAGS_C99FSE -fexcess-precision=standard \ || { test "$ARCH" = i386 && tryflag CFLAGS_C99FSE -ffloat-store ; } tryflag CFLAGS_C99FSE -frounding-math +# +# Semantically we want to insist that our sources follow the +# C rules for type-based aliasing, but most if not all real-world +# compilers are known or suspected to have critical bugs in their +# type-based aliasing analysis. See for example GCC bug 107107. +# +tryflag CFLAGS_C99FSE -fno-strict-aliasing + # # We may use the may_alias attribute if __GNUC__ is defined, so # if the compiler defines __GNUC__ but does not provide it, @@ -723,11 +731,6 @@ fi test "$SUBARCH" \ && printf "configured for %s variant: %s\n" "$ARCH" "$ARCH$SUBARCH" -case "$ARCH$SUBARCH" in -arm) ASMSUBARCH=el ;; -*) ASMSUBARCH=$SUBARCH ;; -esac - # # Some archs (powerpc) have different possible long double formats # that the compiler can be configured for. The logic for whether this diff --git a/system/lib/libc/musl/include/arpa/nameser.h b/system/lib/libc/musl/include/arpa/nameser.h index 581925a43367a..9c1327a1f5428 100644 --- a/system/lib/libc/musl/include/arpa/nameser.h +++ b/system/lib/libc/musl/include/arpa/nameser.h @@ -188,6 +188,36 @@ typedef enum __ns_type { ns_t_sink = 40, ns_t_opt = 41, ns_t_apl = 42, + ns_t_ds = 43, + ns_t_sshfp = 44, + ns_t_ipseckey = 45, + ns_t_rrsig = 46, + ns_t_nsec = 47, + ns_t_dnskey = 48, + ns_t_dhcid = 49, + ns_t_nsec3 = 50, + ns_t_nsec3param = 51, + ns_t_tlsa = 52, + ns_t_smimea = 53, + ns_t_hip = 55, + ns_t_ninfo = 56, + ns_t_rkey = 57, + ns_t_talink = 58, + ns_t_cds = 59, + ns_t_cdnskey = 60, + ns_t_openpgpkey = 61, + ns_t_csync = 62, + ns_t_spf = 99, + ns_t_uinfo = 100, + ns_t_uid = 101, + ns_t_gid = 102, + ns_t_unspec = 103, + ns_t_nid = 104, + ns_t_l32 = 105, + ns_t_l64 = 106, + ns_t_lp = 107, + ns_t_eui48 = 108, + ns_t_eui64 = 109, ns_t_tkey = 249, ns_t_tsig = 250, ns_t_ixfr = 251, @@ -196,6 +226,11 @@ typedef enum __ns_type { ns_t_maila = 254, ns_t_any = 255, ns_t_zxfr = 256, + ns_t_uri = 256, + ns_t_caa = 257, + ns_t_avc = 258, + ns_t_ta = 32768, + ns_t_dlv = 32769, ns_t_max = 65536 } ns_type; @@ -430,12 +465,48 @@ typedef struct { #define T_NAPTR ns_t_naptr #define T_A6 ns_t_a6 #define T_DNAME ns_t_dname +#define T_DS ns_t_ds +#define T_SSHFP ns_t_sshfp +#define T_IPSECKEY ns_t_ipseckey +#define T_RRSIG ns_t_rrsig +#define T_NSEC ns_t_nsec +#define T_DNSKEY ns_t_dnskey +#define T_DHCID ns_t_dhcid +#define T_NSEC3 ns_t_nsec3 +#define T_NSEC3PARAM ns_t_nsec3param +#define T_TLSA ns_t_tlsa +#define T_SMIMEA ns_t_smimea +#define T_HIP ns_t_hip +#define T_NINFO ns_t_ninfo +#define T_RKEY ns_t_rkey +#define T_TALINK ns_t_talink +#define T_CDS ns_t_cds +#define T_CDNSKEY ns_t_cdnskey +#define T_OPENPGPKEY ns_t_openpgpkey +#define T_CSYNC ns_t_csync +#define T_SPF ns_t_spf +#define T_UINFO ns_t_uinfo +#define T_UID ns_t_uid +#define T_GID ns_t_gid +#define T_UNSPEC ns_t_unspec +#define T_NID ns_t_nid +#define T_L32 ns_t_l32 +#define T_L64 ns_t_l64 +#define T_LP ns_t_lp +#define T_EUI48 ns_t_eui48 +#define T_EUI64 ns_t_eui64 +#define T_TKEY ns_t_tkey #define T_TSIG ns_t_tsig #define T_IXFR ns_t_ixfr #define T_AXFR ns_t_axfr #define T_MAILB ns_t_mailb #define T_MAILA ns_t_maila #define T_ANY ns_t_any +#define T_URI ns_t_uri +#define T_CAA ns_t_caa +#define T_AVC ns_t_avc +#define T_TA ns_t_ta +#define T_DLV ns_t_dlv #define C_IN ns_c_in #define C_CHAOS ns_c_chaos diff --git a/system/lib/libc/musl/include/dirent.h b/system/lib/libc/musl/include/dirent.h index 650ecf646ad71..2d8fffb23f001 100644 --- a/system/lib/libc/musl/include/dirent.h +++ b/system/lib/libc/musl/include/dirent.h @@ -56,7 +56,7 @@ int getdents(int, struct dirent *, size_t); int versionsort(const struct dirent **, const struct dirent **); #endif -#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) +#if defined(_LARGEFILE64_SOURCE) #define dirent64 dirent #define readdir64 readdir #define readdir64_r readdir_r diff --git a/system/lib/libc/musl/include/elf.h b/system/lib/libc/musl/include/elf.h index 86e2f0bb7d04a..23f2c4bc1b51e 100644 --- a/system/lib/libc/musl/include/elf.h +++ b/system/lib/libc/musl/include/elf.h @@ -385,7 +385,8 @@ typedef struct { #define SHT_PREINIT_ARRAY 16 #define SHT_GROUP 17 #define SHT_SYMTAB_SHNDX 18 -#define SHT_NUM 19 +#define SHT_RELR 19 +#define SHT_NUM 20 #define SHT_LOOS 0x60000000 #define SHT_GNU_ATTRIBUTES 0x6ffffff5 #define SHT_GNU_HASH 0x6ffffff6 @@ -436,6 +437,7 @@ typedef struct { } Elf64_Chdr; #define ELFCOMPRESS_ZLIB 1 +#define ELFCOMPRESS_ZSTD 2 #define ELFCOMPRESS_LOOS 0x60000000 #define ELFCOMPRESS_HIOS 0x6fffffff #define ELFCOMPRESS_LOPROC 0x70000000 @@ -754,7 +756,10 @@ typedef struct { #define DT_PREINIT_ARRAY 32 #define DT_PREINIT_ARRAYSZ 33 #define DT_SYMTAB_SHNDX 34 -#define DT_NUM 35 +#define DT_RELRSZ 35 +#define DT_RELR 36 +#define DT_RELRENT 37 +#define DT_NUM 38 #define DT_LOOS 0x6000000d #define DT_HIOS 0x6ffff000 #define DT_LOPROC 0x70000000 diff --git a/system/lib/libc/musl/include/fcntl.h b/system/lib/libc/musl/include/fcntl.h index 0467f397e5aec..d00f12ed7e30d 100644 --- a/system/lib/libc/musl/include/fcntl.h +++ b/system/lib/libc/musl/include/fcntl.h @@ -205,7 +205,7 @@ ssize_t tee(int, int, size_t, unsigned); #define loff_t off_t #endif -#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) +#if defined(_LARGEFILE64_SOURCE) #define F_GETLK64 F_GETLK #define F_SETLK64 F_SETLK #define F_SETLKW64 F_SETLKW diff --git a/system/lib/libc/musl/include/ftw.h b/system/lib/libc/musl/include/ftw.h index b15c062a8389e..d0445e8ad26a3 100644 --- a/system/lib/libc/musl/include/ftw.h +++ b/system/lib/libc/musl/include/ftw.h @@ -29,7 +29,7 @@ struct FTW { int ftw(const char *, int (*)(const char *, const struct stat *, int), int); int nftw(const char *, int (*)(const char *, const struct stat *, int, struct FTW *), int, int); -#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) +#if defined(_LARGEFILE64_SOURCE) #define ftw64 ftw #define nftw64 nftw #endif diff --git a/system/lib/libc/musl/include/glob.h b/system/lib/libc/musl/include/glob.h index 4a562a206d520..fed06745354a7 100644 --- a/system/lib/libc/musl/include/glob.h +++ b/system/lib/libc/musl/include/glob.h @@ -39,7 +39,7 @@ void globfree(glob_t *); #define GLOB_NOMATCH 3 #define GLOB_NOSYS 4 -#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) +#if defined(_LARGEFILE64_SOURCE) #define glob64 glob #define globfree64 globfree #define glob64_t glob_t diff --git a/system/lib/libc/musl/include/netdb.h b/system/lib/libc/musl/include/netdb.h index d096c78183b56..3af065e2b6b5e 100644 --- a/system/lib/libc/musl/include/netdb.h +++ b/system/lib/libc/musl/include/netdb.h @@ -44,6 +44,7 @@ struct addrinfo { #define EAI_NONAME -2 #define EAI_AGAIN -3 #define EAI_FAIL -4 +#define EAI_NODATA -5 #define EAI_FAMILY -6 #define EAI_SOCKTYPE -7 #define EAI_SERVICE -8 diff --git a/system/lib/libc/musl/include/sched.h b/system/lib/libc/musl/include/sched.h index fda4b48460309..204c34f5679f3 100644 --- a/system/lib/libc/musl/include/sched.h +++ b/system/lib/libc/musl/include/sched.h @@ -124,7 +124,7 @@ __CPU_op_func_S(XOR, ^) #define CPU_ALLOC(n) ((cpu_set_t *)calloc(1,CPU_ALLOC_SIZE(n))) #define CPU_FREE(set) free(set) -#define CPU_SETSIZE 128 +#define CPU_SETSIZE 1024 #define CPU_SET(i, set) CPU_SET_S(i,sizeof(cpu_set_t),set) #define CPU_CLR(i, set) CPU_CLR_S(i,sizeof(cpu_set_t),set) diff --git a/system/lib/libc/musl/include/stdio.h b/system/lib/libc/musl/include/stdio.h index 37e745a57b757..609fad5fdff3e 100644 --- a/system/lib/libc/musl/include/stdio.h +++ b/system/lib/libc/musl/include/stdio.h @@ -215,7 +215,7 @@ typedef struct _IO_cookie_io_functions_t { FILE *fopencookie(void *, const char *, cookie_io_functions_t); #endif -#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) +#if defined(_LARGEFILE64_SOURCE) #define tmpfile64 tmpfile #define fopen64 fopen #define freopen64 freopen diff --git a/system/lib/libc/musl/include/stdlib.h b/system/lib/libc/musl/include/stdlib.h index 5e740526ade4d..efbd0b55a99e2 100644 --- a/system/lib/libc/musl/include/stdlib.h +++ b/system/lib/libc/musl/include/stdlib.h @@ -95,7 +95,7 @@ size_t __ctype_get_mb_cur_max(void); #define WTERMSIG(s) ((s) & 0x7f) #define WSTOPSIG(s) WEXITSTATUS(s) #define WIFEXITED(s) (!WTERMSIG(s)) -#define WIFSTOPPED(s) ((short)((((s)&0xffff)*0x10001)>>8) > 0x7f00) +#define WIFSTOPPED(s) ((short)((((s)&0xffff)*0x10001U)>>8) > 0x7f00) #define WIFSIGNALED(s) (((s)&0xffff)-1U < 0xffu) int posix_memalign (void **, size_t, size_t); @@ -163,7 +163,7 @@ double strtod_l(const char *__restrict, char **__restrict, struct __locale_struc long double strtold_l(const char *__restrict, char **__restrict, struct __locale_struct *); #endif -#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) +#if defined(_LARGEFILE64_SOURCE) #define mkstemp64 mkstemp #define mkostemp64 mkostemp #if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) diff --git a/system/lib/libc/musl/include/string.h b/system/lib/libc/musl/include/string.h index d50eb941be35f..5b3d81b90ead4 100644 --- a/system/lib/libc/musl/include/string.h +++ b/system/lib/libc/musl/include/string.h @@ -73,6 +73,7 @@ char *strsignal(int); char *strerror_l (int, locale_t); int strcoll_l (const char *, const char *, locale_t); size_t strxfrm_l (char *__restrict, const char *__restrict, size_t, locale_t); +void *memmem(const void *, size_t, const void *, size_t); #endif #if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) \ @@ -92,7 +93,6 @@ void explicit_bzero (void *, size_t); int strverscmp (const char *, const char *); char *strchrnul(const char *, int); char *strcasestr(const char *, const char *); -void *memmem(const void *, size_t, const void *, size_t); void *memrchr(const void *, int, size_t); void *mempcpy(void *, const void *, size_t); #ifndef __cplusplus diff --git a/system/lib/libc/musl/include/strings.h b/system/lib/libc/musl/include/strings.h index db0960b4eb87a..b7a5ea0893274 100644 --- a/system/lib/libc/musl/include/strings.h +++ b/system/lib/libc/musl/include/strings.h @@ -5,6 +5,7 @@ extern "C" { #endif +#include #define __NEED_size_t #define __NEED_locale_t diff --git a/system/lib/libc/musl/include/sys/mman.h b/system/lib/libc/musl/include/sys/mman.h index 80a3baae23bb5..3d5d0f9c23383 100644 --- a/system/lib/libc/musl/include/sys/mman.h +++ b/system/lib/libc/musl/include/sys/mman.h @@ -141,7 +141,7 @@ int mincore (void *, size_t, unsigned char *); int shm_open (const char *, int, mode_t); int shm_unlink (const char *); -#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) +#if defined(_LARGEFILE64_SOURCE) #define mmap64 mmap #define off64_t off_t #endif diff --git a/system/lib/libc/musl/include/sys/resource.h b/system/lib/libc/musl/include/sys/resource.h index 3068328d09612..e8bfbe1f08dc1 100644 --- a/system/lib/libc/musl/include/sys/resource.h +++ b/system/lib/libc/musl/include/sys/resource.h @@ -95,7 +95,7 @@ int prlimit(pid_t, int, const struct rlimit *, struct rlimit *); #define RLIM_NLIMITS RLIMIT_NLIMITS -#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) +#if defined(_LARGEFILE64_SOURCE) #define RLIM64_INFINITY RLIM_INFINITY #define RLIM64_SAVED_CUR RLIM_SAVED_CUR #define RLIM64_SAVED_MAX RLIM_SAVED_MAX diff --git a/system/lib/libc/musl/include/sys/stat.h b/system/lib/libc/musl/include/sys/stat.h index 10d446c463eca..e6d0049c3d901 100644 --- a/system/lib/libc/musl/include/sys/stat.h +++ b/system/lib/libc/musl/include/sys/stat.h @@ -98,7 +98,7 @@ int lchmod(const char *, mode_t); #define S_IEXEC S_IXUSR #endif -#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) +#if defined(_LARGEFILE64_SOURCE) #define stat64 stat #define fstat64 fstat #define lstat64 lstat diff --git a/system/lib/libc/musl/include/sys/statfs.h b/system/lib/libc/musl/include/sys/statfs.h index 6f4c6230f7a0a..7a2e11cd56977 100644 --- a/system/lib/libc/musl/include/sys/statfs.h +++ b/system/lib/libc/musl/include/sys/statfs.h @@ -18,7 +18,7 @@ typedef struct __fsid_t { int statfs (const char *, struct statfs *); int fstatfs (int, struct statfs *); -#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) +#if defined(_LARGEFILE64_SOURCE) #define statfs64 statfs #define fstatfs64 fstatfs #define fsblkcnt64_t fsblkcnt_t diff --git a/system/lib/libc/musl/include/sys/statvfs.h b/system/lib/libc/musl/include/sys/statvfs.h index 793490b6dc8c1..57a6b8068e5b3 100644 --- a/system/lib/libc/musl/include/sys/statvfs.h +++ b/system/lib/libc/musl/include/sys/statvfs.h @@ -42,7 +42,7 @@ int fstatvfs (int, struct statvfs *); #define ST_NODIRATIME 2048 #define ST_RELATIME 4096 -#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) +#if defined(_LARGEFILE64_SOURCE) #define statvfs64 statvfs #define fstatvfs64 fstatvfs #define fsblkcnt64_t fsblkcnt_t diff --git a/system/lib/libc/musl/include/sys/types.h b/system/lib/libc/musl/include/sys/types.h index 0c35541da0754..3363374fd3d6f 100644 --- a/system/lib/libc/musl/include/sys/types.h +++ b/system/lib/libc/musl/include/sys/types.h @@ -71,7 +71,7 @@ typedef unsigned long long u_quad_t; #include #endif -#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) +#if defined(_LARGEFILE64_SOURCE) #define blkcnt64_t blkcnt_t #define fsblkcnt64_t fsblkcnt_t #define fsfilcnt64_t fsfilcnt_t diff --git a/system/lib/libc/musl/include/sys/uio.h b/system/lib/libc/musl/include/sys/uio.h index 00f73a2f0525b..90e5939ed0b92 100644 --- a/system/lib/libc/musl/include/sys/uio.h +++ b/system/lib/libc/musl/include/sys/uio.h @@ -29,7 +29,7 @@ ssize_t writev (int, const struct iovec *, int); #if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) ssize_t preadv (int, const struct iovec *, int, off_t); ssize_t pwritev (int, const struct iovec *, int, off_t); -#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) +#if defined(_LARGEFILE64_SOURCE) #define preadv64 preadv #define pwritev64 pwritev #define off64_t off_t diff --git a/system/lib/libc/musl/include/sys/wait.h b/system/lib/libc/musl/include/sys/wait.h index d4b1f2e185c66..8ced671b9a81d 100644 --- a/system/lib/libc/musl/include/sys/wait.h +++ b/system/lib/libc/musl/include/sys/wait.h @@ -50,7 +50,7 @@ pid_t wait4 (pid_t, int *, int, struct rusage *); #define WSTOPSIG(s) WEXITSTATUS(s) #define WCOREDUMP(s) ((s) & 0x80) #define WIFEXITED(s) (!WTERMSIG(s)) -#define WIFSTOPPED(s) ((short)((((s)&0xffff)*0x10001)>>8) > 0x7f00) +#define WIFSTOPPED(s) ((short)((((s)&0xffff)*0x10001U)>>8) > 0x7f00) #define WIFSIGNALED(s) (((s)&0xffff)-1U < 0xffu) #define WIFCONTINUED(s) ((s) == 0xffff) diff --git a/system/lib/libc/musl/include/unistd.h b/system/lib/libc/musl/include/unistd.h index 902f4281260b2..73a075c24dd47 100644 --- a/system/lib/libc/musl/include/unistd.h +++ b/system/lib/libc/musl/include/unistd.h @@ -208,7 +208,7 @@ ssize_t copy_file_range(int, off_t *, int, off_t *, size_t, unsigned); pid_t gettid(void); #endif -#if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) +#if defined(_LARGEFILE64_SOURCE) #define lseek64 lseek #define pread64 pread #define pwrite64 pwrite @@ -457,6 +457,8 @@ pid_t gettid(void); #define _SC_XOPEN_STREAMS 246 #define _SC_THREAD_ROBUST_PRIO_INHERIT 247 #define _SC_THREAD_ROBUST_PRIO_PROTECT 248 +#define _SC_MINSIGSTKSZ 249 +#define _SC_SIGSTKSZ 250 #define _CS_PATH 0 #define _CS_POSIX_V6_WIDTH_RESTRICTED_ENVS 1 @@ -499,6 +501,8 @@ pid_t gettid(void); #define _CS_POSIX_V7_LPBIG_OFFBIG_LINTFLAGS 1147 #define _CS_V6_ENV 1148 #define _CS_V7_ENV 1149 +#define _CS_POSIX_V7_THREADS_CFLAGS 1150 +#define _CS_POSIX_V7_THREADS_LDFLAGS 1151 #ifdef __cplusplus } diff --git a/system/lib/libc/musl/ldso/dlstart.c b/system/lib/libc/musl/ldso/dlstart.c index 20d50f2cbc8d6..259f5e18eecf8 100644 --- a/system/lib/libc/musl/ldso/dlstart.c +++ b/system/lib/libc/musl/ldso/dlstart.c @@ -140,6 +140,21 @@ hidden void _dlstart_c(size_t *sp, size_t *dynv) size_t *rel_addr = (void *)(base + rel[0]); *rel_addr = base + rel[2]; } + + rel = (void *)(base+dyn[DT_RELR]); + rel_size = dyn[DT_RELRSZ]; + size_t *relr_addr = 0; + for (; rel_size; rel++, rel_size-=sizeof(size_t)) { + if ((rel[0]&1) == 0) { + relr_addr = (void *)(base + rel[0]); + *relr_addr++ += base; + } else { + for (size_t i=0, bitmap=rel[0]; bitmap>>=1; i++) + if (bitmap&1) + relr_addr[i] += base; + relr_addr += 8*sizeof(size_t)-1; + } + } #endif stage2_func dls2; diff --git a/system/lib/libc/musl/ldso/dynlink.c b/system/lib/libc/musl/ldso/dynlink.c index 5b9c8be42160c..ceca3c98a4642 100644 --- a/system/lib/libc/musl/ldso/dynlink.c +++ b/system/lib/libc/musl/ldso/dynlink.c @@ -21,15 +21,23 @@ #include #include "pthread_impl.h" #include "fork_impl.h" -#include "libc.h" #include "dynlink.h" +static size_t ldso_page_size; +#ifndef PAGE_SIZE +#define PAGE_SIZE ldso_page_size +#endif + +#include "libc.h" + #define malloc __libc_malloc #define calloc __libc_calloc #define realloc __libc_realloc #define free __libc_free -static void error(const char *, ...); +static void error_impl(const char *, ...); +static void error_noop(const char *, ...); +static void (*error)(const char *, ...) = error_noop; #define MAXP2(a,b) (-(-(a)&-(b))) #define ALIGN(x,y) ((x)+(y)-1 & -(y)) @@ -208,7 +216,8 @@ static void decode_vec(size_t *v, size_t *a, size_t cnt) size_t i; for (i=0; i= sizeof buf) goto nomatch; + buf[l] = name[l]; + } + if (!strcmp(name, "readdir64_r")) + return find_sym(&ldso, "readdir_r", 1); + if (l<2 || name[l-2]!='6' || name[l-1]!='4') + goto nomatch; + buf[l-=2] = 0; + for (p=lfs64_list; *p; p++) { + if (!strcmp(buf, p)) return find_sym(&ldso, buf, 1); + while (*p) p++; + } +nomatch: + return (struct symdef){ 0 }; +} + static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stride) { unsigned char *base = dso->base; @@ -387,6 +430,7 @@ static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stri def = (sym->st_info>>4) == STB_LOCAL ? (struct symdef){ .dso = dso, .sym = sym } : find_sym(ctx, name, type==REL_PLT); + if (!def.sym) def = get_lfs64(name); if (!def.sym && (sym->st_shndx != SHN_UNDEF || sym->st_info>>4 != STB_WEAK)) { if (dso->lazy && (type==REL_PLT || type==REL_GOT)) { @@ -513,6 +557,24 @@ static void do_relocs(struct dso *dso, size_t *rel, size_t rel_size, size_t stri } } +static void do_relr_relocs(struct dso *dso, size_t *relr, size_t relr_size) +{ + if (dso == &ldso) return; /* self-relocation was done in _dlstart */ + unsigned char *base = dso->base; + size_t *reloc_addr; + for (; relr_size; relr++, relr_size-=sizeof(size_t)) + if ((relr[0]&1) == 0) { + reloc_addr = laddr(dso, relr[0]); + *reloc_addr++ += (size_t)base; + } else { + int i = 0; + for (size_t bitmap=relr[0]; (bitmap>>=1); i++) + if (bitmap&1) + reloc_addr[i] += (size_t)base; + reloc_addr += 8*sizeof(size_t)-1; + } +} + static void redo_lazy_relocs() { struct dso *p = lazy_head, *next; @@ -866,7 +928,7 @@ static int fixup_rpath(struct dso *p, char *buf, size_t buf_size) case ENOENT: case ENOTDIR: case EACCES: - break; + return 0; default: return -1; } @@ -1355,13 +1417,17 @@ static void reloc_all(struct dso *p) 2+(dyn[DT_PLTREL]==DT_RELA)); do_relocs(p, laddr(p, dyn[DT_REL]), dyn[DT_RELSZ], 2); do_relocs(p, laddr(p, dyn[DT_RELA]), dyn[DT_RELASZ], 3); - - if (head != &ldso && p->relro_start != p->relro_end && - mprotect(laddr(p, p->relro_start), p->relro_end-p->relro_start, PROT_READ) - && errno != ENOSYS) { - error("Error relocating %s: RELRO protection failed: %m", - p->name); - if (runtime) longjmp(*rtld_fail, 1); + if (!DL_FDPIC) + do_relr_relocs(p, laddr(p, dyn[DT_RELR]), dyn[DT_RELRSZ]); + + if (head != &ldso && p->relro_start != p->relro_end) { + long ret = __syscall(SYS_mprotect, laddr(p, p->relro_start), + p->relro_end-p->relro_start, PROT_READ); + if (ret != 0 && ret != -ENOSYS) { + error("Error relocating %s: RELRO protection failed: %m", + p->name); + if (runtime) longjmp(*rtld_fail, 1); + } } p->relocated = 1; @@ -1664,6 +1730,7 @@ hidden void __dls2(unsigned char *base, size_t *sp) ldso.phnum = ehdr->e_phnum; ldso.phdr = laddr(&ldso, ehdr->e_phoff); ldso.phentsize = ehdr->e_phentsize; + search_vec(auxv, &ldso_page_size, AT_PAGESZ); kernel_mapped_dso(&ldso); decode_dyn(&ldso); @@ -1756,6 +1823,9 @@ void __dls3(size_t *sp, size_t *auxv) env_preload = getenv("LD_PRELOAD"); } + /* Activate error handler function */ + error = error_impl; + /* If the main program was already loaded by the kernel, * AT_PHDR will point to some location other than the dynamic * linker's program headers. */ @@ -1923,6 +1993,10 @@ void __dls3(size_t *sp, size_t *auxv) size_t *ptr = (size_t *) app.dynv[i+1]; *ptr = (size_t)&debug; } + if (app.dynv[i]==DT_DEBUG_INDIRECT_REL) { + size_t *ptr = (size_t *)((size_t)&app.dynv[i] + app.dynv[i+1]); + *ptr = (size_t)&debug; + } } /* This must be done before final relocations, since it calls @@ -2345,7 +2419,7 @@ int dl_iterate_phdr(int(*callback)(struct dl_phdr_info *info, size_t size, void return ret; } -static void error(const char *fmt, ...) +static void error_impl(const char *fmt, ...) { va_list ap; va_start(ap, fmt); @@ -2359,3 +2433,7 @@ static void error(const char *fmt, ...) __dl_vseterr(fmt, ap); va_end(ap); } + +static void error_noop(const char *fmt, ...) +{ +} diff --git a/system/lib/libc/musl/src/aio/aio.c b/system/lib/libc/musl/src/aio/aio.c index a1a3e7914b02e..d7e063bf93ca8 100644 --- a/system/lib/libc/musl/src/aio/aio.c +++ b/system/lib/libc/musl/src/aio/aio.c @@ -82,6 +82,8 @@ static size_t io_thread_stack_size; static struct aio_queue *__aio_get_queue(int fd, int need) { + sigset_t allmask, origmask; + int masked = 0; if (fd < 0) { errno = EBADF; return 0; @@ -93,6 +95,9 @@ static struct aio_queue *__aio_get_queue(int fd, int need) if ((!map || !map[a] || !map[a][b] || !map[a][b][c] || !(q=map[a][b][c][d])) && need) { pthread_rwlock_unlock(&maplock); if (fcntl(fd, F_GETFD) < 0) return 0; + sigfillset(&allmask); + masked = 1; + pthread_sigmask(SIG_BLOCK, &allmask, &origmask); pthread_rwlock_wrlock(&maplock); if (!io_thread_stack_size) { unsigned long val = __getauxval(AT_MINSIGSTKSZ); @@ -119,6 +124,7 @@ static struct aio_queue *__aio_get_queue(int fd, int need) if (q) pthread_mutex_lock(&q->lock); out: pthread_rwlock_unlock(&maplock); + if (masked) pthread_sigmask(SIG_SETMASK, &origmask, 0); return q; } @@ -401,18 +407,26 @@ void __aio_atfork(int who) if (who<0) { pthread_rwlock_rdlock(&maplock); return; + } else if (!who) { + pthread_rwlock_unlock(&maplock); + return; } - if (who>0 && map) for (int a=0; a<(-1U/2+1)>>24; a++) + aio_fd_cnt = 0; + if (pthread_rwlock_tryrdlock(&maplock)) { + /* Obtaining lock may fail if _Fork was called nor via + * fork. In this case, no further aio is possible from + * child and we can just null out map so __aio_close + * does not attempt to do anything. */ + map = 0; + return; + } + if (map) for (int a=0; a<(-1U/2+1)>>24; a++) if (map[a]) for (int b=0; b<256; b++) if (map[a][b]) for (int c=0; c<256; c++) if (map[a][b][c]) for (int d=0; d<256; d++) map[a][b][c][d] = 0; - pthread_rwlock_unlock(&maplock); + /* Re-initialize the rwlock rather than unlocking since there + * may have been more than one reference on it in the parent. + * We are not a lock holder anyway; the thread in the parent was. */ + pthread_rwlock_init(&maplock, 0); } - -weak_alias(aio_cancel, aio_cancel64); -weak_alias(aio_error, aio_error64); -weak_alias(aio_fsync, aio_fsync64); -weak_alias(aio_read, aio_read64); -weak_alias(aio_write, aio_write64); -weak_alias(aio_return, aio_return64); diff --git a/system/lib/libc/musl/src/aio/aio_suspend.c b/system/lib/libc/musl/src/aio/aio_suspend.c index 1c1060e340a13..1f0c9aaaa1f22 100644 --- a/system/lib/libc/musl/src/aio/aio_suspend.c +++ b/system/lib/libc/musl/src/aio/aio_suspend.c @@ -9,7 +9,7 @@ int aio_suspend(const struct aiocb *const cbs[], int cnt, const struct timespec { int i, tid = 0, ret, expect = 0; struct timespec at; - volatile int dummy_fut, *pfut; + volatile int dummy_fut = 0, *pfut; int nzcnt = 0; const struct aiocb *cb = 0; @@ -73,7 +73,3 @@ int aio_suspend(const struct aiocb *const cbs[], int cnt, const struct timespec } } } - -#if !_REDIR_TIME64 -weak_alias(aio_suspend, aio_suspend64); -#endif diff --git a/system/lib/libc/musl/src/aio/lio_listio.c b/system/lib/libc/musl/src/aio/lio_listio.c index 0799c15d8b16f..a672812f47746 100644 --- a/system/lib/libc/musl/src/aio/lio_listio.c +++ b/system/lib/libc/musl/src/aio/lio_listio.c @@ -139,5 +139,3 @@ int lio_listio(int mode, struct aiocb *restrict const *restrict cbs, int cnt, st return 0; } - -weak_alias(lio_listio, lio_listio64); diff --git a/system/lib/libc/musl/src/conf/confstr.c b/system/lib/libc/musl/src/conf/confstr.c index 0dba71fca542d..9c12d365babf2 100644 --- a/system/lib/libc/musl/src/conf/confstr.c +++ b/system/lib/libc/musl/src/conf/confstr.c @@ -26,7 +26,7 @@ size_t confstr(int name, char *buf, size_t len) } else if (name == _CS_POSIX_V6_ILP32_OFFBIG_CFLAGS) { s = "-m32 -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64"; #endif - } else if ((name&~4U)!=1 && name-_CS_POSIX_V6_ILP32_OFF32_CFLAGS>33U) { + } else if ((name&~4U)!=1 && name-_CS_POSIX_V6_ILP32_OFF32_CFLAGS>35U) { errno = EINVAL; return 0; } diff --git a/system/lib/libc/musl/src/conf/sysconf.c b/system/lib/libc/musl/src/conf/sysconf.c index 6465ef5d3074d..c300a834c1248 100644 --- a/system/lib/libc/musl/src/conf/sysconf.c +++ b/system/lib/libc/musl/src/conf/sysconf.c @@ -4,6 +4,9 @@ #include #include #include +#ifndef __EMSCRIPTEN__ +#include +#endif #include "syscall.h" #include "libc.h" @@ -24,6 +27,8 @@ #define JT_AVPHYS_PAGES JT(9) #define JT_ZERO JT(10) #define JT_DELAYTIMER_MAX JT(11) +#define JT_MINSIGSTKSZ JT(12) +#define JT_SIGSTKSZ JT(13) #define RLIM(x) (-32768|(RLIMIT_ ## x)) @@ -170,6 +175,9 @@ long sysconf(int name) [_SC_XOPEN_STREAMS] = JT_ZERO, [_SC_THREAD_ROBUST_PRIO_INHERIT] = -1, [_SC_THREAD_ROBUST_PRIO_PROTECT] = -1, + + [_SC_MINSIGSTKSZ] = JT_MINSIGSTKSZ, + [_SC_SIGSTKSZ] = JT_SIGSTKSZ, }; if (name >= sizeof(values)/sizeof(values[0]) || !values[name]) { @@ -224,6 +232,13 @@ long sysconf(int name) mem *= si.mem_unit; mem /= PAGE_SIZE; return (mem > LONG_MAX) ? LONG_MAX : mem; + case JT_MINSIGSTKSZ & 255: + case JT_SIGSTKSZ & 255: ; + long val = __getauxval(AT_MINSIGSTKSZ); + if (val < MINSIGSTKSZ) val = MINSIGSTKSZ; + if (values[name] == JT_SIGSTKSZ) + val += SIGSTKSZ - MINSIGSTKSZ; + return val; #endif case JT_ZERO & 255: return 0; diff --git a/system/lib/libc/musl/src/dirent/alphasort.c b/system/lib/libc/musl/src/dirent/alphasort.c index bee672ebda0c5..ab2624e2cc415 100644 --- a/system/lib/libc/musl/src/dirent/alphasort.c +++ b/system/lib/libc/musl/src/dirent/alphasort.c @@ -5,5 +5,3 @@ int alphasort(const struct dirent **a, const struct dirent **b) { return strcoll((*a)->d_name, (*b)->d_name); } - -weak_alias(alphasort, alphasort64); diff --git a/system/lib/libc/musl/src/dirent/readdir.c b/system/lib/libc/musl/src/dirent/readdir.c index 569fc70577378..5a03b36352f91 100644 --- a/system/lib/libc/musl/src/dirent/readdir.c +++ b/system/lib/libc/musl/src/dirent/readdir.c @@ -25,5 +25,3 @@ struct dirent *readdir(DIR *dir) dir->tell = de->d_off; return de; } - -weak_alias(readdir, readdir64); diff --git a/system/lib/libc/musl/src/dirent/readdir_r.c b/system/lib/libc/musl/src/dirent/readdir_r.c index e2a818f36a0c6..0d5de5f56ddda 100644 --- a/system/lib/libc/musl/src/dirent/readdir_r.c +++ b/system/lib/libc/musl/src/dirent/readdir_r.c @@ -25,5 +25,3 @@ int readdir_r(DIR *restrict dir, struct dirent *restrict buf, struct dirent **re *result = buf; return 0; } - -weak_alias(readdir_r, readdir64_r); diff --git a/system/lib/libc/musl/src/dirent/scandir.c b/system/lib/libc/musl/src/dirent/scandir.c index 7ee195dd8ab31..7456b9b8bcec4 100644 --- a/system/lib/libc/musl/src/dirent/scandir.c +++ b/system/lib/libc/musl/src/dirent/scandir.c @@ -43,5 +43,3 @@ int scandir(const char *path, struct dirent ***res, *res = names; return cnt; } - -weak_alias(scandir, scandir64); diff --git a/system/lib/libc/musl/src/dirent/versionsort.c b/system/lib/libc/musl/src/dirent/versionsort.c index d4c489230abb8..9769610518eb3 100644 --- a/system/lib/libc/musl/src/dirent/versionsort.c +++ b/system/lib/libc/musl/src/dirent/versionsort.c @@ -6,6 +6,3 @@ int versionsort(const struct dirent **a, const struct dirent **b) { return strverscmp((*a)->d_name, (*b)->d_name); } - -#undef versionsort64 -weak_alias(versionsort, versionsort64); diff --git a/system/lib/libc/musl/src/fcntl/creat.c b/system/lib/libc/musl/src/fcntl/creat.c index 8f8aab64631cf..c9c43910d8245 100644 --- a/system/lib/libc/musl/src/fcntl/creat.c +++ b/system/lib/libc/musl/src/fcntl/creat.c @@ -4,5 +4,3 @@ int creat(const char *filename, mode_t mode) { return open(filename, O_CREAT|O_WRONLY|O_TRUNC, mode); } - -weak_alias(creat, creat64); diff --git a/system/lib/libc/musl/src/fcntl/open.c b/system/lib/libc/musl/src/fcntl/open.c index 3bf96fd11535f..b95a90e017274 100644 --- a/system/lib/libc/musl/src/fcntl/open.c +++ b/system/lib/libc/musl/src/fcntl/open.c @@ -21,5 +21,3 @@ int open(const char *filename, int flags, ...) return __syscall_ret(fd); } - -weak_alias(open, open64); diff --git a/system/lib/libc/musl/src/fcntl/openat.c b/system/lib/libc/musl/src/fcntl/openat.c index ad165ec323f77..83a9e0d008c46 100644 --- a/system/lib/libc/musl/src/fcntl/openat.c +++ b/system/lib/libc/musl/src/fcntl/openat.c @@ -15,5 +15,3 @@ int openat(int fd, const char *filename, int flags, ...) return syscall_cp(SYS_openat, fd, filename, flags|O_LARGEFILE, mode); } - -weak_alias(openat, openat64); diff --git a/system/lib/libc/musl/src/fcntl/posix_fadvise.c b/system/lib/libc/musl/src/fcntl/posix_fadvise.c index 75b8e1aed87f7..07346d21ae2f1 100644 --- a/system/lib/libc/musl/src/fcntl/posix_fadvise.c +++ b/system/lib/libc/musl/src/fcntl/posix_fadvise.c @@ -14,5 +14,3 @@ int posix_fadvise(int fd, off_t base, off_t len, int advice) __SYSCALL_LL_E(len), advice); #endif } - -weak_alias(posix_fadvise, posix_fadvise64); diff --git a/system/lib/libc/musl/src/fcntl/posix_fallocate.c b/system/lib/libc/musl/src/fcntl/posix_fallocate.c index c57a24aef4d9a..80a65cbfd62e9 100644 --- a/system/lib/libc/musl/src/fcntl/posix_fallocate.c +++ b/system/lib/libc/musl/src/fcntl/posix_fallocate.c @@ -6,5 +6,3 @@ int posix_fallocate(int fd, off_t base, off_t len) return -__syscall(SYS_fallocate, fd, 0, __SYSCALL_LL_E(base), __SYSCALL_LL_E(len)); } - -weak_alias(posix_fallocate, posix_fallocate64); diff --git a/system/lib/libc/musl/src/include/sys/stat.h b/system/lib/libc/musl/src/include/sys/stat.h new file mode 100644 index 0000000000000..59339beecb17e --- /dev/null +++ b/system/lib/libc/musl/src/include/sys/stat.h @@ -0,0 +1,9 @@ +#ifndef SYS_STAT_H +#define SYS_STAT_H + +#include "../../../include/sys/stat.h" + +hidden int __fstat(int, struct stat *); +hidden int __fstatat(int, const char *restrict, struct stat *restrict, int); + +#endif diff --git a/system/lib/libc/musl/src/internal/dynlink.h b/system/lib/libc/musl/src/internal/dynlink.h index a90658bbb45d7..5393ae0349179 100644 --- a/system/lib/libc/musl/src/internal/dynlink.h +++ b/system/lib/libc/musl/src/internal/dynlink.h @@ -126,8 +126,12 @@ struct fdpic_dummy_loadmap { #define DT_DEBUG_INDIRECT 0 #endif +#ifndef DT_DEBUG_INDIRECT_REL +#define DT_DEBUG_INDIRECT_REL 0 +#endif + #define AUX_CNT 32 -#define DYN_CNT 32 +#define DYN_CNT 37 typedef void (*stage2_func)(unsigned char *, size_t *); diff --git a/system/lib/libc/musl/src/internal/fork_impl.h b/system/lib/libc/musl/src/internal/fork_impl.h index 5892c13bf90a5..354e733b91bdd 100644 --- a/system/lib/libc/musl/src/internal/fork_impl.h +++ b/system/lib/libc/musl/src/internal/fork_impl.h @@ -2,7 +2,6 @@ extern hidden volatile int *const __at_quick_exit_lockptr; extern hidden volatile int *const __atexit_lockptr; -extern hidden volatile int *const __dlerror_lockptr; extern hidden volatile int *const __gettext_lockptr; extern hidden volatile int *const __locale_lockptr; extern hidden volatile int *const __random_lockptr; @@ -17,3 +16,4 @@ extern hidden volatile int *const __vmlock_lockptr; hidden void __malloc_atfork(int); hidden void __ldso_atfork(int); +hidden void __pthread_key_atfork(int); diff --git a/system/lib/libc/musl/src/internal/ksigaction.h b/system/lib/libc/musl/src/internal/ksigaction.h index 8ebd5938352e7..ef333f33ccfd3 100644 --- a/system/lib/libc/musl/src/internal/ksigaction.h +++ b/system/lib/libc/musl/src/internal/ksigaction.h @@ -6,8 +6,13 @@ struct k_sigaction { void (*handler)(int); unsigned long flags; +#ifdef SA_RESTORER void (*restorer)(void); +#endif unsigned mask[2]; +#ifndef SA_RESTORER + void *unused; +#endif }; hidden void __restore(), __restore_rt(); diff --git a/system/lib/libc/musl/src/internal/syscall.h b/system/lib/libc/musl/src/internal/syscall.h index ec67b735dd7dd..62dfd1fc7d44c 100644 --- a/system/lib/libc/musl/src/internal/syscall.h +++ b/system/lib/libc/musl/src/internal/syscall.h @@ -95,7 +95,6 @@ hidden long __syscall_ret(unsigned long), #define __socketcall(nm,a,b,c,d,e,f) __syscall(SYS_##nm, a, b, c, d, e, f) #define __socketcall_cp(nm,a,b,c,d,e,f) __syscall_cp(SYS_##nm, a, b, c, d, e, f) #else -static inline long __alt_socketcall(int sys, int sock, int cp, long a, long b, long c, long d, long e, long f) { long r; if (cp) r = __syscall_cp(sys, a, b, c, d, e, f); @@ -108,9 +107,9 @@ static inline long __alt_socketcall(int sys, int sock, int cp, long a, long b, l return r; } #define __socketcall(nm, a, b, c, d, e, f) __alt_socketcall(SYS_##nm, __SC_##nm, 0, \ - (long)(a), (long)(b), (long)(c), (long)(d), (long)(e), (long)(f)) + __scc(a), __scc(b), __scc(c), __scc(d), __scc(e), __scc(f)) #define __socketcall_cp(nm, a, b, c, d, e, f) __alt_socketcall(SYS_##nm, __SC_##nm, 1, \ - (long)(a), (long)(b), (long)(c), (long)(d), (long)(e), (long)(f)) + __scc(a), __scc(b), __scc(c), __scc(d), __scc(e), __scc(f)) #endif /* fixup legacy 16-bit junk */ @@ -237,43 +236,43 @@ static inline long __alt_socketcall(int sys, int sock, int cp, long a, long b, l #define SYS_sendfile SYS_sendfile64 #endif -#ifndef SYS_timer_settime +#ifdef SYS_timer_settime32 #define SYS_timer_settime SYS_timer_settime32 #endif -#ifndef SYS_timer_gettime +#ifdef SYS_timer_gettime32 #define SYS_timer_gettime SYS_timer_gettime32 #endif -#ifndef SYS_timerfd_settime +#ifdef SYS_timerfd_settime32 #define SYS_timerfd_settime SYS_timerfd_settime32 #endif -#ifndef SYS_timerfd_gettime +#ifdef SYS_timerfd_gettime32 #define SYS_timerfd_gettime SYS_timerfd_gettime32 #endif -#ifndef SYS_clock_settime +#ifdef SYS_clock_settime32 #define SYS_clock_settime SYS_clock_settime32 #endif -#ifndef SYS_clock_gettime +#ifdef SYS_clock_gettime32 #define SYS_clock_gettime SYS_clock_gettime32 #endif -#ifndef SYS_clock_getres +#ifdef SYS_clock_getres_time32 #define SYS_clock_getres SYS_clock_getres_time32 #endif -#ifndef SYS_clock_nanosleep +#ifdef SYS_clock_nanosleep_time32 #define SYS_clock_nanosleep SYS_clock_nanosleep_time32 #endif -#ifndef SYS_gettimeofday +#ifdef SYS_gettimeofday_time32 #define SYS_gettimeofday SYS_gettimeofday_time32 #endif -#ifndef SYS_settimeofday +#ifdef SYS_settimeofday_time32 #define SYS_settimeofday SYS_settimeofday_time32 #endif diff --git a/system/lib/libc/musl/src/internal/version.h b/system/lib/libc/musl/src/internal/version.h index a9327dd446289..36bfc49c872bb 100644 --- a/system/lib/libc/musl/src/internal/version.h +++ b/system/lib/libc/musl/src/internal/version.h @@ -1 +1 @@ -#define VERSION "1.2.3" +#define VERSION "1.2.4" diff --git a/system/lib/libc/musl/src/ipc/semtimedop.c b/system/lib/libc/musl/src/ipc/semtimedop.c index 1632e7b03f38a..a104af21895e1 100644 --- a/system/lib/libc/musl/src/ipc/semtimedop.c +++ b/system/lib/libc/musl/src/ipc/semtimedop.c @@ -7,7 +7,8 @@ #define IS32BIT(x) !((x)+0x80000000ULL>>32) #define CLAMP(x) (int)(IS32BIT(x) ? (x) : 0x7fffffffU+((0ULL+(x))>>63)) -#if !defined(SYS_semtimedop) && !defined(SYS_ipc) +#if !defined(SYS_semtimedop) && !defined(SYS_ipc) || \ + SYS_semtimedop == SYS_semtimedop_time64 #define NO_TIME32 1 #else #define NO_TIME32 0 diff --git a/system/lib/libc/musl/src/ldso/dlerror.c b/system/lib/libc/musl/src/ldso/dlerror.c index afe59253ea0ee..dae0f3a9b24a9 100644 --- a/system/lib/libc/musl/src/ldso/dlerror.c +++ b/system/lib/libc/musl/src/ldso/dlerror.c @@ -3,8 +3,7 @@ #include #include "pthread_impl.h" #include "dynlink.h" -#include "lock.h" -#include "fork_impl.h" +#include "atomic.h" #define malloc __libc_malloc #define calloc __libc_calloc @@ -23,28 +22,31 @@ char *dlerror() return s; } -static volatile int freebuf_queue_lock[1]; -static void **freebuf_queue; -volatile int *const __dlerror_lockptr = freebuf_queue_lock; +/* Atomic singly-linked list, used to store list of thread-local dlerror + * buffers for deferred free. They cannot be freed at thread exit time + * because, by the time it's known they can be freed, the exiting thread + * is in a highly restrictive context where it cannot call (even the + * libc-internal) free. It also can't take locks; thus the atomic list. */ + +static void *volatile freebuf_queue; void __dl_thread_cleanup(void) { pthread_t self = __pthread_self(); - if (self->dlerror_buf && self->dlerror_buf != (void *)-1) { - LOCK(freebuf_queue_lock); - void **p = (void **)self->dlerror_buf; - *p = freebuf_queue; - freebuf_queue = p; - UNLOCK(freebuf_queue_lock); - } + if (!self->dlerror_buf || self->dlerror_buf == (void *)-1) + return; + void *h; + do { + h = freebuf_queue; + *(void **)self->dlerror_buf = h; + } while (a_cas_p(&freebuf_queue, h, self->dlerror_buf) != h); } hidden void __dl_vseterr(const char *fmt, va_list ap) { - LOCK(freebuf_queue_lock); - void **q = freebuf_queue; - freebuf_queue = 0; - UNLOCK(freebuf_queue_lock); + void **q; + do q = freebuf_queue; + while (q && a_cas_p(&freebuf_queue, q, 0) != q); while (q) { void **p = *q; diff --git a/system/lib/libc/musl/src/legacy/ftw.c b/system/lib/libc/musl/src/legacy/ftw.c index 506bd29cedf3b..e757fc6f0ce20 100644 --- a/system/lib/libc/musl/src/legacy/ftw.c +++ b/system/lib/libc/musl/src/legacy/ftw.c @@ -7,5 +7,3 @@ int ftw(const char *path, int (*fn)(const char *, const struct stat *, int), int * actually undefined, but works on all real-world machines. */ return nftw(path, (int (*)())fn, fd_limit, FTW_PHYS); } - -weak_alias(ftw, ftw64); diff --git a/system/lib/libc/musl/src/linux/epoll.c b/system/lib/libc/musl/src/linux/epoll.c index 93baa8147e422..e56e8f4c8293b 100644 --- a/system/lib/libc/musl/src/linux/epoll.c +++ b/system/lib/libc/musl/src/linux/epoll.c @@ -5,6 +5,7 @@ int epoll_create(int size) { + if (size<=0) return __syscall_ret(-EINVAL); return epoll_create1(0); } diff --git a/system/lib/libc/musl/src/linux/fallocate.c b/system/lib/libc/musl/src/linux/fallocate.c index 7d68bc8f64f6e..9146350e3c7f0 100644 --- a/system/lib/libc/musl/src/linux/fallocate.c +++ b/system/lib/libc/musl/src/linux/fallocate.c @@ -7,6 +7,3 @@ int fallocate(int fd, int mode, off_t base, off_t len) return syscall(SYS_fallocate, fd, mode, __SYSCALL_LL_E(base), __SYSCALL_LL_E(len)); } - -#undef fallocate64 -weak_alias(fallocate, fallocate64); diff --git a/system/lib/libc/musl/src/linux/getdents.c b/system/lib/libc/musl/src/linux/getdents.c index 796c1e5c92499..97f76e1479419 100644 --- a/system/lib/libc/musl/src/linux/getdents.c +++ b/system/lib/libc/musl/src/linux/getdents.c @@ -8,5 +8,3 @@ int getdents(int fd, struct dirent *buf, size_t len) if (len>INT_MAX) len = INT_MAX; return syscall(SYS_getdents, fd, buf, len); } - -weak_alias(getdents, getdents64); diff --git a/system/lib/libc/musl/src/linux/membarrier.c b/system/lib/libc/musl/src/linux/membarrier.c index 343f7360ee119..f64fe7e189fbd 100644 --- a/system/lib/libc/musl/src/linux/membarrier.c +++ b/system/lib/libc/musl/src/linux/membarrier.c @@ -35,7 +35,7 @@ int __membarrier(int cmd, int flags) __tl_lock(); sem_init(&barrier_sem, 0, 0); struct sigaction sa = { - .sa_flags = SA_RESTART, + .sa_flags = SA_RESTART | SA_ONSTACK, .sa_handler = bcast_barrier }; memset(&sa.sa_mask, -1, sizeof sa.sa_mask); diff --git a/system/lib/libc/musl/src/linux/prlimit.c b/system/lib/libc/musl/src/linux/prlimit.c index 3df9ffba7af84..fcf45aaba5376 100644 --- a/system/lib/libc/musl/src/linux/prlimit.c +++ b/system/lib/libc/musl/src/linux/prlimit.c @@ -21,6 +21,3 @@ int prlimit(pid_t pid, int resource, const struct rlimit *new_limit, struct rlim } return r; } - -#undef prlimit64 -weak_alias(prlimit, prlimit64); diff --git a/system/lib/libc/musl/src/linux/sendfile.c b/system/lib/libc/musl/src/linux/sendfile.c index 9afe6dd61c203..fc1577d34330f 100644 --- a/system/lib/libc/musl/src/linux/sendfile.c +++ b/system/lib/libc/musl/src/linux/sendfile.c @@ -5,5 +5,3 @@ ssize_t sendfile(int out_fd, int in_fd, off_t *ofs, size_t count) { return syscall(SYS_sendfile, out_fd, in_fd, ofs, count); } - -weak_alias(sendfile, sendfile64); diff --git a/system/lib/libc/musl/src/linux/wait4.c b/system/lib/libc/musl/src/linux/wait4.c index 83650e34a860c..ff2e3e6649003 100644 --- a/system/lib/libc/musl/src/linux/wait4.c +++ b/system/lib/libc/musl/src/linux/wait4.c @@ -12,7 +12,7 @@ pid_t wait4(pid_t pid, int *status, int options, struct rusage *ru) if (ru) { long long kru64[18]; r = __syscall(SYS_wait4_time64, pid, status, options, kru64); - if (!r) { + if (r > 0) { ru->ru_utime = (struct timeval) { .tv_sec = kru64[0], .tv_usec = kru64[1] }; ru->ru_stime = (struct timeval) diff --git a/system/lib/libc/musl/src/math/logf.c b/system/lib/libc/musl/src/math/logf.c index 7ee5d7fe623d6..e4c2237caa2eb 100644 --- a/system/lib/libc/musl/src/math/logf.c +++ b/system/lib/libc/musl/src/math/logf.c @@ -53,7 +53,7 @@ float logf(float x) tmp = ix - OFF; i = (tmp >> (23 - LOGF_TABLE_BITS)) % N; k = (int32_t)tmp >> 23; /* arithmetic shift */ - iz = ix - (tmp & 0x1ff << 23); + iz = ix - (tmp & 0xff800000); invc = T[i].invc; logc = T[i].logc; z = (double_t)asfloat(iz); diff --git a/system/lib/libc/musl/src/misc/getopt.c b/system/lib/libc/musl/src/misc/getopt.c index c3f6699559b5c..b02b81c34329b 100644 --- a/system/lib/libc/musl/src/misc/getopt.c +++ b/system/lib/libc/musl/src/misc/getopt.c @@ -87,7 +87,8 @@ int getopt(int argc, char * const argv[], const char *optstring) if (optstring[i] == ':') { optarg = 0; if (optstring[i+1] != ':' || optpos) { - optarg = argv[optind++] + optpos; + optarg = argv[optind++]; + if (optpos) optarg += optpos; optpos = 0; } if (optind > argc) { diff --git a/system/lib/libc/musl/src/misc/getrlimit.c b/system/lib/libc/musl/src/misc/getrlimit.c index 2ab2f0f4faadd..a5558d8151525 100644 --- a/system/lib/libc/musl/src/misc/getrlimit.c +++ b/system/lib/libc/musl/src/misc/getrlimit.c @@ -6,12 +6,13 @@ int getrlimit(int resource, struct rlimit *rlim) { - unsigned long k_rlim[2]; int ret = syscall(SYS_prlimit64, 0, resource, 0, rlim); if (!ret) { FIX(rlim->rlim_cur); FIX(rlim->rlim_max); } +#ifdef SYS_getrlimit + unsigned long k_rlim[2]; if (!ret || errno != ENOSYS) return ret; if (syscall(SYS_getrlimit, resource, k_rlim) < 0) @@ -21,6 +22,7 @@ int getrlimit(int resource, struct rlimit *rlim) FIX(rlim->rlim_cur); FIX(rlim->rlim_max); return 0; +#else + return ret; +#endif } - -weak_alias(getrlimit, getrlimit64); diff --git a/system/lib/libc/musl/src/misc/lockf.c b/system/lib/libc/musl/src/misc/lockf.c index 16a80bec13206..0162442b0ba6b 100644 --- a/system/lib/libc/musl/src/misc/lockf.c +++ b/system/lib/libc/musl/src/misc/lockf.c @@ -28,5 +28,3 @@ int lockf(int fd, int op, off_t size) errno = EINVAL; return -1; } - -weak_alias(lockf, lockf64); diff --git a/system/lib/libc/musl/src/misc/mntent.c b/system/lib/libc/musl/src/misc/mntent.c index eabb8200bf94d..d404fbe3929b0 100644 --- a/system/lib/libc/musl/src/misc/mntent.c +++ b/system/lib/libc/musl/src/misc/mntent.c @@ -2,6 +2,7 @@ #include #include #include +#include static char *internal_buf; static size_t internal_bufsize; @@ -21,7 +22,8 @@ int endmntent(FILE *f) struct mntent *getmntent_r(FILE *f, struct mntent *mnt, char *linebuf, int buflen) { - int cnt, n[8], use_internal = (linebuf == SENTINEL); + int n[8], use_internal = (linebuf == SENTINEL); + size_t len, i; mnt->mnt_freq = 0; mnt->mnt_passno = 0; @@ -39,10 +41,14 @@ struct mntent *getmntent_r(FILE *f, struct mntent *mnt, char *linebuf, int bufle errno = ERANGE; return 0; } - cnt = sscanf(linebuf, " %n%*s%n %n%*s%n %n%*s%n %n%*s%n %d %d", + + len = strlen(linebuf); + if (len > INT_MAX) continue; + for (i = 0; i < sizeof n / sizeof *n; i++) n[i] = len; + sscanf(linebuf, " %n%*s%n %n%*s%n %n%*s%n %n%*s%n %d %d", n, n+1, n+2, n+3, n+4, n+5, n+6, n+7, &mnt->mnt_freq, &mnt->mnt_passno); - } while (cnt < 2 || linebuf[n[0]] == '#'); + } while (linebuf[n[0]] == '#' || n[1]==len); linebuf[n[1]] = 0; linebuf[n[3]] = 0; diff --git a/system/lib/libc/musl/src/misc/nftw.c b/system/lib/libc/musl/src/misc/nftw.c index 8dcff7fefd2a3..71bc62eecdeab 100644 --- a/system/lib/libc/musl/src/misc/nftw.c +++ b/system/lib/libc/musl/src/misc/nftw.c @@ -31,6 +31,8 @@ static int do_nftw(char *path, int (*fn)(const char *, const struct stat *, int, int err; struct FTW lev; + st.st_dev = st.st_ino = 0; + if ((flags & FTW_PHYS) ? lstat(path, &st) : stat(path, &st) < 0) { if (!(flags & FTW_PHYS) && errno==ENOENT && !lstat(path, &st)) type = FTW_SLN; @@ -46,7 +48,7 @@ static int do_nftw(char *path, int (*fn)(const char *, const struct stat *, int, type = FTW_F; } - if ((flags & FTW_MOUNT) && h && st.st_dev != h->dev) + if ((flags & FTW_MOUNT) && h && type != FTW_NS && st.st_dev != h->dev) return 0; new.chain = h; @@ -138,5 +140,3 @@ int nftw(const char *path, int (*fn)(const char *, const struct stat *, int, str pthread_setcancelstate(cs, 0); return r; } - -weak_alias(nftw, nftw64); diff --git a/system/lib/libc/musl/src/misc/setrlimit.c b/system/lib/libc/musl/src/misc/setrlimit.c index 8340aee096413..edb413fa78e47 100644 --- a/system/lib/libc/musl/src/misc/setrlimit.c +++ b/system/lib/libc/musl/src/misc/setrlimit.c @@ -12,12 +12,14 @@ struct ctx { int err; }; +#ifdef SYS_setrlimit static void do_setrlimit(void *p) { struct ctx *c = p; if (c->err>0) return; c->err = -__syscall(SYS_setrlimit, c->res, c->lim); } +#endif int setrlimit(int resource, const struct rlimit *rlim) { @@ -29,6 +31,7 @@ int setrlimit(int resource, const struct rlimit *rlim) rlim = &tmp; } int ret = __syscall(SYS_prlimit64, 0, resource, rlim, 0); +#ifdef SYS_setrlimit if (ret != -ENOSYS) return __syscall_ret(ret); struct ctx c = { @@ -42,6 +45,7 @@ int setrlimit(int resource, const struct rlimit *rlim) return -1; } return 0; +#else + return __syscall_ret(ret); +#endif } - -weak_alias(setrlimit, setrlimit64); diff --git a/system/lib/libc/musl/src/mman/mmap.c b/system/lib/libc/musl/src/mman/mmap.c index e22f3110efe7a..c755ca849eff4 100644 --- a/system/lib/libc/musl/src/mman/mmap.c +++ b/system/lib/libc/musl/src/mman/mmap.c @@ -38,5 +38,3 @@ void *__mmap(void *start, size_t len, int prot, int flags, int fd, off_t off) weak_alias(__mmap, mmap); weak_alias(__mmap, emscripten_builtin_mmap); - -weak_alias(mmap, mmap64); diff --git a/system/lib/libc/musl/src/mq/mq_notify.c b/system/lib/libc/musl/src/mq/mq_notify.c index 221591c73ad50..0e1e6c7ab73bb 100644 --- a/system/lib/libc/musl/src/mq/mq_notify.c +++ b/system/lib/libc/musl/src/mq/mq_notify.c @@ -4,11 +4,14 @@ #include #include #include +#include #include "syscall.h" struct args { - pthread_barrier_t barrier; + sem_t sem; int sock; + mqd_t mqd; + int err; const struct sigevent *sev; }; @@ -20,8 +23,19 @@ static void *start(void *p) int s = args->sock; void (*func)(union sigval) = args->sev->sigev_notify_function; union sigval val = args->sev->sigev_value; + struct sigevent sev2; + static const char zeros[32]; + int err; + + sev2.sigev_notify = SIGEV_THREAD; + sev2.sigev_signo = s; + sev2.sigev_value.sival_ptr = (void *)&zeros; + + args->err = err = -__syscall(SYS_mq_notify, args->mqd, &sev2); + sem_post(&args->sem); + if (err) return 0; - pthread_barrier_wait(&args->barrier); + pthread_detach(pthread_self()); n = recv(s, buf, sizeof(buf), MSG_NOSIGNAL|MSG_WAITALL); close(s); if (n==sizeof buf && buf[sizeof buf - 1] == 1) @@ -35,8 +49,8 @@ int mq_notify(mqd_t mqd, const struct sigevent *sev) pthread_attr_t attr; pthread_t td; int s; - struct sigevent sev2; - static const char zeros[32]; + int cs; + sigset_t allmask, origmask; if (!sev || sev->sigev_notify != SIGEV_THREAD) return syscall(SYS_mq_notify, mqd, sev); @@ -44,30 +58,35 @@ int mq_notify(mqd_t mqd, const struct sigevent *sev) s = socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC, 0); if (s < 0) return -1; args.sock = s; + args.mqd = mqd; if (sev->sigev_notify_attributes) attr = *sev->sigev_notify_attributes; else pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - pthread_barrier_init(&args.barrier, 0, 2); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + sem_init(&args.sem, 0, 0); + sigfillset(&allmask); + pthread_sigmask(SIG_BLOCK, &allmask, &origmask); if (pthread_create(&td, &attr, start, &args)) { __syscall(SYS_close, s); + pthread_sigmask(SIG_SETMASK, &origmask, 0); errno = EAGAIN; return -1; } + pthread_sigmask(SIG_SETMASK, &origmask, 0); - pthread_barrier_wait(&args.barrier); - pthread_barrier_destroy(&args.barrier); - - sev2.sigev_notify = SIGEV_THREAD; - sev2.sigev_signo = s; - sev2.sigev_value.sival_ptr = (void *)&zeros; + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + sem_wait(&args.sem); + sem_destroy(&args.sem); - if (syscall(SYS_mq_notify, mqd, &sev2) < 0) { - pthread_cancel(td); + if (args.err) { __syscall(SYS_close, s); + pthread_join(td, 0); + pthread_setcancelstate(cs, 0); + errno = args.err; return -1; } + pthread_setcancelstate(cs, 0); return 0; } diff --git a/system/lib/libc/musl/src/network/accept4.c b/system/lib/libc/musl/src/network/accept4.c index 59ab1726bdcb3..765a38edc37d8 100644 --- a/system/lib/libc/musl/src/network/accept4.c +++ b/system/lib/libc/musl/src/network/accept4.c @@ -9,6 +9,10 @@ int accept4(int fd, struct sockaddr *restrict addr, socklen_t *restrict len, int if (!flg) return accept(fd, addr, len); int ret = socketcall_cp(accept4, fd, addr, len, flg, 0, 0); if (ret>=0 || (errno != ENOSYS && errno != EINVAL)) return ret; + if (flg & ~(SOCK_CLOEXEC|SOCK_NONBLOCK)) { + errno = EINVAL; + return -1; + } ret = accept(fd, addr, len); if (ret<0) return ret; if (flg & SOCK_CLOEXEC) diff --git a/system/lib/libc/musl/src/network/dns_parse.c b/system/lib/libc/musl/src/network/dns_parse.c index e6ee19d9a6f88..7f83e791abbe3 100644 --- a/system/lib/libc/musl/src/network/dns_parse.c +++ b/system/lib/libc/musl/src/network/dns_parse.c @@ -1,7 +1,7 @@ #include #include "lookup.h" -int __dns_parse(const unsigned char *r, int rlen, int (*callback)(void *, int, const void *, int, const void *), void *ctx) +int __dns_parse(const unsigned char *r, int rlen, int (*callback)(void *, int, const void *, int, const void *, int), void *ctx) { int qdcount, ancount; const unsigned char *p; @@ -15,18 +15,18 @@ int __dns_parse(const unsigned char *r, int rlen, int (*callback)(void *, int, c if (qdcount+ancount > 64) return -1; while (qdcount--) { while (p-r < rlen && *p-1U < 127) p++; - if (*p>193 || (*p==193 && p[1]>254) || p>r+rlen-6) + if (p>r+rlen-6 || *p>193 || (*p==193 && p[1]>254)) return -1; p += 5 + !!*p; } while (ancount--) { while (p-r < rlen && *p-1U < 127) p++; - if (*p>193 || (*p==193 && p[1]>254) || p>r+rlen-6) + if (p>r+rlen-12 || *p>193 || (*p==193 && p[1]>254)) return -1; p += 1 + !!*p; len = p[8]*256 + p[9]; - if (p+len > r+rlen) return -1; - if (callback(ctx, p[1], p+10, len, r) < 0) return -1; + if (len+10 > r+rlen-p) return -1; + if (callback(ctx, p[1], p+10, len, r, rlen) < 0) return -1; p += 10 + len; } return 0; diff --git a/system/lib/libc/musl/src/network/gai_strerror.c b/system/lib/libc/musl/src/network/gai_strerror.c index 9596580e9ffbd..56b7150313409 100644 --- a/system/lib/libc/musl/src/network/gai_strerror.c +++ b/system/lib/libc/musl/src/network/gai_strerror.c @@ -6,7 +6,7 @@ static const char msgs[] = "Name does not resolve\0" "Try again\0" "Non-recoverable error\0" - "Unknown error\0" + "Name has no usable address\0" "Unrecognized address family or invalid length\0" "Unrecognized socket type\0" "Unrecognized service\0" diff --git a/system/lib/libc/musl/src/network/getaddrinfo.c b/system/lib/libc/musl/src/network/getaddrinfo.c index efaab306828e8..64ad259acae87 100644 --- a/system/lib/libc/musl/src/network/getaddrinfo.c +++ b/system/lib/libc/musl/src/network/getaddrinfo.c @@ -16,6 +16,7 @@ int getaddrinfo(const char *restrict host, const char *restrict serv, const stru char canon[256], *outcanon; int nservs, naddrs, nais, canon_len, i, j, k; int family = AF_UNSPEC, flags = 0, proto = 0, socktype = 0; + int no_family = 0; struct aibuf *out; if (!host && !serv) return EAI_NONAME; @@ -66,9 +67,11 @@ int getaddrinfo(const char *restrict host, const char *restrict serv, const stru pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, &cs); int r = connect(s, ta[i], tl[i]); + int saved_errno = errno; pthread_setcancelstate(cs, 0); close(s); if (!r) continue; + errno = saved_errno; } switch (errno) { case EADDRNOTAVAIL: @@ -80,7 +83,7 @@ int getaddrinfo(const char *restrict host, const char *restrict serv, const stru default: return EAI_SYSTEM; } - if (family == tf[i]) return EAI_NONAME; + if (family == tf[i]) no_family = 1; family = tf[1-i]; } } @@ -91,6 +94,8 @@ int getaddrinfo(const char *restrict host, const char *restrict serv, const stru naddrs = __lookup_name(addrs, canon, host, family, flags); if (naddrs < 0) return naddrs; + if (no_family) return EAI_NODATA; + nais = nservs * naddrs; canon_len = strlen(canon); out = calloc(1, nais * sizeof(*out) + canon_len + 1); diff --git a/system/lib/libc/musl/src/network/gethostbyaddr.c b/system/lib/libc/musl/src/network/gethostbyaddr.c index 598e2241a9f80..c3cacaac1466f 100644 --- a/system/lib/libc/musl/src/network/gethostbyaddr.c +++ b/system/lib/libc/musl/src/network/gethostbyaddr.c @@ -20,5 +20,5 @@ struct hostent *gethostbyaddr(const void *a, socklen_t l, int af) err = gethostbyaddr_r(a, l, af, h, (void *)(h+1), size-sizeof *h, &res, &h_errno); } while (err == ERANGE); - return err ? 0 : h; + return res; } diff --git a/system/lib/libc/musl/src/network/gethostbyaddr_r.c b/system/lib/libc/musl/src/network/gethostbyaddr_r.c index 0f1e61aa0c358..ceaf3935cf78b 100644 --- a/system/lib/libc/musl/src/network/gethostbyaddr_r.c +++ b/system/lib/libc/musl/src/network/gethostbyaddr_r.c @@ -54,9 +54,10 @@ int gethostbyaddr_r(const void *a, socklen_t l, int af, case EAI_OVERFLOW: return ERANGE; default: - case EAI_MEMORY: - case EAI_SYSTEM: case EAI_FAIL: + *err = NO_RECOVERY; + return EBADMSG; + case EAI_SYSTEM: *err = NO_RECOVERY; return errno; case 0: diff --git a/system/lib/libc/musl/src/network/gethostbyname2.c b/system/lib/libc/musl/src/network/gethostbyname2.c index dc9d6621be565..bd0da7f806a04 100644 --- a/system/lib/libc/musl/src/network/gethostbyname2.c +++ b/system/lib/libc/musl/src/network/gethostbyname2.c @@ -21,5 +21,5 @@ struct hostent *gethostbyname2(const char *name, int af) err = gethostbyname2_r(name, af, h, (void *)(h+1), size-sizeof *h, &res, &h_errno); } while (err == ERANGE); - return err ? 0 : h; + return res; } diff --git a/system/lib/libc/musl/src/network/gethostbyname2_r.c b/system/lib/libc/musl/src/network/gethostbyname2_r.c index fc8948776d35f..a5eb67fe6dbe3 100644 --- a/system/lib/libc/musl/src/network/gethostbyname2_r.c +++ b/system/lib/libc/musl/src/network/gethostbyname2_r.c @@ -22,7 +22,10 @@ int gethostbyname2_r(const char *name, int af, if (cnt<0) switch (cnt) { case EAI_NONAME: *err = HOST_NOT_FOUND; - return ENOENT; + return 0; + case EAI_NODATA: + *err = NO_DATA; + return 0; case EAI_AGAIN: *err = TRY_AGAIN; return EAGAIN; @@ -30,7 +33,6 @@ int gethostbyname2_r(const char *name, int af, case EAI_FAIL: *err = NO_RECOVERY; return EBADMSG; - case EAI_MEMORY: case EAI_SYSTEM: *err = NO_RECOVERY; return errno; diff --git a/system/lib/libc/musl/src/network/getifaddrs.c b/system/lib/libc/musl/src/network/getifaddrs.c index fed75bd8d9293..74df4d6c6a211 100644 --- a/system/lib/libc/musl/src/network/getifaddrs.c +++ b/system/lib/libc/musl/src/network/getifaddrs.c @@ -39,8 +39,8 @@ struct ifaddrs_storage { }; struct ifaddrs_ctx { - struct ifaddrs_storage *first; - struct ifaddrs_storage *last; + struct ifaddrs *first; + struct ifaddrs *last; struct ifaddrs_storage *hash[IFADDRS_HASH_SIZE]; }; @@ -195,9 +195,9 @@ static int netlink_msg_to_ifaddr(void *pctx, struct nlmsghdr *h) } if (ifs->ifa.ifa_name) { - if (!ctx->first) ctx->first = ifs; - if (ctx->last) ctx->last->ifa.ifa_next = &ifs->ifa; - ctx->last = ifs; + if (!ctx->first) ctx->first = &ifs->ifa; + if (ctx->last) ctx->last->ifa_next = &ifs->ifa; + ctx->last = &ifs->ifa; } else { free(ifs); } @@ -210,7 +210,7 @@ int getifaddrs(struct ifaddrs **ifap) int r; memset(ctx, 0, sizeof *ctx); r = __rtnetlink_enumerate(AF_UNSPEC, AF_UNSPEC, netlink_msg_to_ifaddr, ctx); - if (r == 0) *ifap = &ctx->first->ifa; - else freeifaddrs(&ctx->first->ifa); + if (r == 0) *ifap = ctx->first; + else freeifaddrs(ctx->first); return r; } diff --git a/system/lib/libc/musl/src/network/getnameinfo.c b/system/lib/libc/musl/src/network/getnameinfo.c index 949e18115a7b4..7abe0fa9b9eb4 100644 --- a/system/lib/libc/musl/src/network/getnameinfo.c +++ b/system/lib/libc/musl/src/network/getnameinfo.c @@ -58,6 +58,7 @@ static void reverse_hosts(char *buf, const unsigned char *a, unsigned scopeid, i if ((p=strchr(line, '#'))) *p++='\n', *p=0; for (p=line; *p && !isspace(*p); p++); + if (!*p) continue; *p++ = 0; if (__lookup_ipliteral(&iplit, line, AF_UNSPEC)<=0) continue; @@ -108,10 +109,10 @@ static void reverse_services(char *buf, int port, int dgram) __fclose_ca(f); } -static int dns_parse_callback(void *c, int rr, const void *data, int len, const void *packet) +static int dns_parse_callback(void *c, int rr, const void *data, int len, const void *packet, int plen) { if (rr != RR_PTR) return 0; - if (__dn_expand(packet, (const unsigned char *)packet + 512, + if (__dn_expand(packet, (const unsigned char *)packet + plen, data, c, 256) <= 0) *(char *)c = 0; return 0; diff --git a/system/lib/libc/musl/src/network/getservbyport_r.c b/system/lib/libc/musl/src/network/getservbyport_r.c index b7f21c6b398a5..e4cc3079c1d19 100644 --- a/system/lib/libc/musl/src/network/getservbyport_r.c +++ b/system/lib/libc/musl/src/network/getservbyport_r.c @@ -26,7 +26,7 @@ int getservbyport_r(int port, const char *prots, /* Align buffer */ i = (uintptr_t)buf & sizeof(char *)-1; if (!i) i = sizeof(char *); - if (buflen < 3*sizeof(char *)-i) + if (buflen <= 3*sizeof(char *)-i) return ERANGE; buf += sizeof(char *)-i; buflen -= sizeof(char *)-i; @@ -46,6 +46,8 @@ int getservbyport_r(int port, const char *prots, case EAI_MEMORY: case EAI_SYSTEM: return ENOMEM; + case EAI_OVERFLOW: + return ERANGE; default: return ENOENT; case 0: diff --git a/system/lib/libc/musl/src/network/inet_pton.c b/system/lib/libc/musl/src/network/inet_pton.c index d36c368917da5..bcbdd9ef29fbe 100644 --- a/system/lib/libc/musl/src/network/inet_pton.c +++ b/system/lib/libc/musl/src/network/inet_pton.c @@ -54,6 +54,7 @@ int inet_pton(int af, const char *restrict s, void *restrict a0) if (s[j]!='.' || (i<6 && brk<0)) return 0; need_v4=1; i++; + ip[i&7]=0; break; } s += j+1; diff --git a/system/lib/libc/musl/src/network/lookup.h b/system/lib/libc/musl/src/network/lookup.h index ef6627256756a..54b2f8b5bff1b 100644 --- a/system/lib/libc/musl/src/network/lookup.h +++ b/system/lib/libc/musl/src/network/lookup.h @@ -50,6 +50,6 @@ hidden int __lookup_ipliteral(struct address buf[static 1], const char *name, in hidden int __get_resolv_conf(struct resolvconf *, char *, size_t); hidden int __res_msend_rc(int, const unsigned char *const *, const int *, unsigned char *const *, int *, int, const struct resolvconf *); -hidden int __dns_parse(const unsigned char *, int, int (*)(void *, int, const void *, int, const void *), void *); +hidden int __dns_parse(const unsigned char *, int, int (*)(void *, int, const void *, int, const void *, int), void *); #endif diff --git a/system/lib/libc/musl/src/network/lookup_ipliteral.c b/system/lib/libc/musl/src/network/lookup_ipliteral.c index 2fddab7373253..1e76620656b26 100644 --- a/system/lib/libc/musl/src/network/lookup_ipliteral.c +++ b/system/lib/libc/musl/src/network/lookup_ipliteral.c @@ -15,7 +15,7 @@ int __lookup_ipliteral(struct address buf[static 1], const char *name, int famil struct in6_addr a6; if (__inet_aton(name, &a4) > 0) { if (family == AF_INET6) /* wrong family */ - return EAI_NONAME; + return EAI_NODATA; memcpy(&buf[0].addr, &a4, sizeof a4); buf[0].family = AF_INET; buf[0].scopeid = 0; @@ -34,7 +34,7 @@ int __lookup_ipliteral(struct address buf[static 1], const char *name, int famil if (inet_pton(AF_INET6, name, &a6) <= 0) return 0; if (family == AF_INET) /* wrong family */ - return EAI_NONAME; + return EAI_NODATA; memcpy(&buf[0].addr, &a6, sizeof a6); buf[0].family = AF_INET6; diff --git a/system/lib/libc/musl/src/network/lookup_name.c b/system/lib/libc/musl/src/network/lookup_name.c index aa558c197abe8..4281482efb253 100644 --- a/system/lib/libc/musl/src/network/lookup_name.c +++ b/system/lib/libc/musl/src/network/lookup_name.c @@ -79,7 +79,7 @@ static int name_from_hosts(struct address buf[static MAXADDRS], char canon[stati case 0: continue; default: - badfam = EAI_NONAME; + badfam = EAI_NODATA; break; } @@ -102,45 +102,50 @@ struct dpc_ctx { struct address *addrs; char *canon; int cnt; + int rrtype; }; #define RR_A 1 #define RR_CNAME 5 #define RR_AAAA 28 -static int dns_parse_callback(void *c, int rr, const void *data, int len, const void *packet) +#define ABUF_SIZE 768 + +static int dns_parse_callback(void *c, int rr, const void *data, int len, const void *packet, int plen) { char tmp[256]; + int family; struct dpc_ctx *ctx = c; - if (ctx->cnt >= MAXADDRS) return -1; + if (rr == RR_CNAME) { + if (__dn_expand(packet, (const unsigned char *)packet + plen, + data, tmp, sizeof tmp) > 0 && is_valid_hostname(tmp)) + strcpy(ctx->canon, tmp); + return 0; + } + if (ctx->cnt >= MAXADDRS) return 0; + if (rr != ctx->rrtype) return 0; switch (rr) { case RR_A: if (len != 4) return -1; - ctx->addrs[ctx->cnt].family = AF_INET; - ctx->addrs[ctx->cnt].scopeid = 0; - memcpy(ctx->addrs[ctx->cnt++].addr, data, 4); + family = AF_INET; break; case RR_AAAA: if (len != 16) return -1; - ctx->addrs[ctx->cnt].family = AF_INET6; - ctx->addrs[ctx->cnt].scopeid = 0; - memcpy(ctx->addrs[ctx->cnt++].addr, data, 16); - break; - case RR_CNAME: - if (__dn_expand(packet, (const unsigned char *)packet + 512, - data, tmp, sizeof tmp) > 0 && is_valid_hostname(tmp)) - strcpy(ctx->canon, tmp); + family = AF_INET6; break; } + ctx->addrs[ctx->cnt].family = family; + ctx->addrs[ctx->cnt].scopeid = 0; + memcpy(ctx->addrs[ctx->cnt++].addr, data, len); return 0; } static int name_from_dns(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family, const struct resolvconf *conf) { - unsigned char qbuf[2][280], abuf[2][512]; + unsigned char qbuf[2][280], abuf[2][ABUF_SIZE]; const unsigned char *qp[2] = { qbuf[0], qbuf[1] }; unsigned char *ap[2] = { abuf[0], abuf[1] }; - int qlens[2], alens[2]; + int qlens[2], alens[2], qtypes[2]; int i, nq = 0; struct dpc_ctx ctx = { .addrs = buf, .canon = canon }; static const struct { int af; int rr; } afrr[2] = { @@ -153,8 +158,12 @@ static int name_from_dns(struct address buf[static MAXADDRS], char canon[static qlens[nq] = __res_mkquery(0, name, 1, afrr[i].rr, 0, 0, 0, qbuf[nq], sizeof *qbuf); if (qlens[nq] == -1) - return EAI_NONAME; + return 0; + qtypes[nq] = afrr[i].rr; qbuf[nq][3] = 0; /* don't need AD flag */ + /* Ensure query IDs are distinct. */ + if (nq && qbuf[nq][0] == qbuf[0][0]) + qbuf[nq][0]++; nq++; } } @@ -168,11 +177,14 @@ static int name_from_dns(struct address buf[static MAXADDRS], char canon[static if ((abuf[i][3] & 15) != 0) return EAI_FAIL; } - for (i=0; i=0; i--) { + ctx.rrtype = qtypes[i]; + if (alens[i] > sizeof(abuf[i])) alens[i] = sizeof abuf[i]; __dns_parse(abuf[i], alens[i], dns_parse_callback, &ctx); + } if (ctx.cnt) return ctx.cnt; - return EAI_NONAME; + return EAI_NODATA; } static int name_from_dns_search(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family) diff --git a/system/lib/libc/musl/src/network/netlink.h b/system/lib/libc/musl/src/network/netlink.h index 38acb178928d3..873fabe2b8035 100644 --- a/system/lib/libc/musl/src/network/netlink.h +++ b/system/lib/libc/musl/src/network/netlink.h @@ -86,7 +86,7 @@ struct ifaddrmsg { #define RTA_DATALEN(rta) ((rta)->rta_len-sizeof(struct rtattr)) #define RTA_DATAEND(rta) ((char*)(rta)+(rta)->rta_len) #define RTA_NEXT(rta) (struct rtattr*)((char*)(rta)+NETLINK_ALIGN((rta)->rta_len)) -#define RTA_OK(nlh,end) ((char*)(end)-(char*)(rta) >= sizeof(struct rtattr)) +#define RTA_OK(rta,end) ((char*)(end)-(char*)(rta) >= sizeof(struct rtattr)) #define NLMSG_RTA(nlh,len) ((void*)((char*)(nlh)+sizeof(struct nlmsghdr)+NETLINK_ALIGN(len))) #define NLMSG_RTAOK(rta,nlh) RTA_OK(rta,NLMSG_DATAEND(nlh)) diff --git a/system/lib/libc/musl/src/network/res_mkquery.c b/system/lib/libc/musl/src/network/res_mkquery.c index 33f50cb9339ac..614bf7864b489 100644 --- a/system/lib/libc/musl/src/network/res_mkquery.c +++ b/system/lib/libc/musl/src/network/res_mkquery.c @@ -13,6 +13,7 @@ int __res_mkquery(int op, const char *dname, int class, int type, int n; if (l && dname[l-1]=='.') l--; + if (l && dname[l-1]=='.') return -1; n = 17+l+!!l; if (l>253 || buflen15u || class>255u || type>255u) return -1; diff --git a/system/lib/libc/musl/src/network/res_msend.c b/system/lib/libc/musl/src/network/res_msend.c index ab11fc270408c..109942806c29e 100644 --- a/system/lib/libc/musl/src/network/res_msend.c +++ b/system/lib/libc/musl/src/network/res_msend.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -16,21 +17,69 @@ static void cleanup(void *p) { + struct pollfd *pfd = p; + for (int i=0; pfd[i].fd >= -1; i++) #ifdef __EMSCRIPTEN__ - __wasi_fd_close((intptr_t)p); + if (pfd[i].fd >= 0) __wasi_fd_close((intptr_t)pfd[i].fd); #else - __syscall(SYS_close, (intptr_t)p); + if (pfd[i].fd >= 0) __syscall(SYS_close, pfd[i].fd); #endif } static unsigned long mtime() { struct timespec ts; - clock_gettime(CLOCK_REALTIME, &ts); + if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0 && errno == ENOSYS) + clock_gettime(CLOCK_REALTIME, &ts); return (unsigned long)ts.tv_sec * 1000 + ts.tv_nsec / 1000000; } +static int start_tcp(struct pollfd *pfd, int family, const void *sa, socklen_t sl, const unsigned char *q, int ql) +{ + struct msghdr mh = { + .msg_name = (void *)sa, + .msg_namelen = sl, + .msg_iovlen = 2, + .msg_iov = (struct iovec [2]){ + { .iov_base = (uint8_t[]){ ql>>8, ql }, .iov_len = 2 }, + { .iov_base = (void *)q, .iov_len = ql } } + }; + int r; + int fd = socket(family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + pfd->fd = fd; + pfd->events = POLLOUT; + if (!setsockopt(fd, IPPROTO_TCP, TCP_FASTOPEN_CONNECT, + &(int){1}, sizeof(int))) { + r = sendmsg(fd, &mh, MSG_FASTOPEN|MSG_NOSIGNAL); + if (r == ql+2) pfd->events = POLLIN; + if (r >= 0) return r; + if (errno == EINPROGRESS) return 0; + } + r = connect(fd, sa, sl); + if (!r || errno == EINPROGRESS) return 0; + close(fd); + pfd->fd = -1; + return -1; +} + +static void step_mh(struct msghdr *mh, size_t n) +{ + /* Adjust iovec in msghdr to skip first n bytes. */ + while (mh->msg_iovlen && n >= mh->msg_iov->iov_len) { + n -= mh->msg_iov->iov_len; + mh->msg_iov++; + mh->msg_iovlen--; + } + if (!mh->msg_iovlen) return; + mh->msg_iov->iov_base = (char *)mh->msg_iov->iov_base + n; + mh->msg_iov->iov_len -= n; +} + +/* Internal contract for __res_msend[_rc]: asize must be >=512, nqueries + * must be sufficiently small to be safe as VLA size. In practice it's + * either 1 or 2, anyway. */ + int __res_msend_rc(int nqueries, const unsigned char *const *queries, const int *qlens, unsigned char *const *answers, int *alens, int asize, const struct resolvconf *conf) @@ -48,7 +97,10 @@ int __res_msend_rc(int nqueries, const unsigned char *const *queries, int next; int i, j; int cs; - struct pollfd pfd; + struct pollfd pfd[nqueries+2]; + int qpos[nqueries], apos[nqueries]; + unsigned char alen_buf[nqueries][2]; + int r; unsigned long t0, t1, t2; pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); @@ -72,29 +124,22 @@ int __res_msend_rc(int nqueries, const unsigned char *const *queries, } /* Get local address and open/bind a socket */ - sa.sin.sin_family = family; fd = socket(family, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); /* Handle case where system lacks IPv6 support */ if (fd < 0 && family == AF_INET6 && errno == EAFNOSUPPORT) { + for (i=0; ins[nns].family == AF_INET6; i++); + if (i==nns) { + pthread_setcancelstate(cs, 0); + return -1; + } fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); family = AF_INET; + sl = sizeof sa.sin; } - if (fd < 0 || bind(fd, (void *)&sa, sl) < 0) { - if (fd >= 0) close(fd); - pthread_setcancelstate(cs, 0); - return -1; - } - - /* Past this point, there are no errors. Each individual query will - * yield either no reply (indicated by zero length) or an answer - * packet which is up to the caller to interpret. */ - - pthread_cleanup_push(cleanup, (void *)(intptr_t)fd); - pthread_setcancelstate(cs, 0); /* Convert any IPv4 addresses in a mixed environment to v4-mapped */ - if (family == AF_INET6) { + if (fd >= 0 && family == AF_INET6) { setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &(int){0}, sizeof 0); for (i=0; i= 0) close(fd); + pthread_setcancelstate(cs, 0); + return -1; + } + + /* Past this point, there are no errors. Each individual query will + * yield either no reply (indicated by zero length) or an answer + * packet which is up to the caller to interpret. */ + + for (i=0; i0; i++); + if (i==nqueries) break; + if (t2-t1 >= retry_interval) { /* Query all configured namservers in parallel */ for (i=0; i= 0) { + while (next < nqueries) { + struct msghdr mh = { + .msg_name = (void *)&sa, + .msg_namelen = sl, + .msg_iovlen = 1, + .msg_iov = (struct iovec []){ + { .iov_base = (void *)answers[next], + .iov_len = asize } + } + }; + rlen = recvmsg(fd, &mh, 0); + if (rlen < 0) break; /* Ignore non-identifiable packets */ if (rlen < 4) continue; @@ -174,12 +251,76 @@ int __res_msend_rc(int nqueries, const unsigned char *const *queries, else memcpy(answers[i], answers[next], rlen); - if (next == nqueries) goto out; + /* Ignore further UDP if all slots full or TCP-mode */ + if (next == nqueries) pfd[nqueries].events = 0; + + /* If answer is truncated (TC bit), fallback to TCP */ + if ((answers[i][2] & 2) || (mh.msg_flags & MSG_TRUNC)) { + alens[i] = -1; + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0); + r = start_tcp(pfd+i, family, ns+j, sl, queries[i], qlens[i]); + pthread_setcancelstate(cs, 0); + if (r >= 0) { + qpos[i] = r; + apos[i] = 0; + } + continue; + } + } + + for (i=0; i>8, qlens[i] }, .iov_len = 2 }, + { .iov_base = (void *)queries[i], .iov_len = qlens[i] } } + }; + step_mh(&mh, qpos[i]); + r = sendmsg(pfd[i].fd, &mh, MSG_NOSIGNAL); + if (r < 0) goto out; + qpos[i] += r; + if (qpos[i] == qlens[i]+2) + pfd[i].events = POLLIN; + } + + for (i=0; i +#include int __res_send(const unsigned char *msg, int msglen, unsigned char *answer, int anslen) { - int r = __res_msend(1, &msg, &msglen, &answer, &anslen, anslen); + int r; + if (anslen < 512) { + unsigned char buf[512]; + r = __res_send(msg, msglen, buf, sizeof buf); + if (r >= 0) memcpy(answer, buf, r < anslen ? r : anslen); + return r; + } + r = __res_msend(1, &msg, &msglen, &answer, &anslen, anslen); return r<0 || !anslen ? -1 : anslen; } diff --git a/system/lib/libc/musl/src/network/sendmsg.c b/system/lib/libc/musl/src/network/sendmsg.c index 1cfc5af5161c2..fbdc00e07377f 100644 --- a/system/lib/libc/musl/src/network/sendmsg.c +++ b/system/lib/libc/musl/src/network/sendmsg.c @@ -8,13 +8,16 @@ ssize_t sendmsg(int fd, const struct msghdr *msg, int flags) { #if LONG_MAX > INT_MAX && !defined(__EMSCRIPTEN__) struct msghdr h; - struct cmsghdr chbuf[1024/sizeof(struct cmsghdr)+1], *c; + /* Kernels before 2.6.38 set SCM_MAX_FD to 255, allocate enough + * space to support an SCM_RIGHTS ancillary message with 255 fds. + * Kernels since 2.6.38 set SCM_MAX_FD to 253. */ + struct cmsghdr chbuf[CMSG_SPACE(255*sizeof(int))/sizeof(struct cmsghdr)+1], *c; if (msg) { h = *msg; h.__pad1 = h.__pad2 = 0; msg = &h; if (h.msg_controllen) { - if (h.msg_controllen > 1024) { + if (h.msg_controllen > sizeof chbuf) { errno = ENOMEM; return -1; } diff --git a/system/lib/libc/musl/src/process/_Fork.c b/system/lib/libc/musl/src/process/_Fork.c index da063868150bc..fb0fdc2c830cd 100644 --- a/system/lib/libc/musl/src/process/_Fork.c +++ b/system/lib/libc/musl/src/process/_Fork.c @@ -14,7 +14,6 @@ pid_t _Fork(void) pid_t ret; sigset_t set; __block_all_sigs(&set); - __aio_atfork(-1); LOCK(__abort_lock); #ifdef SYS_fork ret = __syscall(SYS_fork); @@ -32,7 +31,7 @@ pid_t _Fork(void) if (libc.need_locks) libc.need_locks = -1; } UNLOCK(__abort_lock); - __aio_atfork(!ret); + if (!ret) __aio_atfork(1); __restore_sigs(&set); return __syscall_ret(ret); } diff --git a/system/lib/libc/musl/src/process/fork.c b/system/lib/libc/musl/src/process/fork.c index 54bc289202955..56f1931331f9b 100644 --- a/system/lib/libc/musl/src/process/fork.c +++ b/system/lib/libc/musl/src/process/fork.c @@ -9,7 +9,6 @@ static volatile int *const dummy_lockptr = 0; weak_alias(dummy_lockptr, __at_quick_exit_lockptr); weak_alias(dummy_lockptr, __atexit_lockptr); -weak_alias(dummy_lockptr, __dlerror_lockptr); weak_alias(dummy_lockptr, __gettext_lockptr); weak_alias(dummy_lockptr, __locale_lockptr); weak_alias(dummy_lockptr, __random_lockptr); @@ -24,7 +23,6 @@ weak_alias(dummy_lockptr, __vmlock_lockptr); static volatile int *const *const atfork_locks[] = { &__at_quick_exit_lockptr, &__atexit_lockptr, - &__dlerror_lockptr, &__gettext_lockptr, &__locale_lockptr, &__random_lockptr, @@ -38,6 +36,8 @@ static volatile int *const *const atfork_locks[] = { static void dummy(int x) { } weak_alias(dummy, __fork_handler); weak_alias(dummy, __malloc_atfork); +weak_alias(dummy, __aio_atfork); +weak_alias(dummy, __pthread_key_atfork); weak_alias(dummy, __ldso_atfork); static void dummy_0(void) { } @@ -52,6 +52,8 @@ pid_t fork(void) int need_locks = libc.need_locks > 0; if (need_locks) { __ldso_atfork(-1); + __pthread_key_atfork(-1); + __aio_atfork(-1); __inhibit_ptc(); for (int i=0; igl_pathc = 0; g->gl_pathv = NULL; } - -weak_alias(glob, glob64); -weak_alias(globfree, globfree64); diff --git a/system/lib/libc/musl/src/search/hsearch.c b/system/lib/libc/musl/src/search/hsearch.c index b3ac8796e70fd..2634a67f42f93 100644 --- a/system/lib/libc/musl/src/search/hsearch.c +++ b/system/lib/libc/musl/src/search/hsearch.c @@ -41,9 +41,9 @@ static int resize(size_t nel, struct hsearch_data *htab) { size_t newsize; size_t i, j; + size_t oldsize = htab->__tab->mask + 1; ENTRY *e, *newe; ENTRY *oldtab = htab->__tab->entries; - ENTRY *oldend = htab->__tab->entries + htab->__tab->mask + 1; if (nel > MAXSIZE) nel = MAXSIZE; @@ -56,7 +56,7 @@ static int resize(size_t nel, struct hsearch_data *htab) htab->__tab->mask = newsize - 1; if (!oldtab) return 1; - for (e = oldtab; e < oldend; e++) + for (e = oldtab; e < oldtab + oldsize; e++) if (e->key) { for (i=keyhash(e->key),j=1; ; i+=j++) { newe = htab->__tab->entries + (i & htab->__tab->mask); diff --git a/system/lib/libc/musl/src/select/poll.c b/system/lib/libc/musl/src/select/poll.c index c84c8a999ccca..7883dfab478a2 100644 --- a/system/lib/libc/musl/src/select/poll.c +++ b/system/lib/libc/musl/src/select/poll.c @@ -8,8 +8,13 @@ int poll(struct pollfd *fds, nfds_t n, int timeout) #ifdef SYS_poll return syscall_cp(SYS_poll, fds, n, timeout); #else +#if SYS_ppoll_time64 == SYS_ppoll + typedef long long ppoll_ts_t[2]; +#else + typedef long ppoll_ts_t[2]; +#endif return syscall_cp(SYS_ppoll, fds, n, timeout>=0 ? - &((struct timespec){ .tv_sec = timeout/1000, - .tv_nsec = timeout%1000*1000000 }) : 0, 0, _NSIG/8); + ((ppoll_ts_t){ timeout/1000, timeout%1000*1000000 }) : 0, + 0, _NSIG/8); #endif } diff --git a/system/lib/libc/musl/src/select/select.c b/system/lib/libc/musl/src/select/select.c index 8a78688403047..f1d72863c6759 100644 --- a/system/lib/libc/musl/src/select/select.c +++ b/system/lib/libc/musl/src/select/select.c @@ -33,6 +33,7 @@ int select(int n, fd_set *restrict rfds, fd_set *restrict wfds, fd_set *restrict ((syscall_arg_t[]){ 0, _NSIG/8 })); if (SYS_pselect6 == SYS_pselect6_time64 || r!=-ENOSYS) return __syscall_ret(r); + s = CLAMP(s); #endif #ifdef SYS_select return syscall_cp(SYS_select, n, rfds, wfds, efds, diff --git a/system/lib/libc/musl/src/signal/sigaction.c b/system/lib/libc/musl/src/signal/sigaction.c index 2203471b243d9..e45308fae5fbf 100644 --- a/system/lib/libc/musl/src/signal/sigaction.c +++ b/system/lib/libc/musl/src/signal/sigaction.c @@ -44,8 +44,11 @@ int __libc_sigaction(int sig, const struct sigaction *restrict sa, struct sigact } } ksa.handler = sa->sa_handler; - ksa.flags = sa->sa_flags | SA_RESTORER; + ksa.flags = sa->sa_flags; +#ifdef SA_RESTORER + ksa.flags |= SA_RESTORER; ksa.restorer = (sa->sa_flags & SA_SIGINFO) ? __restore_rt : __restore; +#endif memcpy(&ksa.mask, &sa->sa_mask, _NSIG/8); } int r = __syscall(SYS_rt_sigaction, sig, sa?&ksa:0, old?&ksa_old:0, _NSIG/8); diff --git a/system/lib/libc/musl/src/stat/__xstat.c b/system/lib/libc/musl/src/stat/__xstat.c index 630936a0faf3f..b4560df7cdd70 100644 --- a/system/lib/libc/musl/src/stat/__xstat.c +++ b/system/lib/libc/musl/src/stat/__xstat.c @@ -22,11 +22,6 @@ int __xstat(int ver, const char *path, struct stat *buf) return stat(path, buf); } -weak_alias(__fxstat, __fxstat64); -weak_alias(__fxstatat, __fxstatat64); -weak_alias(__lxstat, __lxstat64); -weak_alias(__xstat, __xstat64); - #endif int __xmknod(int ver, const char *path, mode_t mode, dev_t *dev) diff --git a/system/lib/libc/musl/src/stat/fchmodat.c b/system/lib/libc/musl/src/stat/fchmodat.c index 934c5355fbd45..76c6ca20004f6 100644 --- a/system/lib/libc/musl/src/stat/fchmodat.c +++ b/system/lib/libc/musl/src/stat/fchmodat.c @@ -2,7 +2,6 @@ #include #include #include "syscall.h" -#include "kstat.h" int fchmodat(int fd, const char *path, mode_t mode, int flag) { @@ -11,12 +10,12 @@ int fchmodat(int fd, const char *path, mode_t mode, int flag) if (flag != AT_SYMLINK_NOFOLLOW) return __syscall_ret(-EINVAL); - struct kstat st; + struct stat st; int ret, fd2; char proc[15+3*sizeof(int)]; - if ((ret = __syscall(SYS_fstatat, fd, path, &st, flag))) - return __syscall_ret(ret); + if (fstatat(fd, path, &st, flag)) + return -1; if (S_ISLNK(st.st_mode)) return __syscall_ret(-EOPNOTSUPP); @@ -27,10 +26,10 @@ int fchmodat(int fd, const char *path, mode_t mode, int flag) } __procfdname(proc, fd2); - ret = __syscall(SYS_fstatat, AT_FDCWD, proc, &st, 0); + ret = stat(proc, &st); if (!ret) { - if (S_ISLNK(st.st_mode)) ret = -EOPNOTSUPP; - else ret = __syscall(SYS_fchmodat, AT_FDCWD, proc, mode); + if (S_ISLNK(st.st_mode)) ret = __syscall_ret(-EOPNOTSUPP); + else ret = syscall(SYS_fchmodat, AT_FDCWD, proc, mode); } #ifdef __EMSCRIPTEN__ @@ -38,5 +37,5 @@ int fchmodat(int fd, const char *path, mode_t mode, int flag) #else __syscall(SYS_close, fd2); #endif - return __syscall_ret(ret); + return ret; } diff --git a/system/lib/libc/musl/src/stat/fstat.c b/system/lib/libc/musl/src/stat/fstat.c index 9bbb46decb035..fd28b8ac405a5 100644 --- a/system/lib/libc/musl/src/stat/fstat.c +++ b/system/lib/libc/musl/src/stat/fstat.c @@ -4,12 +4,10 @@ #include #include "syscall.h" -int fstat(int fd, struct stat *st) +int __fstat(int fd, struct stat *st) { if (fd<0) return __syscall_ret(-EBADF); - return fstatat(fd, "", st, AT_EMPTY_PATH); + return __fstatat(fd, "", st, AT_EMPTY_PATH); } -#if !_REDIR_TIME64 -weak_alias(fstat, fstat64); -#endif +weak_alias(__fstat, fstat); diff --git a/system/lib/libc/musl/src/stat/fstatat.c b/system/lib/libc/musl/src/stat/fstatat.c index 8da7d68e18d15..59e451012af3b 100644 --- a/system/lib/libc/musl/src/stat/fstatat.c +++ b/system/lib/libc/musl/src/stat/fstatat.c @@ -6,7 +6,6 @@ #include #include #include "syscall.h" -#include "kstat.h" /* XXX Emscripten: We #define kstat to stat so we can simply make the syscall * without the extra copy. @@ -74,6 +73,10 @@ static int fstatat_statx(int fd, const char *restrict path, struct stat *restric return 0; } +#ifdef SYS_fstatat + +#include "kstat.h" + static int fstatat_kstat(int fd, const char *restrict path, struct stat *restrict st, int flag) { int ret; @@ -136,8 +139,9 @@ static int fstatat_kstat(int fd, const char *restrict path, struct stat *restric return 0; } #endif +#endif -int fstatat(int fd, const char *restrict path, struct stat *restrict st, int flag) +int __fstatat(int fd, const char *restrict path, struct stat *restrict st, int flag) { int ret; #ifdef __EMSCRIPTEN__ @@ -151,15 +155,17 @@ int fstatat(int fd, const char *restrict path, struct stat *restrict st, int fla else ret = __syscall(SYS_fstatat, fd, path, st, flag); #else +#ifdef SYS_fstatat if (sizeof((struct kstat){0}.st_atime_sec) < sizeof(time_t)) { ret = fstatat_statx(fd, path, st, flag); if (ret!=-ENOSYS) return __syscall_ret(ret); } ret = fstatat_kstat(fd, path, st, flag); +#else + ret = fstatat_statx(fd, path, st, flag); +#endif #endif return __syscall_ret(ret); } -#if !_REDIR_TIME64 -weak_alias(fstatat, fstatat64); -#endif +weak_alias(__fstatat, fstatat); diff --git a/system/lib/libc/musl/src/stat/lstat.c b/system/lib/libc/musl/src/stat/lstat.c index 6fe004dec28c4..6822fcae4b1ed 100644 --- a/system/lib/libc/musl/src/stat/lstat.c +++ b/system/lib/libc/musl/src/stat/lstat.c @@ -5,7 +5,3 @@ int lstat(const char *restrict path, struct stat *restrict buf) { return fstatat(AT_FDCWD, path, buf, AT_SYMLINK_NOFOLLOW); } - -#if !_REDIR_TIME64 -weak_alias(lstat, lstat64); -#endif diff --git a/system/lib/libc/musl/src/stat/stat.c b/system/lib/libc/musl/src/stat/stat.c index ea70efc4a0a4e..23570e7a2460a 100644 --- a/system/lib/libc/musl/src/stat/stat.c +++ b/system/lib/libc/musl/src/stat/stat.c @@ -5,7 +5,3 @@ int stat(const char *restrict path, struct stat *restrict buf) { return fstatat(AT_FDCWD, path, buf, 0); } - -#if !_REDIR_TIME64 -weak_alias(stat, stat64); -#endif diff --git a/system/lib/libc/musl/src/stat/statvfs.c b/system/lib/libc/musl/src/stat/statvfs.c index f65d1b548d41e..bfbb5feed5255 100644 --- a/system/lib/libc/musl/src/stat/statvfs.c +++ b/system/lib/libc/musl/src/stat/statvfs.c @@ -56,8 +56,3 @@ int fstatvfs(int fd, struct statvfs *buf) fixup(buf, &kbuf); return 0; } - -weak_alias(statvfs, statvfs64); -weak_alias(statfs, statfs64); -weak_alias(fstatvfs, fstatvfs64); -weak_alias(fstatfs, fstatfs64); diff --git a/system/lib/libc/musl/src/stdio/fgetpos.c b/system/lib/libc/musl/src/stdio/fgetpos.c index 50813d2c50eea..392f7323cf58f 100644 --- a/system/lib/libc/musl/src/stdio/fgetpos.c +++ b/system/lib/libc/musl/src/stdio/fgetpos.c @@ -7,5 +7,3 @@ int fgetpos(FILE *restrict f, fpos_t *restrict pos) *(long long *)pos = off; return 0; } - -weak_alias(fgetpos, fgetpos64); diff --git a/system/lib/libc/musl/src/stdio/fgets.c b/system/lib/libc/musl/src/stdio/fgets.c index 6171f398dacb4..4a100b3937bf0 100644 --- a/system/lib/libc/musl/src/stdio/fgets.c +++ b/system/lib/libc/musl/src/stdio/fgets.c @@ -12,13 +12,14 @@ char *fgets(char *restrict s, int n, FILE *restrict f) FLOCK(f); - if (n--<=1) { + if (n<=1) { f->mode |= f->mode-1; FUNLOCK(f); - if (n) return 0; + if (n<1) return 0; *s = 0; return s; } + n--; while (n) { if (f->rpos != f->rend) { diff --git a/system/lib/libc/musl/src/stdio/fopen.c b/system/lib/libc/musl/src/stdio/fopen.c index 5692da61aea4f..97a5f816af077 100644 --- a/system/lib/libc/musl/src/stdio/fopen.c +++ b/system/lib/libc/musl/src/stdio/fopen.c @@ -35,5 +35,3 @@ FILE *fopen(const char *restrict filename, const char *restrict mode) #endif return 0; } - -weak_alias(fopen, fopen64); diff --git a/system/lib/libc/musl/src/stdio/freopen.c b/system/lib/libc/musl/src/stdio/freopen.c index b636a87484efc..206b5c3eeff21 100644 --- a/system/lib/libc/musl/src/stdio/freopen.c +++ b/system/lib/libc/musl/src/stdio/freopen.c @@ -42,6 +42,8 @@ FILE *freopen(const char *restrict filename, const char *restrict mode, FILE *re fclose(f2); } + f->mode = 0; + f->locale = 0; FUNLOCK(f); return f; @@ -51,5 +53,3 @@ FILE *freopen(const char *restrict filename, const char *restrict mode, FILE *re fclose(f); return NULL; } - -weak_alias(freopen, freopen64); diff --git a/system/lib/libc/musl/src/stdio/fseek.c b/system/lib/libc/musl/src/stdio/fseek.c index c07f7e952642b..c7425802cee7e 100644 --- a/system/lib/libc/musl/src/stdio/fseek.c +++ b/system/lib/libc/musl/src/stdio/fseek.c @@ -46,5 +46,3 @@ int fseek(FILE *f, long off, int whence) } weak_alias(__fseeko, fseeko); - -weak_alias(fseeko, fseeko64); diff --git a/system/lib/libc/musl/src/stdio/fsetpos.c b/system/lib/libc/musl/src/stdio/fsetpos.c index 77ab8d8206034..779cb3ccf4d37 100644 --- a/system/lib/libc/musl/src/stdio/fsetpos.c +++ b/system/lib/libc/musl/src/stdio/fsetpos.c @@ -4,5 +4,3 @@ int fsetpos(FILE *f, const fpos_t *pos) { return __fseeko(f, *(const long long *)pos, SEEK_SET); } - -weak_alias(fsetpos, fsetpos64); diff --git a/system/lib/libc/musl/src/stdio/ftell.c b/system/lib/libc/musl/src/stdio/ftell.c index 1a2afbbce3a62..1e1a08d8281dc 100644 --- a/system/lib/libc/musl/src/stdio/ftell.c +++ b/system/lib/libc/musl/src/stdio/ftell.c @@ -37,5 +37,3 @@ long ftell(FILE *f) } weak_alias(__ftello, ftello); - -weak_alias(ftello, ftello64); diff --git a/system/lib/libc/musl/src/stdio/open_wmemstream.c b/system/lib/libc/musl/src/stdio/open_wmemstream.c index ed1b561d9c92f..b8ae4a790cae9 100644 --- a/system/lib/libc/musl/src/stdio/open_wmemstream.c +++ b/system/lib/libc/musl/src/stdio/open_wmemstream.c @@ -40,8 +40,12 @@ static off_t wms_seek(FILE *f, off_t off, int whence) static size_t wms_write(FILE *f, const unsigned char *buf, size_t len) { struct cookie *c = f->cookie; - size_t len2; + size_t len2 = f->wpos - f->wbase; wchar_t *newbuf; + if (len2) { + f->wpos = f->wbase; + if (wms_write(f, f->wbase, len2) < len2) return 0; + } if (len + c->pos >= c->space) { len2 = 2*c->space+1 | c->pos+len+1; if (len2 > SSIZE_MAX/4) return 0; diff --git a/system/lib/libc/musl/src/stdio/tempnam.c b/system/lib/libc/musl/src/stdio/tempnam.c index 565df6b656a95..0c65b1f08e5e4 100644 --- a/system/lib/libc/musl/src/stdio/tempnam.c +++ b/system/lib/libc/musl/src/stdio/tempnam.c @@ -6,7 +6,6 @@ #include #include #include "syscall.h" -#include "kstat.h" #define MAXTRIES 100 @@ -37,11 +36,10 @@ char *tempnam(const char *dir, const char *pfx) for (try=0; try #include #include "syscall.h" -#include "kstat.h" #define MAXTRIES 100 @@ -17,11 +16,10 @@ char *tmpnam(char *buf) int r; for (try=0; tryflags & F_ERR)) __fwritex((void *)s, l, f); + if (!ferror(f)) __fwritex((void *)s, l, f); } static void pad(FILE *f, char c, int w, int l, int fl) @@ -530,8 +530,8 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg, if (*s=='*') { if (isdigit(s[1]) && s[2]=='$') { l10n=1; - nl_type[s[1]-'0'] = INT; - w = nl_arg[s[1]-'0'].i; + if (!f) nl_type[s[1]-'0'] = INT, w = 0; + else w = nl_arg[s[1]-'0'].i; s+=3; } else if (!l10n) { w = f ? va_arg(*ap, int) : 0; @@ -543,8 +543,8 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg, /* Read precision */ if (*s=='.' && s[1]=='*') { if (isdigit(s[2]) && s[3]=='$') { - nl_type[s[2]-'0'] = INT; - p = nl_arg[s[2]-'0'].i; + if (!f) nl_type[s[2]-'0'] = INT, p = 0; + else p = nl_arg[s[2]-'0'].i; s+=4; } else if (!l10n) { p = f ? va_arg(*ap, int) : 0; @@ -573,13 +573,18 @@ static int printf_core(FILE *f, const char *fmt, va_list *ap, union arg *nl_arg, if (st==NOARG) { if (argpos>=0) goto inval; } else { - if (argpos>=0) nl_type[argpos]=st, arg=nl_arg[argpos]; - else if (f) pop_arg(&arg, st, ap, pop_arg_long_double); + if (argpos>=0) { + if (!f) nl_type[argpos]=st; + else arg=nl_arg[argpos]; + } else if (f) pop_arg(&arg, st, ap, pop_arg_long_double); else return 0; } if (!f) continue; + /* Do not process any new directives once in error state. */ + if (ferror(f)) return -1; + z = buf + sizeof(buf); prefix = "-+ 0X0x"; pl = 0; @@ -728,7 +733,7 @@ int __vfprintf_internal(FILE *restrict f, const char *restrict fmt, va_list ap, FLOCK(f); olderr = f->flags & F_ERR; - if (f->mode < 1) f->flags &= ~F_ERR; + f->flags &= ~F_ERR; if (!f->buf_size) { saved_buf = f->buf; f->buf = internal_buf; @@ -744,7 +749,7 @@ int __vfprintf_internal(FILE *restrict f, const char *restrict fmt, va_list ap, f->buf_size = 0; f->wpos = f->wbase = f->wend = 0; } - if (f->flags & F_ERR) ret = -1; + if (ferror(f)) ret = -1; f->flags |= olderr; FUNLOCK(f); va_end(ap2); diff --git a/system/lib/libc/musl/src/stdio/vfwprintf.c b/system/lib/libc/musl/src/stdio/vfwprintf.c index 85b036c3dfe2a..53697701432ca 100644 --- a/system/lib/libc/musl/src/stdio/vfwprintf.c +++ b/system/lib/libc/musl/src/stdio/vfwprintf.c @@ -125,7 +125,13 @@ static void pop_arg(union arg *arg, int type, va_list *ap) static void out(FILE *f, const wchar_t *s, size_t l) { - while (l-- && !(f->flags & F_ERR)) fputwc(*s++, f); + while (l-- && !ferror(f)) fputwc(*s++, f); +} + +static void pad(FILE *f, int n, int fl) +{ + if ((fl & LEFT_ADJ) || !n || ferror(f)) return; + fprintf(f, "%*s", n, ""); } static int getint(wchar_t **s) { @@ -242,6 +248,10 @@ static int wprintf_core(FILE *f, const wchar_t *fmt, va_list *ap, union arg *nl_ } if (!f) continue; + + /* Do not process any new directives once in error state. */ + if (ferror(f)) return -1; + t = s[-1]; if (ps && (t&15)==3) t&=~32; @@ -258,25 +268,22 @@ static int wprintf_core(FILE *f, const wchar_t *fmt, va_list *ap, union arg *nl_ } continue; case 'c': + case 'C': if (w<1) w=1; - if (w>1 && !(fl&LEFT_ADJ)) fprintf(f, "%*s", w-1, ""); - fputwc(btowc(arg.i), f); - if (w>1 && (fl&LEFT_ADJ)) fprintf(f, "%*s", w-1, ""); + pad(f, w-1, fl); + out(f, &(wchar_t){t=='C' ? arg.i : btowc(arg.i)}, 1); + pad(f, w-1, fl^LEFT_ADJ); l = w; continue; - case 'C': - fputwc(arg.i, f); - l = 1; - continue; case 'S': a = arg.p; z = a + wcsnlen(a, p<0 ? INT_MAX : p); if (p<0 && *z) goto overflow; p = z-a; if (wflags & F_ERR; f->flags &= ~F_ERR; ret = wprintf_core(f, fmt, &ap2, nl_arg, nl_type); - if (f->flags & F_ERR) ret = -1; + if (ferror(f)) ret = -1; f->flags |= olderr; FUNLOCK(f); va_end(ap2); diff --git a/system/lib/libc/musl/src/stdio/vswprintf.c b/system/lib/libc/musl/src/stdio/vswprintf.c index 7f98c5c9690e4..fc223cf2b8c58 100644 --- a/system/lib/libc/musl/src/stdio/vswprintf.c +++ b/system/lib/libc/musl/src/stdio/vswprintf.c @@ -18,6 +18,7 @@ static size_t sw_write(FILE *f, const unsigned char *s, size_t l) if (s!=f->wbase && sw_write(f, f->wbase, f->wpos-f->wbase)==-1) return -1; while (c->l && l && (i=mbtowc(c->ws, (void *)s, l))>=0) { + if (!i) i=1; s+=i; l-=i; c->l--; diff --git a/system/lib/libc/musl/src/stdlib/qsort_nr.c b/system/lib/libc/musl/src/stdlib/qsort_nr.c index efe7ccecd1f36..8ffe71d03819c 100644 --- a/system/lib/libc/musl/src/stdlib/qsort_nr.c +++ b/system/lib/libc/musl/src/stdlib/qsort_nr.c @@ -10,5 +10,5 @@ static int wrapper_cmp(const void *v1, const void *v2, void *cmp) void qsort(void *base, size_t nel, size_t width, cmpfun cmp) { - __qsort_r(base, nel, width, wrapper_cmp, cmp); + __qsort_r(base, nel, width, wrapper_cmp, (void *)cmp); } diff --git a/system/lib/libc/musl/src/string/strverscmp.c b/system/lib/libc/musl/src/string/strverscmp.c index 4daf276d0cfeb..16c1da224a4d2 100644 --- a/system/lib/libc/musl/src/string/strverscmp.c +++ b/system/lib/libc/musl/src/string/strverscmp.c @@ -18,9 +18,9 @@ int strverscmp(const char *l0, const char *r0) else if (c!='0') z=0; } - if (l[dp]!='0' && r[dp]!='0') { - /* If we're not looking at a digit sequence that began - * with a zero, longest digit string is greater. */ + if (l[dp]-'1'<9U && r[dp]-'1'<9U) { + /* If we're looking at non-degenerate digit sequences starting + * with nonzero digits, longest digit string is greater. */ for (j=i; isdigit(l[j]); j++) if (!isdigit(r[j])) return 1; if (isdigit(r[j])) return -1; diff --git a/system/lib/libc/musl/src/string/wcscmp.c b/system/lib/libc/musl/src/string/wcscmp.c index 26eeee7045612..286ec3ea4028b 100644 --- a/system/lib/libc/musl/src/string/wcscmp.c +++ b/system/lib/libc/musl/src/string/wcscmp.c @@ -3,5 +3,5 @@ int wcscmp(const wchar_t *l, const wchar_t *r) { for (; *l==*r && *l && *r; l++, r++); - return *l - *r; + return *l < *r ? -1 : *l > *r; } diff --git a/system/lib/libc/musl/src/string/wcsncmp.c b/system/lib/libc/musl/src/string/wcsncmp.c index 4ab32a924c465..2b3558bf72f69 100644 --- a/system/lib/libc/musl/src/string/wcsncmp.c +++ b/system/lib/libc/musl/src/string/wcsncmp.c @@ -3,5 +3,5 @@ int wcsncmp(const wchar_t *l, const wchar_t *r, size_t n) { for (; n && *l==*r && *l && *r; n--, l++, r++); - return n ? *l - *r : 0; + return n ? (*l < *r ? -1 : *l > *r) : 0; } diff --git a/system/lib/libc/musl/src/string/wmemcmp.c b/system/lib/libc/musl/src/string/wmemcmp.c index 2a193263ce5c6..717d77b174434 100644 --- a/system/lib/libc/musl/src/string/wmemcmp.c +++ b/system/lib/libc/musl/src/string/wmemcmp.c @@ -3,5 +3,5 @@ int wmemcmp(const wchar_t *l, const wchar_t *r, size_t n) { for (; n && *l==*r; n--, l++, r++); - return n ? *l-*r : 0; + return n ? (*l < *r ? -1 : *l > *r) : 0; } diff --git a/system/lib/libc/musl/src/temp/__randname.c b/system/lib/libc/musl/src/temp/__randname.c index f672ddb8796d1..62152de05b5ed 100644 --- a/system/lib/libc/musl/src/temp/__randname.c +++ b/system/lib/libc/musl/src/temp/__randname.c @@ -1,5 +1,6 @@ #include #include +#include "pthread_impl.h" /* This assumes that a check for the template size has already been made */ @@ -10,7 +11,7 @@ char *__randname(char *template) unsigned long r; __clock_gettime(CLOCK_REALTIME, &ts); - r = ts.tv_nsec*65537 ^ (uintptr_t)&ts / 16 + (uintptr_t)template; + r = ts.tv_sec + ts.tv_nsec + __pthread_self()->tid * 65537UL; /* XXX EMSCRIPTEN: avoid repeating the same result when __clock_gettime does not change between calls. */ static unsigned int counter = 0; diff --git a/system/lib/libc/musl/src/temp/mkostemp.c b/system/lib/libc/musl/src/temp/mkostemp.c index d8dcb8052da56..e3dfdd912428c 100644 --- a/system/lib/libc/musl/src/temp/mkostemp.c +++ b/system/lib/libc/musl/src/temp/mkostemp.c @@ -5,5 +5,3 @@ int mkostemp(char *template, int flags) { return __mkostemps(template, 0, flags); } - -weak_alias(mkostemp, mkostemp64); diff --git a/system/lib/libc/musl/src/temp/mkostemps.c b/system/lib/libc/musl/src/temp/mkostemps.c index ef24eeae2ce92..093d2380d86bd 100644 --- a/system/lib/libc/musl/src/temp/mkostemps.c +++ b/system/lib/libc/musl/src/temp/mkostemps.c @@ -26,4 +26,3 @@ int __mkostemps(char *template, int len, int flags) } weak_alias(__mkostemps, mkostemps); -weak_alias(__mkostemps, mkostemps64); diff --git a/system/lib/libc/musl/src/temp/mkstemp.c b/system/lib/libc/musl/src/temp/mkstemp.c index 166b8afe49bb2..76c835bb01bc5 100644 --- a/system/lib/libc/musl/src/temp/mkstemp.c +++ b/system/lib/libc/musl/src/temp/mkstemp.c @@ -4,5 +4,3 @@ int mkstemp(char *template) { return __mkostemps(template, 0, 0); } - -weak_alias(mkstemp, mkstemp64); diff --git a/system/lib/libc/musl/src/temp/mkstemps.c b/system/lib/libc/musl/src/temp/mkstemps.c index 6b7531b5e9a97..f8eabfec0aec6 100644 --- a/system/lib/libc/musl/src/temp/mkstemps.c +++ b/system/lib/libc/musl/src/temp/mkstemps.c @@ -5,5 +5,3 @@ int mkstemps(char *template, int len) { return __mkostemps(template, len, 0); } - -weak_alias(mkstemps, mkstemps64); diff --git a/system/lib/libc/musl/src/thread/pthread_atfork.c b/system/lib/libc/musl/src/thread/pthread_atfork.c index 0ed71fd434823..f1b40eb57ddc0 100644 --- a/system/lib/libc/musl/src/thread/pthread_atfork.c +++ b/system/lib/libc/musl/src/thread/pthread_atfork.c @@ -1,8 +1,14 @@ #include +#include #include "libc.h" #include "lock.h" #ifndef __EMSCRIPTEN__ // XXX Emscripten fork() is not supported: pthread_atfork is a no-op +#define malloc __libc_malloc +#define calloc undef +#define realloc undef +#define free undef + static struct atfork_funcs { void (*prepare)(void); void (*parent)(void); @@ -39,7 +45,7 @@ int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(vo return 0; #else struct atfork_funcs *new = malloc(sizeof *new); - if (!new) return -1; + if (!new) return ENOMEM; LOCK(lock); new->next = funcs; diff --git a/system/lib/libc/musl/src/thread/pthread_cancel.c b/system/lib/libc/musl/src/thread/pthread_cancel.c index e974746fa4634..ef9ca61dbb4d8 100644 --- a/system/lib/libc/musl/src/thread/pthread_cancel.c +++ b/system/lib/libc/musl/src/thread/pthread_cancel.c @@ -57,7 +57,12 @@ static void cancel_handler(int sig, siginfo_t *si, void *ctx) _sigaddset(&uc->uc_sigmask, SIGCANCEL); - if (self->cancelasync || pc >= (uintptr_t)__cp_begin && pc < (uintptr_t)__cp_end) { + if (self->cancelasync) { + pthread_sigmask(SIG_SETMASK, &uc->uc_sigmask, 0); + __cancel(); + } + + if (pc >= (uintptr_t)__cp_begin && pc < (uintptr_t)__cp_end) { uc->uc_mcontext.MC_PC = (uintptr_t)__cp_cancel; #ifdef CANCEL_GOT uc->uc_mcontext.MC_GOT = CANCEL_GOT; @@ -80,7 +85,7 @@ void __testcancel() static void init_cancellation() { struct sigaction sa = { - .sa_flags = SA_SIGINFO | SA_RESTART, + .sa_flags = SA_SIGINFO | SA_RESTART | SA_ONSTACK, .sa_sigaction = cancel_handler }; memset(&sa.sa_mask, -1, _NSIG/8); diff --git a/system/lib/libc/musl/src/thread/pthread_create.c b/system/lib/libc/musl/src/thread/pthread_create.c index 6f187ee89d3dd..087f6206d5d64 100644 --- a/system/lib/libc/musl/src/thread/pthread_create.c +++ b/system/lib/libc/musl/src/thread/pthread_create.c @@ -107,6 +107,16 @@ _Noreturn void __pthread_exit(void *result) /* At this point we are committed to thread termination. */ + /* After the kernel thread exits, its tid may be reused. Clear it + * to prevent inadvertent use and inform functions that would use + * it that it's no longer available. At this point the killlock + * may be released, since functions that use it will consistently + * see the thread as having exited. Release it now so that no + * remaining locks (except thread list) are held if we end up + * resetting need_locks below. */ + self->tid = 0; + UNLOCK(self->killlock); + /* Process robust list in userspace to handle non-pshared mutexes * and the detached thread case where the robust list head will * be invalid when the kernel would process it. */ @@ -159,12 +169,6 @@ _Noreturn void __pthread_exit(void *result) a_store(&self->detach_state, DT_EXITED); __wake(&self->detach_state, 1, 1); - /* After the kernel thread exits, its tid may be reused. Clear it - * to prevent inadvertent use and inform functions that would use - * it that it's no longer available. */ - self->tid = 0; - UNLOCK(self->killlock); - for (;;) __syscall(SYS_exit, 0); } diff --git a/system/lib/libc/musl/src/thread/pthread_detach.c b/system/lib/libc/musl/src/thread/pthread_detach.c index bdcd2ddfbe576..69831cf58b875 100644 --- a/system/lib/libc/musl/src/thread/pthread_detach.c +++ b/system/lib/libc/musl/src/thread/pthread_detach.c @@ -8,11 +8,20 @@ static int __pthread_detach(pthread_t t) // for the benefit of the conformance tests. if (!_emscripten_thread_is_valid(t)) return ESRCH; + // Even though the man page says this is undefined behaviour to attempt to + // detach an already-detached thread we have several tests in the posixtest + // suite that depend on this (pthread_join.c) + if (a_cas(&t->detach_state, DT_JOINABLE, DT_DETACHED) == DT_DETACHED) + return EINVAL; #endif /* If the cas fails, detach state is either already-detached * or exiting/exited, and pthread_join will trap or cleanup. */ - if (a_cas(&t->detach_state, DT_JOINABLE, DT_DETACHED) != DT_JOINABLE) - return __pthread_join(t, 0); + if (a_cas(&t->detach_state, DT_JOINABLE, DT_DETACHED) != DT_JOINABLE) { + int cs; + __pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + __pthread_join(t, 0); + __pthread_setcancelstate(cs, 0); + } return 0; } diff --git a/system/lib/libc/musl/src/thread/pthread_join.c b/system/lib/libc/musl/src/thread/pthread_join.c index d68d149ceb944..d209324a9ab84 100644 --- a/system/lib/libc/musl/src/thread/pthread_join.c +++ b/system/lib/libc/musl/src/thread/pthread_join.c @@ -29,9 +29,8 @@ static int __pthread_timedjoin_np(pthread_t t, void **res, const struct timespec // This also handle cases where the thread becomes detached // *during* the join. if (state >= DT_DETACHED) { - // Even though the man page says this is undefined - // behaviour we ave several tests in the posixtest suite - // that depend on this. + // Even though the man page says this is undefined behaviour we have + // several tests in the posixtest suite that depend on this. r = EINVAL; break; } diff --git a/system/lib/libc/musl/src/thread/pthread_key_create.c b/system/lib/libc/musl/src/thread/pthread_key_create.c index 522dd0767e474..f45553919647a 100644 --- a/system/lib/libc/musl/src/thread/pthread_key_create.c +++ b/system/lib/libc/musl/src/thread/pthread_key_create.c @@ -1,4 +1,5 @@ #include "pthread_impl.h" +#include "fork_impl.h" #ifdef __EMSCRIPTEN__ #include @@ -24,6 +25,13 @@ static void dummy_0(void) weak_alias(dummy_0, __tl_lock); weak_alias(dummy_0, __tl_unlock); +void __pthread_key_atfork(int who) +{ + if (who<0) __pthread_rwlock_rdlock(&key_lock); + else if (!who) __pthread_rwlock_unlock(&key_lock); + else key_lock = (pthread_rwlock_t)PTHREAD_RWLOCK_INITIALIZER; +} + int __pthread_key_create(pthread_key_t *k, void (*dtor)(void *)) { pthread_t self = __pthread_self(); diff --git a/system/lib/libc/musl/src/thread/sem_getvalue.c b/system/lib/libc/musl/src/thread/sem_getvalue.c index d9d830717730d..c0b7762d3e11b 100644 --- a/system/lib/libc/musl/src/thread/sem_getvalue.c +++ b/system/lib/libc/musl/src/thread/sem_getvalue.c @@ -1,8 +1,9 @@ #include +#include int sem_getvalue(sem_t *restrict sem, int *restrict valp) { int val = sem->__val[0]; - *valp = val < 0 ? 0 : val; + *valp = val & SEM_VALUE_MAX; return 0; } diff --git a/system/lib/libc/musl/src/thread/sem_post.c b/system/lib/libc/musl/src/thread/sem_post.c index 31e3293d20504..5c2517f23606d 100644 --- a/system/lib/libc/musl/src/thread/sem_post.c +++ b/system/lib/libc/musl/src/thread/sem_post.c @@ -1,17 +1,21 @@ #include +#include #include "pthread_impl.h" int sem_post(sem_t *sem) { - int val, waiters, priv = sem->__val[2]; + int val, new, waiters, priv = sem->__val[2]; do { val = sem->__val[0]; waiters = sem->__val[1]; - if (val == SEM_VALUE_MAX) { + if ((val & SEM_VALUE_MAX) == SEM_VALUE_MAX) { errno = EOVERFLOW; return -1; } - } while (a_cas(sem->__val, val, val+1+(val<0)) != val); - if (val<0 || waiters) __wake(sem->__val, 1, priv); + new = val + 1; + if (waiters <= 1) + new &= ~0x80000000; + } while (a_cas(sem->__val, val, new) != val); + if (val<0) __wake(sem->__val, waiters>1 ? 1 : -1, priv); return 0; } diff --git a/system/lib/libc/musl/src/thread/sem_timedwait.c b/system/lib/libc/musl/src/thread/sem_timedwait.c index ca41ec583b828..757795a9589dd 100644 --- a/system/lib/libc/musl/src/thread/sem_timedwait.c +++ b/system/lib/libc/musl/src/thread/sem_timedwait.c @@ -1,4 +1,5 @@ #include +#include #include "pthread_impl.h" static void cleanup(void *p) @@ -13,14 +14,15 @@ int sem_timedwait(sem_t *restrict sem, const struct timespec *restrict at) if (!sem_trywait(sem)) return 0; int spins = 100; - while (spins-- && sem->__val[0] <= 0 && !sem->__val[1]) a_spin(); + while (spins-- && !(sem->__val[0] & SEM_VALUE_MAX) && !sem->__val[1]) + a_spin(); while (sem_trywait(sem)) { - int r; + int r, priv = sem->__val[2]; a_inc(sem->__val+1); - a_cas(sem->__val, 0, -1); + a_cas(sem->__val, 0, 0x80000000); pthread_cleanup_push(cleanup, (void *)(sem->__val+1)); - r = __timedwait_cp(sem->__val, -1, CLOCK_REALTIME, at, sem->__val[2]); + r = __timedwait_cp(sem->__val, 0x80000000, CLOCK_REALTIME, at, priv); pthread_cleanup_pop(1); if (r) { #ifdef __EMSCRIPTEN__ diff --git a/system/lib/libc/musl/src/thread/sem_trywait.c b/system/lib/libc/musl/src/thread/sem_trywait.c index 04edf46b524de..beb435da7c14a 100644 --- a/system/lib/libc/musl/src/thread/sem_trywait.c +++ b/system/lib/libc/musl/src/thread/sem_trywait.c @@ -1,12 +1,12 @@ #include +#include #include "pthread_impl.h" int sem_trywait(sem_t *sem) { int val; - while ((val=sem->__val[0]) > 0) { - int new = val-1-(val==1 && sem->__val[1]); - if (a_cas(sem->__val, val, new)==val) return 0; + while ((val=sem->__val[0]) & SEM_VALUE_MAX) { + if (a_cas(sem->__val, val, val-1)==val) return 0; } errno = EAGAIN; return -1; diff --git a/system/lib/libc/musl/src/thread/synccall.c b/system/lib/libc/musl/src/thread/synccall.c index d58c851fcff4a..a6b177c06fd3d 100644 --- a/system/lib/libc/musl/src/thread/synccall.c +++ b/system/lib/libc/musl/src/thread/synccall.c @@ -45,7 +45,7 @@ void __synccall(void (*func)(void *), void *ctx) { sigset_t oldmask; int cs, i, r; - struct sigaction sa = { .sa_flags = SA_RESTART, .sa_handler = handler }; + struct sigaction sa = { .sa_flags = SA_RESTART | SA_ONSTACK, .sa_handler = handler }; pthread_t self = __pthread_self(), td; int count = 0; diff --git a/system/lib/libc/musl/src/time/__map_file.c b/system/lib/libc/musl/src/time/__map_file.c index 95b7fe07def0a..f4520b124c0b3 100644 --- a/system/lib/libc/musl/src/time/__map_file.c +++ b/system/lib/libc/musl/src/time/__map_file.c @@ -2,15 +2,14 @@ #include #include #include "syscall.h" -#include "kstat.h" const char unsigned *__map_file(const char *pathname, size_t *size) { - struct kstat st; + struct stat st; const unsigned char *map = MAP_FAILED; int fd = sys_open(pathname, O_RDONLY|O_CLOEXEC|O_NONBLOCK); if (fd < 0) return 0; - if (!syscall(SYS_fstat, fd, &st)) { + if (!__fstat(fd, &st)) { map = __mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0); *size = st.st_size; } diff --git a/system/lib/libc/musl/src/time/clock_getcpuclockid.c b/system/lib/libc/musl/src/time/clock_getcpuclockid.c index 8a0e2d4c3a622..bce1e8ab29013 100644 --- a/system/lib/libc/musl/src/time/clock_getcpuclockid.c +++ b/system/lib/libc/musl/src/time/clock_getcpuclockid.c @@ -8,6 +8,7 @@ int clock_getcpuclockid(pid_t pid, clockid_t *clk) struct timespec ts; clockid_t id = (-pid-1)*8U + 2; int ret = __syscall(SYS_clock_getres, id, &ts); + if (ret == -EINVAL) ret = -ESRCH; if (ret) return -ret; *clk = id; return 0; diff --git a/system/lib/libc/musl/src/time/clock_gettime.c b/system/lib/libc/musl/src/time/clock_gettime.c index e84c67d41b7ac..18926de8ce8f3 100644 --- a/system/lib/libc/musl/src/time/clock_gettime.c +++ b/system/lib/libc/musl/src/time/clock_gettime.c @@ -42,6 +42,9 @@ static int cgt_init(clockid_t clk, struct timespec *ts) p = cgt_time32_wrap; } } +#ifdef VDSO_CGT_WORKAROUND + if (!__vdsosym(VDSO_CGT32_VER, VDSO_CGT32_SYM)) p = 0; +#endif #endif int (*f)(clockid_t, struct timespec *) = (int (*)(clockid_t, struct timespec *))p; @@ -98,10 +101,12 @@ int __clock_gettime(clockid_t clk, struct timespec *ts) return __syscall_ret(r); long ts32[2]; r = __syscall(SYS_clock_gettime, clk, ts32); +#ifdef SYS_gettimeofday if (r==-ENOSYS && clk==CLOCK_REALTIME) { r = __syscall(SYS_gettimeofday, ts32, 0); ts32[1] *= 1000; } +#endif if (!r) { ts->tv_sec = ts32[0]; ts->tv_nsec = ts32[1]; @@ -110,6 +115,7 @@ int __clock_gettime(clockid_t clk, struct timespec *ts) return __syscall_ret(r); #else r = __syscall(SYS_clock_gettime, clk, ts); +#ifdef SYS_gettimeofday if (r == -ENOSYS) { if (clk == CLOCK_REALTIME) { __syscall(SYS_gettimeofday, ts, 0); @@ -118,6 +124,7 @@ int __clock_gettime(clockid_t clk, struct timespec *ts) } r = -EINVAL; } +#endif return __syscall_ret(r); #endif } diff --git a/system/lib/libc/musl/src/time/timer_create.c b/system/lib/libc/musl/src/time/timer_create.c index 4bef23905103e..cd32c945b6a87 100644 --- a/system/lib/libc/musl/src/time/timer_create.c +++ b/system/lib/libc/musl/src/time/timer_create.c @@ -43,6 +43,8 @@ static void *start(void *arg) union sigval val = args->sev->sigev_value; pthread_barrier_wait(&args->b); + if (self->cancel) + return 0; for (;;) { siginfo_t si; while (sigwaitinfo(SIGTIMER_SET, &si) < 0); @@ -113,8 +115,10 @@ int timer_create(clockid_t clk, struct sigevent *restrict evp, timer_t *restrict ksev.sigev_signo = SIGTIMER; ksev.sigev_notify = SIGEV_THREAD_ID; ksev.sigev_tid = td->tid; - if (syscall(SYS_timer_create, clk, &ksev, &timerid) < 0) + if (syscall(SYS_timer_create, clk, &ksev, &timerid) < 0) { timerid = -1; + td->cancel = 1; + } td->timer_id = timerid; pthread_barrier_wait(&args.b); if (timerid < 0) return -1; diff --git a/system/lib/libc/musl/src/unistd/dup3.c b/system/lib/libc/musl/src/unistd/dup3.c index c895d5cc5f48f..311ec4360617a 100644 --- a/system/lib/libc/musl/src/unistd/dup3.c +++ b/system/lib/libc/musl/src/unistd/dup3.c @@ -9,13 +9,15 @@ int __dup3(int old, int new, int flags) int r; #ifdef SYS_dup2 if (old==new) return __syscall_ret(-EINVAL); - if (flags & O_CLOEXEC) { + if (flags) { while ((r=__syscall(SYS_dup3, old, new, flags))==-EBUSY); if (r!=-ENOSYS) return __syscall_ret(r); + if (flags & ~O_CLOEXEC) return __syscall_ret(-EINVAL); } while ((r=__syscall(SYS_dup2, old, new))==-EBUSY); #ifndef __EMSCRIPTEN__ // CLOEXEC makes no sense for a single process - if (flags & O_CLOEXEC) __syscall(SYS_fcntl, new, F_SETFD, FD_CLOEXEC); + if (r >= 0 && (flags & O_CLOEXEC)) + __syscall(SYS_fcntl, new, F_SETFD, FD_CLOEXEC); #endif #else while ((r=__syscall(SYS_dup3, old, new, flags))==-EBUSY); diff --git a/system/lib/libc/musl/src/unistd/ftruncate.c b/system/lib/libc/musl/src/unistd/ftruncate.c index b41be0fa6f9ec..54ff34bc3ebd7 100644 --- a/system/lib/libc/musl/src/unistd/ftruncate.c +++ b/system/lib/libc/musl/src/unistd/ftruncate.c @@ -5,5 +5,3 @@ int ftruncate(int fd, off_t length) { return syscall(SYS_ftruncate, fd, __SYSCALL_LL_O(length)); } - -weak_alias(ftruncate, ftruncate64); diff --git a/system/lib/libc/musl/src/unistd/lseek.c b/system/lib/libc/musl/src/unistd/lseek.c index aafb6f62d2d5c..199e784c01d74 100644 --- a/system/lib/libc/musl/src/unistd/lseek.c +++ b/system/lib/libc/musl/src/unistd/lseek.c @@ -17,4 +17,3 @@ off_t __lseek(int fd, off_t offset, int whence) } weak_alias(__lseek, lseek); -weak_alias(__lseek, lseek64); diff --git a/system/lib/libc/musl/src/unistd/pipe2.c b/system/lib/libc/musl/src/unistd/pipe2.c index 9e4e8549f9ac3..f215000b31c4d 100644 --- a/system/lib/libc/musl/src/unistd/pipe2.c +++ b/system/lib/libc/musl/src/unistd/pipe2.c @@ -8,6 +8,7 @@ int pipe2(int fd[2], int flag) if (!flag) return pipe(fd); int ret = __syscall(SYS_pipe2, fd, flag); if (ret != -ENOSYS) return __syscall_ret(ret); + if (flag & ~(O_CLOEXEC|O_NONBLOCK)) return __syscall_ret(-EINVAL); ret = pipe(fd); if (ret) return ret; #ifndef __EMSCRIPTEN__ // CLOEXEC makes no sense for a single process diff --git a/system/lib/libc/musl/src/unistd/pread.c b/system/lib/libc/musl/src/unistd/pread.c index f05bbe6e8b98e..a2361a0473b51 100644 --- a/system/lib/libc/musl/src/unistd/pread.c +++ b/system/lib/libc/musl/src/unistd/pread.c @@ -17,5 +17,3 @@ ssize_t pread(int fd, void *buf, size_t size, off_t ofs) return syscall_cp(SYS_pread, fd, buf, size, __SYSCALL_LL_PRW(ofs)); #endif } - -weak_alias(pread, pread64); diff --git a/system/lib/libc/musl/src/unistd/preadv.c b/system/lib/libc/musl/src/unistd/preadv.c index 018c7dd2454ee..fa6b78c101b3f 100644 --- a/system/lib/libc/musl/src/unistd/preadv.c +++ b/system/lib/libc/musl/src/unistd/preadv.c @@ -16,5 +16,3 @@ ssize_t preadv(int fd, const struct iovec *iov, int count, off_t ofs) (long)(ofs), (long)(ofs>>32)); #endif } - -weak_alias(preadv, preadv64); diff --git a/system/lib/libc/musl/src/unistd/pwrite.c b/system/lib/libc/musl/src/unistd/pwrite.c index f0964fb016bec..3573ab3902f82 100644 --- a/system/lib/libc/musl/src/unistd/pwrite.c +++ b/system/lib/libc/musl/src/unistd/pwrite.c @@ -17,5 +17,3 @@ ssize_t pwrite(int fd, const void *buf, size_t size, off_t ofs) return syscall_cp(SYS_pwrite, fd, buf, size, __SYSCALL_LL_PRW(ofs)); #endif } - -weak_alias(pwrite, pwrite64); diff --git a/system/lib/libc/musl/src/unistd/pwritev.c b/system/lib/libc/musl/src/unistd/pwritev.c index 845be153a92ba..bb44236c51ef7 100644 --- a/system/lib/libc/musl/src/unistd/pwritev.c +++ b/system/lib/libc/musl/src/unistd/pwritev.c @@ -16,5 +16,3 @@ ssize_t pwritev(int fd, const struct iovec *iov, int count, off_t ofs) (long)(ofs), (long)(ofs>>32)); #endif } - -weak_alias(pwritev, pwritev64); diff --git a/system/lib/libc/musl/src/unistd/truncate.c b/system/lib/libc/musl/src/unistd/truncate.c index 9729680076572..077351e1be241 100644 --- a/system/lib/libc/musl/src/unistd/truncate.c +++ b/system/lib/libc/musl/src/unistd/truncate.c @@ -5,5 +5,3 @@ int truncate(const char *path, off_t length) { return syscall(SYS_truncate, path, __SYSCALL_LL_O(length)); } - -weak_alias(truncate, truncate64); diff --git a/system/lib/standalone/standalone.c b/system/lib/standalone/standalone.c index d1d4cf45911ff..0238e91e54fd2 100644 --- a/system/lib/standalone/standalone.c +++ b/system/lib/standalone/standalone.c @@ -126,6 +126,14 @@ weak int __syscall_mkdirat(int dirfd, intptr_t path, int mode) { return -ENOSYS; } +weak int __syscall_newfstatat(int dirfd, intptr_t path, intptr_t buf, int flags) { + return -ENOSYS; +} + +weak int __syscall_lstat64(intptr_t path, intptr_t buf) { + return -ENOSYS; +} + // There is no good source of entropy without an import. Make this weak so that // it can be replaced with a pRNG or a proper import. weak int getentropy(void* buffer, size_t length) { diff --git a/system/lib/wasmfs/syscalls.cpp b/system/lib/wasmfs/syscalls.cpp index 63bf754d48934..261b4aead7ddc 100644 --- a/system/lib/wasmfs/syscalls.cpp +++ b/system/lib/wasmfs/syscalls.cpp @@ -6,6 +6,8 @@ // old JS version. Current Status: Work in Progress. See // https://github.com/emscripten-core/emscripten/issues/15041. +#define _LARGEFILE64_SOURCE // For F_GETLK64 etc + #include #include #include diff --git a/test/code_size/random_printf_wasm.json b/test/code_size/random_printf_wasm.json index 512d510f3dd09..8c293a8b8b617 100644 --- a/test/code_size/random_printf_wasm.json +++ b/test/code_size/random_printf_wasm.json @@ -1,6 +1,6 @@ { - "a.html": 12741, - "a.html.gz": 6972, - "total": 12741, - "total_gz": 6972 + "a.html": 12793, + "a.html.gz": 6942, + "total": 12793, + "total_gz": 6942 } diff --git a/test/code_size/random_printf_wasm2js.json b/test/code_size/random_printf_wasm2js.json index 149fc4aab1f20..0414ed3307096 100644 --- a/test/code_size/random_printf_wasm2js.json +++ b/test/code_size/random_printf_wasm2js.json @@ -1,6 +1,6 @@ { - "a.html": 17361, - "a.html.gz": 7553, - "total": 17361, - "total_gz": 7553 + "a.html": 17380, + "a.html.gz": 7542, + "total": 17380, + "total_gz": 7542 } diff --git a/test/other/metadce/test_metadce_cxx_ctors1.size b/test/other/metadce/test_metadce_cxx_ctors1.size index 89cb22ba96f60..465935cf3c3fe 100644 --- a/test/other/metadce/test_metadce_cxx_ctors1.size +++ b/test/other/metadce/test_metadce_cxx_ctors1.size @@ -1 +1 @@ -123583 +123615 diff --git a/test/other/metadce/test_metadce_cxx_ctors2.size b/test/other/metadce/test_metadce_cxx_ctors2.size index a2ee3fdaebe58..edde1079d6e92 100644 --- a/test/other/metadce/test_metadce_cxx_ctors2.size +++ b/test/other/metadce/test_metadce_cxx_ctors2.size @@ -1 +1 @@ -123488 +123520 diff --git a/test/other/metadce/test_metadce_cxx_except.size b/test/other/metadce/test_metadce_cxx_except.size index cd180f98728b2..b04970de1c1f9 100644 --- a/test/other/metadce/test_metadce_cxx_except.size +++ b/test/other/metadce/test_metadce_cxx_except.size @@ -1 +1 @@ -166418 +166450 diff --git a/test/other/metadce/test_metadce_cxx_except_wasm.size b/test/other/metadce/test_metadce_cxx_except_wasm.size index b8afba096689b..cbd31f6da1877 100644 --- a/test/other/metadce/test_metadce_cxx_except_wasm.size +++ b/test/other/metadce/test_metadce_cxx_except_wasm.size @@ -1 +1 @@ -137211 +137243 diff --git a/test/other/metadce/test_metadce_cxx_mangle.size b/test/other/metadce/test_metadce_cxx_mangle.size index 464a54e303ebc..6e1566916dce7 100644 --- a/test/other/metadce/test_metadce_cxx_mangle.size +++ b/test/other/metadce/test_metadce_cxx_mangle.size @@ -1 +1 @@ -221380 +221412 diff --git a/test/other/metadce/test_metadce_cxx_noexcept.size b/test/other/metadce/test_metadce_cxx_noexcept.size index 2827a22520f95..747eb858d0844 100644 --- a/test/other/metadce/test_metadce_cxx_noexcept.size +++ b/test/other/metadce/test_metadce_cxx_noexcept.size @@ -1 +1 @@ -126387 +126419 diff --git a/test/other/metadce/test_metadce_cxx_wasmfs.size b/test/other/metadce/test_metadce_cxx_wasmfs.size index 662d7caaeaf39..8a85c8d248f6d 100644 --- a/test/other/metadce/test_metadce_cxx_wasmfs.size +++ b/test/other/metadce/test_metadce_cxx_wasmfs.size @@ -1 +1 @@ -164526 +164558 diff --git a/test/other/metadce/test_metadce_hello_O0.size b/test/other/metadce/test_metadce_hello_O0.size index e8b15f251ccec..39fb891cb1844 100644 --- a/test/other/metadce/test_metadce_hello_O0.size +++ b/test/other/metadce/test_metadce_hello_O0.size @@ -1 +1 @@ -12123 +12156 diff --git a/test/other/test_unoptimized_code_size.wasm.size b/test/other/test_unoptimized_code_size.wasm.size index 39fb891cb1844..8be8535efff58 100644 --- a/test/other/test_unoptimized_code_size.wasm.size +++ b/test/other/test_unoptimized_code_size.wasm.size @@ -1 +1 @@ -12156 +12189 diff --git a/test/other/test_unoptimized_code_size_no_asserts.wasm.size b/test/other/test_unoptimized_code_size_no_asserts.wasm.size index 9a1c49f077bd0..7230c6821ca4a 100644 --- a/test/other/test_unoptimized_code_size_no_asserts.wasm.size +++ b/test/other/test_unoptimized_code_size_no_asserts.wasm.size @@ -1 +1 @@ -11603 +11636 diff --git a/test/other/test_unoptimized_code_size_strict.wasm.size b/test/other/test_unoptimized_code_size_strict.wasm.size index 39fb891cb1844..8be8535efff58 100644 --- a/test/other/test_unoptimized_code_size_strict.wasm.size +++ b/test/other/test_unoptimized_code_size_strict.wasm.size @@ -1 +1 @@ -12156 +12189 diff --git a/test/sockets/test_getaddrinfo.c b/test/sockets/test_getaddrinfo.c index f61eaf1fd38fe..2b76ecea9e9ac 100644 --- a/test/sockets/test_getaddrinfo.c +++ b/test/sockets/test_getaddrinfo.c @@ -252,7 +252,7 @@ int main() { assert(strcmp(gai_strerror(EAI_MEMORY), "Out of memory") == 0); assert(strcmp(gai_strerror(EAI_SYSTEM), "System error") == 0); assert(strcmp(gai_strerror(EAI_OVERFLOW), "Overflow") == 0); - assert(strcmp(gai_strerror(-5), "Unknown error") == 0); + assert(strcmp(gai_strerror(EAI_NODATA), "Name has no usable address") == 0); assert(strcmp(gai_strerror(-9), "Unknown error") == 0); assert(strcmp(gai_strerror(-13), "Unknown error") == 0); assert(strcmp(gai_strerror(-100), "Unknown error") == 0); diff --git a/tools/system_libs.py b/tools/system_libs.py index 982ba20e12d3d..c0b5d2c2873e2 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -1929,6 +1929,7 @@ class libsanitizer_common_rt(CompilerRTLibrary, MTLibrary): 'system/lib/compiler-rt/lib', 'system/lib/libc'] never_force = True + cflags = ['-D_LARGEFILE64_SOURCE'] src_dir = 'system/lib/compiler-rt/lib/sanitizer_common' src_glob = '*.cpp' From 6de6ccae34fefee7f1746606d9fea013637d273e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Beaufort?= Date: Tue, 11 Jul 2023 03:58:56 +0200 Subject: [PATCH 0546/1523] Change WGPUDepthStencilState.depthBias type to i32 (#19777) --- src/library_webgpu.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/library_webgpu.js b/src/library_webgpu.js index 9d4c4b0f07910..e67272f06913e 100644 --- a/src/library_webgpu.js +++ b/src/library_webgpu.js @@ -1294,7 +1294,7 @@ var LibraryWebGPU = { "stencilBack": makeStencilStateFace(dssPtr + {{{ C_STRUCTS.WGPUDepthStencilState.stencilBack }}}), "stencilReadMask": {{{ gpu.makeGetU32('dssPtr', C_STRUCTS.WGPUDepthStencilState.stencilReadMask) }}}, "stencilWriteMask": {{{ gpu.makeGetU32('dssPtr', C_STRUCTS.WGPUDepthStencilState.stencilWriteMask) }}}, - "depthBias": {{{ makeGetValue('dssPtr', C_STRUCTS.WGPUDepthStencilState.depthBias, '*') }}}, + "depthBias": {{{ makeGetValue('dssPtr', C_STRUCTS.WGPUDepthStencilState.depthBias, 'i32') }}}, "depthBiasSlopeScale": {{{ makeGetValue('dssPtr', C_STRUCTS.WGPUDepthStencilState.depthBiasSlopeScale, 'float') }}}, "depthBiasClamp": {{{ makeGetValue('dssPtr', C_STRUCTS.WGPUDepthStencilState.depthBiasClamp, 'float') }}}, }; From ac1e7085f117828ab10442fde1246999386d403a Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 11 Jul 2023 11:15:51 -0700 Subject: [PATCH 0547/1523] Don't generate function wrappers for exported tags. NFC (#19809) Back in #17064 we added tags to `metadata.exports`, which previously contained only functions. However, emscripten.py makes wrapper functions for each element of this list which is not desirable for tag exports. This change makes things more explicit by calling this `function_exports` and creating a new `metadata.all_exports`. We can also now be more precise when creating the metadce graph and include all exports (except wasm globals which are just constants), which in turn allows us to remove the hardcoded handling for the table and memory export. This should be a minor code size saving for wasm-exceptions-using programs since we no longer generate the needless function wrapper for the tag. --- emscripten.py | 32 +++++++++++--------------------- src/settings_internal.js | 4 ++-- tools/building.py | 22 ++++------------------ tools/extract_metadata.py | 10 ++++++---- tools/shared.py | 4 ++-- 5 files changed, 25 insertions(+), 47 deletions(-) diff --git a/emscripten.py b/emscripten.py index ec6592a551bbe..6d76fe6ba758c 100644 --- a/emscripten.py +++ b/emscripten.py @@ -28,7 +28,7 @@ from tools import extract_metadata from tools.utils import exit_with_error, path_from_root, removeprefix from tools.shared import DEBUG, asmjs_mangle -from tools.shared import treat_as_user_function +from tools.shared import treat_as_user_export from tools.settings import settings logger = logging.getLogger('emscripten') @@ -126,18 +126,13 @@ def update_settings_glue(wasm_file, metadata): settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE = [] else: syms = settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE + metadata.imports - syms = set(syms).difference(metadata.exports) + syms = set(syms).difference(metadata.all_exports) settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE = sorted(syms) if settings.MAIN_MODULE: get_weak_imports(wasm_file) - settings.WASM_EXPORTS = metadata.exports + list(metadata.namedGlobals.keys()) - settings.WASM_EXPORTS += list(metadata.emJsFuncs.keys()) - - # Store function exports so that Closure and metadce can track these even in - # -sDECLARE_ASM_MODULE_EXPORTS=0 builds. - settings.WASM_FUNCTION_EXPORTS = metadata.exports - + settings.WASM_EXPORTS = metadata.all_exports + settings.WASM_GLOBAL_EXPORTS = list(metadata.namedGlobals.keys()) settings.HAVE_EM_ASM = bool(settings.MAIN_MODULE or len(metadata.asmConsts) != 0) # start with the MVP features, and add any detected features. @@ -165,7 +160,7 @@ def update_settings_glue(wasm_file, metadata): if settings.STACK_OVERFLOW_CHECK and not settings.SIDE_MODULE: # writeStackCookie and checkStackCookie both rely on emscripten_stack_get_end being # exported. In theory it should always be present since its defined in compiler-rt. - assert 'emscripten_stack_get_end' in metadata.exports + assert 'emscripten_stack_get_end' in metadata.function_exports for deps in metadata.jsDeps: settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.extend(deps.split(',')) @@ -317,7 +312,7 @@ def emscript(in_wasm, out_wasm, outfile_js, memfile, js_syms): metadata.imports += ['__memory_base32'] if settings.ASYNCIFY == 1: - metadata.exports += ['asyncify_start_unwind', 'asyncify_stop_unwind', 'asyncify_start_rewind', 'asyncify_stop_rewind'] + metadata.function_exports += ['asyncify_start_unwind', 'asyncify_stop_unwind', 'asyncify_start_rewind', 'asyncify_stop_rewind'] update_settings_glue(out_wasm, metadata) @@ -390,8 +385,6 @@ def emscript(in_wasm, out_wasm, outfile_js, memfile, js_syms): pre += f" ignoredModuleProp('{sym}');\n" pre += "}\n" - exports = metadata.exports - report_missing_symbols(forwarded_json['librarySymbols']) if not outfile_js: @@ -422,11 +415,11 @@ def emscript(in_wasm, out_wasm, outfile_js, memfile, js_syms): out.write(pre) pre = None - receiving = create_receiving(exports) + receiving = create_receiving(metadata.function_exports) if settings.MINIMAL_RUNTIME: if settings.DECLARE_ASM_MODULE_EXPORTS: - post = compute_minimal_runtime_initializer_and_exports(post, exports, receiving) + post = compute_minimal_runtime_initializer_and_exports(post, metadata.function_exports, receiving) receiving = '' module = create_module(receiving, metadata, forwarded_json['librarySymbols']) @@ -546,7 +539,7 @@ def finalize_wasm(infile, outfile, memfile, js_syms): # EMSCRIPTEN_KEEPALIVE (llvm.used). # These are any exports that were not requested on the command line and are # not known auto-generated system functions. - unexpected_exports = [e for e in metadata.exports if treat_as_user_function(e)] + unexpected_exports = [e for e in metadata.all_exports if treat_as_user_export(e)] unexpected_exports = [asmjs_mangle(e) for e in unexpected_exports] unexpected_exports = [e for e in unexpected_exports if e not in expected_exports] if '_main' in unexpected_exports: @@ -702,7 +695,7 @@ def create_sending(metadata, library_symbols): # that are part of EXPORTED_FUNCTIONS (or in the case of MAIN_MODULE=1 add # all JS library functions). This allows `dlsym(RTLD_DEFAULT)` to lookup JS # library functions, since `wasmImports` acts as the global symbol table. - wasm_exports = set(metadata.exports) + wasm_exports = set(metadata.function_exports) library_symbols = set(library_symbols) if settings.MAIN_MODULE == 1: for f in library_symbols: @@ -746,9 +739,6 @@ def install_wrapper(sym): return True for name in exports: - # Tags cannot be wrapped in createExportWrapper - if name == '__cpp_exception': - continue mangled = asmjs_mangle(name) wrapper = '/** @type {function(...*):?} */\nvar %s = ' % mangled @@ -913,7 +903,7 @@ def create_pointer_conversion_wrappers(metadata): sigs_seen = set() wrap_functions = [] - for symbol in metadata.exports: + for symbol in metadata.function_exports: sig = mapping.get(symbol) if sig: if settings.MEMORY64: diff --git a/src/settings_internal.js b/src/settings_internal.js index cc02a3a404f17..1abe54889f666 100644 --- a/src/settings_internal.js +++ b/src/settings_internal.js @@ -16,8 +16,8 @@ // underscore. var WASM_EXPORTS = []; -// Similar to above but only includes the functions symbols. -var WASM_FUNCTION_EXPORTS = []; +// Similar to above but only includes the global/data symbols. +var WASM_GLOBAL_EXPORTS = []; // An array of all symbols exported from all the side modules specified on the // command line. diff --git a/tools/building.py b/tools/building.py index cbbfd0a453f20..21c54cc7771dc 100644 --- a/tools/building.py +++ b/tools/building.py @@ -517,9 +517,9 @@ def closure_compiler(filename, pretty, advanced=True, extra_closure_args=None): # Closure compiler needs to know about all exports that come from the wasm module, because to optimize for small code size, # the exported symbols are added to global scope via a foreach loop in a way that evades Closure's static analysis. With an explicit # externs file for the exports, Closure is able to reason about the exports. - if settings.WASM_FUNCTION_EXPORTS and not settings.DECLARE_ASM_MODULE_EXPORTS: + if settings.WASM_EXPORTS and not settings.DECLARE_ASM_MODULE_EXPORTS: # Generate an exports file that records all the exported symbols from the wasm module. - module_exports_suppressions = '\n'.join(['/**\n * @suppress {duplicate, undefinedVars}\n */\nvar %s;\n' % asmjs_mangle(i) for i in settings.WASM_FUNCTION_EXPORTS]) + module_exports_suppressions = '\n'.join(['/**\n * @suppress {duplicate, undefinedVars}\n */\nvar %s;\n' % asmjs_mangle(i) for i in settings.WASM_EXPORTS]) exports_file = shared.get_temp_files().get('.js', prefix='emcc_module_exports_') exports_file.write(module_exports_suppressions.encode()) exports_file.close() @@ -722,7 +722,8 @@ def metadce(js_file, wasm_file, minify_whitespace, debug_info): # will take precedence. exports = settings.WASM_EXPORTS else: - exports = settings.WASM_FUNCTION_EXPORTS + # Ignore exported wasm globals. Those get inlined directly into the JS code. + exports = sorted(set(settings.WASM_EXPORTS) - set(settings.WASM_GLOBAL_EXPORTS)) extra_info = '{ "exports": [' + ','.join(f'["{asmjs_mangle(x)}", "{x}"]' for x in exports) + ']}' @@ -735,21 +736,6 @@ def metadce(js_file, wasm_file, minify_whitespace, debug_info): export = asmjs_mangle(item['export']) if settings.EXPORT_ALL or export in required_symbols: item['root'] = True - # in standalone wasm, always export the memory - if not settings.IMPORTED_MEMORY: - graph.append({ - 'export': 'memory', - 'name': 'emcc$export$memory', - 'reaches': [], - 'root': True - }) - if not settings.RELOCATABLE: - graph.append({ - 'export': '__indirect_function_table', - 'name': 'emcc$export$__indirect_function_table', - 'reaches': [], - 'root': True - }) # fix wasi imports TODO: support wasm stable with an option? WASI_IMPORTS = { 'environ_get', diff --git a/tools/extract_metadata.py b/tools/extract_metadata.py index c9dec19856600..ed95ecfd6677f 100644 --- a/tools/extract_metadata.py +++ b/tools/extract_metadata.py @@ -247,8 +247,8 @@ def get_named_globals(module, exports): return named_globals -def get_export_names(module): - return [e.name for e in module.get_exports() if e.kind in [webassembly.ExternType.FUNC, webassembly.ExternType.TAG]] +def get_function_exports(module): + return [e.name for e in module.get_exports() if e.kind == webassembly.ExternType.FUNC] def update_metadata(filename, metadata): @@ -264,7 +264,8 @@ def update_metadata(filename, metadata): elif i.kind in (webassembly.ExternType.GLOBAL, webassembly.ExternType.TAG): imports.append(i.field) - metadata.exports = get_export_names(module) + metadata.function_exports = get_function_exports(module) + metadata.all_exports = [utils.removeprefix(e.name, '__em_js__') for e in module.get_exports()] metadata.imports = imports metadata.invokeFuncs = invoke_funcs @@ -333,7 +334,8 @@ def extract_metadata(filename): # calls __original_main (which has no parameters). metadata = Metadata() metadata.imports = import_names - metadata.exports = get_export_names(module) + metadata.function_exports = get_function_exports(module) + metadata.all_exports = [utils.removeprefix(e.name, '__em_js__') for e in exports] metadata.asmConsts = get_section_strings(module, export_map, 'em_asm') metadata.jsDeps = [d for d in get_section_strings(module, export_map, 'em_lib_deps').values() if d] metadata.emJsFuncs = em_js_funcs diff --git a/tools/shared.py b/tools/shared.py index 0e0c2ac24a0f4..157d57f9eceb4 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -628,7 +628,7 @@ def is_c_symbol(name): return name.startswith('_') or name in settings.WASM_SYSTEM_EXPORTS -def treat_as_user_function(name): +def treat_as_user_export(name): if name.startswith('dynCall_'): return False if name in settings.WASM_SYSTEM_EXPORTS: @@ -646,7 +646,7 @@ def asmjs_mangle(name): # to simply `main` which is expected by the emscripten JS glue code. if name == '__main_argc_argv': name = 'main' - if treat_as_user_function(name): + if treat_as_user_export(name): return '_' + name return name From b6f2c021bc287a3ce11e4d12a9c1a0f23f1b3a01 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 11 Jul 2023 12:21:53 -0700 Subject: [PATCH 0548/1523] `SUPPORT_BASE64_EMBEDDING` no longer depends on `intArrayToString`. NFC (#19829) Should really have been part of #19792 --- emcc.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/emcc.py b/emcc.py index 5e347e303d72f..2069014e72469 100755 --- a/emcc.py +++ b/emcc.py @@ -3175,10 +3175,7 @@ def phase_emscript(options, in_wasm, wasm_target, memfile, js_syms): # Emscripten logger.debug('emscript') - if embed_memfile(options): - settings.SUPPORT_BASE64_EMBEDDING = 1 - # _read in shell.js depends on intArrayToString when SUPPORT_BASE64_EMBEDDING is set - settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.append('$intArrayToString') + settings.SUPPORT_BASE64_EMBEDDING = embed_memfile(options) emscripten.run(in_wasm, wasm_target, final_js, memfile, js_syms) save_intermediate('original') From 9c3f23180772cc5725a0af421e20268676408a7b Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 11 Jul 2023 16:30:20 -0700 Subject: [PATCH 0549/1523] Avoid the use of `arguments` global in `__cxa_find_matching_catch`. NFC (#19760) Instead, stamp about unique functions that call the internal `findMatchingCatch` with and array of arguments. The use of `arguments` is problematic as it is not available in strict mode, and also within arrow functions. It can also, IIUC, generate garbage at runtime. --- emscripten.py | 1 + src/jsifier.js | 17 +++++-- src/library_dylink.js | 21 ++++++-- src/library_exceptions.js | 50 +++++++++++-------- test/common.py | 4 +- .../metadce/test_metadce_cxx_except.jssize | 2 +- .../metadce/test_metadce_cxx_mangle.jssize | 2 +- .../metadce/test_metadce_hello_O0.jssize | 2 +- .../metadce/test_metadce_minimal_O0.jssize | 2 +- 9 files changed, 66 insertions(+), 35 deletions(-) diff --git a/emscripten.py b/emscripten.py index 6d76fe6ba758c..e9b58b9da8032 100644 --- a/emscripten.py +++ b/emscripten.py @@ -893,6 +893,7 @@ def create_pointer_conversion_wrappers(metadata): '_wasmfs_mkdir': '_p_', '_wasmfs_open': '_p__', 'emscripten_wasm_worker_initialize': '_p_', + '__get_exception_message': '_ppp', } wrappers = ''' diff --git a/src/jsifier.js b/src/jsifier.js index edb6a5fa11edc..fd0d992b9df6a 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -164,6 +164,12 @@ function runJSify() { // For functions that where we need to mutate the return value, we // also need to wrap the body in an inner function. if (oneliner) { + if (argConvertions) { + return `${async_}(${args}) => { +${argConvertions} + return ${makeReturn64(body)}; +}` + } return `${async_}(${args}) => ${makeReturn64(body)};` } return `\ @@ -274,15 +280,18 @@ function(${args}) { // In LLVM, exceptions generate a set of functions of form // __cxa_find_matching_catch_1(), __cxa_find_matching_catch_2(), etc. where // the number specifies the number of arguments. In Emscripten, route all - // these to a single function '__cxa_find_matching_catch' that variadically - // processes all of these functions using JS 'arguments' object. + // these to a single function 'findMatchingCatch' that takes an array + // of argument. if (!WASM_EXCEPTIONS && symbol.startsWith('__cxa_find_matching_catch_')) { if (DISABLE_EXCEPTION_THROWING) { error('DISABLE_EXCEPTION_THROWING was set (likely due to -fno-exceptions), which means no C++ exception throwing support code is linked in, but exception catching code appears. Either do not set DISABLE_EXCEPTION_THROWING (if you do want exception throwing) or compile all source files with -fno-except (so that no exceptions support code is required); also make sure DISABLE_EXCEPTION_CATCHING is set to the right value - if you want exceptions, it should be off, and vice versa.'); return; } - const num = +symbol.split('_').slice(-1)[0]; - addCxaCatch(num); + if (!(symbol in LibraryManager.library)) { + // Create a new __cxa_find_matching_catch variant on demand. + const num = +symbol.split('_').slice(-1)[0]; + addCxaCatch(num); + } // Continue, with the code below emitting the proper JavaScript based on // what we just added to the library. } diff --git a/src/library_dylink.js b/src/library_dylink.js index 119728ed19cc1..d95f87a67cb91 100644 --- a/src/library_dylink.js +++ b/src/library_dylink.js @@ -117,11 +117,6 @@ var LibraryDylink = { if (direct && ('orig$' + symName in wasmImports)) { symName = 'orig$' + symName; } -#endif -#if !DISABLE_EXCEPTION_CATCHING - if (symName.startsWith('__cxa_find_matching_catch_')) { - symName = '__cxa_find_matching_catch'; - } #endif if (isSymbolDefined(symName)) { sym = wasmImports[symName]; @@ -132,6 +127,22 @@ var LibraryDylink = { // Create (and cache) new invoke_ functions on demand. sym = wasmImports[symName] = createInvokeFunction(symName.split('_')[1]); } +#endif +#if !DISABLE_EXCEPTION_CATCHING + else if (symName.startsWith('__cxa_find_matching_catch_')) { + // When the main module is linked we create whichever variants of + // `__cxa_find_matching_catch_` (see jsifier.js) that we know are needed, + // but a side module loaded at runtime might need different/additional + // variants so we create those dynamically. + sym = wasmImports[symName] = function() { + var args = Array.from(arguments); +#if MEMORY64 + args = args.map(Number); +#endif + var rtn = findMatchingCatch(args); + return {{{ to64('rtn') }}}; + } + } #endif return {sym, name: symName}; }, diff --git a/src/library_exceptions.js b/src/library_exceptions.js index 68a2162d6e258..3b796c8422ace 100644 --- a/src/library_exceptions.js +++ b/src/library_exceptions.js @@ -194,7 +194,7 @@ var LibraryExceptions = { __cxa_get_exception_ptr: function(ptr) { var rtn = new ExceptionInfo(ptr).get_exception_ptr(); #if EXCEPTION_DEBUG - err('__cxa_get_exception_ptr ' + ptrToString(ptr) + ' -> ' + ptrToString(rtn)); + dbg('__cxa_get_exception_ptr ' + ptrToString(ptr) + ' -> ' + ptrToString(rtn)); #endif return rtn; }, @@ -242,12 +242,8 @@ var LibraryExceptions = { // unwinding using 'if' blocks around each function, so the remaining // functionality boils down to picking a suitable 'catch' block. // We'll do that here, instead, to keep things simpler. - __cxa_find_matching_catch__deps: ['$exceptionLast', '$ExceptionInfo', '__resumeException', '__cxa_can_catch', 'setTempRet0'], - __cxa_find_matching_catch: function() { - // Here we use explicit calls to `from64`/`to64` rather then using the - // `__sig` attribute to perform these automatically. This is because the - // `__sig` wrapper uses arrow function notation, which is not compatible - // with the use of `arguments` in this function. + $findMatchingCatch__deps: ['$exceptionLast', '$ExceptionInfo', '__resumeException', '__cxa_can_catch', 'setTempRet0'], + $findMatchingCatch: (args) => { var thrown = #if EXCEPTION_STACK_TRACES exceptionLast && exceptionLast.excPtr; @@ -257,7 +253,7 @@ var LibraryExceptions = { if (!thrown) { // just pass through the null ptr setTempRet0(0); - return {{{ to64(0) }}}; + return 0; } var info = new ExceptionInfo(thrown); info.set_adjusted_ptr(thrown); @@ -265,20 +261,19 @@ var LibraryExceptions = { if (!thrownType) { // just pass through the thrown ptr setTempRet0(0); - return {{{ to64('thrown') }}}; + return thrown; } // can_catch receives a **, add indirection #if EXCEPTION_DEBUG - dbg("__cxa_find_matching_catch on " + ptrToString(thrown)); + dbg("findMatchingCatch on " + ptrToString(thrown)); #endif // The different catch blocks are denoted by different types. // Due to inheritance, those types may not precisely match the // type of the thrown object. Find one which matches, and // return the type of the catch block which should be called. - for (var i = 0; i < arguments.length; i++) { - var caughtType = arguments[i]; - {{{ from64('caughtType') }}}; + for (var arg in args) { + var caughtType = args[arg]; if (caughtType === 0 || caughtType === thrownType) { // Catch all clause matched or exactly the same type is caught @@ -287,14 +282,14 @@ var LibraryExceptions = { var adjusted_ptr_addr = info.ptr + {{{ C_STRUCTS.__cxa_exception.adjustedPtr }}}; if (___cxa_can_catch(caughtType, thrownType, adjusted_ptr_addr)) { #if EXCEPTION_DEBUG - dbg(" __cxa_find_matching_catch found " + [ptrToString(info.get_adjusted_ptr()), caughtType]); + dbg(" findMatchingCatch found " + [ptrToString(info.get_adjusted_ptr()), caughtType]); #endif setTempRet0(caughtType); - return {{{ to64('thrown') }}}; + return thrown; } } setTempRet0(thrownType); - return {{{ to64('thrown') }}}; + return thrown; }, __resumeException__deps: ['$exceptionLast'], @@ -303,7 +298,7 @@ var LibraryExceptions = { #if EXCEPTION_DEBUG dbg("__resumeException " + [ptrToString(ptr), exceptionLast]); #endif - if (!exceptionLast) { + if (!exceptionLast) { {{{ storeException('exceptionLast', 'ptr') }}} } {{{ makeThrow('exceptionLast') }}} @@ -315,7 +310,7 @@ var LibraryExceptions = { $getExceptionMessageCommon: (ptr) => withStackSave(() => { var type_addr_addr = stackAlloc({{{ POINTER_SIZE }}}); var message_addr_addr = stackAlloc({{{ POINTER_SIZE }}}); - ___get_exception_message({{{ to64('ptr') }}}, {{{ to64('type_addr_addr') }}}, {{{ to64('message_addr_addr') }}}); + ___get_exception_message(ptr, type_addr_addr, message_addr_addr); var type_addr = {{{ makeGetValue('type_addr_addr', 0, '*') }}}; var message_addr = {{{ makeGetValue('message_addr_addr', 0, '*') }}}; var type = UTF8ToString(type_addr); @@ -422,8 +417,23 @@ var LibraryExceptions = { // number specifies the number of arguments. In Emscripten, route all these to // a single function '__cxa_find_matching_catch' that variadically processes all // of these functions using JS 'arguments' object. -addCxaCatch = function(n) { - LibraryManager.library['__cxa_find_matching_catch_' + n] = '__cxa_find_matching_catch'; +addCxaCatch = (n) => { + const args = []; + // Confusingly, the actual number of asrgument is n - 2. According to the llvm + // code in WebAssemblyLowerEmscriptenEHSjLj.cpp: + // This is because a landingpad instruction contains two more arguments, a + // personality function and a cleanup bit, and __cxa_find_matching_catch_N + // functions are named after the number of arguments in the original landingpad + // instruction. + let sig = 'p'; + for (let i = 0; i < n - 2; i++) { + args.push(`arg${i}`); + sig += 'p'; + } + const argString = args.join(','); + LibraryManager.library[`__cxa_find_matching_catch_${n}__sig`] = sig; + LibraryManager.library[`__cxa_find_matching_catch_${n}__deps`] = ['$findMatchingCatch']; + LibraryManager.library[`__cxa_find_matching_catch_${n}`] = eval(`(${args}) => findMatchingCatch([${argString}])`); }; // Add the first 2-5 catch handlers premptively. Others get added on demand in diff --git a/test/common.py b/test/common.py index 9cbc5e00ae3da..18011ab6bbd2f 100644 --- a/test/common.py +++ b/test/common.py @@ -651,9 +651,9 @@ def require_wasm_eh(self): return if 'EMTEST_SKIP_EH' in os.environ: - self.skipTest('test requires node >= 16 or d8 (and EMTEST_SKIP_EH is set)') + self.skipTest('test requires node >= 17 or d8 (and EMTEST_SKIP_EH is set)') else: - self.fail('either d8 or node >= 16 required to run wasm-eh tests. Use EMTEST_SKIP_EH to skip') + self.fail('either d8 or node >= 17 required to run wasm-eh tests. Use EMTEST_SKIP_EH to skip') def require_jspi(self): if not self.is_wasm(): diff --git a/test/other/metadce/test_metadce_cxx_except.jssize b/test/other/metadce/test_metadce_cxx_except.jssize index 8b099f187cde1..6725bb96222e1 100644 --- a/test/other/metadce/test_metadce_cxx_except.jssize +++ b/test/other/metadce/test_metadce_cxx_except.jssize @@ -1 +1 @@ -29717 +29699 diff --git a/test/other/metadce/test_metadce_cxx_mangle.jssize b/test/other/metadce/test_metadce_cxx_mangle.jssize index d1094910961a1..6007cf304f276 100644 --- a/test/other/metadce/test_metadce_cxx_mangle.jssize +++ b/test/other/metadce/test_metadce_cxx_mangle.jssize @@ -1 +1 @@ -29716 +29698 diff --git a/test/other/metadce/test_metadce_hello_O0.jssize b/test/other/metadce/test_metadce_hello_O0.jssize index 2906db3ee25dd..952e9263c84bc 100644 --- a/test/other/metadce/test_metadce_hello_O0.jssize +++ b/test/other/metadce/test_metadce_hello_O0.jssize @@ -1 +1 @@ -23701 +23719 diff --git a/test/other/metadce/test_metadce_minimal_O0.jssize b/test/other/metadce/test_metadce_minimal_O0.jssize index c92cbadeec027..33fed85da8acd 100644 --- a/test/other/metadce/test_metadce_minimal_O0.jssize +++ b/test/other/metadce/test_metadce_minimal_O0.jssize @@ -1 +1 @@ -20123 +20141 From 8a5b72746768fe46b804abbbef38ff3d6488da30 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 11 Jul 2023 16:30:42 -0700 Subject: [PATCH 0550/1523] WasmFS: Add missing heartbeat dep (#19836) --- src/library_wasmfs.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/library_wasmfs.js b/src/library_wasmfs.js index f8f3ab2c65104..970520c9d2a4a 100644 --- a/src/library_wasmfs.js +++ b/src/library_wasmfs.js @@ -417,6 +417,7 @@ FS.createPreloadedFile = FS_createPreloadedFile; HEAPU8.set(wasmFSPreloadedFiles[index].fileData, buffer); }, + _wasmfs_thread_utils_heartbeat__deps: ['emscripten_proxy_execute_queue'], _wasmfs_thread_utils_heartbeat: (queue) => { var intervalID = setInterval(() => { From f38ebefa9101b8fed3085a4f90c17dcb7e000d41 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 11 Jul 2023 18:50:45 -0700 Subject: [PATCH 0551/1523] Avoid use of JS `arguments` in export wrappers (#19830) This allows the wrappers to be implemented as arrow functions, which saves some code size, and also avoids creating garbage when these functions are first called. --- emscripten.py | 26 +++++++------ src/deterministic.js | 2 +- src/library_exceptions.js | 2 +- src/library_pthread.js | 4 +- src/library_trace.js | 2 +- src/runtime_safe_heap.js | 4 +- .../optimizer/applyDCEGraphRemovals-output.js | 16 ++------ test/optimizer/applyDCEGraphRemovals.js | 25 ++++-------- test/optimizer/emitDCEGraph.js | 29 +++++--------- test/optimizer/emitDCEGraph2.js | 8 ++-- test/optimizer/emitDCEGraph3.js | 8 ++-- test/optimizer/emitDCEGraph4.js | 8 ++-- test/optimizer/emitDCEGraph5.js | 8 ++-- .../metadce/test_metadce_cxx_ctors1.jssize | 2 +- .../metadce/test_metadce_cxx_ctors2.jssize | 2 +- .../metadce/test_metadce_cxx_except.jssize | 2 +- .../test_metadce_cxx_except_wasm.jssize | 2 +- .../metadce/test_metadce_cxx_mangle.jssize | 2 +- .../metadce/test_metadce_cxx_noexcept.jssize | 2 +- .../metadce/test_metadce_cxx_wasmfs.jssize | 2 +- .../metadce/test_metadce_files_js_fs.jssize | 2 +- .../metadce/test_metadce_files_wasmfs.jssize | 2 +- .../metadce/test_metadce_hello_O0.jssize | 2 +- .../metadce/test_metadce_hello_O1.jssize | 2 +- .../metadce/test_metadce_hello_O2.jssize | 2 +- .../metadce/test_metadce_hello_O3.jssize | 2 +- .../metadce/test_metadce_hello_Os.jssize | 2 +- .../metadce/test_metadce_hello_Oz.jssize | 2 +- .../metadce/test_metadce_hello_dylink.jssize | 2 +- .../metadce/test_metadce_hello_wasmfs.jssize | 2 +- .../test_metadce_libcxxabi_message_O3.jssize | 2 +- ...dce_libcxxabi_message_O3_standalone.jssize | 2 +- test/other/metadce/test_metadce_mem_O3.jssize | 2 +- .../metadce/test_metadce_mem_O3_grow.jssize | 2 +- ...test_metadce_mem_O3_grow_standalone.jssize | 2 +- .../test_metadce_mem_O3_standalone.jssize | 2 +- .../test_metadce_mem_O3_standalone_lib.jssize | 2 +- ...test_metadce_mem_O3_standalone_narg.jssize | 2 +- ...metadce_mem_O3_standalone_narg_flto.jssize | 2 +- .../metadce/test_metadce_minimal_64.jssize | 2 +- .../metadce/test_metadce_minimal_O0.jssize | 2 +- .../metadce/test_metadce_minimal_O1.jssize | 2 +- .../metadce/test_metadce_minimal_O2.jssize | 2 +- .../metadce/test_metadce_minimal_O3.jssize | 2 +- .../metadce/test_metadce_minimal_Os.jssize | 2 +- .../test_metadce_minimal_Oz-ctors.jssize | 2 +- .../metadce/test_metadce_minimal_Oz.jssize | 2 +- .../test_metadce_minimal_pthreads.jssize | 2 +- .../test_metadce_minimal_wasmfs.jssize | 2 +- test/other/test_unoptimized_code_size.js.size | 2 +- ...t_unoptimized_code_size_no_asserts.js.size | 2 +- .../test_unoptimized_code_size_strict.js.size | 2 +- test/test_browser.py | 2 +- test/test_other.py | 3 +- tools/acorn-optimizer.js | 38 ++++++------------- tools/extract_metadata.py | 6 ++- 56 files changed, 118 insertions(+), 151 deletions(-) diff --git a/emscripten.py b/emscripten.py index e9b58b9da8032..d5f744d24fe04 100644 --- a/emscripten.py +++ b/emscripten.py @@ -312,7 +312,10 @@ def emscript(in_wasm, out_wasm, outfile_js, memfile, js_syms): metadata.imports += ['__memory_base32'] if settings.ASYNCIFY == 1: - metadata.function_exports += ['asyncify_start_unwind', 'asyncify_stop_unwind', 'asyncify_start_rewind', 'asyncify_stop_rewind'] + metadata.function_exports['asyncify_start_unwind'] = 1 + metadata.function_exports['asyncify_stop_unwind'] = 0 + metadata.function_exports['asyncify_start_rewind'] = 1 + metadata.function_exports['asyncify_stop_rewind'] = 0 update_settings_glue(out_wasm, metadata) @@ -720,7 +723,7 @@ def create_sending(metadata, library_symbols): return '{\n ' + ',\n '.join(f'{prefix}{k}: {v}' for k, v in sorted_items) + '\n}' -def make_export_wrappers(exports, delay_assignment): +def make_export_wrappers(function_exports, delay_assignment): wrappers = [] # The emscripten stack functions are called very early (by writeStackCookie) before @@ -738,9 +741,9 @@ def install_wrapper(sym): return False return True - for name in exports: + for name, nargs in function_exports.items(): mangled = asmjs_mangle(name) - wrapper = '/** @type {function(...*):?} */\nvar %s = ' % mangled + wrapper = 'var %s = ' % mangled # TODO(sbc): Can we avoid exporting the dynCall_ functions on the module. should_export = settings.EXPORT_KEEPALIVE and mangled in settings.EXPORTED_FUNCTIONS @@ -757,10 +760,9 @@ def install_wrapper(sym): elif delay_assignment: # With assertions disabled the wrapper will replace the global var and Module var on # first use. - wrapper += f'''function() {{ - return ({mangled} = {exported}Module['asm']['{name}']).apply(null, arguments); -}}; -''' + args = [f'a{i}' for i in range(nargs)] + args = ', '.join(args) + wrapper += f"({args}) => ({mangled} = {exported}Module['asm']['{name}'])({args});" else: wrapper += 'asm["%s"]' % name @@ -768,7 +770,7 @@ def install_wrapper(sym): return wrappers -def create_receiving(exports): +def create_receiving(function_exports): # When not declaring asm exports this section is empty and we instead programatically export # symbols on the global object by calling exportAsmFunctions after initialization if not settings.DECLARE_ASM_MODULE_EXPORTS: @@ -788,7 +790,7 @@ def create_receiving(exports): # var asm = output.instance.exports; # _main = asm["_main"]; generate_dyncall_assignment = settings.DYNCALLS and '$dynCall' in settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE - exports_that_are_not_initializers = [x for x in exports if x != building.WASM_CALL_CTORS] + exports_that_are_not_initializers = [x for x in function_exports if x != building.WASM_CALL_CTORS] for s in exports_that_are_not_initializers: mangled = asmjs_mangle(s) @@ -799,9 +801,9 @@ def create_receiving(exports): export_assignment = f"Module['{mangled}'] = " receiving += [f'{export_assignment}{dynCallAssignment}{mangled} = asm["{s}"]'] else: - receiving += make_export_wrappers(exports, delay_assignment) + receiving += make_export_wrappers(function_exports, delay_assignment) else: - receiving += make_export_wrappers(exports, delay_assignment) + receiving += make_export_wrappers(function_exports, delay_assignment) if settings.MINIMAL_RUNTIME: return '\n '.join(receiving) + '\n' diff --git a/src/deterministic.js b/src/deterministic.js index ed0df9c6bc92e..4a99e37487b9b 100644 --- a/src/deterministic.js +++ b/src/deterministic.js @@ -26,7 +26,7 @@ Module['thisProgram'] = 'thisProgram'; // for consistency between different buil function hashMemory(id) { var ret = 0; - var len = _sbrk(); + var len = _sbrk(0); for (var i = 0; i < len; i++) { ret = (ret*17 + HEAPU8[i])|0; } diff --git a/src/library_exceptions.js b/src/library_exceptions.js index 3b796c8422ace..18a5df50cc702 100644 --- a/src/library_exceptions.js +++ b/src/library_exceptions.js @@ -175,7 +175,7 @@ var LibraryExceptions = { __cxa_end_catch__sig: 'v', __cxa_end_catch: function() { // Clear state flag. - _setThrew(0); + _setThrew(0, 0); #if ASSERTIONS assert(exceptionCaught.length > 0); #endif diff --git a/src/library_pthread.js b/src/library_pthread.js index a7afb838226ff..ac1505428216a 100644 --- a/src/library_pthread.js +++ b/src/library_pthread.js @@ -721,7 +721,9 @@ var LibraryPThread = { /*canBlock=*/!ENVIRONMENT_IS_WEB, {{{ DEFAULT_PTHREAD_STACK_SIZE }}}, #if PTHREADS_PROFILING - /*start_profiling=*/true + /*start_profiling=*/true, +#else + /*start_profiling=*/false, #endif ); PThread.threadInitTLS(); diff --git a/src/library_trace.js b/src/library_trace.js index 781bb5f66d489..ff67363c97318 100644 --- a/src/library_trace.js +++ b/src/library_trace.js @@ -266,7 +266,7 @@ var LibraryTracing = { 'stack_base': _emscripten_stack_get_base(), 'stack_top': _emscripten_stack_get_current(), 'stack_max': _emscripten_stack_get_end(), - 'dynamic_top': _sbrk(), + 'dynamic_top': _sbrk(0), 'total_memory': HEAP8.length }; var now = EmscriptenTrace.now(); diff --git a/src/runtime_safe_heap.js b/src/runtime_safe_heap.js index a02e142e0c732..547586f11e529 100644 --- a/src/runtime_safe_heap.js +++ b/src/runtime_safe_heap.js @@ -42,7 +42,7 @@ function SAFE_HEAP_STORE(dest, value, bytes, isFloat) { #else if (runtimeInitialized) { #endif - var brk = _sbrk(); + var brk = _sbrk(0); if (dest + bytes > brk) abort(`segmentation fault, exceeded the top of the available dynamic heap when storing ${bytes} bytes to address ${dest}. DYNAMICTOP=${brk}`); assert(brk >= _emscripten_stack_get_base(), `brk >= _emscripten_stack_get_base() (brk=${brk}, _emscripten_stack_get_base()=${_emscripten_stack_get_base()})`); // sbrk-managed memory must be above the stack assert(brk <= wasmMemory.buffer.byteLength, `brk <= wasmMemory.buffer.byteLength (brk=${brk}, wasmMemory.buffer.byteLength=${wasmMemory.buffer.byteLength})`); @@ -70,7 +70,7 @@ function SAFE_HEAP_LOAD(dest, bytes, unsigned, isFloat) { #else if (runtimeInitialized) { #endif - var brk = _sbrk(); + var brk = _sbrk(0); if (dest + bytes > brk) abort(`segmentation fault, exceeded the top of the available dynamic heap when loading ${bytes} bytes from address ${dest}. DYNAMICTOP=${brk}`); assert(brk >= _emscripten_stack_get_base(), `brk >= _emscripten_stack_get_base() (brk=${brk}, _emscripten_stack_get_base()=${_emscripten_stack_get_base()})`); // sbrk-managed memory must be above the stack assert(brk <= wasmMemory.buffer.byteLength, `brk <= wasmMemory.buffer.byteLength (brk=${brk}, wasmMemory.buffer.byteLength=${wasmMemory.buffer.byteLength})`); diff --git a/test/optimizer/applyDCEGraphRemovals-output.js b/test/optimizer/applyDCEGraphRemovals-output.js index f0e92efe82b9e..8037ddb96f47f 100644 --- a/test/optimizer/applyDCEGraphRemovals-output.js +++ b/test/optimizer/applyDCEGraphRemovals-output.js @@ -17,23 +17,15 @@ var expD5 = asm["expD5"]; var expD6; -var expI1 = Module["expI1"] = function() { - return (expI1 = Module["expI1"] = Module["asm"]["expI1"]).apply(null, arguments); -}; +var expI1 = Module["expI1"] = () => (expI1 = Module["expI1"] = Module["asm"]["expI1"])(); -var expI2 = Module["expI2"] = function() { - return (expI2 = Module["expI2"] = Module["asm"]["expI2"]).apply(null, arguments); -}; +var expI2 = Module["expI2"] = () => (expI2 = Module["expI2"] = Module["asm"]["expI2"])(); -var expI3 = Module["expI3"] = function() { - return (expI3 = Module["expI3"] = Module["asm"]["expI3"]).apply(null, arguments); -}; +var expI3 = Module["expI3"] = () => (expI3 = Module["expI3"] = Module["asm"]["expI3"])(); var expI4; -var expI5 = function() { - return (expI5 = Module["asm"]["expI5"]).apply(null, arguments); -}; +var expI5 = () => (expI5 = Module["asm"]["expI5"])(); var expI6; diff --git a/test/optimizer/applyDCEGraphRemovals.js b/test/optimizer/applyDCEGraphRemovals.js index 64264dac31cea..7fe977e3e33fb 100644 --- a/test/optimizer/applyDCEGraphRemovals.js +++ b/test/optimizer/applyDCEGraphRemovals.js @@ -11,25 +11,14 @@ var expD5 = asm['expD5']; var expD6 = asm['expD6']; // exports gotten indirectly (async compilation -var expI1 = Module['expI1'] = (function() { - return (expI1 = Module['expI1'] = Module['asm']['expI1']).apply(null, arguments); -}); -var expI2 = Module['expI2'] = (function() { - return (expI2 = Module['expI2'] = Module['asm']['expI2']).apply(null, arguments); -}); -var expI3 = Module['expI3'] = (function() { - return (expI3 = Module['expI3'] = Module['asm']['expI3']).apply(null, arguments); -}); -var expI4 = Module['expI4'] = (function() { - return (expI4 = Module['expI4'] = Module['asm']['expI4']).apply(null, arguments); -}); +var expI1 = Module['expI1'] = () => (expI1 = Module['expI1'] = Module['asm']['expI1'])(); +var expI2 = Module['expI2'] = () => (expI2 = Module['expI2'] = Module['asm']['expI2'])(); +var expI3 = Module['expI3'] = () => (expI3 = Module['expI3'] = Module['asm']['expI3'])(); +var expI4 = Module['expI4'] = () => (expI4 = Module['expI4'] = Module['asm']['expI4'])(); + // Like above, but not exported on the Module -var expI5 = (function() { - return (expI5 = Module['asm']['expI5']).apply(null, arguments); -}); -var expI6 = (function() { - return (expI6 = Module['asm']['expI6']).apply(null, arguments); -}); +var expI5 = () => (expI5 = Module['asm']['expI5'])(); +var expI6 = () => (expI6 = Module['asm']['expI6'])(); // add uses for some of them, leave *4 as non-roots expD1; diff --git a/test/optimizer/emitDCEGraph.js b/test/optimizer/emitDCEGraph.js index cabb1ea20609e..5a696f3d6149b 100644 --- a/test/optimizer/emitDCEGraph.js +++ b/test/optimizer/emitDCEGraph.js @@ -53,22 +53,13 @@ var expD4 = Module['expD4'] = asm['expD4']; var expD5 = asm['expD5']; // exports gotten indirectly (async compilation -var expI1 = Module['expI1'] = function() { - return (expI1 = Module['expI1'] = Module['asm']['expI1']).apply(null, arguments); -}; -var expI2 = Module['expI2'] = function() { - return (expI2 = Module['expI2'] = Module['asm']['expI2']).apply(null, arguments); -}; -var expI3 = Module['expI3'] = function() { - return (expI3 = Module['expI3'] = Module['asm']['expI3']).apply(null, arguments); -}; -var expI4 = Module['expI4'] = function() { - return (expI4 = Module['expI4'] = Module['asm']['expI4']).apply(null, arguments); -}; +var expI1 = Module['expI1'] = () => (expI1 = Module['expI1'] = Module['asm']['expI1'])(); +var expI2 = Module['expI2'] = () => (expI2 = Module['expI2'] = Module['asm']['expI2'])(); +var expI3 = Module['expI3'] = () => (expI3 = Module['expI3'] = Module['asm']['expI3'])(); +var expI4 = Module['expI4'] = () => (expI4 = Module['expI4'] = Module['asm']['expI4'])(); + // Same as above but not export on the Module. -var expI5 = function() { - return (expI5 = Module['asm']['expI5']).apply(null, arguments); -}; +var expI5 = () => (expI5 = Module['asm']['expI5'])(); // add uses for some of them expD1; @@ -95,10 +86,10 @@ var func = function() { }; // dyncalls -var dynCall_v = Module["dynCall_v"] = function() { return Module["asm"]["dynCall_v"].apply(null, arguments) }; -var dynCall_vi = Module["dynCall_vi"] = function() { return Module["asm"]["dynCall_vi"].apply(null, arguments) }; -var dynCall_vii = Module["dynCall_vii"] = function() { return Module["asm"]["dynCall_vii"].apply(null, arguments) }; -var dynCall_viii = Module["dynCall_viii"] = function() { return Module["asm"]["dynCall_viii"].apply(null, arguments) }; +var dynCall_v = Module["dynCall_v"] = () => Module["asm"]["dynCall_v"](); +var dynCall_vi = Module["dynCall_vi"] = () => Module["asm"]["dynCall_vi"](); +var dynCall_vii = Module["dynCall_vii"] = () => Module["asm"]["dynCall_vii"](); +var dynCall_viii = Module["dynCall_viii"] = () => Module["asm"]["dynCall_viii"](); dynCall_v(ptr); // use directly Module['dynCall_vi'](ptr, 1); // use on module diff --git a/test/optimizer/emitDCEGraph2.js b/test/optimizer/emitDCEGraph2.js index 8d424969f9986..36c0c5b82553b 100644 --- a/test/optimizer/emitDCEGraph2.js +++ b/test/optimizer/emitDCEGraph2.js @@ -1,8 +1,8 @@ // dyncalls -var dynCall_v = Module["dynCall_v"] = function() { return Module["asm"]["dynCall_v"].apply(null, arguments) }; -var dynCall_vi = Module["dynCall_vi"] = function() { return Module["asm"]["dynCall_vi"].apply(null, arguments) }; -var dynCall_vii = Module["dynCall_vii"] = function() { return Module["asm"]["dynCall_vii"].apply(null, arguments) }; -var dynCall_viii = Module["dynCall_viii"] = function() { return Module["asm"]["dynCall_viii"].apply(null, arguments) }; +var dynCall_v = Module["dynCall_v"] = () => Module["asm"]["dynCall_v"](); +var dynCall_vi = Module["dynCall_vi"] = () => Module["asm"]["dynCall_vi"](); +var dynCall_vii = Module["dynCall_vii"] = () => Module["asm"]["dynCall_vii"](); +var dynCall_viii = Module["dynCall_viii"] = () => Module["asm"]["dynCall_viii"](); // a dynamic dynCall function dynCall(sig) { diff --git a/test/optimizer/emitDCEGraph3.js b/test/optimizer/emitDCEGraph3.js index 83c4c5a193f8a..86649d06adf11 100644 --- a/test/optimizer/emitDCEGraph3.js +++ b/test/optimizer/emitDCEGraph3.js @@ -1,8 +1,8 @@ // dyncalls -var dynCall_v = Module["dynCall_v"] = function() { return Module["asm"]["dynCall_v"].apply(null, arguments) }; -var dynCall_vi = Module["dynCall_vi"] = function() { return Module["asm"]["dynCall_vi"].apply(null, arguments) }; -var dynCall_vii = Module["dynCall_vii"] = function() { return Module["asm"]["dynCall_vii"].apply(null, arguments) }; -var dynCall_viii = Module["dynCall_viii"] = function() { return Module["asm"]["dynCall_viii"].apply(null, arguments) }; +var dynCall_v = Module["dynCall_v"] = () => Module["asm"]["dynCall_v"](); +var dynCall_vi = Module["dynCall_vi"] = () => Module["asm"]["dynCall_vi"](); +var dynCall_vii = Module["dynCall_vii"] = () => Module["asm"]["dynCall_vii"](); +var dynCall_viii = Module["dynCall_viii"] = () => Module["asm"]["dynCall_viii"](); // a dynamic dynCall function dynCall(sig) { diff --git a/test/optimizer/emitDCEGraph4.js b/test/optimizer/emitDCEGraph4.js index 50109e954b32e..01a2b5ba3c4e2 100644 --- a/test/optimizer/emitDCEGraph4.js +++ b/test/optimizer/emitDCEGraph4.js @@ -1,8 +1,8 @@ // dyncalls -var dynCall_v = Module["dynCall_v"] = function() { return Module["asm"]["dynCall_v"].apply(null, arguments) }; -var dynCall_vi = Module["dynCall_vi"] = function() { return Module["asm"]["dynCall_vi"].apply(null, arguments) }; -var dynCall_vii = Module["dynCall_vii"] = function() { return Module["asm"]["dynCall_vii"].apply(null, arguments) }; -var dynCall_viii = Module["dynCall_viii"] = function() { return Module["asm"]["dynCall_viii"].apply(null, arguments) }; +var dynCall_v = Module["dynCall_v"] = () => Module["asm"]["dynCall_v"](); +var dynCall_vi = Module["dynCall_vi"] = () => Module["asm"]["dynCall_vi"](); +var dynCall_vii = Module["dynCall_vii"] = () => Module["asm"]["dynCall_vii"](); +var dynCall_viii = Module["dynCall_viii"] = () => Module["asm"]["dynCall_viii"](); // a dynamic dynCall function dynCall(sig) { diff --git a/test/optimizer/emitDCEGraph5.js b/test/optimizer/emitDCEGraph5.js index 5e8e6d93d0c18..1fe3255725eb4 100644 --- a/test/optimizer/emitDCEGraph5.js +++ b/test/optimizer/emitDCEGraph5.js @@ -1,14 +1,14 @@ // wasm backend notation has one fewer _ in the wasm __GLOBAL__I_000101(); // var use -var __GLOBAL__I_000101 = Module["__GLOBAL__I_000101"] = function() { return Module["asm"]["_GLOBAL__I_000101"].apply(null, arguments) }; +var __GLOBAL__I_000101 = Module["__GLOBAL__I_000101"] = () => Module["asm"]["_GLOBAL__I_000101"](); __ATINIT__.push({ func: function() { __GLOBAL__I_iostream() } }); // var use inside other scope -var __GLOBAL__I_iostream = Module["__GLOBAL__I_iostream"] = function() { return Module["asm"]["_GLOBAL__I_iostream.cpp"].apply(null, arguments) }; // also "." => "_" +var __GLOBAL__I_iostream = Module["__GLOBAL__I_iostream"] = () => Module["asm"]["_GLOBAL__I_iostream.cpp"](); Module["__DUB"](); // module use -var __DUB = Module["__DUB"] = function() { return Module["asm"]["_DUB"].apply(null, arguments) }; +var __DUB = Module["__DUB"] = () => Module["asm"]["_DUB"](); -var __UNUSED = Module["__UNUSED"] = function() { return Module["asm"]["_UNUSED"].apply(null, arguments) }; +var __UNUSED = Module["__UNUSED"] = () => Module["asm"]["_UNUSED"](); var wasmImports = { }; diff --git a/test/other/metadce/test_metadce_cxx_ctors1.jssize b/test/other/metadce/test_metadce_cxx_ctors1.jssize index 7a9b638c8d9ff..932008f582603 100644 --- a/test/other/metadce/test_metadce_cxx_ctors1.jssize +++ b/test/other/metadce/test_metadce_cxx_ctors1.jssize @@ -1 +1 @@ -25218 +25162 diff --git a/test/other/metadce/test_metadce_cxx_ctors2.jssize b/test/other/metadce/test_metadce_cxx_ctors2.jssize index b39eea3a351aa..7d6f9f4fcb113 100644 --- a/test/other/metadce/test_metadce_cxx_ctors2.jssize +++ b/test/other/metadce/test_metadce_cxx_ctors2.jssize @@ -1 +1 @@ -25182 +25126 diff --git a/test/other/metadce/test_metadce_cxx_except.jssize b/test/other/metadce/test_metadce_cxx_except.jssize index 6725bb96222e1..31382fbfc5b6f 100644 --- a/test/other/metadce/test_metadce_cxx_except.jssize +++ b/test/other/metadce/test_metadce_cxx_except.jssize @@ -1 +1 @@ -29699 +29381 diff --git a/test/other/metadce/test_metadce_cxx_except_wasm.jssize b/test/other/metadce/test_metadce_cxx_except_wasm.jssize index 4bc6ac2684e29..9f5a6b7e142b5 100644 --- a/test/other/metadce/test_metadce_cxx_except_wasm.jssize +++ b/test/other/metadce/test_metadce_cxx_except_wasm.jssize @@ -1 +1 @@ -25023 +24934 diff --git a/test/other/metadce/test_metadce_cxx_mangle.jssize b/test/other/metadce/test_metadce_cxx_mangle.jssize index 6007cf304f276..bf13479dc9dbe 100644 --- a/test/other/metadce/test_metadce_cxx_mangle.jssize +++ b/test/other/metadce/test_metadce_cxx_mangle.jssize @@ -1 +1 @@ -29698 +29380 diff --git a/test/other/metadce/test_metadce_cxx_noexcept.jssize b/test/other/metadce/test_metadce_cxx_noexcept.jssize index 7a9b638c8d9ff..932008f582603 100644 --- a/test/other/metadce/test_metadce_cxx_noexcept.jssize +++ b/test/other/metadce/test_metadce_cxx_noexcept.jssize @@ -1 +1 @@ -25218 +25162 diff --git a/test/other/metadce/test_metadce_cxx_wasmfs.jssize b/test/other/metadce/test_metadce_cxx_wasmfs.jssize index efbeb684f3ba4..061a3386086a8 100644 --- a/test/other/metadce/test_metadce_cxx_wasmfs.jssize +++ b/test/other/metadce/test_metadce_cxx_wasmfs.jssize @@ -1 +1 @@ -12897 +12782 diff --git a/test/other/metadce/test_metadce_files_js_fs.jssize b/test/other/metadce/test_metadce_files_js_fs.jssize index d7de18da4f7d2..d40d40ee4a8c4 100644 --- a/test/other/metadce/test_metadce_files_js_fs.jssize +++ b/test/other/metadce/test_metadce_files_js_fs.jssize @@ -1 +1 @@ -20045 +20017 diff --git a/test/other/metadce/test_metadce_files_wasmfs.jssize b/test/other/metadce/test_metadce_files_wasmfs.jssize index 7045ac3e702cd..4f40381880967 100644 --- a/test/other/metadce/test_metadce_files_wasmfs.jssize +++ b/test/other/metadce/test_metadce_files_wasmfs.jssize @@ -1 +1 @@ -7289 +7261 diff --git a/test/other/metadce/test_metadce_hello_O0.jssize b/test/other/metadce/test_metadce_hello_O0.jssize index 952e9263c84bc..cf408f75c258d 100644 --- a/test/other/metadce/test_metadce_hello_O0.jssize +++ b/test/other/metadce/test_metadce_hello_O0.jssize @@ -1 +1 @@ -23719 +23608 diff --git a/test/other/metadce/test_metadce_hello_O1.jssize b/test/other/metadce/test_metadce_hello_O1.jssize index be63ecadc8208..e6f91cf78f618 100644 --- a/test/other/metadce/test_metadce_hello_O1.jssize +++ b/test/other/metadce/test_metadce_hello_O1.jssize @@ -1 +1 @@ -8166 +8120 diff --git a/test/other/metadce/test_metadce_hello_O2.jssize b/test/other/metadce/test_metadce_hello_O2.jssize index 5c22f3f453a70..f6cc210c14d5d 100644 --- a/test/other/metadce/test_metadce_hello_O2.jssize +++ b/test/other/metadce/test_metadce_hello_O2.jssize @@ -1 +1 @@ -5814 +5770 diff --git a/test/other/metadce/test_metadce_hello_O3.jssize b/test/other/metadce/test_metadce_hello_O3.jssize index f855f8f17c6df..a0096d7853f16 100644 --- a/test/other/metadce/test_metadce_hello_O3.jssize +++ b/test/other/metadce/test_metadce_hello_O3.jssize @@ -1 +1 @@ -5640 +5612 diff --git a/test/other/metadce/test_metadce_hello_Os.jssize b/test/other/metadce/test_metadce_hello_Os.jssize index f855f8f17c6df..a0096d7853f16 100644 --- a/test/other/metadce/test_metadce_hello_Os.jssize +++ b/test/other/metadce/test_metadce_hello_Os.jssize @@ -1 +1 @@ -5640 +5612 diff --git a/test/other/metadce/test_metadce_hello_Oz.jssize b/test/other/metadce/test_metadce_hello_Oz.jssize index ffc5531867cd6..a9842242a955f 100644 --- a/test/other/metadce/test_metadce_hello_Oz.jssize +++ b/test/other/metadce/test_metadce_hello_Oz.jssize @@ -1 +1 @@ -5607 +5579 diff --git a/test/other/metadce/test_metadce_hello_dylink.jssize b/test/other/metadce/test_metadce_hello_dylink.jssize index 5db4648686679..275ec65133ebe 100644 --- a/test/other/metadce/test_metadce_hello_dylink.jssize +++ b/test/other/metadce/test_metadce_hello_dylink.jssize @@ -1 +1 @@ -15218 +14984 diff --git a/test/other/metadce/test_metadce_hello_wasmfs.jssize b/test/other/metadce/test_metadce_hello_wasmfs.jssize index f855f8f17c6df..a0096d7853f16 100644 --- a/test/other/metadce/test_metadce_hello_wasmfs.jssize +++ b/test/other/metadce/test_metadce_hello_wasmfs.jssize @@ -1 +1 @@ -5640 +5612 diff --git a/test/other/metadce/test_metadce_libcxxabi_message_O3.jssize b/test/other/metadce/test_metadce_libcxxabi_message_O3.jssize index a635065fa4aa4..e8ca47dace4bb 100644 --- a/test/other/metadce/test_metadce_libcxxabi_message_O3.jssize +++ b/test/other/metadce/test_metadce_libcxxabi_message_O3.jssize @@ -1 +1 @@ -4928 +4900 diff --git a/test/other/metadce/test_metadce_libcxxabi_message_O3_standalone.jssize b/test/other/metadce/test_metadce_libcxxabi_message_O3_standalone.jssize index 12991ec44dcde..032c246660549 100644 --- a/test/other/metadce/test_metadce_libcxxabi_message_O3_standalone.jssize +++ b/test/other/metadce/test_metadce_libcxxabi_message_O3_standalone.jssize @@ -1 +1 @@ -4989 +4955 diff --git a/test/other/metadce/test_metadce_mem_O3.jssize b/test/other/metadce/test_metadce_mem_O3.jssize index 3542781fb9290..33f6a20952b66 100644 --- a/test/other/metadce/test_metadce_mem_O3.jssize +++ b/test/other/metadce/test_metadce_mem_O3.jssize @@ -1 +1 @@ -5856 +5791 diff --git a/test/other/metadce/test_metadce_mem_O3_grow.jssize b/test/other/metadce/test_metadce_mem_O3_grow.jssize index 55f73b9c653fd..124a6d8c38ff0 100644 --- a/test/other/metadce/test_metadce_mem_O3_grow.jssize +++ b/test/other/metadce/test_metadce_mem_O3_grow.jssize @@ -1 +1 @@ -6176 +6111 diff --git a/test/other/metadce/test_metadce_mem_O3_grow_standalone.jssize b/test/other/metadce/test_metadce_mem_O3_grow_standalone.jssize index 76674f153193b..ceaeb5c589e57 100644 --- a/test/other/metadce/test_metadce_mem_O3_grow_standalone.jssize +++ b/test/other/metadce/test_metadce_mem_O3_grow_standalone.jssize @@ -1 +1 @@ -5568 +5534 diff --git a/test/other/metadce/test_metadce_mem_O3_standalone.jssize b/test/other/metadce/test_metadce_mem_O3_standalone.jssize index 7d47b0bc11059..4e8a6e6d26b46 100644 --- a/test/other/metadce/test_metadce_mem_O3_standalone.jssize +++ b/test/other/metadce/test_metadce_mem_O3_standalone.jssize @@ -1 +1 @@ -5498 +5464 diff --git a/test/other/metadce/test_metadce_mem_O3_standalone_lib.jssize b/test/other/metadce/test_metadce_mem_O3_standalone_lib.jssize index d344ba0896151..a98eb3384ccbe 100644 --- a/test/other/metadce/test_metadce_mem_O3_standalone_lib.jssize +++ b/test/other/metadce/test_metadce_mem_O3_standalone_lib.jssize @@ -1 +1 @@ -5015 +4947 diff --git a/test/other/metadce/test_metadce_mem_O3_standalone_narg.jssize b/test/other/metadce/test_metadce_mem_O3_standalone_narg.jssize index 12991ec44dcde..032c246660549 100644 --- a/test/other/metadce/test_metadce_mem_O3_standalone_narg.jssize +++ b/test/other/metadce/test_metadce_mem_O3_standalone_narg.jssize @@ -1 +1 @@ -4989 +4955 diff --git a/test/other/metadce/test_metadce_mem_O3_standalone_narg_flto.jssize b/test/other/metadce/test_metadce_mem_O3_standalone_narg_flto.jssize index 12991ec44dcde..032c246660549 100644 --- a/test/other/metadce/test_metadce_mem_O3_standalone_narg_flto.jssize +++ b/test/other/metadce/test_metadce_mem_O3_standalone_narg_flto.jssize @@ -1 +1 @@ -4989 +4955 diff --git a/test/other/metadce/test_metadce_minimal_64.jssize b/test/other/metadce/test_metadce_minimal_64.jssize index e72c6b3f4abd0..069ccfea1e738 100644 --- a/test/other/metadce/test_metadce_minimal_64.jssize +++ b/test/other/metadce/test_metadce_minimal_64.jssize @@ -1 +1 @@ -3844 +3816 diff --git a/test/other/metadce/test_metadce_minimal_O0.jssize b/test/other/metadce/test_metadce_minimal_O0.jssize index 33fed85da8acd..f13838c964c6f 100644 --- a/test/other/metadce/test_metadce_minimal_O0.jssize +++ b/test/other/metadce/test_metadce_minimal_O0.jssize @@ -1 +1 @@ -20141 +20071 diff --git a/test/other/metadce/test_metadce_minimal_O1.jssize b/test/other/metadce/test_metadce_minimal_O1.jssize index e2f5cf779fa0e..e796b990fedb2 100644 --- a/test/other/metadce/test_metadce_minimal_O1.jssize +++ b/test/other/metadce/test_metadce_minimal_O1.jssize @@ -1 +1 @@ -4626 +4594 diff --git a/test/other/metadce/test_metadce_minimal_O2.jssize b/test/other/metadce/test_metadce_minimal_O2.jssize index 6e751d7298cfd..f10d1076aa29f 100644 --- a/test/other/metadce/test_metadce_minimal_O2.jssize +++ b/test/other/metadce/test_metadce_minimal_O2.jssize @@ -1 +1 @@ -3546 +3518 diff --git a/test/other/metadce/test_metadce_minimal_O3.jssize b/test/other/metadce/test_metadce_minimal_O3.jssize index 0f97e969535cd..50f95fc714b79 100644 --- a/test/other/metadce/test_metadce_minimal_O3.jssize +++ b/test/other/metadce/test_metadce_minimal_O3.jssize @@ -1 +1 @@ -3475 +3447 diff --git a/test/other/metadce/test_metadce_minimal_Os.jssize b/test/other/metadce/test_metadce_minimal_Os.jssize index 0f97e969535cd..50f95fc714b79 100644 --- a/test/other/metadce/test_metadce_minimal_Os.jssize +++ b/test/other/metadce/test_metadce_minimal_Os.jssize @@ -1 +1 @@ -3475 +3447 diff --git a/test/other/metadce/test_metadce_minimal_Oz-ctors.jssize b/test/other/metadce/test_metadce_minimal_Oz-ctors.jssize index 169efa8bd26e4..d6ff78ac4e40f 100644 --- a/test/other/metadce/test_metadce_minimal_Oz-ctors.jssize +++ b/test/other/metadce/test_metadce_minimal_Oz-ctors.jssize @@ -1 +1 @@ -3456 +3428 diff --git a/test/other/metadce/test_metadce_minimal_Oz.jssize b/test/other/metadce/test_metadce_minimal_Oz.jssize index 0f97e969535cd..50f95fc714b79 100644 --- a/test/other/metadce/test_metadce_minimal_Oz.jssize +++ b/test/other/metadce/test_metadce_minimal_Oz.jssize @@ -1 +1 @@ -3475 +3447 diff --git a/test/other/metadce/test_metadce_minimal_pthreads.jssize b/test/other/metadce/test_metadce_minimal_pthreads.jssize index 157d7144163c0..9f678c8e9b1ab 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.jssize +++ b/test/other/metadce/test_metadce_minimal_pthreads.jssize @@ -1 +1 @@ -15050 +14608 diff --git a/test/other/metadce/test_metadce_minimal_wasmfs.jssize b/test/other/metadce/test_metadce_minimal_wasmfs.jssize index 0f97e969535cd..50f95fc714b79 100644 --- a/test/other/metadce/test_metadce_minimal_wasmfs.jssize +++ b/test/other/metadce/test_metadce_minimal_wasmfs.jssize @@ -1 +1 @@ -3475 +3447 diff --git a/test/other/test_unoptimized_code_size.js.size b/test/other/test_unoptimized_code_size.js.size index a8124ba7c02fd..73e9bd10685b5 100644 --- a/test/other/test_unoptimized_code_size.js.size +++ b/test/other/test_unoptimized_code_size.js.size @@ -1 +1 @@ -58765 +58144 diff --git a/test/other/test_unoptimized_code_size_no_asserts.js.size b/test/other/test_unoptimized_code_size_no_asserts.js.size index 9d0f802d763aa..c71d392167be6 100644 --- a/test/other/test_unoptimized_code_size_no_asserts.js.size +++ b/test/other/test_unoptimized_code_size_no_asserts.js.size @@ -1 +1 @@ -32432 +31977 diff --git a/test/other/test_unoptimized_code_size_strict.js.size b/test/other/test_unoptimized_code_size_strict.js.size index 331794ba20866..73b60adfbfa97 100644 --- a/test/other/test_unoptimized_code_size_strict.js.size +++ b/test/other/test_unoptimized_code_size_strict.js.size @@ -1 +1 @@ -57731 +57110 diff --git a/test/test_browser.py b/test/test_browser.py index a2ef4d447738f..ac284ae98420f 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -4452,7 +4452,7 @@ def test_small_js_flags(self): size = os.path.getsize('test.js') print('size:', size) # Note that this size includes test harness additions (for reporting the result, etc.). - self.assertLess(abs(size - 4930), 100) + self.assertLess(abs(size - 4800), 100) # Tests that it is possible to initialize and render WebGL content in a pthread by using OffscreenCanvas. # -DTEST_CHAINED_WEBGL_CONTEXT_PASSING: Tests that it is possible to transfer WebGL canvas in a chain from main thread -> thread 1 -> thread 2 and then init and render WebGL content there. diff --git a/test/test_other.py b/test/test_other.py index b27f4dcbc73e2..2a1e298d8359e 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -2494,7 +2494,8 @@ def test_extern_prepost(self): 'JSDCE-fors': ('optimizer/JSDCE-fors.js', ['JSDCE']), 'AJSDCE': ('optimizer/AJSDCE.js', ['AJSDCE']), 'emitDCEGraph': ('optimizer/emitDCEGraph.js', ['emitDCEGraph', 'noPrint']), - 'emitDCEGraph1': ('optimizer/emitDCEGraph2.js', ['emitDCEGraph', 'noPrint']), + 'emitDCEGraph-closure': ('optimizer/emitDCEGraph.js', ['emitDCEGraph', 'noPrint', '--closureFriendly']), + 'emitDCEGraph2': ('optimizer/emitDCEGraph2.js', ['emitDCEGraph', 'noPrint']), 'emitDCEGraph3': ('optimizer/emitDCEGraph3.js', ['emitDCEGraph', 'noPrint']), 'emitDCEGraph4': ('optimizer/emitDCEGraph4.js', ['emitDCEGraph', 'noPrint']), 'emitDCEGraph5': ('optimizer/emitDCEGraph5.js', ['emitDCEGraph', 'noPrint']), diff --git a/tools/acorn-optimizer.js b/tools/acorn-optimizer.js index d5b54c452f40e..abb405a493577 100755 --- a/tools/acorn-optimizer.js +++ b/tools/acorn-optimizer.js @@ -585,32 +585,18 @@ function isDynamicDynCall(node) { // Matches the wasm export wrappers generated by emcc (see make_export_wrappers // in emscripten.py). For example: // -// var _foo = function() { -// return (_foo = Module['asm']['foo']).apply(null, argument) -// } +// var _foo = (a0, a1) => (_foo = Module['asm']['foo'])(a0, a1): // function isExportWrapperFunction(f) { - if (f.body.type != 'BlockStatement') return null; - if (f.body.body.length != 1) return null; - const expr = f.body.body[0]; - if (expr.type == 'ReturnStatement') { - const rtn = expr.argument; - // We are looking for a call of special target, like (x = y)(), and not a - // non-call or a normal direct call such as z(). - if (rtn.type == 'CallExpression' && rtn.callee.object) { - let target = rtn.callee.object; - if (target.type == 'ParenthesizedExpression') { - target = target.expression; - } - if (target.type == 'AssignmentExpression') { - const rhs = target.right; - if (isAsmUse(rhs)) { - return getAsmOrModuleUseName(rhs); - } - } - } + if (f.body.type != 'CallExpression') return null; + let callee = f.body.callee; + if (callee.type == 'ParenthesizedExpression') { + callee = callee.expression; } - return null; + if (callee.type != 'AssignmentExpression' || callee.right.type != 'MemberExpression') return null; + const rhs = callee.right; + if (rhs.object.type != 'MemberExpression' || !isModuleUse(rhs.object)) return null; + return getAsmOrModuleUseName(rhs); } // @@ -737,9 +723,9 @@ function emitDCEGraph(ast) { // var _x = asm['x']; saveAsmExport(name, asmName); emptyOut(node); - } else if (value && value.type === 'FunctionExpression') { + } else if (value && value.type === 'ArrowFunctionExpression') { // this is - // var x = function() { return (x = Module['asm']['x']).apply .. } + // var x = () => (x = Module['asm']['x'])(..) let asmName = isExportWrapperFunction(value); if (asmName) { saveAsmExport(name, asmName); @@ -1013,7 +999,7 @@ function applyDCEGraphRemovals(ast) { if (unused.has(full)) { convertToNothingInVarInit(init); } - } else if (init.type == 'FunctionExpression') { + } else if (init.type == 'ArrowFunctionExpression') { const name = isExportWrapperFunction(init); const full = 'emcc$export$' + name; if (unused.has(full)) { diff --git a/tools/extract_metadata.py b/tools/extract_metadata.py index ed95ecfd6677f..cbe826064fed1 100644 --- a/tools/extract_metadata.py +++ b/tools/extract_metadata.py @@ -248,7 +248,11 @@ def get_named_globals(module, exports): def get_function_exports(module): - return [e.name for e in module.get_exports() if e.kind == webassembly.ExternType.FUNC] + rtn = {} + for e in module.get_exports(): + if e.kind == webassembly.ExternType.FUNC: + rtn[e.name] = len(module.get_function_type(e.index).params) + return rtn def update_metadata(filename, metadata): From 353d9ee6bff40ea0bba529ffbd5ea0fa3696eb29 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 12 Jul 2023 09:44:17 -0700 Subject: [PATCH 0552/1523] Allow `-target` to be specified on the command line. NFC (#19840) This makes `-target wasm64` work and imply `-sMEMORY64`. Supporting these flags makes us more compatible with upstream clang and with wasi-sdk. See #19834 --- emcc.py | 16 +++++++++++++--- test/test_other.py | 14 ++++++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/emcc.py b/emcc.py index 2069014e72469..b6e1ae7907d96 100755 --- a/emcc.py +++ b/emcc.py @@ -248,6 +248,7 @@ def add_link_flag(state, i, f): class EmccOptions: def __init__(self): + self.target = '' self.output_file = None self.post_link = False self.executable = False @@ -1460,14 +1461,14 @@ def phase_setup(options, state, newargs): continue arg = newargs[i] - if arg in ('-MT', '-MF', '-MJ', '-MQ', '-D', '-U', '-o', '-x', + if arg in {'-MT', '-MF', '-MJ', '-MQ', '-D', '-U', '-o', '-x', '-Xpreprocessor', '-include', '-imacros', '-idirafter', '-iprefix', '-iwithprefix', '-iwithprefixbefore', '-isysroot', '-imultilib', '-A', '-isystem', '-iquote', '-install_name', '-compatibility_version', '-current_version', '-I', '-L', '-include-pch', - '-undefined', - '-Xlinker', '-Xclang', '-z'): + '-undefined', '-target', + '-Xlinker', '-Xclang', '-z'}: skip = True if not arg.startswith('-'): @@ -1639,7 +1640,12 @@ def phase_setup(options, state, newargs): if settings.DISABLE_EXCEPTION_THROWING and not settings.DISABLE_EXCEPTION_CATCHING: exit_with_error("DISABLE_EXCEPTION_THROWING was set (probably from -fno-exceptions) but is not compatible with enabling exception catching (DISABLE_EXCEPTION_CATCHING=0). If you don't want exceptions, set DISABLE_EXCEPTION_CATCHING to 1; if you do want exceptions, don't link with -fno-exceptions") + if options.target.startswith('wasm64'): + default_setting('MEMORY64', 1) + if settings.MEMORY64: + if options.target.startswith('wasm32'): + exit_with_error('wasm32 target is not compatible with -sMEMORY64') diagnostics.warning('experimental', '-sMEMORY64 is still experimental. Many features may not work.') # Wasm SjLj cannot be used with Emscripten EH @@ -3637,6 +3643,10 @@ def consume_arg_file(): elif arg.startswith('-o'): options.output_file = removeprefix(arg, '-o') newargs[i] = '' + elif check_arg('-target') or check_arg('--target'): + options.target = consume_arg() + if options.target not in ('wasm32', 'wasm64', 'wasm64-unknown-emscripten', 'wasm32-unknown-emscripten'): + exit_with_error(f'unsupported target: {options.target} (emcc only supports wasm64-unknown-emscripten and wasm32-unknown-emscripten)') elif arg == '-mllvm': # Ignore the next argument rather than trying to parse it. This is needed # because llvm args could, for example, start with `-o` and we don't want diff --git a/test/test_other.py b/test/test_other.py index 2a1e298d8359e..5314461328205 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -13562,3 +13562,17 @@ def test_proxy_to_worker(self): @also_with_standalone_wasm() def test_console_out(self): self.do_other_test('test_console_out.c') + + @requires_wasm64 + def test_explicit_target(self): + self.do_runf(test_file('hello_world.c'), emcc_args=['-target', 'wasm32']) + self.do_runf(test_file('hello_world.c'), emcc_args=['-target', 'wasm64-unknown-emscripten', '-Wno-experimental']) + + self.do_runf(test_file('hello_world.c'), emcc_args=['--target=wasm32']) + self.do_runf(test_file('hello_world.c'), emcc_args=['--target=wasm64-unknown-emscripten', '-Wno-experimental']) + + err = self.expect_fail([EMCC, test_file('hello_world.c'), '-target', 'wasm32', '-sMEMORY64']) + self.assertContained('emcc: error: wasm32 target is not compatible with -sMEMORY64', err) + + err = self.expect_fail([EMCC, test_file('hello_world.c'), '--target=arm64']) + self.assertContained('emcc: error: unsupported target: arm64 (emcc only supports wasm64-unknown-emscripten and wasm32-unknown-emscripten', err) From 5a45f3f099f182c79c084ed118844773e19c9b51 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 12 Jul 2023 10:46:18 -0700 Subject: [PATCH 0553/1523] Remove unused function in emscripten.py. NFC (#19841) Loosk like its usage was removed in #11972. --- emscripten.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/emscripten.py b/emscripten.py index d5f744d24fe04..88a395696cc0f 100644 --- a/emscripten.py +++ b/emscripten.py @@ -239,15 +239,6 @@ def report_missing_symbols(js_symbols): exit_with_error('entry symbol not defined (pass --no-entry to suppress): main') -def proxy_debug_print(sync): - if settings.PTHREADS_DEBUG: - if sync: - return 'warnOnce("sync proxying function " + code);' - else: - return 'warnOnce("async proxying function " + code);' - return '' - - # Test if the parentheses at body[openIdx] and body[closeIdx] are a match to # each other. def parentheses_match(body, openIdx, closeIdx): From 1a308a884ca5f1c0767190bad77cdb783bfa6f7c Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 12 Jul 2023 12:10:29 -0700 Subject: [PATCH 0554/1523] Fix typo in ChangeLog.md (#19828) --- ChangeLog.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ChangeLog.md b/ChangeLog.md index ba8f4442d6216..8c99c99c2e664 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -24,7 +24,8 @@ See docs/process.md for more on how version tagging works. - The `EM_LOG_FUNC_PARAMS` flag to `emscripten_log`/`emscripten_get_callstack` has been deprecated and no longer has any effect. It was based on a long-deprecated JS API. (#19820) -- The internal `read_` and `readAsync` functions no longer handle date URIs. +- The internal `read_` and `readAsync` functions no longer handle data URIs. + (Higher-level functions are expected to handle that themselves, before calling.) This only effects builds that use `-sSINGLE_FILE` or `--memory-init-file`. (#19792) From f2fc7137969ddcce5b1f5496e91a3c2c75d05b28 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 12 Jul 2023 13:08:23 -0700 Subject: [PATCH 0555/1523] Allow DEFAULT_LIBRARY_FUNCS_TO_INCLUDE to have native deps. NFC (#19843) Fixes: #19759 --- emcc.py | 30 +++++++++++------------------- src/library.js | 3 +++ src/library_async.js | 2 +- src/library_wasmfs_opfs.js | 3 +++ test/test_other.py | 2 +- 5 files changed, 19 insertions(+), 21 deletions(-) diff --git a/emcc.py b/emcc.py index b6e1ae7907d96..6983af8f1d61e 100755 --- a/emcc.py +++ b/emcc.py @@ -1321,6 +1321,17 @@ def run(args): js_info = get_js_sym_info() if not settings.SIDE_MODULE: js_syms = js_info['deps'] + + def add_js_deps(sym): + if sym in js_syms: + native_deps = js_syms[sym] + if native_deps: + settings.REQUIRED_EXPORTS += native_deps + + for sym in settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE: + add_js_deps(sym) + for sym in settings.EXPORTED_RUNTIME_METHODS: + add_js_deps(shared.demangle_c_symbol_name(sym)) if settings.ASYNCIFY: settings.ASYNCIFY_IMPORTS += ['env.' + x for x in js_info['asyncFuncs']] @@ -1733,13 +1744,6 @@ def setup_pthreads(target): if settings.MINIMAL_RUNTIME: building.user_requested_exports.add('exit') - # All proxying async backends will need this. - if settings.WASMFS: - settings.REQUIRED_EXPORTS += ['emscripten_proxy_finish'] - # TODO: Remove this once we no longer need the heartbeat hack in - # wasmfs/thread_utils.h - settings.REQUIRED_EXPORTS += ['emscripten_proxy_execute_queue'] - # pthread stack setup and other necessary utilities def include_and_export(name): settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['$' + name] @@ -2091,7 +2095,6 @@ def phase_linker_setup(options, state, newargs): settings.INCLUDE_FULL_LIBRARY = 1 # Called from preamble.js once the main module is instantiated. settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['$loadDylibs'] - settings.REQUIRED_EXPORTS += ['malloc'] if settings.MAIN_MODULE == 1 or settings.SIDE_MODULE == 1: settings.LINKABLE = 1 @@ -2125,10 +2128,6 @@ def phase_linker_setup(options, state, newargs): '__asyncify_data' ] - # Emscripten EH dependency in library_dylink.js - if settings.SUPPORT_LONGJMP == 'emscripten' or not settings.DISABLE_EXCEPTION_CATCHING: - settings.REQUIRED_EXPORTS += ['setThrew'] - if settings.MINIMAL_RUNTIME: exit_with_error('MINIMAL_RUNTIME is not compatible with relocatable output') if settings.WASM2JS: @@ -2156,9 +2155,6 @@ def phase_linker_setup(options, state, newargs): # See: https://github.com/emscripten-core/emscripten/issues/12065 # See: https://github.com/emscripten-core/emscripten/issues/12066 settings.DYNCALLS = 1 - settings.REQUIRED_EXPORTS += ['emscripten_stack_get_base', - 'emscripten_stack_get_end', - 'emscripten_stack_set_limits'] settings.ASYNCIFY_ADD = unmangle_symbols_from_cmdline(settings.ASYNCIFY_ADD) settings.ASYNCIFY_REMOVE = unmangle_symbols_from_cmdline(settings.ASYNCIFY_REMOVE) @@ -2506,10 +2502,6 @@ def phase_linker_setup(options, state, newargs): 'removeRunDependency', ] - if options.embind_emit_tsd: - # TODO: Remove after #19759 is resolved. - settings.REQUIRED_EXPORTS += ['free'] - def check_memory_setting(setting): if settings[setting] % webassembly.WASM_PAGE_SIZE != 0: exit_with_error(f'{setting} must be a multiple of WebAssembly page size (64KiB), was {settings[setting]}') diff --git a/src/library.js b/src/library.js index 83820a17219fc..e0ab4c8a8c603 100644 --- a/src/library.js +++ b/src/library.js @@ -3347,6 +3347,9 @@ mergeInto(LibraryManager.library, { }, #if !MINIMAL_RUNTIME +#if STACK_OVERFLOW_CHECK + $handleException__deps: ['emscripten_stack_get_current'], +#endif $handleException: (e) => { // Certain exception types we do not treat as errors since they are used for // internal control flow. diff --git a/src/library_async.js b/src/library_async.js index 776a084a97ac6..da238044f4bee 100644 --- a/src/library_async.js +++ b/src/library_async.js @@ -531,7 +531,7 @@ mergeInto(LibraryManager.library, { }); }, - $Fibers__deps: ['$Asyncify'], + $Fibers__deps: ['$Asyncify', 'emscripten_stack_set_limits'], $Fibers: { nextFiber: 0, trampolineRunning: false, diff --git a/src/library_wasmfs_opfs.js b/src/library_wasmfs_opfs.js index ae72cc375728b..21935caab9787 100644 --- a/src/library_wasmfs_opfs.js +++ b/src/library_wasmfs_opfs.js @@ -58,6 +58,9 @@ mergeInto(LibraryManager.library, { }, #endif +#if PTHREADS + $wasmfsOPFSProxyFinish__deps: ['emscripten_proxy_finish'], +#endif $wasmfsOPFSProxyFinish: function(ctx) { // When using pthreads the proxy needs to know when the work is finished. // When used with JSPI the work will be executed in an async block so there diff --git a/test/test_other.py b/test/test_other.py index 5314461328205..7c4175bdb4e37 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -11310,7 +11310,7 @@ def test_bitcode_input(self): @with_env_modify({'EMCC_LOGGING': '0'}) # this test assumes no emcc output def test_nostdlib(self): - err = 'symbol exported via --export not found: __errno_location' + err = 'undefined symbol' self.assertContained(err, self.expect_fail([EMCC, test_file('unistd/close.c'), '-nostdlib'])) self.assertContained(err, self.expect_fail([EMCC, test_file('unistd/close.c'), '-nodefaultlibs'])) From 68ee2af6e5bff5ffdd2f0d2997d3371ba51960fd Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 12 Jul 2023 13:08:57 -0700 Subject: [PATCH 0556/1523] Replace `Module["asm"]` with `wasmExports` global (#19816) This brings the regular runtime closer `MINIMAL_RUNTIME` which uses the global `asm` to refer to exports object. As a followup we should consider merging these two symbols. --- ChangeLog.md | 4 + emscripten.py | 2 +- .../docs/optimizing/Module-Splitting.rst | 4 +- src/library_async.js | 8 +- src/library_exceptions.js | 2 +- src/library_exports.js | 2 +- src/modules.js | 2 + src/parseTools.js | 10 ++ src/postamble_minimal.js | 2 +- src/preamble.js | 24 +++-- src/runtime_debug.js | 8 +- src/shell.js | 1 + .../optimizer/applyDCEGraphRemovals-output.js | 8 +- test/optimizer/applyDCEGraphRemovals.js | 12 +-- .../applyImportAndExportNameChanges-output.js | 2 +- .../applyImportAndExportNameChanges.js | 2 +- test/optimizer/emitDCEGraph.js | 20 ++-- test/optimizer/emitDCEGraph2.js | 8 +- test/optimizer/emitDCEGraph3.js | 8 +- test/optimizer/emitDCEGraph4.js | 8 +- test/optimizer/emitDCEGraph5.js | 8 +- .../metadce/test_metadce_cxx_ctors1.jssize | 2 +- .../metadce/test_metadce_cxx_ctors2.jssize | 2 +- .../metadce/test_metadce_cxx_except.jssize | 2 +- .../test_metadce_cxx_except_wasm.jssize | 2 +- .../metadce/test_metadce_cxx_mangle.jssize | 2 +- .../metadce/test_metadce_cxx_noexcept.jssize | 2 +- .../metadce/test_metadce_cxx_wasmfs.jssize | 2 +- .../metadce/test_metadce_files_js_fs.jssize | 2 +- .../metadce/test_metadce_files_wasmfs.jssize | 2 +- .../metadce/test_metadce_hello_O0.jssize | 2 +- .../metadce/test_metadce_hello_O1.jssize | 2 +- .../metadce/test_metadce_hello_O2.jssize | 2 +- .../metadce/test_metadce_hello_O3.jssize | 2 +- .../metadce/test_metadce_hello_Os.jssize | 2 +- .../metadce/test_metadce_hello_Oz.jssize | 2 +- .../metadce/test_metadce_hello_dylink.jssize | 2 +- .../test_metadce_hello_export_nothing.jssize | 2 +- .../metadce/test_metadce_hello_wasmfs.jssize | 2 +- .../test_metadce_libcxxabi_message_O3.jssize | 2 +- ...dce_libcxxabi_message_O3_standalone.jssize | 2 +- test/other/metadce/test_metadce_mem_O3.jssize | 2 +- .../metadce/test_metadce_mem_O3_grow.jssize | 2 +- ...test_metadce_mem_O3_grow_standalone.jssize | 2 +- .../test_metadce_mem_O3_standalone.jssize | 2 +- .../test_metadce_mem_O3_standalone_lib.jssize | 2 +- ...test_metadce_mem_O3_standalone_narg.jssize | 2 +- ...metadce_mem_O3_standalone_narg_flto.jssize | 2 +- .../metadce/test_metadce_minimal_64.jssize | 2 +- .../metadce/test_metadce_minimal_O0.jssize | 2 +- .../metadce/test_metadce_minimal_O1.jssize | 2 +- .../metadce/test_metadce_minimal_O2.jssize | 2 +- .../metadce/test_metadce_minimal_O3.jssize | 2 +- .../metadce/test_metadce_minimal_Os.jssize | 2 +- .../test_metadce_minimal_Oz-ctors.jssize | 2 +- .../metadce/test_metadce_minimal_Oz.jssize | 2 +- .../test_metadce_minimal_pthreads.jssize | 2 +- .../test_metadce_minimal_wasmfs.jssize | 2 +- test/other/test_split_module.post.js | 2 +- test/other/test_unoptimized_code_size.js.size | 2 +- ...t_unoptimized_code_size_no_asserts.js.size | 2 +- .../test_unoptimized_code_size_strict.js.size | 2 +- test/test_other.py | 43 ++++++--- tools/acorn-optimizer.js | 94 ++++++++----------- tools/building.py | 2 +- 65 files changed, 194 insertions(+), 172 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 8c99c99c2e664..b12ecc3640613 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -28,6 +28,10 @@ See docs/process.md for more on how version tagging works. (Higher-level functions are expected to handle that themselves, before calling.) This only effects builds that use `-sSINGLE_FILE` or `--memory-init-file`. (#19792) +- The `asm` property of the Module object (which held the raw exports of the + wasm module) has been removed. Internally, this is now accessed via the + `wasmExports` global. If necessary, it is possible to export `wasmExports` + on the Module object using `-sEXPORTED_RUNTIME_METHODS=wasmExports`. (#19816) 3.1.43 - 07/10/23 ----------------- diff --git a/emscripten.py b/emscripten.py index 88a395696cc0f..3939a1c32ca2f 100644 --- a/emscripten.py +++ b/emscripten.py @@ -753,7 +753,7 @@ def install_wrapper(sym): # first use. args = [f'a{i}' for i in range(nargs)] args = ', '.join(args) - wrapper += f"({args}) => ({mangled} = {exported}Module['asm']['{name}'])({args});" + wrapper += f"({args}) => ({mangled} = {exported}wasmExports['{name}'])({args});" else: wrapper += 'asm["%s"]' % name diff --git a/site/source/docs/optimizing/Module-Splitting.rst b/site/source/docs/optimizing/Module-Splitting.rst index 7206942979fbf..851127d9a6ed7 100644 --- a/site/source/docs/optimizing/Module-Splitting.rst +++ b/site/source/docs/optimizing/Module-Splitting.rst @@ -124,7 +124,7 @@ included in the profile. Here’s the function to write the profile and our new main function:: EM_JS(void, write_profile, (), { - var __write_profile = Module['asm']['__write_profile']; + var __write_profile = wasmExports['__write_profile']; if (__write_profile) { // Get the size of the profile and allocate a buffer for it. @@ -338,7 +338,7 @@ be called either. When eagerly instantiating the secondary module, the imports object should be:: - {'primary': Module['asm']} + {'primary': wasmExports} Debugging --------- diff --git a/src/library_async.js b/src/library_async.js index da238044f4bee..0c088067b982c 100644 --- a/src/library_async.js +++ b/src/library_async.js @@ -267,9 +267,9 @@ mergeInto(LibraryManager.library, { getDataRewindFunc: function(ptr) { var id = {{{ makeGetValue('ptr', C_STRUCTS.asyncify_data_s.rewind_id, 'i32') }}}; var name = Asyncify.callStackIdToName[id]; - var func = Module['asm'][name]; + var func = wasmExports[name]; #if RELOCATABLE - // Exported functions in side modules are not listed in `Module['asm']`, + // Exported functions in side modules are not listed in `wasmExports`, // So we should use `resolveGlobalSymbol` helper function, which is defined in `library_dylink.js`. if (!func) { func = resolveGlobalSymbol(name, false).sym; @@ -522,8 +522,8 @@ mergeInto(LibraryManager.library, { _load_secondary_module__sig: 'v', _load_secondary_module: async function() { // Mark the module as loading for the wasm module (so it doesn't try to load it again). - Module['asm']['load_secondary_module_status'].value = 1; - var imports = {'primary': Module['asm']}; + wasmExports['load_secondary_module_status'].value = 1; + var imports = {'primary': wasmExports}; // Replace '.wasm' suffix with '.deferred.wasm'. var deferred = wasmBinaryFile.slice(0, -5) + '.deferred.wasm'; await new Promise((resolve) => { diff --git a/src/library_exceptions.js b/src/library_exceptions.js index 18a5df50cc702..f4a481903c6ae 100644 --- a/src/library_exceptions.js +++ b/src/library_exceptions.js @@ -331,7 +331,7 @@ var LibraryExceptions = { #if RELOCATABLE return ___cpp_exception; // defined in library.js #else - return Module['asm']['__cpp_exception']; + return wasmExports['__cpp_exception']; #endif }, diff --git a/src/library_exports.js b/src/library_exports.js index b04839b7e2ae1..62a6cf8b23623 100644 --- a/src/library_exports.js +++ b/src/library_exports.js @@ -16,7 +16,7 @@ mergeInto(LibraryManager.library, { var exportedFunc = asm[name]; #else // In regular runtime, exports are available on the Module object. - var exportedFunc = Module['asm'][name]; + var exportedFunc = wasmExports[name]; #endif if (exportedFunc) { // Record the created function pointer to each function object, diff --git a/src/modules.js b/src/modules.js index 20200c5fd4192..f662d65b19dcf 100644 --- a/src/modules.js +++ b/src/modules.js @@ -382,6 +382,8 @@ function exportRuntime() { 'abort', 'keepRuntimeAlive', 'wasmMemory', + 'wasmTable', + 'wasmExports', ]; // These are actually native wasm functions these days but we allow exporting diff --git a/src/parseTools.js b/src/parseTools.js index 4c9ba4af8c244..60882d38b3ecc 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -865,6 +865,16 @@ function hasExportedSymbol(sym) { return WASM_EXPORTS.has(sym); } +// Called when global runtime symbols such as wasmMemory, wasmExports and +// wasmTable are set. In this case we maybe need to re-export them on the +// Module object. +function receivedSymbol(sym) { + if (EXPORTED_RUNTIME_METHODS.includes(sym)) { + return `Module['${sym}'] = ${sym};` + } + return ''; +} + // 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) { diff --git a/src/postamble_minimal.js b/src/postamble_minimal.js index 55c12852b3d6f..0813e184fbd4e 100644 --- a/src/postamble_minimal.js +++ b/src/postamble_minimal.js @@ -142,7 +142,7 @@ WebAssembly.instantiate(Module['wasm'], imports).then((output) => { #if !LibraryManager.has('library_exports.js') && !EMBIND // If not using the emscripten_get_exported_function() API or embind, keep the - // 'asm' exports variable in local scope to this instantiate function to save + // `asm` exports variable in local scope to this instantiate function to save // code size. (otherwise access it without to export it to outer scope) var #endif diff --git a/src/preamble.js b/src/preamble.js index c89c522ef3abd..719a82973497c 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -53,6 +53,7 @@ if (typeof WebAssembly != 'object') { // Wasm globals var wasmMemory; +var wasmExports; #if SHARED_MEMORY // For sending to workers. @@ -471,7 +472,7 @@ function abort(what) { #if WASM_EXCEPTIONS == 1 // See above, in the meantime, we resort to wasm code for trapping. // - // In case abort() is called before the module is initialized, Module['asm'] + // In case abort() is called before the module is initialized, wasmExports // and its exported '__trap' function is not available, in which case we throw // a RuntimeError. // @@ -527,7 +528,7 @@ function createExportWrapper(name) { #if EXIT_RUNTIME assert(!runtimeExited, `native function \`${name}\` called after runtime exit (use NO_EXIT_RUNTIME to keep it alive after main() exits)`); #endif - var f = Module['asm'][name]; + var f = wasmExports[name]; assert(f, `exported native function \`${name}\` not found`); return f.apply(null, arguments); }; @@ -714,7 +715,7 @@ var splitModuleProxyHandler = { throw new Error('Placeholder function "' + prop + '" should not be called when using JSPI.'); #else err('placeholder function called: ' + prop); - var imports = {'primary': Module['asm']}; + var imports = {'primary': wasmExports}; // Replace '.wasm' suffix with '.deferred.wasm'. var deferred = wasmBinaryFile.slice(0, -5) + '.deferred.wasm' loadSplitModule(deferred, imports, prop); @@ -979,18 +980,20 @@ function createWasm() { exports = applySignatureConversions(exports); #endif - Module['asm'] = exports; + wasmExports = exports; + {{{ receivedSymbol('wasmExports') }}} #if PTHREADS #if MAIN_MODULE - registerTLSInit(Module['asm']['_emscripten_tls_init'], instance.exports, metadata); + registerTLSInit(wasmExports['_emscripten_tls_init'], instance.exports, metadata); #else - registerTLSInit(Module['asm']['_emscripten_tls_init']); + registerTLSInit(wasmExports['_emscripten_tls_init']); #endif #endif #if !IMPORTED_MEMORY - wasmMemory = Module['asm']['memory']; + wasmMemory = wasmExports['memory']; + {{{ receivedSymbol('wasmMemory') }}} #if ASSERTIONS assert(wasmMemory, "memory not found in wasm exports"); // This assertion doesn't hold when emscripten is run in --post-link @@ -1005,7 +1008,8 @@ function createWasm() { #endif #if !RELOCATABLE - wasmTable = Module['asm']['__indirect_function_table']; + wasmTable = wasmExports['__indirect_function_table']; + {{{ receivedSymbol('wasmTable') }}} #if ASSERTIONS && !PURE_WASI assert(wasmTable, "table not found in wasm exports"); #endif @@ -1019,11 +1023,11 @@ function createWasm() { #endif #if hasExportedSymbol('__wasm_call_ctors') - addOnInit(Module['asm']['__wasm_call_ctors']); + addOnInit(wasmExports['__wasm_call_ctors']); #endif #if hasExportedSymbol('__wasm_apply_data_relocs') - __RELOC_FUNCS__.push(Module['asm']['__wasm_apply_data_relocs']); + __RELOC_FUNCS__.push(wasmExports['__wasm_apply_data_relocs']); #endif #if ABORT_ON_WASM_EXCEPTIONS diff --git a/src/runtime_debug.js b/src/runtime_debug.js index db482e376e063..2ab30a8a5d363 100644 --- a/src/runtime_debug.js +++ b/src/runtime_debug.js @@ -6,12 +6,14 @@ #if ASSERTIONS -function legacyModuleProp(prop, newName) { +function legacyModuleProp(prop, newName, incomming=true) { if (!Object.getOwnPropertyDescriptor(Module, prop)) { Object.defineProperty(Module, prop, { configurable: true, get() { - abort('Module.' + prop + ' has been replaced with plain ' + newName + ' (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)'); + let extra = incomming ? ' (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)' : ''; + abort(`\`Module.${prop}\` has been replaced by \`${newName}\`` + extra); + } }); } @@ -19,7 +21,7 @@ function legacyModuleProp(prop, newName) { function ignoredModuleProp(prop) { if (Object.getOwnPropertyDescriptor(Module, prop)) { - abort('`Module.' + prop + '` was supplied but `' + prop + '` not included in INCOMING_MODULE_JS_API'); + abort(`\`Module.${prop}\` was supplied but \`${prop}\` not included in INCOMING_MODULE_JS_API`); } } diff --git a/src/shell.js b/src/shell.js index a997e51d0c3ab..2663771873874 100644 --- a/src/shell.js +++ b/src/shell.js @@ -477,6 +477,7 @@ assert(typeof Module['readAsync'] == 'undefined', 'Module.readAsync option was r assert(typeof Module['readBinary'] == 'undefined', 'Module.readBinary option was removed (modify readBinary in JS)'); assert(typeof Module['setWindowTitle'] == 'undefined', 'Module.setWindowTitle option was removed (modify setWindowTitle in JS)'); assert(typeof Module['TOTAL_MEMORY'] == 'undefined', 'Module.TOTAL_MEMORY has been renamed Module.INITIAL_MEMORY'); +{{{ makeRemovedModuleAPIAssert('asm', 'wasmExports', false) }}} {{{ makeRemovedModuleAPIAssert('read', 'read_') }}} {{{ makeRemovedModuleAPIAssert('readAsync') }}} {{{ makeRemovedModuleAPIAssert('readBinary') }}} diff --git a/test/optimizer/applyDCEGraphRemovals-output.js b/test/optimizer/applyDCEGraphRemovals-output.js index 8037ddb96f47f..6e70e4c9d26eb 100644 --- a/test/optimizer/applyDCEGraphRemovals-output.js +++ b/test/optimizer/applyDCEGraphRemovals-output.js @@ -17,15 +17,15 @@ var expD5 = asm["expD5"]; var expD6; -var expI1 = Module["expI1"] = () => (expI1 = Module["expI1"] = Module["asm"]["expI1"])(); +var expI1 = Module["expI1"] = () => (expI1 = Module["expI1"] = wasmExports["expI1"])(); -var expI2 = Module["expI2"] = () => (expI2 = Module["expI2"] = Module["asm"]["expI2"])(); +var expI2 = Module["expI2"] = () => (expI2 = Module["expI2"] = wasmExports["expI2"])(); -var expI3 = Module["expI3"] = () => (expI3 = Module["expI3"] = Module["asm"]["expI3"])(); +var expI3 = Module["expI3"] = () => (expI3 = Module["expI3"] = wasmExports["expI3"])(); var expI4; -var expI5 = () => (expI5 = Module["asm"]["expI5"])(); +var expI5 = () => (expI5 = wasmExports["expI5"])(); var expI6; diff --git a/test/optimizer/applyDCEGraphRemovals.js b/test/optimizer/applyDCEGraphRemovals.js index 7fe977e3e33fb..2401d772fc3fe 100644 --- a/test/optimizer/applyDCEGraphRemovals.js +++ b/test/optimizer/applyDCEGraphRemovals.js @@ -11,14 +11,14 @@ var expD5 = asm['expD5']; var expD6 = asm['expD6']; // exports gotten indirectly (async compilation -var expI1 = Module['expI1'] = () => (expI1 = Module['expI1'] = Module['asm']['expI1'])(); -var expI2 = Module['expI2'] = () => (expI2 = Module['expI2'] = Module['asm']['expI2'])(); -var expI3 = Module['expI3'] = () => (expI3 = Module['expI3'] = Module['asm']['expI3'])(); -var expI4 = Module['expI4'] = () => (expI4 = Module['expI4'] = Module['asm']['expI4'])(); +var expI1 = Module['expI1'] = () => (expI1 = Module['expI1'] = wasmExports['expI1'])(); +var expI2 = Module['expI2'] = () => (expI2 = Module['expI2'] = wasmExports['expI2'])(); +var expI3 = Module['expI3'] = () => (expI3 = Module['expI3'] = wasmExports['expI3'])(); +var expI4 = Module['expI4'] = () => (expI4 = Module['expI4'] = wasmExports['expI4'])(); // Like above, but not exported on the Module -var expI5 = () => (expI5 = Module['asm']['expI5'])(); -var expI6 = () => (expI6 = Module['asm']['expI6'])(); +var expI5 = () => (expI5 = wasmExports['expI5'])(); +var expI6 = () => (expI6 = wasmExports['expI6'])(); // add uses for some of them, leave *4 as non-roots expD1; diff --git a/test/optimizer/applyImportAndExportNameChanges-output.js b/test/optimizer/applyImportAndExportNameChanges-output.js index d8e836a4f4f1a..00d82577fefdc 100644 --- a/test/optimizer/applyImportAndExportNameChanges-output.js +++ b/test/optimizer/applyImportAndExportNameChanges-output.js @@ -17,5 +17,5 @@ var wasmImports = { var expD1 = Module["expD1"] = asm["c"]; var expI1 = Module["expI1"] = function() { - return Module["asm"]["d"].apply(null, arguments); + return wasmExports["d"].apply(null, arguments); }; diff --git a/test/optimizer/applyImportAndExportNameChanges.js b/test/optimizer/applyImportAndExportNameChanges.js index 39754cc73ff19..ebdc723961a27 100644 --- a/test/optimizer/applyImportAndExportNameChanges.js +++ b/test/optimizer/applyImportAndExportNameChanges.js @@ -18,7 +18,7 @@ var expD1 = Module['expD1'] = asm['expD1']; // exports gotten indirectly (async compilation var expI1 = Module['expI1'] = (function() { - return Module['asm']['expI1'].apply(null, arguments); + return wasmExports['expI1'].apply(null, arguments); }); // EXTRA_INFO: { "mapping": {"save1" : "a", "number": "A", "expD1": "c", "expI1": "d", "__wasm_call_ctors": "e", "stackRestore": "h", "stackAlloc": "g", "__syscall140": "d", "main": "f", "__syscall146": "q", "__syscall54": "c", "__syscall6": "b" }} diff --git a/test/optimizer/emitDCEGraph.js b/test/optimizer/emitDCEGraph.js index 5a696f3d6149b..57f1d680fe37d 100644 --- a/test/optimizer/emitDCEGraph.js +++ b/test/optimizer/emitDCEGraph.js @@ -53,13 +53,13 @@ var expD4 = Module['expD4'] = asm['expD4']; var expD5 = asm['expD5']; // exports gotten indirectly (async compilation -var expI1 = Module['expI1'] = () => (expI1 = Module['expI1'] = Module['asm']['expI1'])(); -var expI2 = Module['expI2'] = () => (expI2 = Module['expI2'] = Module['asm']['expI2'])(); -var expI3 = Module['expI3'] = () => (expI3 = Module['expI3'] = Module['asm']['expI3'])(); -var expI4 = Module['expI4'] = () => (expI4 = Module['expI4'] = Module['asm']['expI4'])(); +var expI1 = Module['expI1'] = () => (expI1 = Module['expI1'] = wasmExports['expI1'])(); +var expI2 = Module['expI2'] = () => (expI2 = Module['expI2'] = wasmExports['expI2'])(); +var expI3 = Module['expI3'] = () => (expI3 = Module['expI3'] = wasmExports['expI3'])(); +var expI4 = Module['expI4'] = () => (expI4 = Module['expI4'] = wasmExports['expI4'])(); // Same as above but not export on the Module. -var expI5 = () => (expI5 = Module['asm']['expI5'])(); +var expI5 = () => (expI5 = wasmExports['expI5'])(); // add uses for some of them expD1; @@ -68,7 +68,7 @@ asm['expD3']; expI1; Module['expI2']; -Module['asm']['expI3']; +wasmExports['expI3']; // deep uses, that we can't scan function usedFromDeep() { @@ -86,10 +86,10 @@ var func = function() { }; // dyncalls -var dynCall_v = Module["dynCall_v"] = () => Module["asm"]["dynCall_v"](); -var dynCall_vi = Module["dynCall_vi"] = () => Module["asm"]["dynCall_vi"](); -var dynCall_vii = Module["dynCall_vii"] = () => Module["asm"]["dynCall_vii"](); -var dynCall_viii = Module["dynCall_viii"] = () => Module["asm"]["dynCall_viii"](); +var dynCall_v = Module["dynCall_v"] = () => wasmExports["dynCall_v"](); +var dynCall_vi = Module["dynCall_vi"] = () => wasmExports["dynCall_vi"](); +var dynCall_vii = Module["dynCall_vii"] = () => wasmExports["dynCall_vii"](); +var dynCall_viii = Module["dynCall_viii"] = () => wasmExports["dynCall_viii"](); dynCall_v(ptr); // use directly Module['dynCall_vi'](ptr, 1); // use on module diff --git a/test/optimizer/emitDCEGraph2.js b/test/optimizer/emitDCEGraph2.js index 36c0c5b82553b..2dc97f6ec4bb2 100644 --- a/test/optimizer/emitDCEGraph2.js +++ b/test/optimizer/emitDCEGraph2.js @@ -1,8 +1,8 @@ // dyncalls -var dynCall_v = Module["dynCall_v"] = () => Module["asm"]["dynCall_v"](); -var dynCall_vi = Module["dynCall_vi"] = () => Module["asm"]["dynCall_vi"](); -var dynCall_vii = Module["dynCall_vii"] = () => Module["asm"]["dynCall_vii"](); -var dynCall_viii = Module["dynCall_viii"] = () => Module["asm"]["dynCall_viii"](); +var dynCall_v = Module["dynCall_v"] = () => wasmExports["dynCall_v"](); +var dynCall_vi = Module["dynCall_vi"] = () => wasmExports["dynCall_vi"](); +var dynCall_vii = Module["dynCall_vii"] = () => wasmExports["dynCall_vii"](); +var dynCall_viii = Module["dynCall_viii"] = () => wasmExports["dynCall_viii"](); // a dynamic dynCall function dynCall(sig) { diff --git a/test/optimizer/emitDCEGraph3.js b/test/optimizer/emitDCEGraph3.js index 86649d06adf11..de8d6a1d5aede 100644 --- a/test/optimizer/emitDCEGraph3.js +++ b/test/optimizer/emitDCEGraph3.js @@ -1,8 +1,8 @@ // dyncalls -var dynCall_v = Module["dynCall_v"] = () => Module["asm"]["dynCall_v"](); -var dynCall_vi = Module["dynCall_vi"] = () => Module["asm"]["dynCall_vi"](); -var dynCall_vii = Module["dynCall_vii"] = () => Module["asm"]["dynCall_vii"](); -var dynCall_viii = Module["dynCall_viii"] = () => Module["asm"]["dynCall_viii"](); +var dynCall_v = Module["dynCall_v"] = () => wasmExports["dynCall_v"](); +var dynCall_vi = Module["dynCall_vi"] = () => wasmExports["dynCall_vi"](); +var dynCall_vii = Module["dynCall_vii"] = () => wasmExports["dynCall_vii"](); +var dynCall_viii = Module["dynCall_viii"] = () => wasmExports["dynCall_viii"](); // a dynamic dynCall function dynCall(sig) { diff --git a/test/optimizer/emitDCEGraph4.js b/test/optimizer/emitDCEGraph4.js index 01a2b5ba3c4e2..0cb8e4fe2cb1b 100644 --- a/test/optimizer/emitDCEGraph4.js +++ b/test/optimizer/emitDCEGraph4.js @@ -1,8 +1,8 @@ // dyncalls -var dynCall_v = Module["dynCall_v"] = () => Module["asm"]["dynCall_v"](); -var dynCall_vi = Module["dynCall_vi"] = () => Module["asm"]["dynCall_vi"](); -var dynCall_vii = Module["dynCall_vii"] = () => Module["asm"]["dynCall_vii"](); -var dynCall_viii = Module["dynCall_viii"] = () => Module["asm"]["dynCall_viii"](); +var dynCall_v = Module["dynCall_v"] = () => wasmExports["dynCall_v"](); +var dynCall_vi = Module["dynCall_vi"] = () => wasmExports["dynCall_vi"](); +var dynCall_vii = Module["dynCall_vii"] = () => wasmExports["dynCall_vii"](); +var dynCall_viii = Module["dynCall_viii"] = () => wasmExports["dynCall_viii"](); // a dynamic dynCall function dynCall(sig) { diff --git a/test/optimizer/emitDCEGraph5.js b/test/optimizer/emitDCEGraph5.js index 1fe3255725eb4..5a8f284fd8110 100644 --- a/test/optimizer/emitDCEGraph5.js +++ b/test/optimizer/emitDCEGraph5.js @@ -1,14 +1,14 @@ // wasm backend notation has one fewer _ in the wasm __GLOBAL__I_000101(); // var use -var __GLOBAL__I_000101 = Module["__GLOBAL__I_000101"] = () => Module["asm"]["_GLOBAL__I_000101"](); +var __GLOBAL__I_000101 = Module["__GLOBAL__I_000101"] = () => wasmExports["_GLOBAL__I_000101"](); __ATINIT__.push({ func: function() { __GLOBAL__I_iostream() } }); // var use inside other scope -var __GLOBAL__I_iostream = Module["__GLOBAL__I_iostream"] = () => Module["asm"]["_GLOBAL__I_iostream.cpp"](); +var __GLOBAL__I_iostream = Module["__GLOBAL__I_iostream"] = () => wasmExports["_GLOBAL__I_iostream.cpp"](); Module["__DUB"](); // module use -var __DUB = Module["__DUB"] = () => Module["asm"]["_DUB"](); +var __DUB = Module["__DUB"] = () => wasmExports["_DUB"](); -var __UNUSED = Module["__UNUSED"] = () => Module["asm"]["_UNUSED"](); +var __UNUSED = Module["__UNUSED"] = () => wasmExports["_UNUSED"](); var wasmImports = { }; diff --git a/test/other/metadce/test_metadce_cxx_ctors1.jssize b/test/other/metadce/test_metadce_cxx_ctors1.jssize index 932008f582603..9c7dcb5f10caa 100644 --- a/test/other/metadce/test_metadce_cxx_ctors1.jssize +++ b/test/other/metadce/test_metadce_cxx_ctors1.jssize @@ -1 +1 @@ -25162 +25131 diff --git a/test/other/metadce/test_metadce_cxx_ctors2.jssize b/test/other/metadce/test_metadce_cxx_ctors2.jssize index 7d6f9f4fcb113..29e6c7956ce8c 100644 --- a/test/other/metadce/test_metadce_cxx_ctors2.jssize +++ b/test/other/metadce/test_metadce_cxx_ctors2.jssize @@ -1 +1 @@ -25126 +25099 diff --git a/test/other/metadce/test_metadce_cxx_except.jssize b/test/other/metadce/test_metadce_cxx_except.jssize index 31382fbfc5b6f..2e168b495c58f 100644 --- a/test/other/metadce/test_metadce_cxx_except.jssize +++ b/test/other/metadce/test_metadce_cxx_except.jssize @@ -1 +1 @@ -29381 +29309 diff --git a/test/other/metadce/test_metadce_cxx_except_wasm.jssize b/test/other/metadce/test_metadce_cxx_except_wasm.jssize index 9f5a6b7e142b5..1ed3deaf231af 100644 --- a/test/other/metadce/test_metadce_cxx_except_wasm.jssize +++ b/test/other/metadce/test_metadce_cxx_except_wasm.jssize @@ -1 +1 @@ -24934 +24899 diff --git a/test/other/metadce/test_metadce_cxx_mangle.jssize b/test/other/metadce/test_metadce_cxx_mangle.jssize index bf13479dc9dbe..2e04db4e448da 100644 --- a/test/other/metadce/test_metadce_cxx_mangle.jssize +++ b/test/other/metadce/test_metadce_cxx_mangle.jssize @@ -1 +1 @@ -29380 +29308 diff --git a/test/other/metadce/test_metadce_cxx_noexcept.jssize b/test/other/metadce/test_metadce_cxx_noexcept.jssize index 932008f582603..9c7dcb5f10caa 100644 --- a/test/other/metadce/test_metadce_cxx_noexcept.jssize +++ b/test/other/metadce/test_metadce_cxx_noexcept.jssize @@ -1 +1 @@ -25162 +25131 diff --git a/test/other/metadce/test_metadce_cxx_wasmfs.jssize b/test/other/metadce/test_metadce_cxx_wasmfs.jssize index 061a3386086a8..d715aa47f772a 100644 --- a/test/other/metadce/test_metadce_cxx_wasmfs.jssize +++ b/test/other/metadce/test_metadce_cxx_wasmfs.jssize @@ -1 +1 @@ -12782 +12738 diff --git a/test/other/metadce/test_metadce_files_js_fs.jssize b/test/other/metadce/test_metadce_files_js_fs.jssize index d40d40ee4a8c4..28928313b7c12 100644 --- a/test/other/metadce/test_metadce_files_js_fs.jssize +++ b/test/other/metadce/test_metadce_files_js_fs.jssize @@ -1 +1 @@ -20017 +20006 diff --git a/test/other/metadce/test_metadce_files_wasmfs.jssize b/test/other/metadce/test_metadce_files_wasmfs.jssize index 4f40381880967..d0e4578842119 100644 --- a/test/other/metadce/test_metadce_files_wasmfs.jssize +++ b/test/other/metadce/test_metadce_files_wasmfs.jssize @@ -1 +1 @@ -7261 +7248 diff --git a/test/other/metadce/test_metadce_hello_O0.jssize b/test/other/metadce/test_metadce_hello_O0.jssize index cf408f75c258d..c1e0a1605ef6d 100644 --- a/test/other/metadce/test_metadce_hello_O0.jssize +++ b/test/other/metadce/test_metadce_hello_O0.jssize @@ -1 +1 @@ -23608 +23618 diff --git a/test/other/metadce/test_metadce_hello_O1.jssize b/test/other/metadce/test_metadce_hello_O1.jssize index e6f91cf78f618..f1a81086075ec 100644 --- a/test/other/metadce/test_metadce_hello_O1.jssize +++ b/test/other/metadce/test_metadce_hello_O1.jssize @@ -1 +1 @@ -8120 +8099 diff --git a/test/other/metadce/test_metadce_hello_O2.jssize b/test/other/metadce/test_metadce_hello_O2.jssize index f6cc210c14d5d..da710c1aba587 100644 --- a/test/other/metadce/test_metadce_hello_O2.jssize +++ b/test/other/metadce/test_metadce_hello_O2.jssize @@ -1 +1 @@ -5770 +5753 diff --git a/test/other/metadce/test_metadce_hello_O3.jssize b/test/other/metadce/test_metadce_hello_O3.jssize index a0096d7853f16..39a15f6e7326d 100644 --- a/test/other/metadce/test_metadce_hello_O3.jssize +++ b/test/other/metadce/test_metadce_hello_O3.jssize @@ -1 +1 @@ -5612 +5599 diff --git a/test/other/metadce/test_metadce_hello_Os.jssize b/test/other/metadce/test_metadce_hello_Os.jssize index a0096d7853f16..39a15f6e7326d 100644 --- a/test/other/metadce/test_metadce_hello_Os.jssize +++ b/test/other/metadce/test_metadce_hello_Os.jssize @@ -1 +1 @@ -5612 +5599 diff --git a/test/other/metadce/test_metadce_hello_Oz.jssize b/test/other/metadce/test_metadce_hello_Oz.jssize index a9842242a955f..41fe758666ae2 100644 --- a/test/other/metadce/test_metadce_hello_Oz.jssize +++ b/test/other/metadce/test_metadce_hello_Oz.jssize @@ -1 +1 @@ -5579 +5566 diff --git a/test/other/metadce/test_metadce_hello_dylink.jssize b/test/other/metadce/test_metadce_hello_dylink.jssize index 275ec65133ebe..3581a17bb1bf0 100644 --- a/test/other/metadce/test_metadce_hello_dylink.jssize +++ b/test/other/metadce/test_metadce_hello_dylink.jssize @@ -1 +1 @@ -14984 +14947 diff --git a/test/other/metadce/test_metadce_hello_export_nothing.jssize b/test/other/metadce/test_metadce_hello_export_nothing.jssize index 47a5f696c312c..38e1efbb38055 100644 --- a/test/other/metadce/test_metadce_hello_export_nothing.jssize +++ b/test/other/metadce/test_metadce_hello_export_nothing.jssize @@ -1 +1 @@ -4399 +4387 diff --git a/test/other/metadce/test_metadce_hello_wasmfs.jssize b/test/other/metadce/test_metadce_hello_wasmfs.jssize index a0096d7853f16..39a15f6e7326d 100644 --- a/test/other/metadce/test_metadce_hello_wasmfs.jssize +++ b/test/other/metadce/test_metadce_hello_wasmfs.jssize @@ -1 +1 @@ -5612 +5599 diff --git a/test/other/metadce/test_metadce_libcxxabi_message_O3.jssize b/test/other/metadce/test_metadce_libcxxabi_message_O3.jssize index e8ca47dace4bb..9110c0a1f5e4e 100644 --- a/test/other/metadce/test_metadce_libcxxabi_message_O3.jssize +++ b/test/other/metadce/test_metadce_libcxxabi_message_O3.jssize @@ -1 +1 @@ -4900 +4884 diff --git a/test/other/metadce/test_metadce_libcxxabi_message_O3_standalone.jssize b/test/other/metadce/test_metadce_libcxxabi_message_O3_standalone.jssize index 032c246660549..f32a182f1e944 100644 --- a/test/other/metadce/test_metadce_libcxxabi_message_O3_standalone.jssize +++ b/test/other/metadce/test_metadce_libcxxabi_message_O3_standalone.jssize @@ -1 +1 @@ -4955 +4943 diff --git a/test/other/metadce/test_metadce_mem_O3.jssize b/test/other/metadce/test_metadce_mem_O3.jssize index 33f6a20952b66..a3e3339d9adde 100644 --- a/test/other/metadce/test_metadce_mem_O3.jssize +++ b/test/other/metadce/test_metadce_mem_O3.jssize @@ -1 +1 @@ -5791 +5774 diff --git a/test/other/metadce/test_metadce_mem_O3_grow.jssize b/test/other/metadce/test_metadce_mem_O3_grow.jssize index 124a6d8c38ff0..3dec175604739 100644 --- a/test/other/metadce/test_metadce_mem_O3_grow.jssize +++ b/test/other/metadce/test_metadce_mem_O3_grow.jssize @@ -1 +1 @@ -6111 +6094 diff --git a/test/other/metadce/test_metadce_mem_O3_grow_standalone.jssize b/test/other/metadce/test_metadce_mem_O3_grow_standalone.jssize index ceaeb5c589e57..5de66124ada49 100644 --- a/test/other/metadce/test_metadce_mem_O3_grow_standalone.jssize +++ b/test/other/metadce/test_metadce_mem_O3_grow_standalone.jssize @@ -1 +1 @@ -5534 +5524 diff --git a/test/other/metadce/test_metadce_mem_O3_standalone.jssize b/test/other/metadce/test_metadce_mem_O3_standalone.jssize index 4e8a6e6d26b46..af7b5602a2960 100644 --- a/test/other/metadce/test_metadce_mem_O3_standalone.jssize +++ b/test/other/metadce/test_metadce_mem_O3_standalone.jssize @@ -1 +1 @@ -5464 +5454 diff --git a/test/other/metadce/test_metadce_mem_O3_standalone_lib.jssize b/test/other/metadce/test_metadce_mem_O3_standalone_lib.jssize index a98eb3384ccbe..b95028bcc655d 100644 --- a/test/other/metadce/test_metadce_mem_O3_standalone_lib.jssize +++ b/test/other/metadce/test_metadce_mem_O3_standalone_lib.jssize @@ -1 +1 @@ -4947 +4931 diff --git a/test/other/metadce/test_metadce_mem_O3_standalone_narg.jssize b/test/other/metadce/test_metadce_mem_O3_standalone_narg.jssize index 032c246660549..f32a182f1e944 100644 --- a/test/other/metadce/test_metadce_mem_O3_standalone_narg.jssize +++ b/test/other/metadce/test_metadce_mem_O3_standalone_narg.jssize @@ -1 +1 @@ -4955 +4943 diff --git a/test/other/metadce/test_metadce_mem_O3_standalone_narg_flto.jssize b/test/other/metadce/test_metadce_mem_O3_standalone_narg_flto.jssize index 032c246660549..f32a182f1e944 100644 --- a/test/other/metadce/test_metadce_mem_O3_standalone_narg_flto.jssize +++ b/test/other/metadce/test_metadce_mem_O3_standalone_narg_flto.jssize @@ -1 +1 @@ -4955 +4943 diff --git a/test/other/metadce/test_metadce_minimal_64.jssize b/test/other/metadce/test_metadce_minimal_64.jssize index 069ccfea1e738..e78293ac9dd39 100644 --- a/test/other/metadce/test_metadce_minimal_64.jssize +++ b/test/other/metadce/test_metadce_minimal_64.jssize @@ -1 +1 @@ -3816 +3800 diff --git a/test/other/metadce/test_metadce_minimal_O0.jssize b/test/other/metadce/test_metadce_minimal_O0.jssize index f13838c964c6f..c1a965883efa2 100644 --- a/test/other/metadce/test_metadce_minimal_O0.jssize +++ b/test/other/metadce/test_metadce_minimal_O0.jssize @@ -1 +1 @@ -20071 +20085 diff --git a/test/other/metadce/test_metadce_minimal_O1.jssize b/test/other/metadce/test_metadce_minimal_O1.jssize index e796b990fedb2..5b9e54fbbe923 100644 --- a/test/other/metadce/test_metadce_minimal_O1.jssize +++ b/test/other/metadce/test_metadce_minimal_O1.jssize @@ -1 +1 @@ -4594 +4581 diff --git a/test/other/metadce/test_metadce_minimal_O2.jssize b/test/other/metadce/test_metadce_minimal_O2.jssize index f10d1076aa29f..142b126313a0a 100644 --- a/test/other/metadce/test_metadce_minimal_O2.jssize +++ b/test/other/metadce/test_metadce_minimal_O2.jssize @@ -1 +1 @@ -3518 +3504 diff --git a/test/other/metadce/test_metadce_minimal_O3.jssize b/test/other/metadce/test_metadce_minimal_O3.jssize index 50f95fc714b79..d0f1d7566f6da 100644 --- a/test/other/metadce/test_metadce_minimal_O3.jssize +++ b/test/other/metadce/test_metadce_minimal_O3.jssize @@ -1 +1 @@ -3447 +3433 diff --git a/test/other/metadce/test_metadce_minimal_Os.jssize b/test/other/metadce/test_metadce_minimal_Os.jssize index 50f95fc714b79..d0f1d7566f6da 100644 --- a/test/other/metadce/test_metadce_minimal_Os.jssize +++ b/test/other/metadce/test_metadce_minimal_Os.jssize @@ -1 +1 @@ -3447 +3433 diff --git a/test/other/metadce/test_metadce_minimal_Oz-ctors.jssize b/test/other/metadce/test_metadce_minimal_Oz-ctors.jssize index d6ff78ac4e40f..7295ecbcfb36c 100644 --- a/test/other/metadce/test_metadce_minimal_Oz-ctors.jssize +++ b/test/other/metadce/test_metadce_minimal_Oz-ctors.jssize @@ -1 +1 @@ -3428 +3418 diff --git a/test/other/metadce/test_metadce_minimal_Oz.jssize b/test/other/metadce/test_metadce_minimal_Oz.jssize index 50f95fc714b79..d0f1d7566f6da 100644 --- a/test/other/metadce/test_metadce_minimal_Oz.jssize +++ b/test/other/metadce/test_metadce_minimal_Oz.jssize @@ -1 +1 @@ -3447 +3433 diff --git a/test/other/metadce/test_metadce_minimal_pthreads.jssize b/test/other/metadce/test_metadce_minimal_pthreads.jssize index 9f678c8e9b1ab..3993878409619 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.jssize +++ b/test/other/metadce/test_metadce_minimal_pthreads.jssize @@ -1 +1 @@ -14608 +14536 diff --git a/test/other/metadce/test_metadce_minimal_wasmfs.jssize b/test/other/metadce/test_metadce_minimal_wasmfs.jssize index 50f95fc714b79..d0f1d7566f6da 100644 --- a/test/other/metadce/test_metadce_minimal_wasmfs.jssize +++ b/test/other/metadce/test_metadce_minimal_wasmfs.jssize @@ -1 +1 @@ -3447 +3433 diff --git a/test/other/test_split_module.post.js b/test/other/test_split_module.post.js index a8e5a51aa3694..4dba106b6759b 100644 --- a/test/other/test_split_module.post.js +++ b/test/other/test_split_module.post.js @@ -1,5 +1,5 @@ function saveProfileData() { - var __write_profile = Module['asm']['__write_profile']; + var __write_profile = wasmExports['__write_profile']; if (__write_profile) { var len = __write_profile(0, 0); var offset = _malloc(len); diff --git a/test/other/test_unoptimized_code_size.js.size b/test/other/test_unoptimized_code_size.js.size index 73e9bd10685b5..74419340f1930 100644 --- a/test/other/test_unoptimized_code_size.js.size +++ b/test/other/test_unoptimized_code_size.js.size @@ -1 +1 @@ -58144 +58278 diff --git a/test/other/test_unoptimized_code_size_no_asserts.js.size b/test/other/test_unoptimized_code_size_no_asserts.js.size index c71d392167be6..699f9230a6da9 100644 --- a/test/other/test_unoptimized_code_size_no_asserts.js.size +++ b/test/other/test_unoptimized_code_size_no_asserts.js.size @@ -1 +1 @@ -31977 +31987 diff --git a/test/other/test_unoptimized_code_size_strict.js.size b/test/other/test_unoptimized_code_size_strict.js.size index 73b60adfbfa97..4a2d303f895ae 100644 --- a/test/other/test_unoptimized_code_size_strict.js.size +++ b/test/other/test_unoptimized_code_size_strict.js.size @@ -1 +1 @@ -57110 +57244 diff --git a/test/test_other.py b/test/test_other.py index 7c4175bdb4e37..98de21eb56347 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -3281,29 +3281,36 @@ def test_exported_runtime_methods(self): create_file('count.c', ''' #include int count(const char *str) { - return (int)strlen(str); + return (int)strlen(str); } ''') create_file('index.js', ''' const count = require('./count.js'); - console.log(count.FS_writeFile); + count.onRuntimeInitialized = () => { + if (count.wasmExports && 'count' in count.wasmExports) { + console.log('wasmExports found'); + } else { + console.log('wasmExports NOT found'); + } + }; ''') - reference_error_text = 'undefined' - - self.run_process([EMCC, 'count.c', '-sFORCE_FILESYSTEM', - '-sEXPORTED_RUNTIME_METHODS=FS_writeFile', '-o', 'count.js']) + self.run_process([EMCC, 'count.c', '-sFORCE_FILESYSTEM', '-sEXPORTED_FUNCTIONS=_count', + '-sEXPORTED_RUNTIME_METHODS=FS_writeFile,wasmExports', '-o', 'count.js']) # Check that the Module.FS_writeFile exists - self.assertNotContained(reference_error_text, self.run_js('index.js')) + out = self.run_js('index.js') + self.assertNotContained('undefined', out) + self.assertContained('wasmExports found', out) self.run_process([EMCC, 'count.c', '-sFORCE_FILESYSTEM', '-o', 'count.js']) # Check that the Module.FS_writeFile is not exported - out = self.run_js('index.js') - self.assertContained(reference_error_text, out) + out = self.run_js('index.js', assert_returncode=NON_ZERO) + self.assertContained('undefined', out), + self.assertContained("Aborted('wasmExports' was not exported. add it to EXPORTED_RUNTIME_METHODS", out) def test_exported_runtime_methods_from_js_library(self): create_file('pre.js', ''' @@ -10802,10 +10809,20 @@ def test_assertions_on_internal_api_changes(self): } catch(e) { out('error: ' + e); } + try { + Module['asm']; + out('it should not be there'); + } catch(e) { + out('error: ' + e); + } }); } ''') - self.do_runf('src.c', 'Module.read has been replaced with plain read', emcc_args=['-sASSERTIONS']) + expected = [ + '`Module.read` has been replaced by `read_`', + '`Module.asm` has been replaced by `wasmExports`', + ] + self.do_runf('src.c', expected, assert_all=True, emcc_args=['-sASSERTIONS']) def test_assertions_on_incoming_module_api_changes(self): create_file('pre.js', 'Module.read = () => {};') @@ -10834,9 +10851,9 @@ def test_assertions_on_outgoing_module_api_changes(self): } ''') expected = ''' -Aborted(Module.read has been replaced with plain read_ (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)) -Aborted(Module.wasmBinary has been replaced with plain wasmBinary (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)) -Aborted(Module.arguments has been replaced with plain arguments_ (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)) +Aborted(`Module.read` has been replaced by `read_` (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)) +Aborted(`Module.wasmBinary` has been replaced by `wasmBinary` (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)) +Aborted(`Module.arguments` has been replaced by `arguments_` (the initial value can be provided on Module, but after startup the value is only looked for on a local variable of that name)) ''' self.do_runf('src.cpp', expected, emcc_args=['-sASSERTIONS']) diff --git a/tools/acorn-optimizer.js b/tools/acorn-optimizer.js index abb405a493577..4ae42317fe656 100755 --- a/tools/acorn-optimizer.js +++ b/tools/acorn-optimizer.js @@ -465,22 +465,23 @@ function getWasmImportsValue(node) { return node.declarations[0].init; } -function isAsmUse(node) { +function isExportUse(node) { + // MINIMAL_RUNTIME calls exports global variable `asm`, whereas regualar + // runtime calls it `wasmExports`. + // + // Here we match either: + // wasmExports['X'] + // or: + // asm['X'] return ( node.type === 'MemberExpression' && - ((node.object.type === 'Identifier' && // asm['X'] - node.object.name === 'asm' && - node.property.type === 'Literal') || - (node.object.type === 'MemberExpression' && // Module['asm']['X'] - node.object.object.type === 'Identifier' && - node.object.object.name === 'Module' && - node.object.property.type === 'Literal' && - node.object.property.value === 'asm' && - isLiteralString(node.property))) + node.object.type === 'Identifier' && + isLiteralString(node.property) && + (node.object.name === 'wasmExports' || node.object.name === 'asm') ); } -function getAsmOrModuleUseName(node) { +function getExportOrModuleUseName(node) { return node.property.value; } @@ -493,19 +494,6 @@ function isModuleUse(node) { ); } -function isModuleAsmUse(node) { - // Module['asm'][..string..] - return ( - node.type === 'MemberExpression' && - node.object.type === 'MemberExpression' && - node.object.object.type === 'Identifier' && - node.object.object.name === 'Module' && - node.object.property.type === 'Literal' && - node.object.property.value === 'asm' && - isLiteralString(node.property) - ); -} - // Apply import/export name changes (after minifying them) function applyImportAndExportNameChanges(ast) { const mapping = extraInfo.mapping; @@ -520,26 +508,20 @@ function applyImportAndExportNameChanges(ast) { } else if (node.type === 'AssignmentExpression') { const target = node.left; const value = node.right; - if (isAsmUse(value)) { + if (isExportUse(value)) { const name = value.property.value; if (mapping[name]) { setLiteralValue(value.property, mapping[name]); } } - } else if (node.type === 'CallExpression' && isAsmUse(node.callee)) { + } else if (node.type === 'CallExpression' && isExportUse(node.callee)) { // asm["___wasm_call_ctors"](); -> asm["M"](); const callee = node.callee; const name = callee.property.value; if (mapping[name]) { setLiteralValue(callee.property, mapping[name]); } - } else if (isModuleAsmUse(node)) { - const prop = node.property; - const name = prop.value; - if (mapping[name]) { - setLiteralValue(prop, mapping[name]); - } - } else if (isAsmUse(node)) { + } else if (isExportUse(node)) { const prop = node.property; const name = prop.value; if (mapping[name]) { @@ -585,7 +567,7 @@ function isDynamicDynCall(node) { // Matches the wasm export wrappers generated by emcc (see make_export_wrappers // in emscripten.py). For example: // -// var _foo = (a0, a1) => (_foo = Module['asm']['foo'])(a0, a1): +// var _foo = (a0, a1) => (_foo = wasmExports['foo'])(a0, a1): // function isExportWrapperFunction(f) { if (f.body.type != 'CallExpression') return null; @@ -594,9 +576,9 @@ function isExportWrapperFunction(f) { callee = callee.expression; } if (callee.type != 'AssignmentExpression' || callee.right.type != 'MemberExpression') return null; - const rhs = callee.right; - if (rhs.object.type != 'MemberExpression' || !isModuleUse(rhs.object)) return null; - return getAsmOrModuleUseName(rhs); + var rhs = callee.right; + if (rhs.type != 'MemberExpression' || !isExportUse(rhs)) return null; + return getExportOrModuleUseName(rhs); } // @@ -659,9 +641,7 @@ function emitDCEGraph(ast) { // // or // - // var _malloc = Module['_malloc'] = (function() { - // return Module['asm']['_malloc'].apply(null, arguments); - // }); + // var _malloc = Module['_malloc'] = (x) => wasmExports['_malloc'](x); // // or, in the minimal runtime, it looks like // @@ -717,15 +697,17 @@ function emitDCEGraph(ast) { const item = node.declarations[0]; const name = item.id.name; const value = item.init; - if (value && isAsmUse(value)) { - const asmName = getAsmOrModuleUseName(value); + if (value && isExportUse(value)) { + const asmName = getExportOrModuleUseName(value); // this is // var _x = asm['x']; + // or + // var _x = wasmExports['x']; saveAsmExport(name, asmName); emptyOut(node); } else if (value && value.type === 'ArrowFunctionExpression') { // this is - // var x = () => (x = Module['asm']['x'])(..) + // var x = () => (x = wasmExports['x'])(..) let asmName = isExportWrapperFunction(value); if (asmName) { saveAsmExport(name, asmName); @@ -733,16 +715,16 @@ function emitDCEGraph(ast) { } } else if (value && value.type === 'AssignmentExpression') { const assigned = value.left; - if (isModuleUse(assigned) && getAsmOrModuleUseName(assigned) === name) { + if (isModuleUse(assigned) && getExportOrModuleUseName(assigned) === name) { // this is // var x = Module['x'] = ? // which looks like a wasm export being received. confirm with the asm use let found = 0; let asmName; fullWalk(value.right, (node) => { - if (isAsmUse(node)) { + if (isExportUse(node)) { found++; - asmName = getAsmOrModuleUseName(node); + asmName = getExportOrModuleUseName(node); } }); // in the wasm backend, the asm name may have one fewer "_" prefixed @@ -891,7 +873,7 @@ function emitDCEGraph(ast) { reached = nameToGraphName[name]; } } else if (isModuleUse(node)) { - const name = getAsmOrModuleUseName(node); + const name = getExportOrModuleUseName(node); if (modulePropertyToGraphName.hasOwnProperty(name)) { reached = modulePropertyToGraphName[name]; } @@ -900,9 +882,9 @@ function emitDCEGraph(ast) { } else if (isDynamicDynCall(node)) { // this can reach *all* dynCall_* targets, we can't narrow it down reached = dynCallNames; - } else if (isAsmUse(node)) { + } else if (isExportUse(node)) { // any remaining asm uses are always rooted in any case - const name = getAsmOrModuleUseName(node); + const name = getExportOrModuleUseName(node); if (exportNameToGraphName.hasOwnProperty(name)) { infos[exportNameToGraphName[name]].root = true; } @@ -977,11 +959,11 @@ function applyDCEGraphRemovals(ast) { // when we assign to a thing we don't need, we can just remove the assign // var x = Module['x'] = asm['x']; const target = node.left; - if (isAsmUse(target) || isModuleUse(target)) { - const name = getAsmOrModuleUseName(target); + if (isExportUse(target) || isModuleUse(target)) { + const name = getExportOrModuleUseName(target); const full = 'emcc$export$' + name; const value = node.right; - if (unused.has(full) && (isAsmUse(value) || !hasSideEffects(value))) { + if (unused.has(full) && (isExportUse(value) || !hasSideEffects(value))) { // This will be in a var init, and we just remove that value. convertToNothingInVarInit(node); } @@ -993,8 +975,8 @@ function applyDCEGraphRemovals(ast) { // var x = function() { return (x = asm['x']).apply(...) }; const init = node.declarations[0].init; if (init) { - if (isAsmUse(init)) { - const name = getAsmOrModuleUseName(init); + if (isExportUse(init)) { + const name = getExportOrModuleUseName(init); const full = 'emcc$export$' + name; if (unused.has(full)) { convertToNothingInVarInit(init); @@ -1012,9 +994,9 @@ function applyDCEGraphRemovals(ast) { // In the minimal runtime code pattern we have just // x = asm['x'] // and never in a var. - if (expr.operator === '=' && expr.left.type === 'Identifier' && isAsmUse(expr.right)) { + if (expr.operator === '=' && expr.left.type === 'Identifier' && isExportUse(expr.right)) { const name = expr.left.name; - if (name === getAsmOrModuleUseName(expr.right)) { + if (name === getExportOrModuleUseName(expr.right)) { const full = 'emcc$export$' + name; if (unused.has(full)) { emptyOut(node); diff --git a/tools/building.py b/tools/building.py index 21c54cc7771dc..8c424b2f97698 100644 --- a/tools/building.py +++ b/tools/building.py @@ -371,7 +371,7 @@ def eval_ctors(js_file, wasm_file, debug_info): if settings.MINIMAL_RUNTIME: CTOR_ADD_PATTERN = f"asm['{WASM_CALL_CTORS}']();" # TODO test else: - CTOR_ADD_PATTERN = f"addOnInit(Module['asm']['{WASM_CALL_CTORS}']);" + CTOR_ADD_PATTERN = f"addOnInit(wasmExports['{WASM_CALL_CTORS}']);" js = utils.read_file(js_file) From a3fd28f4ccdc9742ecd6714fb5e62e4a00a0e6df Mon Sep 17 00:00:00 2001 From: Brendan Dahl Date: Wed, 12 Jul 2023 13:17:02 -0700 Subject: [PATCH 0557/1523] JSPI - Cleanup up testing code. (#19837) - Automatically suppress the experimental warning when using require_jspi - Use require_jspi instead of require_v8 in more places --- test/common.py | 4 ++++ test/test_core.py | 12 ++---------- test/test_other.py | 19 +++++++------------ 3 files changed, 13 insertions(+), 22 deletions(-) diff --git a/test/common.py b/test/common.py index 18011ab6bbd2f..b76beff2d790d 100644 --- a/test/common.py +++ b/test/common.py @@ -656,6 +656,10 @@ def require_wasm_eh(self): self.fail('either d8 or node >= 17 required to run wasm-eh tests. Use EMTEST_SKIP_EH to skip') def require_jspi(self): + # emcc warns about stack switching being experimental, and we build with + # warnings-as-errors, so disable that warning + self.emcc_args += ['-Wno-experimental'] + self.emcc_args += ['-sASYNCIFY=2'] if not self.is_wasm(): self.skipTest('JSPI is not currently supported for WASM2JS') diff --git a/test/test_core.py b/test/test_core.py index d01a41eed2b39..cca29dc84aeed 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -190,11 +190,6 @@ def metafunc(self, jspi): if jspi: self.set_setting('ASYNCIFY', 2) self.require_jspi() - if not self.is_wasm(): - self.skipTest('wasm2js does not support WebAssembly.Suspender yet') - # emcc warns about stack switching being experimental, and we build with - # warnings-as-errors, so disable that warning - self.emcc_args += ['-Wno-experimental'] f(self) else: self.set_setting('ASYNCIFY') @@ -8253,7 +8248,6 @@ def test_async_ccall_good(self): def test_async_ccall_promise(self, exit_runtime, asyncify): if asyncify == 2: self.require_jspi() - self.emcc_args += ['-Wno-experimental'] self.set_setting('ASYNCIFY_EXPORTS', ['stringf', 'floatf']) self.set_setting('ASYNCIFY', asyncify) self.set_setting('EXIT_RUNTIME') @@ -8431,11 +8425,9 @@ def test_pthread_join_and_asyncify(self): # TODO Test with ASYNCIFY=1 https://github.com/emscripten-core/emscripten/issues/17552 self.require_jspi() self.do_runf(test_file('core/test_pthread_join_and_asyncify.c'), 'joining thread!\njoined thread!', - emcc_args=['-sASYNCIFY=2', - '-sASYNCIFY_EXPORTS=run_thread', + emcc_args=['-sASYNCIFY_EXPORTS=run_thread', '-sEXIT_RUNTIME=1', - '-pthread', '-sPROXY_TO_PTHREAD', - '-Wno-experimental']) + '-pthread', '-sPROXY_TO_PTHREAD']) @no_asan('asyncify stack operations confuse asan') @no_wasm64('TODO: asyncify for wasm64') diff --git a/test/test_other.py b/test/test_other.py index 98de21eb56347..debb35bbc9011 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -2745,9 +2745,8 @@ def test_embind_asyncify(self): 'no_dynamic': ['-sDYNAMIC_EXECUTION=0'], }) def test_embind_jspi(self, extra): - self.require_v8() - self.v8_args.append('--experimental-wasm-stack-switching') - self.emcc_args += ['-lembind', '-g', '-sASYNCIFY=2', '-Wno-experimental'] + self.require_jspi() + self.emcc_args += ['-lembind', '-g'] self.emcc_args += [extra] self.do_runf(test_file('embind/embind_jspi_test.cpp'), 'done') @@ -2870,9 +2869,8 @@ def test_embind_finalization(self): self.assertNotContained('Foo* destructed', output) def test_jspi_wildcard(self): - self.require_v8() - self.v8_args.append('--experimental-wasm-stack-switching') - self.emcc_args += ['-sASYNCIFY=2', '-sASYNCIFY_EXPORTS=async*', '-Wno-experimental'] + self.require_jspi() + self.emcc_args += ['-sASYNCIFY_EXPORTS=async*'] self.do_runf(test_file('other/test_jspi_wildcard.c'), 'done') @@ -6685,9 +6683,7 @@ def test_dlopen_blocking(self, asyncify): if asyncify: self.set_setting('ASYNCIFY', asyncify) if asyncify == 2: - self.emcc_args.append('-Wno-experimental') - self.require_v8() - self.v8_args.append('--experimental-wasm-stack-switching') + self.require_jspi() self.emcc_args.append('libside.so') self.do_other_test('test_dlopen_blocking.c') @@ -11821,9 +11817,8 @@ def test_split_module(self, customLoader, jspi): if customLoader: self.emcc_args += ['--pre-js', test_file('other/test_load_split_module.pre.js')] if jspi: - self.require_v8() - self.v8_args.append('--experimental-wasm-stack-switching') - self.emcc_args += ['-g', '-sASYNCIFY=2', '-sASYNCIFY_EXPORTS=[\'say_hello\']'] + self.require_jspi() + self.emcc_args += ['-g', '-sASYNCIFY_EXPORTS=[\'say_hello\']'] self.emcc_args += ['-sEXPORTED_FUNCTIONS=_malloc,_free'] output = self.do_other_test('test_split_module.c') if jspi: From 3a717f637d15839f85415ee31eb1d9d844a19c2d Mon Sep 17 00:00:00 2001 From: Rob Hulswit Date: Thu, 13 Jul 2023 00:05:35 +0200 Subject: [PATCH 0558/1523] Fix synchronous functions being added to Asyncify.asyncExports (#19839) * Fix synchronous functions being added to Asyncify.asyncExports * Use require_jspi, rename to add_function --- src/library_async.js | 2 +- test/other/test_jspi_add_function.c | 23 +++++++++++++++++++++++ test/test_other.py | 10 ++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 test/other/test_jspi_add_function.c diff --git a/src/library_async.js b/src/library_async.js index 0c088067b982c..f076bc11b0ec0 100644 --- a/src/library_async.js +++ b/src/library_async.js @@ -121,8 +121,8 @@ mergeInto(LibraryManager.library, { #if ASYNCIFY == 2 // Wrap all exports with a promising WebAssembly function. var isAsyncifyExport = exportPatterns.some(pattern => !!x.match(pattern)); - Asyncify.asyncExports.add(original); if (isAsyncifyExport) { + Asyncify.asyncExports.add(original); original = Asyncify.makeAsyncFunction(original); } #endif diff --git a/test/other/test_jspi_add_function.c b/test/other/test_jspi_add_function.c new file mode 100644 index 0000000000000..3403e3ad96962 --- /dev/null +++ b/test/other/test_jspi_add_function.c @@ -0,0 +1,23 @@ +// Copyright 2023 The Emscripten Authors. All rights reserved. +// Emscripten is available under two separate licenses, the MIT license and the +// University of Illinois/NCSA Open Source License. Both these licenses can be +// found in the LICENSE file. + +#include +#include + +// Use EMSCRIPTEN_KEEPALIVE to make sure this function ends up in the wasmTable +EMSCRIPTEN_KEEPALIVE void sync1() { + printf("done\n"); +} + +EM_JS(int, getFunc, (em_callback_func func), { + /* this calls updateTableMap, which will call getWasmTableEntry on all functions + in the wasmTable. If sync1 was registered as asynchronous, that function will fail */ + return Module.addFunction(() => dynCall("v", func), "i"); +}); + +int main() { + int (*callback)() = (int (*)())getFunc(&sync1); + callback(); +} diff --git a/test/test_other.py b/test/test_other.py index debb35bbc9011..3196ebdb9e95b 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -2874,6 +2874,16 @@ def test_jspi_wildcard(self): self.do_runf(test_file('other/test_jspi_wildcard.c'), 'done') + def test_jspi_add_function(self): + # make sure synchronous functions in the wasmTable aren't processed with Asyncify.makeAsyncFunction + self.require_jspi() + self.emcc_args += [ + '-sASYNCIFY=2', + '-sEXPORTED_RUNTIME_METHODS=addFunction,dynCall', + '-sALLOW_TABLE_GROWTH=1', + '-Wno-experimental'] + self.do_runf(test_file('other/test_jspi_add_function.c'), 'done') + def test_embind_tsgen(self): self.run_process([EMCC, test_file('other/embind_tsgen.cpp'), '-lembind', '--embind-emit-tsd', 'embind_tsgen.d.ts']) From fd8d7f617faaae9f21ea98b55c6979b10ec6bce6 Mon Sep 17 00:00:00 2001 From: Derek Schuff Date: Wed, 12 Jul 2023 18:01:25 -0700 Subject: [PATCH 0559/1523] Refactor debug info tests (#19852) Previously different tests verified the existence of DWARF, sourcemap, and name section output, for non-overlapping sets of flags. This refactoring unifies the testing logic for the 3 forms of debug info and adds a few combinations. It doesn't change tests that verify the DWARF contents or JS output. --- test/test_other.py | 117 +++++++++++++++++++++------------------------ 1 file changed, 55 insertions(+), 62 deletions(-) diff --git a/test/test_other.py b/test/test_other.py index 3196ebdb9e95b..8aff3929f8d24 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -2664,6 +2664,14 @@ def verify_source_map_exists(self, map_file): self.assertIn('sources', data) self.assertIn('mappings', data) + def verify_name_sec_existence(self, wasm_file, expect_names): + with webassembly.Module(wasm_file) as module: + section = module.get_custom_section("name") + if expect_names: + self.assertIsNotNone(section, "Name section unexpectedly missing") + else: + self.assertIsNone(section, "Name section unexpectedly found") + def test_dwarf(self): def compile_with_dwarf(args, output): # Test that -g enables dwarf info in object files and linked wasm @@ -2673,28 +2681,47 @@ def compile_with_dwarf(args, output): compile_with_dwarf([], 'a.js') self.verify_dwarf_exists('a.wasm') - def test_dwarf_with_source_map(self): + def test_dwarf_sourcemap_names(self): source_file = 'hello_world.c' js_file = 'a.out.js' wasm_file = 'a.out.wasm' map_file = 'a.out.wasm.map' - # Generate only DWARF - self.emcc(test_file(source_file), ['-g'], js_file) - self.verify_dwarf_exists(wasm_file) - self.assertFalse(os.path.isfile(map_file)) - self.clear() + for (flags, expect_dwarf, expect_sourcemap, expect_names) in [ + ([], False, False, False), + (['-g0'], False, False, False), + (['-g1'], False, False, False), + # last numeric g flag "wins", so g0 overrides -g + (['-g', '-g0'], False, False, False), + (['-g2'], False, False, True), + (['-gline-tables-only'], True, False, True), + (['--profiling'], False, False, True), + (['--profiling-funcs'], False, False, True), + (['-g'], True, False, True), + (['-g3'], True, False, True), + (['-O2', '-g'], True, False, True), + (['-gsplit-dwarf'], True, False, True), + (['-gsource-map'], False, True, True), + (['-g0', '-gsource-map'], False, True, True), + # -g0 does not override -gsource-map but does remove name section. TODO: should it? + (['-gsource-map', '-g0'], False, True, False), + (['-g', '-gsource-map'], True, True, True), + # (['-gsplit-dwarf', '-gsource-map'], True, True, True), TODO this currently fails! + ]: + print(flags, expect_dwarf, expect_sourcemap, expect_names) + self.emcc(test_file(source_file), flags, js_file) - # Generate only source map - self.emcc(test_file(source_file), ['-gsource-map'], js_file) - self.verify_dwarf_does_not_exist(wasm_file) - self.verify_source_map_exists(map_file) - self.clear() + assertion = self.assertIn if expect_dwarf else self.assertNotIn + self.verify_dwarf(wasm_file, assertion) - # Generate DWARF with source map - self.emcc(test_file(source_file), ['-g', '-gsource-map'], js_file) - self.verify_dwarf_exists(wasm_file) - self.verify_source_map_exists(map_file) + if expect_sourcemap: + self.verify_source_map_exists(map_file) + else: + self.assertFalse(os.path.isfile(map_file), "Sourcemap unexpectedly exists") + + self.verify_name_sec_existence(wasm_file, expect_names) + + self.clear() @requires_scons @with_env_modify({'EMSCRIPTEN_ROOT': path_from_root()}) @@ -7681,40 +7708,6 @@ def test_output_eol(self): for f in files: delete_file(f) - def test_debug_names(self): - sizes = {} - for args, expect_names in [ - ([], False), - (['-g'], True), - (['-O1'], False), - (['-O2'], False), - (['-O2', '-g'], True), - (['-O2', '-g1'], False), - (['-O2', '-g2'], True), - (['-O2', '--profiling'], True), - (['-O2', '--profiling-funcs'], True), - ]: - print(args, expect_names) - delete_file('a.out.js') - # we use dlmalloc here, as emmalloc has a bunch of asserts that contain the text "malloc" in - # them, which makes counting harder - self.run_process([EMXX, test_file('hello_world.cpp')] + args + ['-sMALLOC="dlmalloc"', '-sEXPORTED_FUNCTIONS=_main,_malloc']) - code = read_binary('a.out.wasm') - if '-g' in args: - # With -g we get full dwarf info which means we there are many occurances of malloc - self.assertGreater(code.count(b'malloc'), 2) - else: - if expect_names: - # name section adds the name of malloc (there is also another one for the export) - self.assertEqual(code.count(b'malloc'), 2) - else: - # should be just malloc for the export - self.assertEqual(code.count(b'malloc'), 1) - sizes[str(args)] = os.path.getsize('a.out.wasm') - print(sizes) - # when -profiling-funcs, the size increases due to function names - self.assertLess(sizes["['-O2']"], sizes["['-O2', '--profiling-funcs']"]) - def test_binaryen_warn_mem(self): # if user changes INITIAL_MEMORY at runtime, the wasm module may not accept the memory import if # it is too big/small @@ -7812,20 +7805,20 @@ def test_binaryen_ctors(self): # test debug info and debuggability of JS output @crossplatform def test_binaryen_debug(self): - for args, expect_dash_g, expect_emit_text, expect_clean_js, expect_whitespace_js, expect_closured in [ - (['-O0'], False, False, False, True, False), - (['-O0', '-g1'], False, False, False, True, False), - (['-O0', '-g2'], True, False, False, True, False), # in -g2+, we emit -g to asm2wasm so function names are saved - (['-O0', '-g'], True, True, False, True, False), - (['-O0', '--profiling-funcs'], True, False, False, True, False), - (['-O1'], False, False, False, True, False), - (['-O2'], False, False, True, False, False), - (['-O2', '-g1'], False, False, True, True, False), - (['-O2', '-g'], True, True, False, True, False), - (['-O2', '--closure=1'], False, False, True, False, True), - (['-O2', '--closure=1', '-g1'], False, False, True, True, True), + for args, expect_emit_text, expect_clean_js, expect_whitespace_js, expect_closured in [ + (['-O0'], False, False, True, False), + (['-O0', '-g1'], False, False, True, False), + (['-O0', '-g2'], False, False, True, False), # in -g2+, we emit -g to asm2wasm so function names are saved + (['-O0', '-g'], True, False, True, False), + (['-O0', '--profiling-funcs'], False, False, True, False), + (['-O1'], False, False, True, False), + (['-O2'], False, True, False, False), + (['-O2', '-g1'], False, True, True, False), + (['-O2', '-g'], True, False, True, False), + (['-O2', '--closure=1'], False, True, False, True), + (['-O2', '--closure=1', '-g1'], False, True, True, True), ]: - print(args, expect_dash_g, expect_emit_text) + print(args, expect_emit_text) delete_file('a.out.wat') cmd = [EMXX, test_file('hello_world.cpp')] + args print(' '.join(cmd)) From f51ae7f00792bcb9d4af7c8fcb73d305f899ba7a Mon Sep 17 00:00:00 2001 From: Brendan Dahl Date: Thu, 13 Jul 2023 10:19:16 -0700 Subject: [PATCH 0560/1523] embind: Document TypeScript definition generation. (#19850) --- .../connecting_cpp_and_javascript/embind.rst | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/site/source/docs/porting/connecting_cpp_and_javascript/embind.rst b/site/source/docs/porting/connecting_cpp_and_javascript/embind.rst index 61fe5a3588f51..e2500f3901e2e 100644 --- a/site/source/docs/porting/connecting_cpp_and_javascript/embind.rst +++ b/site/source/docs/porting/connecting_cpp_and_javascript/embind.rst @@ -1009,6 +1009,21 @@ The following JavaScript can be used to interact with the above C++. retMap.set(10, "OtherValue"); +TypeScript Definitions +====================== + +Embind supports generating TypeScript definition files from :cpp:func:`EMSCRIPTEN_BINDINGS` +blocks. To generate **.d.ts** files invoke *emcc* with the +:ref:`embind-emit-tsd ` option:: + + emcc -lembind quick_example.cpp --embind-emit-tsd interface.d.ts + +Running this command will build the program with an instrumented version of embind +that is then run in *node* to generate the definition files. +Not all of embind's features are currently supported, but many of the commonly used +ones are. Examples of input and output can be seen in `embind_tsgen.cpp`_ and +`embind_tsgen.d.ts`_. + Performance =========== @@ -1030,3 +1045,5 @@ real-world applications has proved to be more than acceptable. .. _Backbone.js: http://backbonejs.org/#Model-extend .. _Web Audio API: https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API .. _Making sine, square, sawtooth and triangle waves: http://stuartmemo.com/making-sine-square-sawtooth-and-triangle-waves/ +.. _embind_tsgen.cpp: https://github.com/emscripten-core/emscripten/blob/main/test/other/embind_tsgen.cpp +.. _embind_tsgen.d.ts: https://github.com/emscripten-core/emscripten/blob/main/test/other/embind_tsgen.d.ts From 96df1a79c63c98deed58b18291f914cbc1208771 Mon Sep 17 00:00:00 2001 From: Arthur Islamov Date: Tue, 18 Jul 2023 00:22:11 +0400 Subject: [PATCH 0561/1523] Fix ASYNCIFY=1 with MEMORY64 (#19790) * dynCall_ receives BigInt as first argument which is an entry in wasmTable and needs to be a number. * binaryen already has i64 pointers in asyncify_data_s; _asyncify_start_rewind and _asyncify_start_unwind need a BigInt argument in MEMORY64 * When rewinding, function is called without any arguments which produces "cannot convert undefined to BigInt". So cache original arguments. --- emcc.py | 4 ++-- emscripten.py | 2 ++ src/library.js | 2 +- src/library_async.js | 46 ++++++++++++++++++++++++----------- test/test_core.py | 57 +++++++++++++++++++++++++------------------- 5 files changed, 70 insertions(+), 41 deletions(-) diff --git a/emcc.py b/emcc.py index 6983af8f1d61e..0fd3408859b5f 100755 --- a/emcc.py +++ b/emcc.py @@ -2441,8 +2441,8 @@ def phase_linker_setup(options, state, newargs): settings.JS_LIBRARIES.append((0, 'library_pthread_stub.js')) if settings.MEMORY64: - if settings.ASYNCIFY == 1 and settings.MEMORY64 == 1: - exit_with_error('MEMORY64=1 is not compatible with ASYNCIFY') + if settings.ASYNCIFY and settings.MEMORY64 == 2: + exit_with_error('MEMORY64=2 is not compatible with ASYNCIFY') # Any "pointers" passed to JS will now be i64's, in both modes. settings.WASM_BIGINT = 1 diff --git a/emscripten.py b/emscripten.py index 3939a1c32ca2f..e1308e5b03192 100644 --- a/emscripten.py +++ b/emscripten.py @@ -886,6 +886,8 @@ def create_pointer_conversion_wrappers(metadata): '_wasmfs_mkdir': '_p_', '_wasmfs_open': '_p__', 'emscripten_wasm_worker_initialize': '_p_', + 'asyncify_start_rewind': '_p', + 'asyncify_start_unwind': '_p', '__get_exception_message': '_ppp', } diff --git a/src/library.js b/src/library.js index e0ab4c8a8c603..ffd53349f58d7 100644 --- a/src/library.js +++ b/src/library.js @@ -3557,7 +3557,7 @@ mergeInto(LibraryManager.library, { #endif #if ASYNCIFY == 1 __asyncify_state: "new WebAssembly.Global({'value': 'i32', 'mutable': true}, 0)", - __asyncify_data: "new WebAssembly.Global({'value': 'i32', 'mutable': true}, 0)", + __asyncify_data: "new WebAssembly.Global({'value': '{{{ POINTER_WASM_TYPE }}}', 'mutable': true}, {{{ to64(0) }}})", #endif #endif diff --git a/src/library_async.js b/src/library_async.js index f076bc11b0ec0..25d84408b7878 100644 --- a/src/library_async.js +++ b/src/library_async.js @@ -34,6 +34,9 @@ mergeInto(LibraryManager.library, { // // Asyncify code that is shared between mode 1 (original) and mode 2 (JSPI). // +#if ASYNCIFY == 1 && MEMORY64 + rewindArguments: {}, +#endif instrumentWasmImports: function(imports) { #if ASYNCIFY_DEBUG dbg('asyncify instrumenting imports'); @@ -104,7 +107,14 @@ mergeInto(LibraryManager.library, { })(x); } }, - +#if ASYNCIFY == 1 && MEMORY64 + saveOrRestoreRewindArguments: function(funcName, passedArguments) { + if (passedArguments.length === 0) { + return Asyncify.rewindArguments[funcName] || [] + } + return Asyncify.rewindArguments[funcName] = Array.from(passedArguments) + }, +#endif instrumentWasmExports: function(exports) { #if ASYNCIFY_DEBUG dbg('asyncify instrumenting exports'); @@ -134,7 +144,15 @@ mergeInto(LibraryManager.library, { Asyncify.exportCallStack.push(x); try { #endif +#if ASYNCIFY == 1 && MEMORY64 + // When re-winding, the arguments to a function are ignored. For i32 arguments we + // can just call the function with no args at all since and the engine will produce zeros + // for all arguments. However, for i64 arguments we get `undefined cannot be converted to + // BigInt`. + return original.apply(null, Asyncify.saveOrRestoreRewindArguments(x, arguments)); +#else return original.apply(null, arguments); +#endif #if ASYNCIFY == 1 } finally { if (!ABORT) { @@ -248,8 +266,8 @@ mergeInto(LibraryManager.library, { }, setDataHeader: function(ptr, stack, stackSize) { - {{{ makeSetValue('ptr', C_STRUCTS.asyncify_data_s.stack_ptr, 'stack', 'i32') }}}; - {{{ makeSetValue('ptr', C_STRUCTS.asyncify_data_s.stack_limit, 'stack + stackSize', 'i32') }}}; + {{{ makeSetValue('ptr', C_STRUCTS.asyncify_data_s.stack_ptr, 'stack', '*') }}}; + {{{ makeSetValue('ptr', C_STRUCTS.asyncify_data_s.stack_limit, 'stack + stackSize', '*') }}}; }, setDataRewindFunc: function(ptr) { @@ -479,7 +497,7 @@ mergeInto(LibraryManager.library, { // can only allocate the buffer after the wakeUp, not during an asyncing var buffer = _malloc(byteArray.length); // must be freed by caller! HEAPU8.set(byteArray, buffer); - {{{ makeSetValue('pbuffer', 0, 'buffer', 'i32') }}}; + {{{ makeSetValue('pbuffer', 0, 'buffer', '*') }}}; {{{ makeSetValue('pnum', 0, 'byteArray.length', 'i32') }}}; {{{ makeSetValue('perror', 0, '0', 'i32') }}}; wakeUp(); @@ -500,8 +518,8 @@ mergeInto(LibraryManager.library, { // could happen if we tried to scan the stack immediately after unwinding. safeSetTimeout(() => { var stackBegin = Asyncify.currData + {{{ C_STRUCTS.asyncify_data_s.__size__ }}}; - var stackEnd = HEAP32[Asyncify.currData >> 2]; - {{{ makeDynCall('vii', 'func') }}}(stackBegin, stackEnd); + var stackEnd = {{{ makeGetValue('Asyncify.currData', 0, '*') }}}; + {{{ makeDynCall('vpp', 'func') }}}(stackBegin, stackEnd); wakeUp(); }, 0); }); @@ -553,17 +571,17 @@ mergeInto(LibraryManager.library, { * NOTE: This function is the asynchronous part of emscripten_fiber_swap. */ finishContextSwitch: function(newFiber) { - var stack_base = {{{ makeGetValue('newFiber', C_STRUCTS.emscripten_fiber_s.stack_base, 'i32') }}}; - var stack_max = {{{ makeGetValue('newFiber', C_STRUCTS.emscripten_fiber_s.stack_limit, 'i32') }}}; + var stack_base = {{{ makeGetValue('newFiber', C_STRUCTS.emscripten_fiber_s.stack_base, '*') }}}; + var stack_max = {{{ makeGetValue('newFiber', C_STRUCTS.emscripten_fiber_s.stack_limit, '*') }}}; _emscripten_stack_set_limits(stack_base, stack_max); #if STACK_OVERFLOW_CHECK >= 2 ___set_stack_limits(stack_base, stack_max); #endif - stackRestore({{{ makeGetValue('newFiber', C_STRUCTS.emscripten_fiber_s.stack_ptr, 'i32') }}}); + stackRestore({{{ makeGetValue('newFiber', C_STRUCTS.emscripten_fiber_s.stack_ptr, '*') }}}); - var entryPoint = {{{ makeGetValue('newFiber', C_STRUCTS.emscripten_fiber_s.entry, 'i32') }}}; + var entryPoint = {{{ makeGetValue('newFiber', C_STRUCTS.emscripten_fiber_s.entry, '*') }}}; if (entryPoint !== 0) { #if STACK_OVERFLOW_CHECK @@ -573,10 +591,10 @@ mergeInto(LibraryManager.library, { dbg('ASYNCIFY/FIBER: entering fiber', newFiber, 'for the first time'); #endif Asyncify.currData = null; - {{{ makeSetValue('newFiber', C_STRUCTS.emscripten_fiber_s.entry, 0, 'i32') }}}; + {{{ makeSetValue('newFiber', C_STRUCTS.emscripten_fiber_s.entry, 0, '*') }}}; - var userData = {{{ makeGetValue('newFiber', C_STRUCTS.emscripten_fiber_s.user_data, 'i32') }}}; - {{{ makeDynCall('vi', 'entryPoint') }}}(userData); + var userData = {{{ makeGetValue('newFiber', C_STRUCTS.emscripten_fiber_s.user_data, '*') }}}; + {{{ makeDynCall('vp', 'entryPoint') }}}(userData); } else { var asyncifyData = newFiber + {{{ C_STRUCTS.emscripten_fiber_s.asyncify_data }}}; Asyncify.currData = asyncifyData; @@ -611,7 +629,7 @@ mergeInto(LibraryManager.library, { _asyncify_start_unwind(asyncifyData); var stackTop = stackSave(); - {{{ makeSetValue('oldFiber', C_STRUCTS.emscripten_fiber_s.stack_ptr, 'stackTop', 'i32') }}}; + {{{ makeSetValue('oldFiber', C_STRUCTS.emscripten_fiber_s.stack_ptr, 'stackTop', '*') }}}; Fibers.nextFiber = newFiber; } else { diff --git a/test/test_core.py b/test/test_core.py index cca29dc84aeed..379aedf5983ab 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -139,6 +139,14 @@ def decorated(f): return decorated +def no_wasm64l(note=''): + assert not callable(note) + + def decorated(f): + return skip_if(f, 'is_wasm64l', note) + return decorated + + def also_with_noderawfs(func): assert callable(func) @@ -328,6 +336,9 @@ def is_wasm2js(self): def is_wasm64(self): return self.get_setting('MEMORY64') + def is_wasm64l(self): + return self.get_setting('MEMORY64') == 2 + # A simple check whether the compiler arguments cause optimization. def is_optimizing(self): return '-O' in str(self.emcc_args) and '-O0' not in self.emcc_args @@ -2099,10 +2110,8 @@ def test_emscripten_get_compiler_setting(self): self.set_setting('RETAIN_COMPILER_SETTINGS') self.do_runf(src, read_file(output).replace('waka', shared.EMSCRIPTEN_VERSION)) + @no_wasm64l("wasm64l doesn't support asyncify") def test_emscripten_has_asyncify(self): - if self.get_setting('MEMORY64') == 1: - # This test passes under MEMORY64=2 but not MEMORY64=1 so we don't use is_wasm64 here. - self.skipTest('TODO: asyncify for wasm64') src = r''' #include #include @@ -4019,8 +4028,8 @@ def test_dlfcn_feature_in_lib(self): ''' self.do_run(src, 'float: 42.\n') + @no_wasm64l("wasm64l doesn't support asyncify") @needs_dylink - @no_wasm64('TODO: asyncify for wasm64') def test_dlfcn_asyncify(self): self.set_setting('ASYNCIFY') @@ -8116,7 +8125,7 @@ def test_vswprintf_utf8(self): self.do_core_test('test_vswprintf_utf8.c') # Test that a main with arguments is automatically asyncified. - @no_wasm64('TODO: asyncify for wasm64') + @no_wasm64l("wasm64l doesn't support jspi") @with_asyncify_and_jspi def test_async_main(self): create_file('main.c', r''' @@ -8130,7 +8139,7 @@ def test_async_main(self): self.do_runf('main.c', 'argc=2 argv=hello', args=['hello']) - @no_wasm64('TODO: asyncify for wasm64') + @no_wasm64l("wasm64l doesn't support jspi") @with_asyncify_and_jspi def test_async_hello(self): # needs to flush stdio streams @@ -8155,7 +8164,7 @@ def test_async_hello(self): self.do_runf('main.c', 'HelloWorld!99') - @no_wasm64('TODO: asyncify for wasm64') + @no_wasm64l("wasm64l doesn't support jspi") @with_asyncify_and_jspi def test_async_loop(self): # needs to flush stdio streams @@ -8175,11 +8184,10 @@ def test_async_loop(self): self.do_runf('main.c', 'hello 0\nhello 1\nhello 2\nhello 3\nhello 4\n') @requires_v8 - @no_wasm64('TODO: asyncify for wasm64') def test_async_hello_v8(self): self.test_async_hello() - @no_wasm64('TODO: asyncify for wasm64') + @no_wasm64l("wasm64l doesn't support asyncify") def test_async_ccall_bad(self): # check bad ccall use # needs to flush stdio streams @@ -8211,7 +8219,7 @@ def test_async_ccall_bad(self): self.emcc_args += ['--pre-js', 'pre.js'] self.do_runf('main.c', 'The call to main is running asynchronously.') - @no_wasm64('TODO: asyncify for wasm64') + @no_wasm64l("wasm64l doesn't support jspi") @with_asyncify_and_jspi def test_async_ccall_good(self): # check reasonable ccall use @@ -8238,13 +8246,13 @@ def test_async_ccall_good(self): self.emcc_args += ['--pre-js', 'pre.js'] self.do_runf('main.c', 'HelloWorld') + @no_wasm64l("wasm64l doesn't support asyncify") @parameterized({ 'asyncify': (False, 1), 'exit_runtime_asyncify': (True, 1), 'jspi': (False, 2), 'exit_runtime_jspi': (True, 2), }) - @no_wasm64('TODO: asyncify for wasm64') def test_async_ccall_promise(self, exit_runtime, asyncify): if asyncify == 2: self.require_jspi() @@ -8287,18 +8295,19 @@ def test_async_ccall_promise(self, exit_runtime, asyncify): self.emcc_args += ['--pre-js', 'pre.js'] self.do_runf('main.c', 'stringf: first\nsecond\n6.4') - @no_wasm64('TODO: asyncify for wasm64') + @no_wasm64l("wasm64l doesn't support asyncify") def test_fibers_asyncify(self): self.set_setting('ASYNCIFY') self.maybe_closure() self.do_runf(test_file('test_fibers.cpp'), '*leaf-0-100-1-101-1-102-2-103-3-104-5-105-8-106-13-107-21-108-34-109-*') - @no_wasm64('TODO: asyncify for wasm64') + @no_wasm64l("wasm64l doesn't support jspi") @with_asyncify_and_jspi def test_asyncify_unused(self): # test a program not using asyncify, but the pref is set self.do_core_test('test_hello_world.c') + @no_wasm64l("wasm64l doesn't support asyncify") @parameterized({ 'normal': ([], True), 'removelist_a': (['-sASYNCIFY_REMOVE=["foo(int, double)"]'], False), @@ -8311,7 +8320,6 @@ def test_asyncify_unused(self): 'onlylist_b_response': ([], True, '["main","__original_main","foo(int, double)","baz()","c_baz","Structy::funcy()"]'), 'onlylist_c_response': ([], False, '["main","__original_main","foo(int, double)","baz()","c_baz"]'), }) - @no_wasm64('TODO: asyncify for wasm64') def test_asyncify_lists(self, args, should_pass, response=None): if response is not None: create_file('response.file', response) @@ -8338,12 +8346,12 @@ def test_asyncify_lists(self, args, should_pass, response=None): binary = read_binary(filename) self.assertFalse(b'main' in binary) + @no_wasm64l("wasm64l doesn't support asyncify") @parameterized({ 'normal': ([], True), 'ignoreindirect': (['-sASYNCIFY_IGNORE_INDIRECT'], False), 'add': (['-sASYNCIFY_IGNORE_INDIRECT', '-sASYNCIFY_ADD=["__original_main","main","virt()"]'], True), }) - @no_wasm64('TODO: asyncify for wasm64') def test_asyncify_indirect_lists(self, args, should_pass): self.set_setting('ASYNCIFY') self.emcc_args += args @@ -8356,8 +8364,8 @@ def test_asyncify_indirect_lists(self, args, should_pass): if should_pass: raise + @no_wasm64l("wasm64l doesn't support asyncify") @needs_dylink - @no_wasm64('TODO: asyncify for wasm64') def test_asyncify_side_module(self): self.set_setting('ASYNCIFY') self.set_setting('ASYNCIFY_IMPORTS', ['my_sleep']) @@ -8386,13 +8394,13 @@ def test_asyncify_side_module(self): } ''', 'before sleep\n42\n42\nafter sleep\n', header='void my_sleep(int);', force_c=True) + @no_wasm64l("wasm64l doesn't support asyncify") @no_asan('asyncify stack operations confuse asan') - @no_wasm64('TODO: asyncify for wasm64') def test_emscripten_scan_registers(self): self.set_setting('ASYNCIFY') self.do_core_test('test_emscripten_scan_registers.cpp') - @no_wasm64('TODO: asyncify for wasm64') + @no_wasm64l("wasm64l doesn't support asyncify") def test_asyncify_assertions(self): self.set_setting('ASYNCIFY') self.set_setting('ASYNCIFY_IMPORTS', ['suspend']) @@ -8401,7 +8409,7 @@ def test_asyncify_assertions(self): @no_lsan('leaks asyncify stack during exit') @no_asan('leaks asyncify stack during exit') - @no_wasm64('TODO: asyncify for wasm64') + @no_wasm64l("wasm64l doesn't support asyncify") def test_asyncify_during_exit(self): self.set_setting('ASYNCIFY') self.set_setting('ASSERTIONS') @@ -8413,13 +8421,14 @@ def test_asyncify_during_exit(self): @no_asan('asyncify stack operations confuse asan') @no_lsan('undefined symbol __global_base') @no_wasm2js('dynamic linking support in wasm2js') - @no_wasm64('TODO: asyncify for wasm64') + @no_wasm64l("wasm64l doesn't support jspi") @with_asyncify_and_jspi def test_asyncify_main_module(self): self.set_setting('MAIN_MODULE', 2) self.do_core_test('test_hello_world.c') # Test that pthread_join works correctly with asyncify. + @no_wasm64l("wasm64l doesn't support asyncify") @requires_node_canary def test_pthread_join_and_asyncify(self): # TODO Test with ASYNCIFY=1 https://github.com/emscripten-core/emscripten/issues/17552 @@ -8429,8 +8438,8 @@ def test_pthread_join_and_asyncify(self): '-sEXIT_RUNTIME=1', '-pthread', '-sPROXY_TO_PTHREAD']) + @no_wasm64l("wasm64l doesn't support asyncify") @no_asan('asyncify stack operations confuse asan') - @no_wasm64('TODO: asyncify for wasm64') @no_wasm2js('TODO: lazy loading in wasm2js') @parameterized({ 'conditional': (True,), @@ -8490,7 +8499,7 @@ def break_wasm(name): return False create_file('wat.wat', wat) shutil.move(name, name + '.orig') - self.run_process([Path(building.get_binaryen_bin(), 'wasm-as'), 'wat.wat', '-o', name, '-g']) + self.run_process([Path(building.get_binaryen_bin(), 'wasm-as'), 'wat.wat', '-o', name, '-g', '--all-features']) return True def verify_working(args): @@ -9662,7 +9671,7 @@ def test_embind_lib_with_asyncify(self, args): self.do_core_test('embind_lib_with_asyncify.cpp') @no_asan('asyncify stack operations confuse asan') - @no_wasm64('TODO: asyncify for wasm64') + @no_wasm64l("wasm64l doesn't support jspi") @with_asyncify_and_jspi def test_em_async_js(self): self.uses_es6 = True @@ -9706,7 +9715,7 @@ def test_promise(self): self.set_setting('MIN_CHROME_VERSION', '85') self.do_core_test('test_promise.c') - @no_wasm64('TODO: asyncify for wasm64') + @no_wasm64l("wasm64l doesn't support jspi") @with_asyncify_and_jspi def test_promise_await(self): self.do_core_test('test_promise_await.c') From 87b495148dc361a5cbdc020408e7a0420f730a0b Mon Sep 17 00:00:00 2001 From: Brendan Dahl Date: Tue, 18 Jul 2023 16:34:24 -0700 Subject: [PATCH 0562/1523] Add changelog note for embind TypeScript definition generation. (#19854) --- ChangeLog.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog.md b/ChangeLog.md index b12ecc3640613..73d9f3eecdc48 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -32,6 +32,8 @@ See docs/process.md for more on how version tagging works. wasm module) has been removed. Internally, this is now accessed via the `wasmExports` global. If necessary, it is possible to export `wasmExports` on the Module object using `-sEXPORTED_RUNTIME_METHODS=wasmExports`. (#19816) +- Embind now supports generating TypeScript definition files using the + `--embind-emit-tsd ` option. 3.1.43 - 07/10/23 ----------------- From 7db868ea9c5ddde28bf92f0dfed1773a812b886a Mon Sep 17 00:00:00 2001 From: JunyueCao Date: Fri, 21 Jul 2023 06:42:32 +0800 Subject: [PATCH 0563/1523] Add can_use conditions to wasm_worker system lib (#19501) Fixes #19482 --- tools/system_libs.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/system_libs.py b/tools/system_libs.py index c0b5d2c2873e2..eb33f0bbacece 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -1380,6 +1380,11 @@ def get_files(self): path='system/lib/wasm_worker', filenames=['library_wasm_worker.c' if self.is_ww or self.is_mt else 'library_wasm_worker_stub.c']) + def can_use(self): + # see src/library_wasm_worker.js + return super().can_use() and not settings.SINGLE_FILE \ + and not settings.RELOCATABLE and not settings.PROXY_TO_WORKER + class libsockets(MuslInternalLibrary, MTLibrary): name = 'libsockets' From bec42dac7873903d09d713963e34020c22a8bd2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Beaufort?= Date: Fri, 21 Jul 2023 11:26:52 +0200 Subject: [PATCH 0564/1523] Add CMake note to debug information section (#19879) --- site/source/docs/compiling/Building-Projects.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/source/docs/compiling/Building-Projects.rst b/site/source/docs/compiling/Building-Projects.rst index 976ab21171b7a..8a8765b6a7fc4 100644 --- a/site/source/docs/compiling/Building-Projects.rst +++ b/site/source/docs/compiling/Building-Projects.rst @@ -169,7 +169,7 @@ with :term:`clang` or *gcc* normally). .. note:: Each build-system defines its own mechanisms for setting debug flags. **To get Clang to emit LLVM debug information, you will need to work out the correct approach for your system**. - - Some build systems have a flag like ``./configure --enable-debug``. + - Some build systems have a flag like ``./configure --enable-debug``. In *CMake*-based build systems, set the ``CMAKE_BUILD_TYPE`` to ``"Debug"``. To get *emcc* to include the debug information present in object files when generating the final JavaScript and WebAssembly, your final ``emcc`` command From 6171d5cf9857c30657842aace6724496bbc5ed99 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 25 Jul 2023 09:14:04 -0700 Subject: [PATCH 0565/1523] Mark 3.1.44 as released (#19893) --- ChangeLog.md | 5 ++++- emscripten-version.txt | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 73d9f3eecdc48..33c455157fda4 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -18,8 +18,11 @@ to browse the changes between the tags. See docs/process.md for more on how version tagging works. -3.1.44 (in development) +3.1.45 (in development) ----------------------- + +3.1.44 - 07/25/23 +----------------- - musl libc updated from v1.2.3 to v1.2.4. (#19812) - The `EM_LOG_FUNC_PARAMS` flag to `emscripten_log`/`emscripten_get_callstack` has been deprecated and no longer has any effect. It was based on a diff --git a/emscripten-version.txt b/emscripten-version.txt index c4a4f68771378..d1b8f9c0f5140 100644 --- a/emscripten-version.txt +++ b/emscripten-version.txt @@ -1 +1 @@ -3.1.44-git +3.1.45-git From a6e04716ca24b5bb95632bdea5c2fe1359068de8 Mon Sep 17 00:00:00 2001 From: Brendan Dahl Date: Tue, 25 Jul 2023 11:50:33 -0700 Subject: [PATCH 0566/1523] embind: Generate TS definitions from class properties. (#19875) --- src/embind/embind_ts.js | 39 ++++++++++++++++++++++++++++++++++++ test/other/embind_tsgen.cpp | 7 +++++++ test/other/embind_tsgen.d.ts | 1 + 3 files changed, 47 insertions(+) diff --git a/src/embind/embind_ts.js b/src/embind/embind_ts.js index de6645848b505..26487f99e09dc 100644 --- a/src/embind/embind_ts.js +++ b/src/embind/embind_ts.js @@ -59,6 +59,7 @@ var LibraryEmbind = { new FunctionDefinition('default', this, []) ]; this.base = base; + this.properties = []; } print(nameMap, out) { @@ -67,6 +68,10 @@ var LibraryEmbind = { out.push(` extends ${this.base.name}`); } out.push(' {\n'); + for (const property of this.properties) { + out.push(' '); + property.print(nameMap, out); + } for (const method of this.methods) { out.push(' '); method.printFunction(nameMap, out); @@ -83,6 +88,16 @@ var LibraryEmbind = { out.push('};\n'); } }, + $ClassProperty: class ClassProperty { + constructor(type, name) { + this.type = type; + this.name = name; + } + + print(nameMap, out) { + out.push(`${this.name}: ${nameMap(this.type)};\n`); + } + }, $ConstantDefinition: class ConstantDefinition { constructor(type, name) { this.type = type; @@ -337,6 +352,30 @@ var LibraryEmbind = { classDef.methods.push(funcDef); }); }, + _embind_register_class_property__deps: [ + '$readLatin1String', '$whenDependentTypesAreResolved', '$ClassProperty'], + _embind_register_class_property: function(classType, + fieldName, + getterReturnType, + getterSignature, + getter, + getterContext, + setterArgumentType, + setterSignature, + setter, + setterContext) { + fieldName = readLatin1String(fieldName); + assert(getterReturnType === setterArgumentType, 'Mismatched getter and setter types are not supported.'); + whenDependentTypesAreResolved([], [classType], function(classType) { + classType = classType[0]; + whenDependentTypesAreResolved([], [getterReturnType], function(types) { + const prop = new ClassProperty(types[0], fieldName); + classType.properties.push(prop); + return []; + }); + return []; + }); + }, _embind_register_enum__deps: ['$readLatin1String', '$EnumDefinition', '$moduleDefinitions'], _embind_register_enum: function(rawType, name, size, isSigned) { name = readLatin1String(name); diff --git a/test/other/embind_tsgen.cpp b/test/other/embind_tsgen.cpp index 111a7b2abaea6..f9ba1345fb809 100644 --- a/test/other/embind_tsgen.cpp +++ b/test/other/embind_tsgen.cpp @@ -12,6 +12,12 @@ class Test { int function_four(bool x) { return 2; } int const_fn() const { return 0; } + + int getX() const { return x; } + void setX(int x_) { x = x_; } + +private: + int x; }; Test class_returning_fn() { return Test(); } @@ -77,6 +83,7 @@ EMSCRIPTEN_BINDINGS(Test) { .function("functionThree", &Test::function_three) .function("functionFour", &Test::function_four) .function("constFn", &Test::const_fn) + .property("x", &Test::getX, &Test::setX) ; function("class_returning_fn", &class_returning_fn); diff --git a/test/other/embind_tsgen.d.ts b/test/other/embind_tsgen.d.ts index ec2a265d99995..5f7816a697487 100644 --- a/test/other/embind_tsgen.d.ts +++ b/test/other/embind_tsgen.d.ts @@ -1,4 +1,5 @@ export interface Test { + x: number; functionOne(_0: number, _1: number): number; functionTwo(_0: number, _1: number): number; functionFour(_0: boolean): number; From b525506dbe8008e86bcad56a377294d470742013 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 25 Jul 2023 15:01:46 -0700 Subject: [PATCH 0567/1523] Fix for SINGLE_FILE running under shell environment (#19851) Include polyfill as needed and add a test for this case. Fixes: #19845 --- src/base64Utils.js | 2 +- src/polyfill/atob.js | 12 ++++++++---- test/test_other.py | 4 ++++ 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/base64Utils.js b/src/base64Utils.js index 4c154468fa61e..57c222a7bc14d 100644 --- a/src/base64Utils.js +++ b/src/base64Utils.js @@ -4,7 +4,7 @@ * SPDX-License-Identifier: MIT */ -#if POLYFILL && ENVIRONMENT_MAY_BE_NODE && MIN_NODE_VERSION < 160000 +#if POLYFILL && (ENVIRONMENT_MAY_BE_SHELL || (ENVIRONMENT_MAY_BE_NODE && MIN_NODE_VERSION < 160000)) #include "polyfill/atob.js" #endif diff --git a/src/polyfill/atob.js b/src/polyfill/atob.js index 108e1befd25fd..44167cf51237b 100644 --- a/src/polyfill/atob.js +++ b/src/polyfill/atob.js @@ -8,16 +8,20 @@ #error "this file should never be included unless POLYFILL is set" #endif -#if !ENVIRONMENT_MAY_BE_NODE -#error "this polyfill should only be included when targetting node" +#if !ENVIRONMENT_MAY_BE_SHELL && !ENVIRONMENT_MAY_BE_NODE +#error "this polyfill should only be included when targetting node or shell" #endif -if (typeof ENVIRONMENT_IS_NODE != 'undefined' && ENVIRONMENT_IS_NODE && !global.atob) { +if (typeof atob == 'undefined') { + if (typeof global != 'undefined' && typeof globalThis == 'undefined') { + globalThis = global; + } + /** * Decodes a base64 string. * @param {string} input The string to decode. */ - global.atob = function(input) { + globalThis.atob = function(input) { var keyStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; var output = ''; diff --git a/test/test_other.py b/test/test_other.py index 8aff3929f8d24..e4807f568bfd6 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -8628,6 +8628,10 @@ def do_test(cmd): else: self.expect_fail(separate_dwarf_cmd) + @requires_v8 + def test_single_file_shell(self): + self.do_runf(test_file('hello_world.c'), emcc_args=['-sSINGLE_FILE']) + def test_emar_M(self): create_file('file1', ' ') create_file('file2', ' ') From f784f97e5a915d27e6fa46d4178aea6c7404a200 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 25 Jul 2023 15:43:58 -0700 Subject: [PATCH 0568/1523] [test] Use create_file helper where possible. NFC (#19892) --- test/common.py | 10 +++--- test/test_benchmark.py | 76 ++++++++++++++++++++---------------------- test/test_other.py | 2 +- test/test_sanity.py | 39 +++++++++------------- 4 files changed, 59 insertions(+), 68 deletions(-) diff --git a/test/common.py b/test/common.py index b76beff2d790d..c59356294f47f 100644 --- a/test/common.py +++ b/test/common.py @@ -32,7 +32,7 @@ import jsrun from tools.shared import EMCC, EMXX, DEBUG, EMCONFIGURE, EMCMAKE from tools.shared import get_canonical_temp_dir, path_from_root -from tools.utils import MACOS, WINDOWS, read_file, read_binary, write_file, write_binary, exit_with_error +from tools.utils import MACOS, WINDOWS, read_file, read_binary, write_binary, exit_with_error from tools import shared, line_endings, building, config, utils logger = logging.getLogger('common') @@ -1438,7 +1438,7 @@ def do_run(self, src, expected_output=None, force_c=False, **kwargs): filename = 'src.c' else: filename = 'src.cpp' - write_file(filename, src) + create_file(filename, src) return self._build_and_run(filename, expected_output, **kwargs) def do_runf(self, filename, expected_output=None, **kwargs): @@ -1458,7 +1458,7 @@ def do_run_in_out_file_test(self, *path, **kwargs): expected = read_file(outfile) output = self._build_and_run(srcfile, expected, **kwargs) if EMTEST_REBASELINE: - write_file(outfile, output) + utils.write_file(outfile, output) return output ## Does a complete test - builds, runs, checks output, etc. @@ -1639,7 +1639,7 @@ def do_POST(self): ensure_dir('dump_out') filename = os.path.join('dump_out', query['file'][0]) contentLength = int(self.headers['Content-Length']) - write_binary(filename, self.rfile.read(contentLength)) + create_file(filename, self.rfile.read(contentLength), binary=True) self.send_response(200) self.end_headers() @@ -1884,7 +1884,7 @@ def reftest(self, expected, manually_trigger=False): basename = os.path.basename(expected) shutil.copyfile(expected, self.in_dir(basename)) reporting = read_file(test_file('browser_reporting.js')) - write_file('reftest.js', ''' + create_file('reftest.js', ''' function doReftest() { if (doReftest.done) return; doReftest.done = true; diff --git a/test/test_benchmark.py b/test/test_benchmark.py index 44f7080dd73eb..47ec4230badcc 100644 --- a/test/test_benchmark.py +++ b/test/test_benchmark.py @@ -416,8 +416,7 @@ def do_benchmark(self, name, src, expected_output='FAIL', args=None, dirname = self.get_dir() filename = os.path.join(dirname, name + '.c' + ('' if force_c else 'pp')) src = self.hardcode_arguments(src) - with open(filename, 'w') as f: - f.write(src) + utils.write_file(filename, src) print() baseline = None @@ -1024,44 +1023,43 @@ def test_zzz_sqlite(self): force_c=True) def test_zzz_poppler(self): - with open('pre.js', 'w') as f: - f.write(''' - var benchmarkArgument = %s; - var benchmarkArgumentToPageCount = { - '0': 0, - '1': 1, - '2': 5, - '3': 15, - '4': 26, - '5': 55, - }; - if (benchmarkArgument === 0) { - Module['arguments'] = ['-?']; - Module['printErr'] = function(){}; - } else { - // Add 'filename' after 'input.pdf' to write the output so it can be verified. - Module['arguments'] = ['-scale-to', '1024', 'input.pdf', '-f', '1', '-l', '' + benchmarkArgumentToPageCount[benchmarkArgument]]; - Module['postRun'] = function() { - var files = []; - for (var x in FS.root.contents) { - if (x.startsWith('filename-')) { - files.push(x); - } + utils.write_file('pre.js', ''' + var benchmarkArgument = %s; + var benchmarkArgumentToPageCount = { + '0': 0, + '1': 1, + '2': 5, + '3': 15, + '4': 26, + '5': 55, + }; + if (benchmarkArgument === 0) { + Module['arguments'] = ['-?']; + Module['printErr'] = function(){}; + } else { + // Add 'filename' after 'input.pdf' to write the output so it can be verified. + Module['arguments'] = ['-scale-to', '1024', 'input.pdf', '-f', '1', '-l', '' + benchmarkArgumentToPageCount[benchmarkArgument]]; + Module['postRun'] = function() { + var files = []; + for (var x in FS.root.contents) { + if (x.startsWith('filename-')) { + files.push(x); } - files.sort(); - var hash = 5381; - var totalSize = 0; - files.forEach(function(file) { - var data = Array.from(MEMFS.getFileDataAsTypedArray(FS.root.contents[file])); - for (var i = 0; i < data.length; i++) { - hash = ((hash << 5) + hash) ^ (data[i] & 0xff); - } - totalSize += data.length; - }); - out(files.length + ' files emitted, total output size: ' + totalSize + ', hashed printout: ' + hash); - }; - } - ''' % DEFAULT_ARG) + } + files.sort(); + var hash = 5381; + var totalSize = 0; + files.forEach(function(file) { + var data = Array.from(MEMFS.getFileDataAsTypedArray(FS.root.contents[file])); + for (var i = 0; i < data.length; i++) { + hash = ((hash << 5) + hash) ^ (data[i] & 0xff); + } + totalSize += data.length; + }); + out(files.length + ' files emitted, total output size: ' + totalSize + ', hashed printout: ' + hash); + }; + } + ''' % DEFAULT_ARG) def lib_builder(name, native, env_init): return self.get_poppler_library(env_init=env_init) diff --git a/test/test_other.py b/test/test_other.py index e4807f568bfd6..97918cbf41232 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -12027,7 +12027,7 @@ def create_o(name, i): # Tests that the filename suffix of the response files can be used to detect which encoding the file is. @crossplatform def test_response_file_encoding(self): - open('äö.c', 'w').write('int main(){}') + create_file('äö.c', 'int main(){}') open('a.rsp', 'w', encoding='utf-8').write('äö.c') # Write a response file with unicode contents ... self.run_process([EMCC, '@a.rsp']) # ... and test that in the absence of a file suffix, it is autodetected to utf-8. diff --git a/test/test_sanity.py b/test/test_sanity.py index f9e904faddab8..1c96333e1d800 100644 --- a/test/test_sanity.py +++ b/test/test_sanity.py @@ -112,7 +112,7 @@ def setUpClass(cls): print('WARNING: This will modify %s, and in theory can break it although it should be restored properly. A backup will be saved in %s_backup' % (EM_CONFIG, EM_CONFIG)) print() print('>>> the original settings file is:') - print(open(EM_CONFIG).read().strip()) + print(utils.read_file(EM_CONFIG).strip()) print('<<<') print() @@ -169,7 +169,7 @@ def test_firstrun(self): temp_bin = tempfile.mkdtemp() def make_new_executable(name): - open(os.path.join(temp_bin, name), 'w').close() + utils.write_file(os.path.join(temp_bin, name), '') make_executable(os.path.join(temp_bin, name)) make_new_executable('wasm-ld') @@ -179,7 +179,7 @@ def make_new_executable(name): output = self.do([EMCC, '--generate-config']) finally: shutil.rmtree(temp_bin) - config_data = open(default_config).read() + config_data = utils.read_file(default_config) self.assertContained('An Emscripten settings file has been generated at:', output) self.assertContained(default_config, output) @@ -212,8 +212,7 @@ def make_new_executable(name): # Second run, with bad EM_CONFIG for settings in ['blah', 'LLVM_ROOT="blarg"; JS_ENGINES=[]; NODE_JS=[]; SPIDERMONKEY_ENGINE=[]']: try: - with open(default_config, 'w') as f: - f.write(settings) + utils.write_file(default_config, settings) output = self.do(command) if 'blah' in settings: @@ -235,8 +234,7 @@ def test_llvm(self): # Fake a different llvm version restore_and_set_up() - with open(EM_CONFIG, 'a') as f: - f.write('LLVM_ROOT = "' + self.in_dir('fake') + '"') + add_to_config('LLVM_ROOT = "' + self.in_dir('fake') + '"') real_version_x = shared.EXPECTED_LLVM_VERSION real_version_y = 0 @@ -276,8 +274,7 @@ def test_node(self): # Fake a different node version restore_and_set_up() - with open(EM_CONFIG, 'a') as f: - f.write('NODE_JS = "' + self.in_dir('fake', 'nodejs') + '"') + add_to_config('NODE_JS = "' + self.in_dir('fake', 'nodejs') + '"') ensure_dir('fake') @@ -289,15 +286,13 @@ def test_node(self): ('cheez', False)]: print(version, succeed) delete_file(SANITY_FILE) - f = open(self.in_dir('fake', 'nodejs'), 'w') - f.write('#!/bin/sh\n') - f.write('''if [ $1 = "--version" ]; then + utils.write_file(self.in_dir('fake', 'nodejs'), '''#!/bin/sh +if [ $1 = "--version" ]; then echo "%s" else %s $@ fi ''' % (version, ' '.join(config.NODE_JS))) - f.close() make_executable(self.in_dir('fake', 'nodejs')) if not succeed: if version[0] == 'v': @@ -318,7 +313,7 @@ def test_emcc(self): output = self.check_working(EMCC) self.assertContained(SANITY_MESSAGE, output) # EMCC should have checked sanity successfully - old_sanity = open(SANITY_FILE).read() + old_sanity = utils.read_file(SANITY_FILE) self.assertNotContained(SANITY_FAIL_MESSAGE, output) # emcc run again should not sanity check, because the sanity file is newer @@ -327,12 +322,12 @@ def test_emcc(self): self.assertNotContained(SANITY_FAIL_MESSAGE, output) # incorrect sanity contents mean we *must* check - open(SANITY_FILE, 'w').write('wakawaka') + utils.write_file(SANITY_FILE, 'wakawaka') output = self.check_working(EMCC) self.assertContained(SANITY_MESSAGE, output) # correct sanity contents mean we need not check - open(SANITY_FILE, 'w').write(old_sanity) + utils.write_file(SANITY_FILE, old_sanity) output = self.check_working(EMCC) self.assertNotContained(SANITY_MESSAGE, output) @@ -505,14 +500,14 @@ def test_emconfig(self): fd, custom_config_filename = tempfile.mkstemp(prefix='.emscripten_config_') - orig_config = open(EM_CONFIG, 'r').read() + orig_config = utils.read_file(EM_CONFIG) # Move the ~/.emscripten to a custom location. with os.fdopen(fd, "w") as f: f.write(get_basic_config()) # Make a syntax error in the original config file so that attempting to access it would fail. - open(EM_CONFIG, 'w').write('asdfasdfasdfasdf\n\'\'\'' + orig_config) + utils.write_file(EM_CONFIG, 'asdfasdfasdfasdf\n\'\'\'' + orig_config) temp_dir = tempfile.mkdtemp(prefix='emscripten_temp_') @@ -574,8 +569,7 @@ def second_use(): second_use() # if the url doesn't match, we retrieve and rebuild - with open(os.path.join(PORTS_DIR, 'sdl2', '.emscripten_url'), 'w') as f: - f.write('foo') + utils.write_file(os.path.join(PORTS_DIR, 'sdl2', '.emscripten_url'), 'foo') first_use() second_use() @@ -664,8 +658,7 @@ def test_with_fake(report, expected): def test_llvm_add_version(self): restore_and_set_up() - with open(EM_CONFIG, 'a') as f: - f.write('LLVM_ROOT = "' + self.in_dir('fake') + '"') + add_to_config(f'LLVM_ROOT = "{self.in_dir("fake")}"') def make_fake(version): print("fake LLVM version: %s" % (version)) @@ -695,7 +688,7 @@ def test_empty_config(self): make_fake_clang(self.in_dir('fake', 'clang'), expected_llvm_version) make_fake_tool(self.in_dir('fake', 'llvm-ar'), expected_llvm_version) make_fake_tool(self.in_dir('fake', 'llvm-nm'), expected_llvm_version) - open(EM_CONFIG, 'w').close() + utils.write_file(EM_CONFIG, '') with env_modify({'PATH': self.in_dir('fake') + os.pathsep + os.environ['PATH']}): self.check_working([EMCC]) From 16bbfdd9353c5cb0e4262d41ff73cbf50cb5ff50 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 25 Jul 2023 16:02:04 -0700 Subject: [PATCH 0569/1523] Update expected LLVM version to 18 (#19896) --- tools/shared.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/shared.py b/tools/shared.py index 157d57f9eceb4..ed367be8e5352 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -55,7 +55,7 @@ # exact requirement, but is the oldest version of node that we do any testing with. # This version aligns with the current Ubuuntu TLS 20.04 (Focal). MINIMUM_NODE_VERSION = (10, 19, 0) -EXPECTED_LLVM_VERSION = 17 +EXPECTED_LLVM_VERSION = 18 # These get set by setup_temp_dirs TEMP_DIR = None From 1da93f16a44644d36fe7735e9bc4fb3c6ca5b3ea Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 26 Jul 2023 03:28:04 -0700 Subject: [PATCH 0570/1523] Add musl quick_exit function and test (#19891) See #2464 --- test/other/test_quick_exit.c | 18 ++++++++++++++++++ test/other/test_quick_exit.out | 1 + test/test_other.py | 3 +++ tools/system_libs.py | 2 +- 4 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 test/other/test_quick_exit.c create mode 100644 test/other/test_quick_exit.out diff --git a/test/other/test_quick_exit.c b/test/other/test_quick_exit.c new file mode 100644 index 0000000000000..a16add1e99a67 --- /dev/null +++ b/test/other/test_quick_exit.c @@ -0,0 +1,18 @@ +#include +#include + +void f1() { + printf("f1\n"); + __builtin_trap(); +} + +void f2() { + printf("f2\n"); +} + +int main() { + atexit(f1); + at_quick_exit(f2); + quick_exit(0); + __builtin_trap(); +} diff --git a/test/other/test_quick_exit.out b/test/other/test_quick_exit.out new file mode 100644 index 0000000000000..9de77c18733ab --- /dev/null +++ b/test/other/test_quick_exit.out @@ -0,0 +1 @@ +f2 diff --git a/test/test_other.py b/test/test_other.py index 97918cbf41232..ee358d05eb382 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -13595,3 +13595,6 @@ def test_explicit_target(self): err = self.expect_fail([EMCC, test_file('hello_world.c'), '--target=arm64']) self.assertContained('emcc: error: unsupported target: arm64 (emcc only supports wasm64-unknown-emscripten and wasm32-unknown-emscripten', err) + + def test_quick_exit(self): + self.do_other_test('test_quick_exit.c') diff --git a/tools/system_libs.py b/tools/system_libs.py index eb33f0bbacece..3ae3d59ad8651 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -1171,7 +1171,7 @@ def get_files(self): libc_files += files_in_path( path='system/lib/libc/musl/src/exit', - filenames=['_Exit.c', 'atexit.c']) + filenames=['_Exit.c', 'atexit.c', 'at_quick_exit.c', 'quick_exit.c']) libc_files += files_in_path( path='system/lib/libc/musl/src/ldso', From fecf6792583ecdcc3f38bf2ab4ca823b49106514 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 26 Jul 2023 03:43:44 -0700 Subject: [PATCH 0571/1523] Rebaseline codesize expectations. NFC --- test/other/metadce/test_metadce_cxx_ctors1.size | 2 +- test/other/metadce/test_metadce_cxx_ctors2.size | 2 +- test/other/metadce/test_metadce_cxx_except.size | 2 +- test/other/metadce/test_metadce_cxx_except_wasm.size | 2 +- test/other/metadce/test_metadce_cxx_mangle.size | 2 +- test/other/metadce/test_metadce_cxx_noexcept.size | 2 +- test/other/metadce/test_metadce_cxx_wasmfs.size | 2 +- test/other/metadce/test_metadce_files_wasmfs.size | 2 +- test/other/metadce/test_metadce_hello_dylink.size | 2 +- test/other/metadce/test_metadce_mem_O3.size | 2 +- test/other/metadce/test_metadce_mem_O3_grow.size | 2 +- test/other/metadce/test_metadce_mem_O3_grow_standalone.size | 2 +- test/other/metadce/test_metadce_mem_O3_standalone.size | 2 +- test/other/metadce/test_metadce_mem_O3_standalone_lib.size | 2 +- test/other/metadce/test_metadce_mem_O3_standalone_narg.size | 2 +- .../other/metadce/test_metadce_mem_O3_standalone_narg_flto.size | 2 +- test/other/metadce/test_metadce_minimal_pthreads.size | 2 +- 17 files changed, 17 insertions(+), 17 deletions(-) diff --git a/test/other/metadce/test_metadce_cxx_ctors1.size b/test/other/metadce/test_metadce_cxx_ctors1.size index 465935cf3c3fe..058f4f6439b55 100644 --- a/test/other/metadce/test_metadce_cxx_ctors1.size +++ b/test/other/metadce/test_metadce_cxx_ctors1.size @@ -1 +1 @@ -123615 +123529 diff --git a/test/other/metadce/test_metadce_cxx_ctors2.size b/test/other/metadce/test_metadce_cxx_ctors2.size index edde1079d6e92..3a0f6f5d0aabe 100644 --- a/test/other/metadce/test_metadce_cxx_ctors2.size +++ b/test/other/metadce/test_metadce_cxx_ctors2.size @@ -1 +1 @@ -123520 +123434 diff --git a/test/other/metadce/test_metadce_cxx_except.size b/test/other/metadce/test_metadce_cxx_except.size index b04970de1c1f9..174744d2076e6 100644 --- a/test/other/metadce/test_metadce_cxx_except.size +++ b/test/other/metadce/test_metadce_cxx_except.size @@ -1 +1 @@ -166450 +166364 diff --git a/test/other/metadce/test_metadce_cxx_except_wasm.size b/test/other/metadce/test_metadce_cxx_except_wasm.size index cbd31f6da1877..6748be003ac5e 100644 --- a/test/other/metadce/test_metadce_cxx_except_wasm.size +++ b/test/other/metadce/test_metadce_cxx_except_wasm.size @@ -1 +1 @@ -137243 +137157 diff --git a/test/other/metadce/test_metadce_cxx_mangle.size b/test/other/metadce/test_metadce_cxx_mangle.size index 6e1566916dce7..264492efef7b6 100644 --- a/test/other/metadce/test_metadce_cxx_mangle.size +++ b/test/other/metadce/test_metadce_cxx_mangle.size @@ -1 +1 @@ -221412 +221326 diff --git a/test/other/metadce/test_metadce_cxx_noexcept.size b/test/other/metadce/test_metadce_cxx_noexcept.size index 747eb858d0844..f5cf2977dfdaf 100644 --- a/test/other/metadce/test_metadce_cxx_noexcept.size +++ b/test/other/metadce/test_metadce_cxx_noexcept.size @@ -1 +1 @@ -126419 +126333 diff --git a/test/other/metadce/test_metadce_cxx_wasmfs.size b/test/other/metadce/test_metadce_cxx_wasmfs.size index 8a85c8d248f6d..c04bb7574f6f2 100644 --- a/test/other/metadce/test_metadce_cxx_wasmfs.size +++ b/test/other/metadce/test_metadce_cxx_wasmfs.size @@ -1 +1 @@ -164558 +164472 diff --git a/test/other/metadce/test_metadce_files_wasmfs.size b/test/other/metadce/test_metadce_files_wasmfs.size index 86eeb43ae5b69..7d423ee08413d 100644 --- a/test/other/metadce/test_metadce_files_wasmfs.size +++ b/test/other/metadce/test_metadce_files_wasmfs.size @@ -1 +1 @@ -52432 +52346 diff --git a/test/other/metadce/test_metadce_hello_dylink.size b/test/other/metadce/test_metadce_hello_dylink.size index 6b4f6ad29f670..ec0cac293a785 100644 --- a/test/other/metadce/test_metadce_hello_dylink.size +++ b/test/other/metadce/test_metadce_hello_dylink.size @@ -1 +1 @@ -9514 +9428 diff --git a/test/other/metadce/test_metadce_mem_O3.size b/test/other/metadce/test_metadce_mem_O3.size index 57e22dba433ab..a52e397ca99c0 100644 --- a/test/other/metadce/test_metadce_mem_O3.size +++ b/test/other/metadce/test_metadce_mem_O3.size @@ -1 +1 @@ -5358 +5272 diff --git a/test/other/metadce/test_metadce_mem_O3_grow.size b/test/other/metadce/test_metadce_mem_O3_grow.size index 0da0b6c62ca1d..6202b2203facb 100644 --- a/test/other/metadce/test_metadce_mem_O3_grow.size +++ b/test/other/metadce/test_metadce_mem_O3_grow.size @@ -1 +1 @@ -5359 +5273 diff --git a/test/other/metadce/test_metadce_mem_O3_grow_standalone.size b/test/other/metadce/test_metadce_mem_O3_grow_standalone.size index 943b0641b04bf..7b6ceee2dc6b8 100644 --- a/test/other/metadce/test_metadce_mem_O3_grow_standalone.size +++ b/test/other/metadce/test_metadce_mem_O3_grow_standalone.size @@ -1 +1 @@ -5672 +5586 diff --git a/test/other/metadce/test_metadce_mem_O3_standalone.size b/test/other/metadce/test_metadce_mem_O3_standalone.size index 10a409ec845ab..5235f087f8981 100644 --- a/test/other/metadce/test_metadce_mem_O3_standalone.size +++ b/test/other/metadce/test_metadce_mem_O3_standalone.size @@ -1 +1 @@ -5595 +5509 diff --git a/test/other/metadce/test_metadce_mem_O3_standalone_lib.size b/test/other/metadce/test_metadce_mem_O3_standalone_lib.size index 5f7d333c97804..008e44a8e9512 100644 --- a/test/other/metadce/test_metadce_mem_O3_standalone_lib.size +++ b/test/other/metadce/test_metadce_mem_O3_standalone_lib.size @@ -1 +1 @@ -5361 +5275 diff --git a/test/other/metadce/test_metadce_mem_O3_standalone_narg.size b/test/other/metadce/test_metadce_mem_O3_standalone_narg.size index 3833169846893..4da72e8420a57 100644 --- a/test/other/metadce/test_metadce_mem_O3_standalone_narg.size +++ b/test/other/metadce/test_metadce_mem_O3_standalone_narg.size @@ -1 +1 @@ -5391 +5305 diff --git a/test/other/metadce/test_metadce_mem_O3_standalone_narg_flto.size b/test/other/metadce/test_metadce_mem_O3_standalone_narg_flto.size index 58109dfb98baf..aaf3bcfb50856 100644 --- a/test/other/metadce/test_metadce_mem_O3_standalone_narg_flto.size +++ b/test/other/metadce/test_metadce_mem_O3_standalone_narg_flto.size @@ -1 +1 @@ -4202 +4122 diff --git a/test/other/metadce/test_metadce_minimal_pthreads.size b/test/other/metadce/test_metadce_minimal_pthreads.size index a264d5d2de1b3..dd9bd2b18e1b9 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.size +++ b/test/other/metadce/test_metadce_minimal_pthreads.size @@ -1 +1 @@ -19055 +18969 From dd7c3aa69c9a49c3622de4d1adca016c7fe49a79 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 26 Jul 2023 10:56:04 -0700 Subject: [PATCH 0572/1523] Minor cleanups to webidl_binder.py. NFC (#19904) --- tools/webidl_binder.py | 81 ++++++++++++++++++++---------------------- 1 file changed, 38 insertions(+), 43 deletions(-) diff --git a/tools/webidl_binder.py b/tools/webidl_binder.py index 946fe7d60fd96..3dbac655be730 100644 --- a/tools/webidl_binder.py +++ b/tools/webidl_binder.py @@ -33,7 +33,7 @@ DEBUG = os.environ.get('IDL_VERBOSE') == '1' if DEBUG: - print("Debug print ON, CHECKS=%s" % CHECKS) + print(f'Debug print ON, CHECKS=${CHECKS}') # We need to avoid some closure errors on the constructors we define here. CONSTRUCTOR_CLOSURE_SUPPRESSIONS = '/** @suppress {undefinedVars, duplicate} @this{Object} */' @@ -50,12 +50,14 @@ def getExtendedAttribute(self, _name): input_file = sys.argv[1] output_base = sys.argv[2] +cpp_output = output_base + '.cpp' +js_output = output_base + '.js' -utils.delete_file(output_base + '.cpp') -utils.delete_file(output_base + '.js') +utils.delete_file(cpp_output) +utils.delete_file(js_output) p = WebIDL.Parser() -p.parse(r''' +p.parse(''' interface VoidPtr { }; ''' + utils.read_file(input_file)) @@ -76,17 +78,13 @@ def getExtendedAttribute(self, _name): # print interfaces # print implements -pre_c = [] -mid_c = [] -mid_js = [] - -pre_c += [r''' +pre_c = [''' #include EM_JS_DEPS(webidl_binder, "$intArrayFromString,$UTF8ToString"); '''] -mid_c += [r''' +mid_c = [''' extern "C" { '''] @@ -101,7 +99,7 @@ def build_constructor(name): '''.format(name=name, implementing=implementing_name)] -mid_js += [''' +mid_js = [''' // Bindings utilities /** @suppress {duplicate} (TODO: avoid emitting this multiple times, it is redundant) */ @@ -176,7 +174,7 @@ def build_constructor(name): temps: [], // extra allocations needed: 0, // the total size we need next time - prepare: function() { + prepare() { if (ensureCache.needed) { // clear the temps for (var i = 0; i < ensureCache.temps.length; i++) { @@ -197,7 +195,7 @@ def build_constructor(name): } ensureCache.pos = 0; }, - alloc: function(array, view) { + alloc(array, view) { assert(ensureCache.buffer); var bytes = view.BYTES_PER_ELEMENT; var len = array.length * bytes; @@ -216,7 +214,7 @@ def build_constructor(name): } return ret; }, - copy: function(array, view, offset) { + copy(array, view, offset) { offset >>>= 0; var bytes = view.BYTES_PER_ELEMENT; switch (bytes) { @@ -289,13 +287,11 @@ def build_constructor(name): '''] mid_c += [''' -// Not using size_t for array indices as the values used by the javascript code are signed. - EM_JS(void, array_bounds_check_error, (size_t idx, size_t size), { throw 'Array index ' + idx + ' out of bounds: [0,' + size + ')'; }); -void array_bounds_check(const int array_size, const int array_idx) { +static void array_bounds_check(size_t array_size, size_t array_idx) { if (array_idx < 0 || array_idx >= array_size) { array_bounds_check_error(array_idx, array_size); } @@ -313,38 +309,37 @@ def type_to_c(t, non_pointing=False): # print 'to c ', t def base_type_to_c(t): if t == 'Long': - ret = 'int' + return 'int' elif t == 'UnsignedLong': - ret = 'unsigned int' + return 'unsigned int' elif t == 'LongLong': - ret = 'long long' + return 'long long' elif t == 'UnsignedLongLong': - ret = 'unsigned long long' + return 'unsigned long long' elif t == 'Short': - ret = 'short' + return 'short' elif t == 'UnsignedShort': - ret = 'unsigned short' + return 'unsigned short' elif t == 'Byte': - ret = 'char' + return 'char' elif t == 'Octet': - ret = 'unsigned char' + return 'unsigned char' elif t == 'Void': - ret = 'void' + return 'void' elif t == 'String': - ret = 'char*' + return 'char*' elif t == 'Float': - ret = 'float' + return 'float' elif t == 'Double': - ret = 'double' + return 'double' elif t == 'Boolean': - ret = 'bool' - elif t == 'Any' or t == 'VoidPtr': - ret = 'void*' + return 'bool' + elif t in ('Any', 'VoidPtr'): + return 'void*' elif t in interfaces: - ret = (interfaces[t].getExtendedAttribute('Prefix') or [''])[0] + t + ('' if non_pointing else '*') + return (interfaces[t].getExtendedAttribute('Prefix') or [''])[0] + t + ('' if non_pointing else '*') else: - ret = t - return ret + return t t = t.replace(' (Wrapper)', '') @@ -770,7 +765,7 @@ def render_function(class_name, func_name, sigs, return_type, non_pointer, # Emit C++ class implementation that calls into JS implementation if js_impl: - pre_c += [r''' + pre_c += [''' class %s : public %s { public: %s @@ -780,12 +775,12 @@ class %s : public %s { deferred_js = [] for name, enum in enums.items(): - mid_c += ['\n// ' + name + '\n'] - deferred_js += ['\n', '// ' + name + '\n'] + mid_c += [f'\n// ${name}\n'] + deferred_js += [f'\n// ${name}\n'] for value in enum.values(): - function_id = "%s_%s" % (name, value.split('::')[-1]) + function_id = '%s_%s' % (name, value.split('::')[-1]) function_id = 'emscripten_enum_%s' % function_id - mid_c += [r'''%s EMSCRIPTEN_KEEPALIVE %s() { + mid_c += ['''%s EMSCRIPTEN_KEEPALIVE %s() { return %s; } ''' % (name, function_id, value)] @@ -802,7 +797,7 @@ class %s : public %s { # namespace is a namespace, so the enums get collapsed into the top level namespace. deferred_js += ["Module['%s'] = _%s();\n" % (identifier, function_id)] else: - raise Exception("Illegal enum value %s" % value) + raise Exception(f'Illegal enum value ${value}') mid_c += ['\n}\n\n'] if len(deferred_js): @@ -818,12 +813,12 @@ class %s : public %s { # Write -with open(output_base + '.cpp', 'w') as c: +with open(cpp_output, 'w') as c: for x in pre_c: c.write(x) for x in mid_c: c.write(x) -with open(output_base + '.js', 'w') as js: +with open(js_output, 'w') as js: for x in mid_js: js.write(x) From fa2a1f3346e7f6643628ab60a04f5e3a3826b98f Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 26 Jul 2023 11:35:40 -0700 Subject: [PATCH 0573/1523] Continue transition from `asm` to `wasmExports`. NFC (#19900) I missed a few cases back in #19816. This change completely the transition saving even more on code size. --- emscripten.py | 4 ++-- src/preamble.js | 1 - src/runtime_debug.js | 3 +++ test/interop/test_add_function.cpp | 2 +- test/other/metadce/test_metadce_cxx_ctors1.jssize | 2 +- test/other/metadce/test_metadce_cxx_ctors2.jssize | 2 +- test/other/metadce/test_metadce_cxx_except.jssize | 2 +- test/other/metadce/test_metadce_cxx_except_wasm.jssize | 2 +- test/other/metadce/test_metadce_cxx_mangle.jssize | 2 +- test/other/metadce/test_metadce_cxx_noexcept.jssize | 2 +- test/other/metadce/test_metadce_cxx_wasmfs.jssize | 2 +- test/other/metadce/test_metadce_files_js_fs.jssize | 2 +- test/other/metadce/test_metadce_files_wasmfs.jssize | 2 +- test/other/metadce/test_metadce_hello_O0.jssize | 2 +- test/other/metadce/test_metadce_hello_O1.jssize | 2 +- test/other/metadce/test_metadce_hello_O2.jssize | 2 +- test/other/metadce/test_metadce_hello_O3.jssize | 2 +- test/other/metadce/test_metadce_hello_Os.jssize | 2 +- test/other/metadce/test_metadce_hello_Oz.jssize | 2 +- test/other/metadce/test_metadce_hello_dylink.jssize | 2 +- test/other/metadce/test_metadce_hello_export_nothing.jssize | 2 +- test/other/metadce/test_metadce_hello_wasmfs.jssize | 2 +- test/other/metadce/test_metadce_libcxxabi_message_O3.jssize | 2 +- .../test_metadce_libcxxabi_message_O3_standalone.jssize | 2 +- test/other/metadce/test_metadce_mem_O3.jssize | 2 +- test/other/metadce/test_metadce_mem_O3_grow.jssize | 2 +- test/other/metadce/test_metadce_mem_O3_grow_standalone.jssize | 2 +- test/other/metadce/test_metadce_mem_O3_standalone.jssize | 2 +- test/other/metadce/test_metadce_mem_O3_standalone_lib.jssize | 2 +- test/other/metadce/test_metadce_mem_O3_standalone_narg.jssize | 2 +- .../metadce/test_metadce_mem_O3_standalone_narg_flto.jssize | 2 +- test/other/metadce/test_metadce_minimal_64.jssize | 2 +- test/other/metadce/test_metadce_minimal_O0.jssize | 2 +- test/other/metadce/test_metadce_minimal_O1.jssize | 2 +- test/other/metadce/test_metadce_minimal_O2.jssize | 2 +- test/other/metadce/test_metadce_minimal_O3.jssize | 2 +- test/other/metadce/test_metadce_minimal_Os.jssize | 2 +- test/other/metadce/test_metadce_minimal_Oz-ctors.jssize | 2 +- test/other/metadce/test_metadce_minimal_Oz.jssize | 2 +- test/other/metadce/test_metadce_minimal_pthreads.jssize | 2 +- test/other/metadce/test_metadce_minimal_wasmfs.jssize | 2 +- test/other/test_unoptimized_code_size.js.size | 2 +- test/other/test_unoptimized_code_size_no_asserts.js.size | 2 +- test/other/test_unoptimized_code_size_strict.js.size | 2 +- 44 files changed, 46 insertions(+), 44 deletions(-) diff --git a/emscripten.py b/emscripten.py index e1308e5b03192..b1c62610f2616 100644 --- a/emscripten.py +++ b/emscripten.py @@ -755,7 +755,7 @@ def install_wrapper(sym): args = ', '.join(args) wrapper += f"({args}) => ({mangled} = {exported}wasmExports['{name}'])({args});" else: - wrapper += 'asm["%s"]' % name + wrapper += 'wasmExports["%s"]' % name wrappers.append(wrapper) return wrappers @@ -815,7 +815,7 @@ def create_module(receiving, metadata, library_symbols): module.append('Asyncify.instrumentWasmImports(wasmImports);\n') if not settings.MINIMAL_RUNTIME: - module.append("var asm = createWasm();\n") + module.append("var wasmExports = createWasm();\n") module.append(receiving) if settings.SUPPORT_LONGJMP == 'emscripten' or not settings.DISABLE_EXCEPTION_CATCHING: diff --git a/src/preamble.js b/src/preamble.js index 719a82973497c..3bdce8a0cc775 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -53,7 +53,6 @@ if (typeof WebAssembly != 'object') { // Wasm globals var wasmMemory; -var wasmExports; #if SHARED_MEMORY // For sending to workers. diff --git a/src/runtime_debug.js b/src/runtime_debug.js index 2ab30a8a5d363..463d75864f610 100644 --- a/src/runtime_debug.js +++ b/src/runtime_debug.js @@ -53,6 +53,9 @@ function missingGlobal(sym, msg) { } missingGlobal('buffer', 'Please use HEAP8.buffer or wasmMemory.buffer'); +#if !MINIMAL_RUNTIME +missingGlobal('asm', 'Please use wasmExports instead'); +#endif function missingLibrarySymbol(sym) { if (typeof globalThis !== 'undefined' && !Object.getOwnPropertyDescriptor(globalThis, sym)) { diff --git a/test/interop/test_add_function.cpp b/test/interop/test_add_function.cpp index d20fc95bf3a51..37e497bfbefbc 100644 --- a/test/interop/test_add_function.cpp +++ b/test/interop/test_add_function.cpp @@ -26,7 +26,7 @@ int main(int argc, char **argv) { #if defined(GROWTH) EM_ASM({ // Get an export that isn't in the table (we never took its address in C). - var baz = asm["baz"]; + var baz = wasmExports["baz"]; var tableSizeBefore = wasmTable.length; var bazIndex = addFunction(baz); assert(bazIndex >= tableSizeBefore, "we actually added it"); diff --git a/test/other/metadce/test_metadce_cxx_ctors1.jssize b/test/other/metadce/test_metadce_cxx_ctors1.jssize index 9c7dcb5f10caa..4d08dc5b9f967 100644 --- a/test/other/metadce/test_metadce_cxx_ctors1.jssize +++ b/test/other/metadce/test_metadce_cxx_ctors1.jssize @@ -1 +1 @@ -25131 +25125 diff --git a/test/other/metadce/test_metadce_cxx_ctors2.jssize b/test/other/metadce/test_metadce_cxx_ctors2.jssize index 29e6c7956ce8c..72f6e6531f550 100644 --- a/test/other/metadce/test_metadce_cxx_ctors2.jssize +++ b/test/other/metadce/test_metadce_cxx_ctors2.jssize @@ -1 +1 @@ -25099 +25093 diff --git a/test/other/metadce/test_metadce_cxx_except.jssize b/test/other/metadce/test_metadce_cxx_except.jssize index 2e168b495c58f..283e578e1bd30 100644 --- a/test/other/metadce/test_metadce_cxx_except.jssize +++ b/test/other/metadce/test_metadce_cxx_except.jssize @@ -1 +1 @@ -29309 +29302 diff --git a/test/other/metadce/test_metadce_cxx_except_wasm.jssize b/test/other/metadce/test_metadce_cxx_except_wasm.jssize index 1ed3deaf231af..3c31c02beb627 100644 --- a/test/other/metadce/test_metadce_cxx_except_wasm.jssize +++ b/test/other/metadce/test_metadce_cxx_except_wasm.jssize @@ -1 +1 @@ -24899 +24893 diff --git a/test/other/metadce/test_metadce_cxx_mangle.jssize b/test/other/metadce/test_metadce_cxx_mangle.jssize index 2e04db4e448da..7e268fce81768 100644 --- a/test/other/metadce/test_metadce_cxx_mangle.jssize +++ b/test/other/metadce/test_metadce_cxx_mangle.jssize @@ -1 +1 @@ -29308 +29301 diff --git a/test/other/metadce/test_metadce_cxx_noexcept.jssize b/test/other/metadce/test_metadce_cxx_noexcept.jssize index 9c7dcb5f10caa..4d08dc5b9f967 100644 --- a/test/other/metadce/test_metadce_cxx_noexcept.jssize +++ b/test/other/metadce/test_metadce_cxx_noexcept.jssize @@ -1 +1 @@ -25131 +25125 diff --git a/test/other/metadce/test_metadce_cxx_wasmfs.jssize b/test/other/metadce/test_metadce_cxx_wasmfs.jssize index d715aa47f772a..6b5f7a5ee6607 100644 --- a/test/other/metadce/test_metadce_cxx_wasmfs.jssize +++ b/test/other/metadce/test_metadce_cxx_wasmfs.jssize @@ -1 +1 @@ -12738 +12731 diff --git a/test/other/metadce/test_metadce_files_js_fs.jssize b/test/other/metadce/test_metadce_files_js_fs.jssize index 28928313b7c12..b92677edb9566 100644 --- a/test/other/metadce/test_metadce_files_js_fs.jssize +++ b/test/other/metadce/test_metadce_files_js_fs.jssize @@ -1 +1 @@ -20006 +20000 diff --git a/test/other/metadce/test_metadce_files_wasmfs.jssize b/test/other/metadce/test_metadce_files_wasmfs.jssize index d0e4578842119..7b5514dfe63ca 100644 --- a/test/other/metadce/test_metadce_files_wasmfs.jssize +++ b/test/other/metadce/test_metadce_files_wasmfs.jssize @@ -1 +1 @@ -7248 +7242 diff --git a/test/other/metadce/test_metadce_hello_O0.jssize b/test/other/metadce/test_metadce_hello_O0.jssize index c1e0a1605ef6d..b915817b43619 100644 --- a/test/other/metadce/test_metadce_hello_O0.jssize +++ b/test/other/metadce/test_metadce_hello_O0.jssize @@ -1 +1 @@ -23618 +23662 diff --git a/test/other/metadce/test_metadce_hello_O1.jssize b/test/other/metadce/test_metadce_hello_O1.jssize index f1a81086075ec..9a01b65102e31 100644 --- a/test/other/metadce/test_metadce_hello_O1.jssize +++ b/test/other/metadce/test_metadce_hello_O1.jssize @@ -1 +1 @@ -8099 +8094 diff --git a/test/other/metadce/test_metadce_hello_O2.jssize b/test/other/metadce/test_metadce_hello_O2.jssize index da710c1aba587..3836e08920cf8 100644 --- a/test/other/metadce/test_metadce_hello_O2.jssize +++ b/test/other/metadce/test_metadce_hello_O2.jssize @@ -1 +1 @@ -5753 +5747 diff --git a/test/other/metadce/test_metadce_hello_O3.jssize b/test/other/metadce/test_metadce_hello_O3.jssize index 39a15f6e7326d..583effc3c250b 100644 --- a/test/other/metadce/test_metadce_hello_O3.jssize +++ b/test/other/metadce/test_metadce_hello_O3.jssize @@ -1 +1 @@ -5599 +5593 diff --git a/test/other/metadce/test_metadce_hello_Os.jssize b/test/other/metadce/test_metadce_hello_Os.jssize index 39a15f6e7326d..583effc3c250b 100644 --- a/test/other/metadce/test_metadce_hello_Os.jssize +++ b/test/other/metadce/test_metadce_hello_Os.jssize @@ -1 +1 @@ -5599 +5593 diff --git a/test/other/metadce/test_metadce_hello_Oz.jssize b/test/other/metadce/test_metadce_hello_Oz.jssize index 41fe758666ae2..b0087ec0066a1 100644 --- a/test/other/metadce/test_metadce_hello_Oz.jssize +++ b/test/other/metadce/test_metadce_hello_Oz.jssize @@ -1 +1 @@ -5566 +5559 diff --git a/test/other/metadce/test_metadce_hello_dylink.jssize b/test/other/metadce/test_metadce_hello_dylink.jssize index 3581a17bb1bf0..73fb1622e867d 100644 --- a/test/other/metadce/test_metadce_hello_dylink.jssize +++ b/test/other/metadce/test_metadce_hello_dylink.jssize @@ -1 +1 @@ -14947 +14946 diff --git a/test/other/metadce/test_metadce_hello_export_nothing.jssize b/test/other/metadce/test_metadce_hello_export_nothing.jssize index 38e1efbb38055..2c5f4915489be 100644 --- a/test/other/metadce/test_metadce_hello_export_nothing.jssize +++ b/test/other/metadce/test_metadce_hello_export_nothing.jssize @@ -1 +1 @@ -4387 +4381 diff --git a/test/other/metadce/test_metadce_hello_wasmfs.jssize b/test/other/metadce/test_metadce_hello_wasmfs.jssize index 39a15f6e7326d..583effc3c250b 100644 --- a/test/other/metadce/test_metadce_hello_wasmfs.jssize +++ b/test/other/metadce/test_metadce_hello_wasmfs.jssize @@ -1 +1 @@ -5599 +5593 diff --git a/test/other/metadce/test_metadce_libcxxabi_message_O3.jssize b/test/other/metadce/test_metadce_libcxxabi_message_O3.jssize index 9110c0a1f5e4e..94166f8c0392a 100644 --- a/test/other/metadce/test_metadce_libcxxabi_message_O3.jssize +++ b/test/other/metadce/test_metadce_libcxxabi_message_O3.jssize @@ -1 +1 @@ -4884 +4878 diff --git a/test/other/metadce/test_metadce_libcxxabi_message_O3_standalone.jssize b/test/other/metadce/test_metadce_libcxxabi_message_O3_standalone.jssize index f32a182f1e944..87c7f9ec33478 100644 --- a/test/other/metadce/test_metadce_libcxxabi_message_O3_standalone.jssize +++ b/test/other/metadce/test_metadce_libcxxabi_message_O3_standalone.jssize @@ -1 +1 @@ -4943 +4937 diff --git a/test/other/metadce/test_metadce_mem_O3.jssize b/test/other/metadce/test_metadce_mem_O3.jssize index a3e3339d9adde..6ac73bc50dd73 100644 --- a/test/other/metadce/test_metadce_mem_O3.jssize +++ b/test/other/metadce/test_metadce_mem_O3.jssize @@ -1 +1 @@ -5774 +5768 diff --git a/test/other/metadce/test_metadce_mem_O3_grow.jssize b/test/other/metadce/test_metadce_mem_O3_grow.jssize index 3dec175604739..a49b0bdb8b0d5 100644 --- a/test/other/metadce/test_metadce_mem_O3_grow.jssize +++ b/test/other/metadce/test_metadce_mem_O3_grow.jssize @@ -1 +1 @@ -6094 +6088 diff --git a/test/other/metadce/test_metadce_mem_O3_grow_standalone.jssize b/test/other/metadce/test_metadce_mem_O3_grow_standalone.jssize index 5de66124ada49..bd8255281aa5f 100644 --- a/test/other/metadce/test_metadce_mem_O3_grow_standalone.jssize +++ b/test/other/metadce/test_metadce_mem_O3_grow_standalone.jssize @@ -1 +1 @@ -5524 +5519 diff --git a/test/other/metadce/test_metadce_mem_O3_standalone.jssize b/test/other/metadce/test_metadce_mem_O3_standalone.jssize index af7b5602a2960..62deb23034eab 100644 --- a/test/other/metadce/test_metadce_mem_O3_standalone.jssize +++ b/test/other/metadce/test_metadce_mem_O3_standalone.jssize @@ -1 +1 @@ -5454 +5449 diff --git a/test/other/metadce/test_metadce_mem_O3_standalone_lib.jssize b/test/other/metadce/test_metadce_mem_O3_standalone_lib.jssize index b95028bcc655d..610ad043b6046 100644 --- a/test/other/metadce/test_metadce_mem_O3_standalone_lib.jssize +++ b/test/other/metadce/test_metadce_mem_O3_standalone_lib.jssize @@ -1 +1 @@ -4931 +4929 diff --git a/test/other/metadce/test_metadce_mem_O3_standalone_narg.jssize b/test/other/metadce/test_metadce_mem_O3_standalone_narg.jssize index f32a182f1e944..87c7f9ec33478 100644 --- a/test/other/metadce/test_metadce_mem_O3_standalone_narg.jssize +++ b/test/other/metadce/test_metadce_mem_O3_standalone_narg.jssize @@ -1 +1 @@ -4943 +4937 diff --git a/test/other/metadce/test_metadce_mem_O3_standalone_narg_flto.jssize b/test/other/metadce/test_metadce_mem_O3_standalone_narg_flto.jssize index f32a182f1e944..87c7f9ec33478 100644 --- a/test/other/metadce/test_metadce_mem_O3_standalone_narg_flto.jssize +++ b/test/other/metadce/test_metadce_mem_O3_standalone_narg_flto.jssize @@ -1 +1 @@ -4943 +4937 diff --git a/test/other/metadce/test_metadce_minimal_64.jssize b/test/other/metadce/test_metadce_minimal_64.jssize index e78293ac9dd39..e67b201f450e6 100644 --- a/test/other/metadce/test_metadce_minimal_64.jssize +++ b/test/other/metadce/test_metadce_minimal_64.jssize @@ -1 +1 @@ -3800 +3798 diff --git a/test/other/metadce/test_metadce_minimal_O0.jssize b/test/other/metadce/test_metadce_minimal_O0.jssize index c1a965883efa2..b48d260d639d5 100644 --- a/test/other/metadce/test_metadce_minimal_O0.jssize +++ b/test/other/metadce/test_metadce_minimal_O0.jssize @@ -1 +1 @@ -20085 +20133 diff --git a/test/other/metadce/test_metadce_minimal_O1.jssize b/test/other/metadce/test_metadce_minimal_O1.jssize index 5b9e54fbbe923..f4b0425c0ebe4 100644 --- a/test/other/metadce/test_metadce_minimal_O1.jssize +++ b/test/other/metadce/test_metadce_minimal_O1.jssize @@ -1 +1 @@ -4581 +4580 diff --git a/test/other/metadce/test_metadce_minimal_O2.jssize b/test/other/metadce/test_metadce_minimal_O2.jssize index 142b126313a0a..1fd5408bc003c 100644 --- a/test/other/metadce/test_metadce_minimal_O2.jssize +++ b/test/other/metadce/test_metadce_minimal_O2.jssize @@ -1 +1 @@ -3504 +3502 diff --git a/test/other/metadce/test_metadce_minimal_O3.jssize b/test/other/metadce/test_metadce_minimal_O3.jssize index d0f1d7566f6da..3a498e9984e60 100644 --- a/test/other/metadce/test_metadce_minimal_O3.jssize +++ b/test/other/metadce/test_metadce_minimal_O3.jssize @@ -1 +1 @@ -3433 +3431 diff --git a/test/other/metadce/test_metadce_minimal_Os.jssize b/test/other/metadce/test_metadce_minimal_Os.jssize index d0f1d7566f6da..3a498e9984e60 100644 --- a/test/other/metadce/test_metadce_minimal_Os.jssize +++ b/test/other/metadce/test_metadce_minimal_Os.jssize @@ -1 +1 @@ -3433 +3431 diff --git a/test/other/metadce/test_metadce_minimal_Oz-ctors.jssize b/test/other/metadce/test_metadce_minimal_Oz-ctors.jssize index 7295ecbcfb36c..22cd4fb27592a 100644 --- a/test/other/metadce/test_metadce_minimal_Oz-ctors.jssize +++ b/test/other/metadce/test_metadce_minimal_Oz-ctors.jssize @@ -1 +1 @@ -3418 +3416 diff --git a/test/other/metadce/test_metadce_minimal_Oz.jssize b/test/other/metadce/test_metadce_minimal_Oz.jssize index d0f1d7566f6da..3a498e9984e60 100644 --- a/test/other/metadce/test_metadce_minimal_Oz.jssize +++ b/test/other/metadce/test_metadce_minimal_Oz.jssize @@ -1 +1 @@ -3433 +3431 diff --git a/test/other/metadce/test_metadce_minimal_pthreads.jssize b/test/other/metadce/test_metadce_minimal_pthreads.jssize index 3993878409619..947d39415a098 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.jssize +++ b/test/other/metadce/test_metadce_minimal_pthreads.jssize @@ -1 +1 @@ -14536 +14534 diff --git a/test/other/metadce/test_metadce_minimal_wasmfs.jssize b/test/other/metadce/test_metadce_minimal_wasmfs.jssize index d0f1d7566f6da..3a498e9984e60 100644 --- a/test/other/metadce/test_metadce_minimal_wasmfs.jssize +++ b/test/other/metadce/test_metadce_minimal_wasmfs.jssize @@ -1 +1 @@ -3433 +3431 diff --git a/test/other/test_unoptimized_code_size.js.size b/test/other/test_unoptimized_code_size.js.size index 74419340f1930..fb626e1286469 100644 --- a/test/other/test_unoptimized_code_size.js.size +++ b/test/other/test_unoptimized_code_size.js.size @@ -1 +1 @@ -58278 +58325 diff --git a/test/other/test_unoptimized_code_size_no_asserts.js.size b/test/other/test_unoptimized_code_size_no_asserts.js.size index 699f9230a6da9..ab38de7ddf479 100644 --- a/test/other/test_unoptimized_code_size_no_asserts.js.size +++ b/test/other/test_unoptimized_code_size_no_asserts.js.size @@ -1 +1 @@ -31987 +31978 diff --git a/test/other/test_unoptimized_code_size_strict.js.size b/test/other/test_unoptimized_code_size_strict.js.size index 4a2d303f895ae..a517e768780f3 100644 --- a/test/other/test_unoptimized_code_size_strict.js.size +++ b/test/other/test_unoptimized_code_size_strict.js.size @@ -1 +1 @@ -57244 +57291 From 5c96b3f32ff4af105532812e3c5c19592269eb50 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 26 Jul 2023 12:49:13 -0700 Subject: [PATCH 0574/1523] Fixes for WebGPU + wasm64 (#19902) These are enough to get the compile and link tests to work. Fixes: #19866 --- embuilder.py | 2 +- src/library.js | 1 + src/library_async.js | 6 ------ src/library_sigs.js | 2 -- src/library_webgpu.js | 17 +++++++++-------- test/test_other.py | 1 + 6 files changed, 12 insertions(+), 17 deletions(-) diff --git a/embuilder.py b/embuilder.py index 3c1ac867d44e3..5e71d49f33e63 100755 --- a/embuilder.py +++ b/embuilder.py @@ -68,6 +68,7 @@ 'libnoexit', 'sqlite3', 'sqlite3-mt', + 'libwebgpu_cpp', ] # Additional tasks on top of MINIMAL_TASKS that are necessary for PIC testing on @@ -97,7 +98,6 @@ 'libsanitizer_common_rt', 'libubsan_rt', 'libwasm_workers_stub-debug', - 'libwebgpu_cpp', 'libfetch', 'libfetch-mt', 'libwasmfs', diff --git a/src/library.js b/src/library.js index ffd53349f58d7..736898c677813 100644 --- a/src/library.js +++ b/src/library.js @@ -2736,6 +2736,7 @@ mergeInto(LibraryManager.library, { emscripten_pc_get_function: (pc) => { #if !USE_OFFSET_CONVERTER abort('Cannot use emscripten_pc_get_function without -sUSE_OFFSET_CONVERTER'); + return 0; #else var name; if (pc & 0x80000000) { diff --git a/src/library_async.js b/src/library_async.js index 25d84408b7878..d6b828130f0ad 100644 --- a/src/library_async.js +++ b/src/library_async.js @@ -657,12 +657,6 @@ mergeInto(LibraryManager.library, { emscripten_scan_registers: function(func) { throw 'Please compile your program with async support in order to use asynchronous operations like emscripten_scan_registers'; }, - emscripten_fiber_init: function() { - throw 'Please compile your program with async support in order to use asynchronous operations like emscripten_fiber_init'; - }, - emscripten_fiber_init_from_current_context: function() { - throw 'Please compile your program with async support in order to use asynchronous operations like emscripten_fiber_init_from_current_context'; - }, emscripten_fiber_swap: function(oldFiber, newFiber) { throw 'Please compile your program with async support in order to use asynchronous operations like emscripten_fiber_swap'; }, diff --git a/src/library_sigs.js b/src/library_sigs.js index 30874c74ecee5..7b7e82a7d0d84 100644 --- a/src/library_sigs.js +++ b/src/library_sigs.js @@ -601,8 +601,6 @@ sigs = { emscripten_exit_pointerlock__sig: 'i', emscripten_exit_soft_fullscreen__sig: 'i', emscripten_exit_with_live_runtime__sig: 'v', - emscripten_fiber_init__sig: 'vppppppp', - emscripten_fiber_init_from_current_context__sig: 'vppp', emscripten_fiber_swap__sig: 'vpp', emscripten_force_exit__sig: 'vi', emscripten_get_battery_status__sig: 'ip', diff --git a/src/library_webgpu.js b/src/library_webgpu.js index e67272f06913e..2c88f7ac9be15 100644 --- a/src/library_webgpu.js +++ b/src/library_webgpu.js @@ -1491,7 +1491,7 @@ var LibraryWebGPU = { wgpuQueueOnSubmittedWorkDone: function(queueId, signalValue, callback, userdata) { var queue = WebGPU.mgrQueue.get(queueId); #if ASSERTIONS - assert(signalValue_low === 0 && signalValue_high === 0, 'signalValue not supported, must be 0'); + assert(signalValue == 0, 'signalValue not supported, must be 0'); #endif {{{ runtimeKeepalivePush() }}} @@ -1759,7 +1759,8 @@ var LibraryWebGPU = { encoder["insertDebugMarker"](UTF8ToString(markerLabelPtr)); }, - wgpuCommandEncoderFinish: function(encoderId) { + wgpuCommandEncoderFinish: function(encoderId, descriptor) { + // TODO: Use the descriptor. var commandEncoder = WebGPU.mgrCommandEncoder.get(encoderId); return WebGPU.mgrCommandBuffer.create(commandEncoder["finish"]()); }, @@ -2331,14 +2332,14 @@ var LibraryWebGPU = { // Instance - wgpuCreateInstance: function() { + wgpuCreateInstance: function(descriptor) { return 1; }, - wgpuInstanceReference: function() { + wgpuInstanceReference: function(instance) { // no-op }, - wgpuInstanceRelease: function() { + wgpuInstanceRelease: function(instance) { // no-op }, @@ -2370,7 +2371,7 @@ var LibraryWebGPU = { return WebGPU.mgrSurface.create(context); }, - wgpuInstanceProcessEvents: function() { + wgpuInstanceProcessEvents: function(instance) { // TODO: This could probably be emulated with ASYNCIFY. #if ASSERTIONS abort('wgpuInstanceProcessEvents is unsupported (use requestAnimationFrame via html5.h instead)'); @@ -2624,7 +2625,7 @@ var LibraryWebGPU = { var context = WebGPU.mgrSwapChain.get(swapChainId); return WebGPU.mgrTextureView.create(context["getCurrentTexture"]()["createView"]()); }, - wgpuSwapChainPresent: function() { + wgpuSwapChainPresent: function(swapChainId) { // TODO: This could probably be emulated with ASYNCIFY. #if ASSERTIONS abort('wgpuSwapChainPresent is unsupported (use requestAnimationFrame via html5.h instead)'); @@ -2633,7 +2634,7 @@ var LibraryWebGPU = { // wgpuGetProcAddress - wgpuGetProcAddress: function() { + wgpuGetProcAddress: function(device, procName) { #if ASSERTIONS abort('TODO(#11526): wgpuGetProcAddress unimplemented'); #endif diff --git a/test/test_other.py b/test/test_other.py index ee358d05eb382..8bb6142ea2cce 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -8833,6 +8833,7 @@ def test_closure_full_js_library(self, args): for sym in glsyms: self.assertContained('.' + sym, js) + @also_with_wasm64 def test_closure_webgpu(self): # This test can be removed if USE_WEBGPU is later included in INCLUDE_FULL_LIBRARY. self.build(test_file('hello_world.c'), emcc_args=[ From ab1e7f2c802f5c8d0ce60ca54e9632b506a02afa Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 26 Jul 2023 14:11:45 -0700 Subject: [PATCH 0575/1523] Fix webidl closure compiler warnings (#19905) I couldn't figure out how to make this work without suppressing them. --- test/test_core.py | 2 -- tools/webidl_binder.py | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_core.py b/test/test_core.py index 379aedf5983ab..fc694163284f0 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -7745,8 +7745,6 @@ def test_embind_no_rtti_followed_by_rtti(self): }) def test_webidl(self, mode, allow_memory_growth): self.uses_es6 = True - # TODO(): Remove once we make webidl output closure-warning free. - self.ldflags.append('-Wno-error=closure') self.set_setting('WASM_ASYNC_COMPILATION', 0) if self.maybe_closure(): # avoid closure minified names competing with our test code in the global name space diff --git a/tools/webidl_binder.py b/tools/webidl_binder.py index 3dbac655be730..866a0835e63f4 100644 --- a/tools/webidl_binder.py +++ b/tools/webidl_binder.py @@ -732,6 +732,7 @@ def render_function(class_name, func_name, sigs, return_type, non_pointer, if m.readonly: mid_js += [r''' + /** @suppress {checkTypes} */ Object.defineProperty(%s.prototype, '%s', { get: %s.prototype.%s });''' % (name, attr, name, get_name)] else: set_name = 'set_' + attr @@ -748,6 +749,7 @@ def render_function(class_name, func_name, sigs, return_type, non_pointer, const=m.getExtendedAttribute('Const'), array_attribute=m.type.isArray()) mid_js += [r''' + /** @suppress {checkTypes} */ Object.defineProperty(%s.prototype, '%s', { get: %s.prototype.%s, set: %s.prototype.%s });''' % (name, attr, name, get_name, name, set_name)] if not interface.getExtendedAttribute('NoDelete'): From 0bf0d39ae3f5135fd186595b304b26af31a82642 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 26 Jul 2023 15:20:14 -0700 Subject: [PATCH 0576/1523] Rename `asm` to `wasmExports` under MINIMAL_RUNTIME (#19901) This matches the name used by the regualar runtime as of #19816 and removes one of them major differences between the two runtimes. --- emscripten.py | 8 +++--- src/library.js | 8 +++--- src/library_async.js | 2 +- src/library_exports.js | 7 +---- src/postamble_minimal.js | 26 +++++++++---------- src/runtime_debug.js | 2 -- .../optimizer/applyDCEGraphRemovals-output.js | 12 ++++----- test/optimizer/applyDCEGraphRemovals.js | 16 ++++++------ .../applyImportAndExportNameChanges-output.js | 2 +- .../applyImportAndExportNameChanges.js | 2 +- ...applyImportAndExportNameChanges2-output.js | 22 ++++++++-------- .../applyImportAndExportNameChanges2.js | 22 ++++++++-------- test/optimizer/emitDCEGraph.js | 12 ++++----- .../minimal-runtime-2-emitDCEGraph.js | 8 +++--- ...al-runtime-applyDCEGraphRemovals-output.js | 12 ++++----- .../minimal-runtime-applyDCEGraphRemovals.js | 14 +++++----- .../optimizer/minimal-runtime-emitDCEGraph.js | 6 ++--- tools/acorn-optimizer.js | 20 +++++++------- tools/emdump.py | 2 +- 19 files changed, 97 insertions(+), 106 deletions(-) diff --git a/emscripten.py b/emscripten.py index b1c62610f2616..630f60eb5d4f8 100644 --- a/emscripten.py +++ b/emscripten.py @@ -49,7 +49,7 @@ def compute_minimal_runtime_initializer_and_exports(post, exports, receiving): declares = 'var ' + ',\n '.join(exports_that_are_not_initializers) + ';' post = shared.do_replace(post, '<<< WASM_MODULE_EXPORTS_DECLARES >>>', declares) - # Generate assignments from all wasm exports out to the JS variables above: e.g. a = asm['a']; b = asm['b']; + # Generate assignments from all wasm exports out to the JS variables above: e.g. a = wasmExports['a']; b = wasmExports['b']; post = shared.do_replace(post, '<<< WASM_MODULE_EXPORTS >>>', receiving) return post @@ -778,8 +778,8 @@ def create_receiving(function_exports): # existing in top level JS scope, i.e. # var _main; # WebAssembly.instantiate(Module['wasm'], imports).then((output) => { - # var asm = output.instance.exports; - # _main = asm["_main"]; + # var wasmExports = output.instance.exports; + # _main = wasmExports["_main"]; generate_dyncall_assignment = settings.DYNCALLS and '$dynCall' in settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE exports_that_are_not_initializers = [x for x in function_exports if x != building.WASM_CALL_CTORS] @@ -790,7 +790,7 @@ def create_receiving(function_exports): export_assignment = '' if settings.MODULARIZE and should_export: export_assignment = f"Module['{mangled}'] = " - receiving += [f'{export_assignment}{dynCallAssignment}{mangled} = asm["{s}"]'] + receiving += [f'{export_assignment}{dynCallAssignment}{mangled} = wasmExports["{s}"]'] else: receiving += make_export_wrappers(function_exports, delay_assignment) else: diff --git a/src/library.js b/src/library.js index 736898c677813..5d9c7b5df4ccb 100644 --- a/src/library.js +++ b/src/library.js @@ -2984,7 +2984,7 @@ mergeInto(LibraryManager.library, { // When DECLARE_ASM_MODULE_EXPORTS is not set we export native symbols // at runtime rather than statically in JS code. $exportAsmFunctions__deps: ['$asmjsMangle'], - $exportAsmFunctions: (asm) => { + $exportAsmFunctions: (wasmExports) => { #if ENVIRONMENT_MAY_BE_NODE && ENVIRONMENT_MAY_BE_WEB var global_object = (typeof process != "undefined" ? global : this); #elif ENVIRONMENT_MAY_BE_NODE @@ -2993,12 +2993,12 @@ mergeInto(LibraryManager.library, { var global_object = this; #endif - for (var __exportedFunc in asm) { + for (var __exportedFunc in wasmExports) { var jsname = asmjsMangle(__exportedFunc); #if MINIMAL_RUNTIME - global_object[jsname] = asm[__exportedFunc]; + global_object[jsname] = wasmExports[__exportedFunc]; #else - global_object[jsname] = Module[jsname] = asm[__exportedFunc]; + global_object[jsname] = Module[jsname] = wasmExports[__exportedFunc]; #endif } diff --git a/src/library_async.js b/src/library_async.js index d6b828130f0ad..c694352c425ab 100644 --- a/src/library_async.js +++ b/src/library_async.js @@ -533,7 +533,7 @@ mergeInto(LibraryManager.library, { // Add a callback for when all run dependencies are fulfilled, which happens when async wasm loading is done. dependenciesFulfilled = wakeUp; // Load the new wasm. - asm = createWasm(); + createWasm(); }); }, diff --git a/src/library_exports.js b/src/library_exports.js index 62a6cf8b23623..e9c875b9d47ea 100644 --- a/src/library_exports.js +++ b/src/library_exports.js @@ -12,12 +12,7 @@ mergeInto(LibraryManager.library, { // Wasm backend does not use C name mangling on exports, // so adjust for that manually. if (name[0] == '_') name = name.substr(1); -#if MINIMAL_RUNTIME - var exportedFunc = asm[name]; -#else - // In regular runtime, exports are available on the Module object. var exportedFunc = wasmExports[name]; -#endif if (exportedFunc) { // Record the created function pointer to each function object, // so that if the same function pointer is obtained several times, @@ -26,7 +21,7 @@ mergeInto(LibraryManager.library, { return exportedFunc.ptr; } #if ASSERTIONS - err('No exported function found by name "' + exportedFunc + '"'); + err(`No exported function found by name "{exportedFunc}"`); #endif // implicit return 0; } diff --git a/src/postamble_minimal.js b/src/postamble_minimal.js index 0813e184fbd4e..e72df02545984 100644 --- a/src/postamble_minimal.js +++ b/src/postamble_minimal.js @@ -48,7 +48,7 @@ function run() { } #endif -function initRuntime(asm) { +function initRuntime(wasmExports) { #if ASSERTIONS || SAFE_HEAP || USE_ASAN runtimeInitialized = true; #endif @@ -77,11 +77,11 @@ function initRuntime(asm) { #endif #if PTHREADS - PThread.tlsInitFunctions.push(asm['_emscripten_tls_init']); + PThread.tlsInitFunctions.push(wasmExports['_emscripten_tls_init']); #endif #if hasExportedSymbol('__wasm_call_ctors') - asm['__wasm_call_ctors'](); + wasmExports['__wasm_call_ctors'](); #endif <<< ATINITS >>> @@ -101,7 +101,7 @@ var imports = { // In non-fastcomp non-asm.js builds, grab wasm exports to outer scope // for emscripten_get_exported_function() to be able to access them. #if LibraryManager.has('library_exports.js') -var asm; +var wasmExports; #endif #if PTHREADS @@ -142,7 +142,7 @@ WebAssembly.instantiate(Module['wasm'], imports).then((output) => { #if !LibraryManager.has('library_exports.js') && !EMBIND // If not using the emscripten_get_exported_function() API or embind, keep the - // `asm` exports variable in local scope to this instantiate function to save + // `wasmExports` variable in local scope to this instantiate function to save // code size. (otherwise access it without to export it to outer scope) var #endif @@ -163,16 +163,16 @@ WebAssembly.instantiate(Module['wasm'], imports).then((output) => { // that case, 'output' is a WebAssembly.Instance. // In main thread, Module['wasm'] is either a typed array or a fetch stream. // In that case, 'output.instance' is the WebAssembly.Instance. - asm = (output.instance || output).exports; + wasmExports = (output.instance || output).exports; #else - asm = output.exports; + wasmExports = output.exports; #endif #else - asm = output.instance.exports; + wasmExports = output.instance.exports; #endif #if MEMORY64 || CAN_ADDRESS_2GB - asm = applySignatureConversions(asm); + wasmExports = applySignatureConversions(wasmExports); #endif #if USE_OFFSET_CONVERTER @@ -183,11 +183,11 @@ WebAssembly.instantiate(Module['wasm'], imports).then((output) => { #endif #if !DECLARE_ASM_MODULE_EXPORTS - exportAsmFunctions(asm); + exportAsmFunctions(wasmExports); #else <<< WASM_MODULE_EXPORTS >>> #endif - wasmTable = asm['__indirect_function_table']; + wasmTable = wasmExports['__indirect_function_table']; #if ASSERTIONS assert(wasmTable); #endif @@ -211,7 +211,7 @@ WebAssembly.instantiate(Module['wasm'], imports).then((output) => { #endif #if !IMPORTED_MEMORY - wasmMemory = asm['memory']; + wasmMemory = wasmExports['memory']; #if ASSERTIONS assert(wasmMemory); assert(wasmMemory.buffer.byteLength === {{{ INITIAL_MEMORY }}}); @@ -226,7 +226,7 @@ WebAssembly.instantiate(Module['wasm'], imports).then((output) => { HEAPU8.set(new Uint8Array(Module['mem']), {{{ GLOBAL_BASE }}}); #endif - initRuntime(asm); + initRuntime(wasmExports); #if PTHREADS // Export Wasm module for pthread creation to access. wasmModule = output.module || Module['wasm']; diff --git a/src/runtime_debug.js b/src/runtime_debug.js index 463d75864f610..23155be7f6356 100644 --- a/src/runtime_debug.js +++ b/src/runtime_debug.js @@ -53,9 +53,7 @@ function missingGlobal(sym, msg) { } missingGlobal('buffer', 'Please use HEAP8.buffer or wasmMemory.buffer'); -#if !MINIMAL_RUNTIME missingGlobal('asm', 'Please use wasmExports instead'); -#endif function missingLibrarySymbol(sym) { if (typeof globalThis !== 'undefined' && !Object.getOwnPropertyDescriptor(globalThis, sym)) { diff --git a/test/optimizer/applyDCEGraphRemovals-output.js b/test/optimizer/applyDCEGraphRemovals-output.js index 6e70e4c9d26eb..7d7efa729f988 100644 --- a/test/optimizer/applyDCEGraphRemovals-output.js +++ b/test/optimizer/applyDCEGraphRemovals-output.js @@ -5,15 +5,15 @@ var wasmImports = { save2: 2 }; -var expD1 = Module["expD1"] = asm["expD1"]; +var expD1 = Module["expD1"] = wasmExports["expD1"]; -var expD2 = Module["expD2"] = asm["expD2"]; +var expD2 = Module["expD2"] = wasmExports["expD2"]; -var expD3 = Module["expD3"] = asm["expD3"]; +var expD3 = Module["expD3"] = wasmExports["expD3"]; var expD4; -var expD5 = asm["expD5"]; +var expD5 = wasmExports["expD5"]; var expD6; @@ -33,10 +33,10 @@ expD1; Module["expD2"]; -asm["expD3"]; +wasmExports["expD3"]; expI1; Module["expI2"]; -asm["expI3"]; +wasmExports["expI3"]; diff --git a/test/optimizer/applyDCEGraphRemovals.js b/test/optimizer/applyDCEGraphRemovals.js index 2401d772fc3fe..874c57caeb1d0 100644 --- a/test/optimizer/applyDCEGraphRemovals.js +++ b/test/optimizer/applyDCEGraphRemovals.js @@ -2,13 +2,13 @@ var name; var wasmImports = { save1: 1, number: 33, name: name, func: function() {}, save2: 2 }; // exports gotten directly -var expD1 = Module['expD1'] = asm['expD1']; -var expD2 = Module['expD2'] = asm['expD2']; -var expD3 = Module['expD3'] = asm['expD3']; -var expD4 = Module['expD4'] = asm['expD4']; +var expD1 = Module['expD1'] = wasmExports['expD1']; +var expD2 = Module['expD2'] = wasmExports['expD2']; +var expD3 = Module['expD3'] = wasmExports['expD3']; +var expD4 = Module['expD4'] = wasmExports['expD4']; // Like above, but not exported on the Module -var expD5 = asm['expD5']; -var expD6 = asm['expD6']; +var expD5 = wasmExports['expD5']; +var expD6 = wasmExports['expD6']; // exports gotten indirectly (async compilation var expI1 = Module['expI1'] = () => (expI1 = Module['expI1'] = wasmExports['expI1'])(); @@ -23,10 +23,10 @@ var expI6 = () => (expI6 = wasmExports['expI6'])(); // add uses for some of them, leave *4 as non-roots expD1; Module['expD2']; -asm['expD3']; +wasmExports['expD3']; expI1; Module['expI2']; -asm['expI3']; +wasmExports['expI3']; // EXTRA_INFO: { "unused": ["emcc$import$number", "emcc$import$name", "emcc$import$func", "emcc$export$expD4", "emcc$export$expD6", "emcc$export$expI4", "emcc$export$expI6"] } diff --git a/test/optimizer/applyImportAndExportNameChanges-output.js b/test/optimizer/applyImportAndExportNameChanges-output.js index 00d82577fefdc..1b1c4de5c1693 100644 --- a/test/optimizer/applyImportAndExportNameChanges-output.js +++ b/test/optimizer/applyImportAndExportNameChanges-output.js @@ -14,7 +14,7 @@ var wasmImports = { q: ___syscall146 }; -var expD1 = Module["expD1"] = asm["c"]; +var expD1 = Module["expD1"] = wasmExports["c"]; var expI1 = Module["expI1"] = function() { return wasmExports["d"].apply(null, arguments); diff --git a/test/optimizer/applyImportAndExportNameChanges.js b/test/optimizer/applyImportAndExportNameChanges.js index ebdc723961a27..abb6ba461c6a9 100644 --- a/test/optimizer/applyImportAndExportNameChanges.js +++ b/test/optimizer/applyImportAndExportNameChanges.js @@ -14,7 +14,7 @@ var wasmImports = { }; // exports -var expD1 = Module['expD1'] = asm['expD1']; +var expD1 = Module['expD1'] = wasmExports['expD1']; // exports gotten indirectly (async compilation var expI1 = Module['expI1'] = (function() { diff --git a/test/optimizer/applyImportAndExportNameChanges2-output.js b/test/optimizer/applyImportAndExportNameChanges2-output.js index 03d3dfdbb746e..d9366ebc0483f 100644 --- a/test/optimizer/applyImportAndExportNameChanges2-output.js +++ b/test/optimizer/applyImportAndExportNameChanges2-output.js @@ -227,8 +227,8 @@ function run() { var ret = _main(); } -function initRuntime(asm) { - asm["i"](); +function initRuntime(wasmExports) { + wasmExports["i"](); } var env = wasmImports; @@ -265,14 +265,14 @@ var imports = { var ___errno_location, _llvm_bswap_i32, _main, _memcpy, _memset, dynCall_ii, dynCall_iiii; WebAssembly.instantiate(Module["wasm"], imports).then(output => { - var asm = output.instance.exports; - ___errno_location = asm["j"]; - _llvm_bswap_i32 = asm["k"]; - _main = asm["l"]; - _memcpy = asm["m"]; - _memset = asm["n"]; - dynCall_ii = asm["o"]; - dynCall_iiii = asm["p"]; - initRuntime(asm); + var wasmExports = output.instance.exports; + ___errno_location = wasmExports["j"]; + _llvm_bswap_i32 = wasmExports["k"]; + _main = wasmExports["l"]; + _memcpy = wasmExports["m"]; + _memset = wasmExports["n"]; + dynCall_ii = wasmExports["o"]; + dynCall_iiii = wasmExports["p"]; + initRuntime(wasmExports); ready(); }); diff --git a/test/optimizer/applyImportAndExportNameChanges2.js b/test/optimizer/applyImportAndExportNameChanges2.js index 4fb4dfe147c4a..0a9f1ec67142d 100644 --- a/test/optimizer/applyImportAndExportNameChanges2.js +++ b/test/optimizer/applyImportAndExportNameChanges2.js @@ -218,8 +218,8 @@ function run() { var ret = _main() } -function initRuntime(asm) { - asm["__GLOBAL__sub_I_test_global_initializer_cpp"]() +function initRuntime(wasmExports) { + wasmExports["__GLOBAL__sub_I_test_global_initializer_cpp"]() } var env = wasmImports; env["memory"] = wasmMemory; @@ -248,15 +248,15 @@ var imports = { }; var ___errno_location, _llvm_bswap_i32, _main, _memcpy, _memset, dynCall_ii, dynCall_iiii; WebAssembly.instantiate(Module["wasm"], imports).then(((output) => { - var asm = output.instance.exports; - ___errno_location = asm["___errno_location"]; - _llvm_bswap_i32 = asm["_llvm_bswap_i32"]; - _main = asm["_main"]; - _memcpy = asm["_memcpy"]; - _memset = asm["_memset"]; - dynCall_ii = asm["dynCall_ii"]; - dynCall_iiii = asm["dynCall_iiii"]; - initRuntime(asm); + var wasmExports = output.instance.exports; + ___errno_location = wasmExports["___errno_location"]; + _llvm_bswap_i32 = wasmExports["_llvm_bswap_i32"]; + _main = wasmExports["_main"]; + _memcpy = wasmExports["_memcpy"]; + _memset = wasmExports["_memset"]; + dynCall_ii = wasmExports["dynCall_ii"]; + dynCall_iiii = wasmExports["dynCall_iiii"]; + initRuntime(wasmExports); ready() })) diff --git a/test/optimizer/emitDCEGraph.js b/test/optimizer/emitDCEGraph.js index 57f1d680fe37d..d9511afee2736 100644 --- a/test/optimizer/emitDCEGraph.js +++ b/test/optimizer/emitDCEGraph.js @@ -45,12 +45,12 @@ var wasmImports = { }; // exports gotten directly -var expD1 = Module['expD1'] = asm['expD1']; -var expD2 = Module['expD2'] = asm['expD2']; -var expD3 = Module['expD3'] = asm['expD3']; -var expD4 = Module['expD4'] = asm['expD4']; +var expD1 = Module['expD1'] = wasmExports['expD1']; +var expD2 = Module['expD2'] = wasmExports['expD2']; +var expD3 = Module['expD3'] = wasmExports['expD3']; +var expD4 = Module['expD4'] = wasmExports['expD4']; // Same as above but not export on the Module -var expD5 = asm['expD5']; +var expD5 = wasmExports['expD5']; // exports gotten indirectly (async compilation var expI1 = Module['expI1'] = () => (expI1 = Module['expI1'] = wasmExports['expI1'])(); @@ -64,7 +64,7 @@ var expI5 = () => (expI5 = wasmExports['expI5'])(); // add uses for some of them expD1; Module['expD2']; -asm['expD3']; +wasmExports['expD3']; expI1; Module['expI2']; diff --git a/test/optimizer/minimal-runtime-2-emitDCEGraph.js b/test/optimizer/minimal-runtime-2-emitDCEGraph.js index ff78bd01d5968..78bb6bc530e95 100644 --- a/test/optimizer/minimal-runtime-2-emitDCEGraph.js +++ b/test/optimizer/minimal-runtime-2-emitDCEGraph.js @@ -64,11 +64,11 @@ var imports = { }) } }; -var _main, _unused, asm; +var _main, _unused, wasmExports; WebAssembly.instantiate(Module["wasm"], imports).then(((output) => { - asm = output.instance.exports; - _main = asm["b"]; - _unused = asm["c"]; + wasmExports = output.instance.exports; + _main = wasmExports["b"]; + _unused = wasmExports["c"]; initRuntime(); ready(); })); diff --git a/test/optimizer/minimal-runtime-applyDCEGraphRemovals-output.js b/test/optimizer/minimal-runtime-applyDCEGraphRemovals-output.js index 465ce4410ab35..39a0eb5c0893b 100644 --- a/test/optimizer/minimal-runtime-applyDCEGraphRemovals-output.js +++ b/test/optimizer/minimal-runtime-applyDCEGraphRemovals-output.js @@ -6,11 +6,11 @@ var wasmImports = { }; WebAssembly.instantiate(Module["wasm"], imports).then(output => { - asm = output.instance.exports; - expD1 = asm["expD1"]; - expD2 = asm["expD2"]; - expD3 = asm["expD3"]; - initRuntime(asm); + wasmExports = output.instance.exports; + expD1 = wasmExports["expD1"]; + expD2 = wasmExports["expD2"]; + expD3 = wasmExports["expD3"]; + initRuntime(wasmExports); ready(); }); @@ -18,4 +18,4 @@ expD1; Module["expD2"]; -asm["expD3"]; +wasmExports["expD3"]; diff --git a/test/optimizer/minimal-runtime-applyDCEGraphRemovals.js b/test/optimizer/minimal-runtime-applyDCEGraphRemovals.js index 73f6d28da9ebd..c7bebd73ac95b 100644 --- a/test/optimizer/minimal-runtime-applyDCEGraphRemovals.js +++ b/test/optimizer/minimal-runtime-applyDCEGraphRemovals.js @@ -3,18 +3,18 @@ var wasmImports = { save1: 1, number: 33, name: name, func: function() {}, save2 // exports gotten directly in the minimal runtime style WebAssembly.instantiate(Module["wasm"], imports).then((output) => { - asm = output.instance.exports; - expD1 = asm['expD1']; - expD2 = asm['expD2']; - expD3 = asm['expD3']; - expD4 = asm['expD4']; - initRuntime(asm); + wasmExports = output.instance.exports; + expD1 = wasmExports['expD1']; + expD2 = wasmExports['expD2']; + expD3 = wasmExports['expD3']; + expD4 = wasmExports['expD4']; + initRuntime(wasmExports); ready(); }); // add uses for some of them, leave *4 as non-roots expD1; Module['expD2']; -asm['expD3']; +wasmExports['expD3']; // EXTRA_INFO: { "unused": ["emcc$import$number", "emcc$import$name", "emcc$import$func", "emcc$export$expD4", "emcc$export$expI4"] } diff --git a/test/optimizer/minimal-runtime-emitDCEGraph.js b/test/optimizer/minimal-runtime-emitDCEGraph.js index 733913f5a583d..ae6d45c1345a1 100644 --- a/test/optimizer/minimal-runtime-emitDCEGraph.js +++ b/test/optimizer/minimal-runtime-emitDCEGraph.js @@ -66,9 +66,9 @@ var imports = { }; var _main, _unused; WebAssembly.instantiate(Module["wasm"], imports).then(((output) => { - var asm = output.instance.exports; - _main = asm["b"]; - _unused = asm["c"]; + var wasmExports = output.instance.exports; + _main = wasmExports["b"]; + _unused = wasmExports["c"]; initRuntime(); ready(); })); diff --git a/tools/acorn-optimizer.js b/tools/acorn-optimizer.js index 4ae42317fe656..2cfa182f2e603 100755 --- a/tools/acorn-optimizer.js +++ b/tools/acorn-optimizer.js @@ -469,15 +469,13 @@ function isExportUse(node) { // MINIMAL_RUNTIME calls exports global variable `asm`, whereas regualar // runtime calls it `wasmExports`. // - // Here we match either: + // Here we match: // wasmExports['X'] - // or: - // asm['X'] return ( node.type === 'MemberExpression' && node.object.type === 'Identifier' && isLiteralString(node.property) && - (node.object.name === 'wasmExports' || node.object.name === 'asm') + node.object.name === 'wasmExports' ); } @@ -646,10 +644,10 @@ function emitDCEGraph(ast) { // or, in the minimal runtime, it looks like // // WebAssembly.instantiate(Module["wasm"], imports).then((output) => { - // var asm = output.instance.exports; // may also not have "var", if - // // declared outside and used elsewhere + // var wasmExports = output.instance.exports; // may also not have "var", if + // // declared outside and used elsewhere // .. - // _malloc = asm["malloc"]; + // _malloc = wasmExports["malloc"]; // .. // }); const imports = []; @@ -760,7 +758,7 @@ function emitDCEGraph(ast) { emptyOut(node); // ignore this in the second pass; we scan defuns separately } else if (node.type === 'ArrowFunctionExpression') { // Check if this is the minimal runtime exports function, which looks like - // (output) => { var asm = output.instance.exports; + // (output) => { var wasmExports = output.instance.exports; if ( node.params.length === 1 && node.params[0].type === 'Identifier' && @@ -772,7 +770,7 @@ function emitDCEGraph(ast) { const first = body[0]; let target; let value; // "(var?) target = value" - // Look either for var asm = or just asm = + // Look either for var wasmExports = or just wasmExports = if (first.type === 'VariableDeclaration' && first.declarations.length === 1) { const decl = first.declarations[0]; target = decl.id; @@ -787,7 +785,7 @@ function emitDCEGraph(ast) { value = assign.right; } } - if (target && target.type === 'Identifier' && target.name === 'asm' && value) { + if (target && target.type === 'Identifier' && target.name === 'wasmExports' && value) { if ( value.type === 'MemberExpression' && value.object.type === 'MemberExpression' && @@ -809,7 +807,7 @@ function emitDCEGraph(ast) { item.expression.left.type === 'Identifier' && item.expression.right.type === 'MemberExpression' && item.expression.right.object.type === 'Identifier' && - item.expression.right.object.name === 'asm' && + item.expression.right.object.name === 'wasmExports' && item.expression.right.property.type === 'Literal' ) { const name = item.expression.left.name; diff --git a/tools/emdump.py b/tools/emdump.py index e205d7bbb5d22..dd2c4cfb41517 100755 --- a/tools/emdump.py +++ b/tools/emdump.py @@ -303,7 +303,7 @@ def analyze_javascript_file_contents(filename, file_contents, total_source_set_s end_brace = file_contents.find(';', var_pos) minified_name = var_match.group(1) - # Special case ignore the 'var asm = (function(global, env, buffer) { 'use asm'; ... }; ' variable that contains all the asm.js code. + # Special case ignore the 'var wasmExports = (function(global, env, buffer) { 'use asm'; ... }; ' variable that contains all the asm.js code. # Ignoring this variable lets all the asm.js code be trated as functions in this parser, instead of assigning them to the asm variable. if file_contents[start_brace] == '(' and ("'use asm'" in file_contents[var_pos:end_brace] or '"use asm"' in file_contents[var_pos:end_brace] or "'almost asm'" in file_contents[var_pos:end_brace] or '"almost asm"' in file_contents[var_pos:end_brace]): continue From 233e00449a4ac4e3982bf715e01194ad11067590 Mon Sep 17 00:00:00 2001 From: Arthur Islamov Date: Thu, 27 Jul 2023 14:04:54 +0400 Subject: [PATCH 0577/1523] Use proxy objects for MEMORY64 HEAP access over 4Gb (#19737) --- .circleci/config.yml | 10 +- src/preamble.js | 6 +- src/runtime_view_proxy.js | 173 ++++++++++++++++++++++++++++ test/other/test_memory64_proxies.js | 40 +++++++ test/test_browser.py | 2 +- test/test_other.py | 20 +++- 6 files changed, 243 insertions(+), 8 deletions(-) create mode 100644 src/runtime_view_proxy.js create mode 100644 test/other/test_memory64_proxies.js diff --git a/.circleci/config.yml b/.circleci/config.yml index 2500e05b55439..8e6f5f9b27b87 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -360,7 +360,7 @@ commands: export EM_FROZEN_CACHE="" test/runner emrun # skip test_zzz_zzz_4gb_fail as it OOMs on the current bot - test/runner posixtest_browser.test_pthread_create_1_1 browser skip:browser.test_zzz_zzz_4gb_fail + test/runner posixtest_browser.test_pthread_create_1_1 browser skip:browser.test_zzz_zzz_4gb_fail skip:browser.test_zzz_zzz_4gb_fail_wasm64 - upload-test-results test-sockets-chrome: description: "Runs emscripten sockets tests under chrome" @@ -587,7 +587,11 @@ jobs: - install-node-canary - run-tests: title: "wasm64" - test_targets: "wasm64 wasm64l.test_bigswitch" + test_targets: " + wasm64 + wasm64l.test_bigswitch + other.test_memory64_proxies + other.test_failing_growth_wasm64" - upload-test-results test-jsc: executor: linux-python @@ -694,6 +698,8 @@ jobs: - upload-test-results test-other: executor: bionic + environment: + EMTEST_SKIP_NODE_CANARY: "1" steps: - run: apt-get install ninja-build scons - run-tests-linux: diff --git a/src/preamble.js b/src/preamble.js index 3bdce8a0cc775..a3e428cf7ddaf 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -139,11 +139,15 @@ function updateMemoryViews() { #if SUPPORT_BIG_ENDIAN Module['HEAP_DATA_VIEW'] = HEAP_DATA_VIEW = new DataView(b); #endif +#if MEMORY64 && MAXIMUM_MEMORY > FOUR_GB +#include "runtime_view_proxy.js" +#else Module['HEAP8'] = HEAP8 = new Int8Array(b); Module['HEAP16'] = HEAP16 = new Int16Array(b); - Module['HEAP32'] = HEAP32 = new Int32Array(b); Module['HEAPU8'] = HEAPU8 = new Uint8Array(b); Module['HEAPU16'] = HEAPU16 = new Uint16Array(b); +#endif + Module['HEAP32'] = HEAP32 = new Int32Array(b); Module['HEAPU32'] = HEAPU32 = new Uint32Array(b); Module['HEAPF32'] = HEAPF32 = new Float32Array(b); Module['HEAPF64'] = HEAPF64 = new Float64Array(b); diff --git a/src/runtime_view_proxy.js b/src/runtime_view_proxy.js new file mode 100644 index 0000000000000..0f97f27ae1801 --- /dev/null +++ b/src/runtime_view_proxy.js @@ -0,0 +1,173 @@ +/** + * @license + * Copyright 2023 The Emscripten Authors + * SPDX-License-Identifier: MIT + */ + +// Chrome does not allow TypedArrays with more than 4294967296 elements +// We'll create proxy objects for HEAP(U)8 when memory is > 4gb and for HEAP(U)16 when > 8gb +// https://bugs.chromium.org/p/v8/issues/detail?id=4153 +var maxArraySize = Math.min(b.byteLength, 4 * 1024 * 1024 * 1024 - 2); +/** + * @param {string} type - Heap type + * @param {number} [offset] - Heap offset + * @param {number} [length] - typed array length + */ +function getHeapBlock(type, offset, length) { + if (!offset) { + offset = 0 + } + + let heap = wasmMemory.buffer + + // we should always limit the length to maxArraySize + function createTypedArray(arrayType, offset, length) { + let bpe = arrayType.BYTES_PER_ELEMENT; + return new arrayType(heap, offset, length || Math.min((heap.byteLength - offset) / bpe, maxArraySize)); + } + + switch (type) { + case 'i1': + case 'i8': + return createTypedArray(Int8Array, offset, length); + case 'u1': + case 'u8': + return createTypedArray(Uint8Array, offset, length); + case 'i16': + return createTypedArray(Int16Array, offset, length); + case 'u16': + return createTypedArray(Uint16Array, offset, length); + default: + throw new Error('Invalid type'); + } +} + +function createProxyHandler(type, heapBlocks) { + let firstHeapBlock = heapBlocks[0] + let bpe = firstHeapBlock.BYTES_PER_ELEMENT + + function getRealStartAndEnd(start, end) { + let startReal = (start || 0) * bpe + let endReal = end ? end * bpe : wasmMemory.byteLength + return [startReal, endReal] + } + + function copyWithin(target, start, end) { + if (target * bpe >= maxArraySize || start * bpe >= maxArraySize || (end && end * bpe >= maxArraySize)) { + let len = end - start + let targetArray = getHeapBlock(type, target * bpe, len) + let sourceArray = getHeapBlock(type, start * bpe, len) + targetArray.set(sourceArray) + return heapBlocks[0] + } else { + return heapBlocks[0].copyWithin(target, start, end) + } + } + + function setOverridden(array, offset) { + let offsetReal = (offset || 0) * bpe + if (offsetReal >= maxArraySize || array.byteLength + offsetReal >= maxArraySize) { + let targetArray = getHeapBlock(type, offsetReal, array.length) + targetArray.set(array) + } else { + firstHeapBlock.set(array, offset) + } + } + + function subarray(start, end) { + let [startReal, endReal] = getRealStartAndEnd(start, end) + if (startReal >= maxArraySize || endReal >= maxArraySize) { + return getHeapBlock(type, startReal, endReal - startReal) + } else { + return firstHeapBlock.subarray(start, end) + } + } + + function fill(value, start, end) { + let [startReal, endReal] = getRealStartAndEnd(start, end) + if (startReal >= maxArraySize || endReal >= maxArraySize) { + let hb = getHeapBlock(type, startReal, endReal - startReal) + hb.fill(value, 0, end - start) + return firstHeapBlock + } else { + return firstHeapBlock.fill(value, start, end) + } + } + function slice(start, end) { + let [startReal, endReal] = getRealStartAndEnd(start, end) + if (startReal >= maxArraySize || endReal >= maxArraySize) { + let hb = getHeapBlock(type, startReal, endReal - startReal) + return hb.slice(start, end) + } else { + return firstHeapBlock.slice(start, end) + } + } + + return { + get(target, property) { + if (parseInt(property, 10) == property) { + let memoryOffset = property * bpe + let blockNumber = Math.floor(memoryOffset / maxArraySize) + return heapBlocks[blockNumber][property - blockNumber * maxArraySize] + } + + if (property === 'copyWithin') { + return copyWithin + } + + if (property === 'set') { + return setOverridden + } + + if (property === 'subarray') { + return subarray + } + + if (property === 'fill') { + return fill + } + + if (property === 'slice') { + return slice + } + + return firstHeapBlock[property] + }, + set(target, property, value) { + if (parseInt(property, 10) == property) { + let memoryOffset = property * bpe + let blockNumber = Math.floor(memoryOffset / maxArraySize) + heapBlocks[blockNumber][property - blockNumber * maxArraySize] = value + return true + } + + firstHeapBlock[property] = value + return true; + }, + } +} + +function createMemoryProxy(type) { + let heapBlocks = []; + let bpe = type === 'i16' || type === 'u16' ? 2 : 1 + let numberOfBlocks = Math.ceil(b.byteLength / maxArraySize / bpe) + for (let i = 0; i < numberOfBlocks; i++) { + heapBlocks.push(getHeapBlock(type, i * maxArraySize * bpe)) + } + return new Proxy(heapBlocks[0], createProxyHandler(type, heapBlocks)); +} + +if (b.byteLength > maxArraySize) { + Module['HEAP8'] = HEAP8 = createMemoryProxy('i8') + Module['HEAPU8'] = HEAPU8 = createMemoryProxy('u8') +} else { + Module['HEAP8'] = HEAP8 = new Int8Array(b); + Module['HEAPU8'] = HEAPU8 = new Uint8Array(b); +} +if (b.byteLength > maxArraySize * 2) { + Module['HEAP16'] = HEAP16 = createMemoryProxy('i16') + Module['HEAPU16'] = HEAPU16 = createMemoryProxy('u16') +} else { + Module['HEAP16'] = HEAP16 = new Int16Array(b); + Module['HEAPU16'] = HEAPU16 = new Uint16Array(b); +} diff --git a/test/other/test_memory64_proxies.js b/test/other/test_memory64_proxies.js new file mode 100644 index 0000000000000..748d0d2abd588 --- /dev/null +++ b/test/other/test_memory64_proxies.js @@ -0,0 +1,40 @@ +addOnPostRun(() => { + // check >4gb alloc + const bigChunk = _malloc(4 * 1024 * 1024 * 1024 + 100); + assert(bigChunk > 0); + + const littleChunk = _malloc(100); + HEAP8[littleChunk] = 2; + assert(HEAP8[littleChunk] === 2); + + // .subarray + const subarray = HEAP8.subarray(littleChunk, littleChunk + 100); + assert(subarray[0] === 2); + + // check .fill + HEAP8.fill(3, littleChunk, littleChunk + 99); + assert(subarray[0] === 3); + assert(subarray[98] === 3); + assert(subarray[99] === 0); + assert(HEAP8[littleChunk] === 3); + assert(HEAP8[littleChunk + 98] === 3); + assert(HEAP8[littleChunk + 99] === 0); + + // check .set + const filler = new Uint8Array(10); + filler[0] = 4; + filler[9] = 4; + HEAP8.set(filler, littleChunk, 10); + assert(subarray[0] === 4); + assert(subarray[9] === 4); + assert(HEAP8[littleChunk] === 4); + + // .copyWithin + HEAP8.copyWithin(bigChunk, littleChunk, littleChunk + 100); + assert(HEAP8[bigChunk] === 4); + + // .slice + const slice = HEAP8.slice(bigChunk, bigChunk + 100); + slice[0] = 5; + assert(HEAP8[bigChunk] === 4); +}); diff --git a/test/test_browser.py b/test/test_browser.py index ac284ae98420f..c73689fcd3d6c 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -5475,7 +5475,7 @@ def test_zzz_zzz_2gb_fail(self): self.do_run_in_out_file_test('browser', 'test_2GB_fail.cpp') @no_firefox('no 4GB support yet') - # @also_with_wasm64 Blocked on https://bugs.chromium.org/p/v8/issues/detail?id=4153 + @also_with_wasm64 @requires_v8 def test_zzz_zzz_4gb_fail(self): # TODO Convert to an actual browser test when it reaches stable. diff --git a/test/test_other.py b/test/test_other.py index 8bb6142ea2cce..76c4d91f20d8a 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -32,7 +32,7 @@ from common import RunnerCore, path_from_root, is_slow_test, ensure_dir, disabled, make_executable from common import env_modify, no_mac, no_windows, only_windows, requires_native_clang, with_env_modify from common import create_file, parameterized, NON_ZERO, node_pthreads, TEST_ROOT, test_file -from common import compiler_for, EMBUILDER, requires_v8, requires_node, requires_wasm64 +from common import compiler_for, EMBUILDER, requires_v8, requires_node, requires_wasm64, requires_node_canary from common import requires_wasm_eh, crossplatform, with_both_sjlj, also_with_standalone_wasm from common import also_with_minimal_runtime, also_with_wasm_bigint, also_with_wasm64 from common import EMTEST_BUILD_VERBOSE, PYTHON @@ -6304,10 +6304,9 @@ def test_failing_growth_2gb(self): self.run_process([EMCC, '-O1', 'test.c', '-sALLOW_MEMORY_GROWTH']) self.assertContained('done', self.run_js('a.out.js')) + @requires_wasm64 + @requires_node_canary def test_failing_growth_wasm64(self): - # For now we skip this test because failure to create the TypedArray views - # causes weird unrecoverable failures. - self.skipTest('https://bugs.chromium.org/p/v8/issues/detail?id=4153') self.require_wasm64() create_file('test.c', r''' #include @@ -13599,3 +13598,16 @@ def test_explicit_target(self): def test_quick_exit(self): self.do_other_test('test_quick_exit.c') + + @requires_wasm64 + @requires_node_canary + def test_memory64_proxies(self): + self.run_process([EMCC, test_file('hello_world.c'), + '-sMEMORY64=1', + '-sINITIAL_MEMORY=5gb', + '-sMAXIMUM_MEMORY=5gb', + '-sALLOW_MEMORY_GROWTH', + '-sEXPORTED_FUNCTIONS=_malloc,_main', + '-Wno-experimental', + '--extern-post-js', test_file('other/test_memory64_proxies.js')]) + self.run_js('a.out.js') From 02b163bb71b80546ed939224bc85bd13fdf81a14 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 27 Jul 2023 10:17:12 -0700 Subject: [PATCH 0578/1523] Enable -sASYNCIFY + -sMEMORY64=2 (#19913) It turns out that simply running the memory64 lowering pass after the asyncify pass is enough to make this work. --- emcc.py | 7 +++---- test/test_core.py | 13 ------------- 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/emcc.py b/emcc.py index 0fd3408859b5f..3840efc2453d0 100755 --- a/emcc.py +++ b/emcc.py @@ -639,8 +639,6 @@ def get_binaryen_passes(): # safe heap must run before post-emscripten, so post-emscripten can apply the sbrk ptr if settings.SAFE_HEAP: passes += ['--safe-heap'] - if settings.MEMORY64 == 2: - passes += ['--memory64-lowering'] # sign-ext is enabled by default by llvm. If the target browser settings don't support # this we lower it away here using a binaryen pass. if not feature_matrix.caniuse(feature_matrix.Feature.SIGN_EXT): @@ -709,6 +707,9 @@ def check_human_readable_list(items): if settings.SPLIT_MODULE: passes += ['--pass-arg=jspi-split-module'] + if settings.MEMORY64 == 2: + passes += ['--memory64-lowering'] + if settings.BINARYEN_IGNORE_IMPLICIT_TRAPS: passes += ['--ignore-implicit-traps'] # normally we can assume the memory, if imported, has not been modified @@ -2441,8 +2442,6 @@ def phase_linker_setup(options, state, newargs): settings.JS_LIBRARIES.append((0, 'library_pthread_stub.js')) if settings.MEMORY64: - if settings.ASYNCIFY and settings.MEMORY64 == 2: - exit_with_error('MEMORY64=2 is not compatible with ASYNCIFY') # Any "pointers" passed to JS will now be i64's, in both modes. settings.WASM_BIGINT = 1 diff --git a/test/test_core.py b/test/test_core.py index fc694163284f0..0f35309f283e6 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -2110,7 +2110,6 @@ def test_emscripten_get_compiler_setting(self): self.set_setting('RETAIN_COMPILER_SETTINGS') self.do_runf(src, read_file(output).replace('waka', shared.EMSCRIPTEN_VERSION)) - @no_wasm64l("wasm64l doesn't support asyncify") def test_emscripten_has_asyncify(self): src = r''' #include @@ -4028,7 +4027,6 @@ def test_dlfcn_feature_in_lib(self): ''' self.do_run(src, 'float: 42.\n') - @no_wasm64l("wasm64l doesn't support asyncify") @needs_dylink def test_dlfcn_asyncify(self): self.set_setting('ASYNCIFY') @@ -8185,7 +8183,6 @@ def test_async_loop(self): def test_async_hello_v8(self): self.test_async_hello() - @no_wasm64l("wasm64l doesn't support asyncify") def test_async_ccall_bad(self): # check bad ccall use # needs to flush stdio streams @@ -8244,7 +8241,6 @@ def test_async_ccall_good(self): self.emcc_args += ['--pre-js', 'pre.js'] self.do_runf('main.c', 'HelloWorld') - @no_wasm64l("wasm64l doesn't support asyncify") @parameterized({ 'asyncify': (False, 1), 'exit_runtime_asyncify': (True, 1), @@ -8293,7 +8289,6 @@ def test_async_ccall_promise(self, exit_runtime, asyncify): self.emcc_args += ['--pre-js', 'pre.js'] self.do_runf('main.c', 'stringf: first\nsecond\n6.4') - @no_wasm64l("wasm64l doesn't support asyncify") def test_fibers_asyncify(self): self.set_setting('ASYNCIFY') self.maybe_closure() @@ -8305,7 +8300,6 @@ def test_asyncify_unused(self): # test a program not using asyncify, but the pref is set self.do_core_test('test_hello_world.c') - @no_wasm64l("wasm64l doesn't support asyncify") @parameterized({ 'normal': ([], True), 'removelist_a': (['-sASYNCIFY_REMOVE=["foo(int, double)"]'], False), @@ -8344,7 +8338,6 @@ def test_asyncify_lists(self, args, should_pass, response=None): binary = read_binary(filename) self.assertFalse(b'main' in binary) - @no_wasm64l("wasm64l doesn't support asyncify") @parameterized({ 'normal': ([], True), 'ignoreindirect': (['-sASYNCIFY_IGNORE_INDIRECT'], False), @@ -8362,7 +8355,6 @@ def test_asyncify_indirect_lists(self, args, should_pass): if should_pass: raise - @no_wasm64l("wasm64l doesn't support asyncify") @needs_dylink def test_asyncify_side_module(self): self.set_setting('ASYNCIFY') @@ -8392,13 +8384,11 @@ def test_asyncify_side_module(self): } ''', 'before sleep\n42\n42\nafter sleep\n', header='void my_sleep(int);', force_c=True) - @no_wasm64l("wasm64l doesn't support asyncify") @no_asan('asyncify stack operations confuse asan') def test_emscripten_scan_registers(self): self.set_setting('ASYNCIFY') self.do_core_test('test_emscripten_scan_registers.cpp') - @no_wasm64l("wasm64l doesn't support asyncify") def test_asyncify_assertions(self): self.set_setting('ASYNCIFY') self.set_setting('ASYNCIFY_IMPORTS', ['suspend']) @@ -8407,7 +8397,6 @@ def test_asyncify_assertions(self): @no_lsan('leaks asyncify stack during exit') @no_asan('leaks asyncify stack during exit') - @no_wasm64l("wasm64l doesn't support asyncify") def test_asyncify_during_exit(self): self.set_setting('ASYNCIFY') self.set_setting('ASSERTIONS') @@ -8426,7 +8415,6 @@ def test_asyncify_main_module(self): self.do_core_test('test_hello_world.c') # Test that pthread_join works correctly with asyncify. - @no_wasm64l("wasm64l doesn't support asyncify") @requires_node_canary def test_pthread_join_and_asyncify(self): # TODO Test with ASYNCIFY=1 https://github.com/emscripten-core/emscripten/issues/17552 @@ -8436,7 +8424,6 @@ def test_pthread_join_and_asyncify(self): '-sEXIT_RUNTIME=1', '-pthread', '-sPROXY_TO_PTHREAD']) - @no_wasm64l("wasm64l doesn't support asyncify") @no_asan('asyncify stack operations confuse asan') @no_wasm2js('TODO: lazy loading in wasm2js') @parameterized({ From 90ad44d7958f4ab9415a102ef02d449a4deb545b Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 27 Jul 2023 10:18:10 -0700 Subject: [PATCH 0579/1523] Remove a few more references to the old `asm` global. NFC (#19909) --- test/test_other.py | 2 +- tools/acorn-optimizer.js | 27 +++++++++++---------------- tools/building.py | 2 +- 3 files changed, 13 insertions(+), 18 deletions(-) diff --git a/test/test_other.py b/test/test_other.py index 76c4d91f20d8a..df7a85799d3ac 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -10059,7 +10059,7 @@ def test(args, closure, opt): output = read_file('a.js') delete_file('a.js') - self.assertNotContained('asm["_thisIsAFunctionExportedFromAsmJsOrWasmWithVeryLongFunction"]', output) + self.assertNotContained('_thisIsAFunctionExportedFromAsmJsOrWasmWithVeryLongFunction', output) # TODO: Add stricter testing when Wasm side is also optimized: (currently Wasm does still need # to reference exports multiple times) diff --git a/tools/acorn-optimizer.js b/tools/acorn-optimizer.js index 2cfa182f2e603..47e5ffbda2db2 100755 --- a/tools/acorn-optimizer.js +++ b/tools/acorn-optimizer.js @@ -466,10 +466,7 @@ function getWasmImportsValue(node) { } function isExportUse(node) { - // MINIMAL_RUNTIME calls exports global variable `asm`, whereas regualar - // runtime calls it `wasmExports`. - // - // Here we match: + // Match usages of symbols on the `wasmExports` object. e.g: // wasmExports['X'] return ( node.type === 'MemberExpression' && @@ -513,7 +510,7 @@ function applyImportAndExportNameChanges(ast) { } } } else if (node.type === 'CallExpression' && isExportUse(node.callee)) { - // asm["___wasm_call_ctors"](); -> asm["M"](); + // wasmExports["___wasm_call_ctors"](); -> wasmExports["M"](); const callee = node.callee; const name = callee.property.value; if (mapping[name]) { @@ -631,11 +628,11 @@ function emitDCEGraph(ast) { // The exports are trickier, as they have a different form whether or not // async compilation is enabled. It can be either: // - // var _malloc = Module['_malloc'] = asm['_malloc']; + // var _malloc = Module['_malloc'] = wasmExports['_malloc']; // // or // - // var _malloc = asm['_malloc']; + // var _malloc = wasmExports['_malloc']; // // or // @@ -655,7 +652,7 @@ function emitDCEGraph(ast) { const dynCallNames = []; const nameToGraphName = {}; const modulePropertyToGraphName = {}; - const exportNameToGraphName = {}; // identical to asm['..'] nameToGraphName + const exportNameToGraphName = {}; // identical to wasmExports['..'] nameToGraphName const graph = []; let foundWasmImportsAssign = false; let foundMinimalRuntimeExports = false; @@ -697,9 +694,7 @@ function emitDCEGraph(ast) { const value = item.init; if (value && isExportUse(value)) { const asmName = getExportOrModuleUseName(value); - // this is - // var _x = asm['x']; - // or + // this is: // var _x = wasmExports['x']; saveAsmExport(name, asmName); emptyOut(node); @@ -955,7 +950,7 @@ function applyDCEGraphRemovals(ast) { }); } else if (node.type === 'AssignmentExpression') { // when we assign to a thing we don't need, we can just remove the assign - // var x = Module['x'] = asm['x']; + // var x = Module['x'] = wasmExports['x']; const target = node.left; if (isExportUse(target) || isModuleUse(target)) { const name = getExportOrModuleUseName(target); @@ -968,9 +963,9 @@ function applyDCEGraphRemovals(ast) { } } else if (node.type === 'VariableDeclaration') { // Handle the case we declare a variable but don't assign to the module: - // var x = asm['x']; + // var x = wasmExports['x']; // and - // var x = function() { return (x = asm['x']).apply(...) }; + // var x = () => (x = wasmExports['x']).apply(...); const init = node.declarations[0].init; if (init) { if (isExportUse(init)) { @@ -989,8 +984,8 @@ function applyDCEGraphRemovals(ast) { } } else if (node.type === 'ExpressionStatement') { const expr = node.expression; - // In the minimal runtime code pattern we have just - // x = asm['x'] + // In the MINIMAL_RUNTIME code pattern we have just + // x = wasmExports['x'] // and never in a var. if (expr.operator === '=' && expr.left.type === 'Identifier' && isExportUse(expr.right)) { const name = expr.left.name; diff --git a/tools/building.py b/tools/building.py index 8c424b2f97698..49412409a0a6e 100644 --- a/tools/building.py +++ b/tools/building.py @@ -369,7 +369,7 @@ def acorn_optimizer(filename, passes, extra_info=None, return_output=False): # for this, and we are in wasm mode def eval_ctors(js_file, wasm_file, debug_info): if settings.MINIMAL_RUNTIME: - CTOR_ADD_PATTERN = f"asm['{WASM_CALL_CTORS}']();" # TODO test + CTOR_ADD_PATTERN = f"wasmExports['{WASM_CALL_CTORS}']();" # TODO test else: CTOR_ADD_PATTERN = f"addOnInit(wasmExports['{WASM_CALL_CTORS}']);" From 985c48927711a964149f50566015cebd95ab379a Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 27 Jul 2023 10:20:45 -0700 Subject: [PATCH 0580/1523] Fix embind error message (#19917) This would be quite hard to test since the existing embind tests currently use assert.throws to check for this error, which doesn't allow us to inspect the error message itself (as far as I can tell). Fixes: #19883 --- src/embind/embind.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index c247626dfa161..6d3d5b326cc7a 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -840,7 +840,7 @@ var LibraryEmbind = { var destructors = []; return function() { if (arguments.length !== expectedArgCount) { - throwBindingError(`function ${humanName} called with ${arguments.length} arguments, expected ${expectedArgCount} args!`); + throwBindingError(`function ${humanName} called with ${arguments.length} arguments, expected ${expectedArgCount}`); } #if EMSCRIPTEN_TRACING Module.emscripten_trace_enter_context(`embind::${humanName}`); @@ -904,7 +904,7 @@ var LibraryEmbind = { var invokerFnBody = ` return function ${makeLegalFunctionName(humanName)}(${argsList}) { if (arguments.length !== ${argCount - 2}) { - throwBindingError('function ${humanName} called with ${arguments.length} arguments, expected ${argCount - 2} args!'); + throwBindingError('function ${humanName} called with ' + arguments.length + ' arguments, expected ${argCount - 2}'); }`; #if EMSCRIPTEN_TRACING From e5b36b77dfad507f49cb1ddbae1555a9a3a00049 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 27 Jul 2023 10:25:53 -0700 Subject: [PATCH 0581/1523] Move getloadavg stub to native code. NFC (#19907) --- src/library.js | 11 ---------- src/library_sigs.js | 1 - system/lib/libc/emscripten_libc_stubs.c | 28 ++++++++++++++++++++++++- 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/src/library.js b/src/library.js index 5d9c7b5df4ccb..70f27ef3d829c 100644 --- a/src/library.js +++ b/src/library.js @@ -384,17 +384,6 @@ mergeInto(LibraryManager.library, { // the initial values of the environment accessible by getenv. $ENV: {}, - getloadavg: (loadavg, nelem) => { - // int getloadavg(double loadavg[], int nelem); - // http://linux.die.net/man/3/getloadavg - var limit = Math.min(nelem, 3); - var doubleSize = {{{ getNativeTypeSize('double') }}}; - for (var i = 0; i < limit; i++) { - {{{ makeSetValue('loadavg', 'i * doubleSize', '0.1', 'double') }}}; - } - return limit; - }, - // In -Oz builds, we replace memcpy() altogether with a non-unrolled wasm // variant, so we should never emit emscripten_memcpy_big() in the build. // In STANDALONE_WASM we avoid the emscripten_memcpy_big dependency so keep diff --git a/src/library_sigs.js b/src/library_sigs.js index 7b7e82a7d0d84..71a8c65d0766a 100644 --- a/src/library_sigs.js +++ b/src/library_sigs.js @@ -940,7 +940,6 @@ sigs = { gethostbyaddr__sig: 'ppii', gethostbyname__sig: 'pp', gethostbyname_r__sig: 'ipppppp', - getloadavg__sig: 'ipi', getnameinfo__sig: 'ipipipii', getprotobyname__sig: 'pp', getprotobynumber__sig: 'pi', diff --git a/system/lib/libc/emscripten_libc_stubs.c b/system/lib/libc/emscripten_libc_stubs.c index 5aa7efe9543a8..fac4b6c278241 100644 --- a/system/lib/libc/emscripten_libc_stubs.c +++ b/system/lib/libc/emscripten_libc_stubs.c @@ -72,8 +72,9 @@ weak int clock_getcpuclockid(pid_t pid, clockid_t *clockid) { return 0; } - +// ========================================================================== // pwd.h +// ========================================================================== struct passwd *getpwnam(const char *name) { errno = ENOENT; @@ -106,7 +107,9 @@ struct passwd *getpwent(void) { return NULL; } +// ========================================================================== // grp.h +// ========================================================================== weak struct group *getgrnam(const char *name) { errno = ENOENT; @@ -187,6 +190,10 @@ weak int posix_spawn(pid_t *pid, const char *path, return -1; } +// ========================================================================== +// stdio.h +// ========================================================================== + weak FILE *popen(const char *command, const char *type) { errno = ENOSYS; return NULL; @@ -214,6 +221,10 @@ weak int sigaltstack(const stack_t *restrict ss, stack_t *restrict old_ss) { return -1; } +// ========================================================================== +// dlfcn.h +// ========================================================================== + #ifndef __PIC__ void __dl_seterr(const char*, ...); @@ -227,3 +238,18 @@ weak void* dlopen(const char* file, int flags) { return NULL; } #endif + +// ========================================================================== +// stdlib.h +// ========================================================================== + +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) + +weak int getloadavg(double loadavg[], int nelem) { + // http://linux.die.net/man/3/getloadavg + int limit = MIN(nelem, 3); + for (int i = 0; i < limit; i++) { + loadavg[i] = 0.1; + } + return limit; +} From c2aab2288077774ddff76df8189a1ca4f587c8cc Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 27 Jul 2023 10:33:22 -0700 Subject: [PATCH 0582/1523] Allow weak undefined symbols in side modules (#19916) Fixes: #19861 --- emcc.py | 8 +++++++- emscripten.py | 10 +--------- test/core/test_dylink_weak_undef.c | 13 +++++++++++++ test/core/test_dylink_weak_undef.out | 2 ++ test/core/test_dylink_weak_undef_side.c | 9 +++++++++ test/test_core.py | 4 ++++ tools/webassembly.py | 10 ++++++++++ 7 files changed, 46 insertions(+), 10 deletions(-) create mode 100644 test/core/test_dylink_weak_undef.c create mode 100644 test/core/test_dylink_weak_undef.out create mode 100644 test/core/test_dylink_weak_undef_side.c diff --git a/emcc.py b/emcc.py index 3840efc2453d0..cbae8d913964a 100755 --- a/emcc.py +++ b/emcc.py @@ -819,6 +819,7 @@ def process_dynamic_libs(dylibs, lib_dirs): while to_process: dylib = to_process.pop() dylink = webassembly.parse_dylink_section(dylib) + print(dylink) for needed in dylink.needed: if needed in seen: continue @@ -848,11 +849,16 @@ def process_dynamic_libs(dylibs, lib_dirs): # main module to avoid creating new invoke functions at runtime. imports = set(imports) imports = set(i for i in imports if not i.startswith('invoke_')) - strong_imports = sorted(imports.difference(exports)) + weak_imports = webassembly.get_weak_imports(dylib) + strong_imports = sorted(imports.difference(weak_imports)) logger.debug('Adding symbols requirements from `%s`: %s', dylib, imports) mangled_imports = [shared.asmjs_mangle(e) for e in sorted(imports)] mangled_strong_imports = [shared.asmjs_mangle(e) for e in strong_imports] + for sym in weak_imports: + mangled = shared.asmjs_mangle(sym) + if mangled not in settings.SIDE_MODULE_IMPORTS and mangled not in building.user_requested_exports: + settings.WEAK_IMPORTS.append(sym) settings.SIDE_MODULE_IMPORTS.extend(mangled_imports) settings.EXPORT_IF_DEFINED.extend(sorted(imports)) settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE.extend(sorted(imports)) diff --git a/emscripten.py b/emscripten.py index 630f60eb5d4f8..3856d855ccafb 100644 --- a/emscripten.py +++ b/emscripten.py @@ -109,14 +109,6 @@ def align_memory(addr): return (addr + 15) & -16 -def get_weak_imports(main_wasm): - dylink_sec = webassembly.parse_dylink_section(main_wasm) - for symbols in dylink_sec.import_info.values(): - for symbol, flags in symbols.items(): - if flags & webassembly.SYMBOL_BINDING_MASK == webassembly.SYMBOL_BINDING_WEAK: - settings.WEAK_IMPORTS.append(symbol) - - def update_settings_glue(wasm_file, metadata): maybe_disable_filesystem(metadata.imports) @@ -129,7 +121,7 @@ def update_settings_glue(wasm_file, metadata): syms = set(syms).difference(metadata.all_exports) settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE = sorted(syms) if settings.MAIN_MODULE: - get_weak_imports(wasm_file) + settings.WEAK_IMPORTS += webassembly.get_weak_imports(wasm_file) settings.WASM_EXPORTS = metadata.all_exports settings.WASM_GLOBAL_EXPORTS = list(metadata.namedGlobals.keys()) diff --git a/test/core/test_dylink_weak_undef.c b/test/core/test_dylink_weak_undef.c new file mode 100644 index 0000000000000..be8011dfa92e8 --- /dev/null +++ b/test/core/test_dylink_weak_undef.c @@ -0,0 +1,13 @@ +#include +#include + +void side(); + +__attribute__((weak)) int foo(); + +int main(int argc, char const *argv[]) { + printf("main &foo: %p\n", &foo); + assert(&foo == NULL); + side(); + return 0; +} diff --git a/test/core/test_dylink_weak_undef.out b/test/core/test_dylink_weak_undef.out new file mode 100644 index 0000000000000..11d6993bcdf23 --- /dev/null +++ b/test/core/test_dylink_weak_undef.out @@ -0,0 +1,2 @@ +main &foo: 0 +side &bar: 0 diff --git a/test/core/test_dylink_weak_undef_side.c b/test/core/test_dylink_weak_undef_side.c new file mode 100644 index 0000000000000..ead1ecb1c50e9 --- /dev/null +++ b/test/core/test_dylink_weak_undef_side.c @@ -0,0 +1,9 @@ +#include +#include + +__attribute__((weak)) int bar(); + +void side() { + printf("side &bar: %p\n", &bar); + assert(&bar == NULL); +} diff --git a/test/test_core.py b/test/test_core.py index 0f35309f283e6..a3dd57debc81a 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -5312,6 +5312,10 @@ def test_dylink_weak(self): # module but that only one gets used at runtime. self.dylink_testf(test_file('core/test_dylink_weak.c'), need_reverse=False) + @needs_dylink + def test_dylink_weak_undef(self): + self.dylink_testf(test_file('core/test_dylink_weak_undef.c'), need_reverse=False) + @node_pthreads @needs_dylink def test_dylink_tls(self): diff --git a/tools/webassembly.py b/tools/webassembly.py index 6ee0bbfe513df..7b956f29eef27 100644 --- a/tools/webassembly.py +++ b/tools/webassembly.py @@ -573,3 +573,13 @@ def get_exports(wasm_file): def get_imports(wasm_file): with Module(wasm_file) as module: return module.get_imports() + + +def get_weak_imports(wasm_file): + weak_imports = [] + dylink_sec = parse_dylink_section(wasm_file) + for symbols in dylink_sec.import_info.values(): + for symbol, flags in symbols.items(): + if flags & SYMBOL_BINDING_MASK == SYMBOL_BINDING_WEAK: + weak_imports.append(symbol) + return weak_imports From f5e33a3058881e5ea74d3ab9827382a9cc296147 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 27 Jul 2023 12:20:54 -0700 Subject: [PATCH 0583/1523] Automatically export malloc/free when using webidl-binder (#19914) Fixes: #14125 --- test/test_core.py | 2 +- tools/webidl_binder.py | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/test/test_core.py b/test/test_core.py index a3dd57debc81a..409e570593885 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -7777,7 +7777,7 @@ def test_webidl(self, mode, allow_memory_growth): # Export things on "TheModule". This matches the typical use pattern of the bound library # being used as Box2D.* or Ammo.*, and we cannot rely on "Module" being always present (closure may remove it). - self.emcc_args += ['-sEXPORTED_FUNCTIONS=_malloc,_free', '--post-js=glue.js', '--extern-post-js=extern-post.js'] + self.emcc_args += ['--post-js=glue.js', '--extern-post-js=extern-post.js'] if mode == 'ALL': self.emcc_args += ['-sASSERTIONS'] if allow_memory_growth: diff --git a/tools/webidl_binder.py b/tools/webidl_binder.py index 866a0835e63f4..9a2fb1c3e3a71 100644 --- a/tools/webidl_binder.py +++ b/tools/webidl_binder.py @@ -80,12 +80,20 @@ def getExtendedAttribute(self, _name): pre_c = [''' #include +#include EM_JS_DEPS(webidl_binder, "$intArrayFromString,$UTF8ToString"); '''] mid_c = [''' extern "C" { + +// Define custom allocator functions that we can force export using +// EMSCRIPTEN_KEEPALIVE. This avoids all webidl users having to add +// malloc/free to -sEXPORTED_FUNCTIONS. +EMSCRIPTEN_KEEPALIVE void webidl_free(void* p) { free(p); } +EMSCRIPTEN_KEEPALIVE void* webidl_malloc(size_t len) { return malloc(len); } + '''] @@ -178,11 +186,11 @@ def build_constructor(name): if (ensureCache.needed) { // clear the temps for (var i = 0; i < ensureCache.temps.length; i++) { - Module['_free'](ensureCache.temps[i]); + Module['_webidl_free'](ensureCache.temps[i]); } ensureCache.temps.length = 0; // prepare to allocate a bigger buffer - Module['_free'](ensureCache.buffer); + Module['_webidl_free'](ensureCache.buffer); ensureCache.buffer = 0; ensureCache.size += ensureCache.needed; // clean up @@ -190,7 +198,7 @@ def build_constructor(name): } if (!ensureCache.buffer) { // happens first time, or when we need to grow ensureCache.size += 128; // heuristic, avoid many small grow events - ensureCache.buffer = Module['_malloc'](ensureCache.size); + ensureCache.buffer = Module['_webidl_malloc'](ensureCache.size); assert(ensureCache.buffer); } ensureCache.pos = 0; @@ -205,7 +213,7 @@ def build_constructor(name): // we failed to allocate in the buffer, ensureCache time around :( assert(len > 0); // null terminator, at least ensureCache.needed += len; - ret = Module['_malloc'](len); + ret = Module['_webidl_malloc'](len); ensureCache.temps.push(ret); } else { // we can allocate in the buffer From 6a83b42c40e1673705e0074b1f0e3b5bcfb695f9 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 27 Jul 2023 14:51:41 -0700 Subject: [PATCH 0584/1523] [Wasm64] Enable remaining asyncify tests (#19920) --- src/library.js | 24 +++++++++++++----------- test/test_core.py | 22 ---------------------- 2 files changed, 13 insertions(+), 33 deletions(-) diff --git a/src/library.js b/src/library.js index 70f27ef3d829c..8f67fc3d2614d 100644 --- a/src/library.js +++ b/src/library.js @@ -3101,6 +3101,9 @@ mergeInto(LibraryManager.library, { $dynCallLegacy__deps: ['$createDyncallWrapper'], #endif $dynCallLegacy: (sig, ptr, args) => { +#if MEMORY64 + sig = sig.replace(/p/g, 'j') +#endif #if ASSERTIONS #if MINIMAL_RUNTIME assert(typeof dynCalls != 'undefined', 'Global dynCalls dictionary was not generated in the build! Pass -sDEFAULT_LIBRARY_FUNCS_TO_INCLUDE=$dynCall linker flag to include it!'); @@ -3155,8 +3158,16 @@ mergeInto(LibraryManager.library, { $dynCall__docs: '/** @param {Object=} args */', $dynCall: (sig, ptr, args) => { +#if MEMORY64 + // With MEMORY64 we have an additional step to convert `p` arguments to + // bigint. This is the runtime equivalent of the wrappers we create for wasm + // exports in `emscripten.py:create_wasm64_wrappers`. + for (var i = 1; i < sig.length; ++i) { + if (sig[i] == 'p') args[i-1] = BigInt(args[i-1]); + } +#endif #if DYNCALLS - return dynCallLegacy(sig, ptr, args); + var rtn = dynCallLegacy(sig, ptr, args); #else #if !WASM_BIGINT // Without WASM_BIGINT support we cannot directly call function with i64 as @@ -3168,22 +3179,13 @@ mergeInto(LibraryManager.library, { #endif #if ASSERTIONS assert(getWasmTableEntry(ptr), `missing table entry in dynCall: ${ptr}`); -#endif -#if MEMORY64 - // With MEMORY64 we have an additional step to convert `p` arguments to - // bigint. This is the runtime equivalent of the wrappers we create for wasm - // exports in `emscripten.py:create_wasm64_wrappers`. - for (var i = 1; i < sig.length; ++i) { - if (sig[i] == 'p') args[i-1] = BigInt(args[i-1]); - } #endif var rtn = getWasmTableEntry(ptr).apply(null, args); +#endif #if MEMORY64 return sig[0] == 'p' ? Number(rtn) : rtn; #else return rtn; -#endif - #endif }, diff --git a/test/test_core.py b/test/test_core.py index 409e570593885..72414079c8a62 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -139,14 +139,6 @@ def decorated(f): return decorated -def no_wasm64l(note=''): - assert not callable(note) - - def decorated(f): - return skip_if(f, 'is_wasm64l', note) - return decorated - - def also_with_noderawfs(func): assert callable(func) @@ -336,9 +328,6 @@ def is_wasm2js(self): def is_wasm64(self): return self.get_setting('MEMORY64') - def is_wasm64l(self): - return self.get_setting('MEMORY64') == 2 - # A simple check whether the compiler arguments cause optimization. def is_optimizing(self): return '-O' in str(self.emcc_args) and '-O0' not in self.emcc_args @@ -6658,8 +6647,6 @@ def test_cubescript(self, asyncify): self.emcc_args += ['--pre-js', test_file('asan-no-leak.js')] if asyncify: - if self.is_wasm64(): - self.skipTest('TODO: asyncify for wasm64') self.set_setting('ASYNCIFY', asyncify) if asyncify == 2: self.require_jspi() @@ -8125,7 +8112,6 @@ def test_vswprintf_utf8(self): self.do_core_test('test_vswprintf_utf8.c') # Test that a main with arguments is automatically asyncified. - @no_wasm64l("wasm64l doesn't support jspi") @with_asyncify_and_jspi def test_async_main(self): create_file('main.c', r''' @@ -8139,7 +8125,6 @@ def test_async_main(self): self.do_runf('main.c', 'argc=2 argv=hello', args=['hello']) - @no_wasm64l("wasm64l doesn't support jspi") @with_asyncify_and_jspi def test_async_hello(self): # needs to flush stdio streams @@ -8164,7 +8149,6 @@ def test_async_hello(self): self.do_runf('main.c', 'HelloWorld!99') - @no_wasm64l("wasm64l doesn't support jspi") @with_asyncify_and_jspi def test_async_loop(self): # needs to flush stdio streams @@ -8218,7 +8202,6 @@ def test_async_ccall_bad(self): self.emcc_args += ['--pre-js', 'pre.js'] self.do_runf('main.c', 'The call to main is running asynchronously.') - @no_wasm64l("wasm64l doesn't support jspi") @with_asyncify_and_jspi def test_async_ccall_good(self): # check reasonable ccall use @@ -8298,7 +8281,6 @@ def test_fibers_asyncify(self): self.maybe_closure() self.do_runf(test_file('test_fibers.cpp'), '*leaf-0-100-1-101-1-102-2-103-3-104-5-105-8-106-13-107-21-108-34-109-*') - @no_wasm64l("wasm64l doesn't support jspi") @with_asyncify_and_jspi def test_asyncify_unused(self): # test a program not using asyncify, but the pref is set @@ -8412,7 +8394,6 @@ def test_asyncify_during_exit(self): @no_asan('asyncify stack operations confuse asan') @no_lsan('undefined symbol __global_base') @no_wasm2js('dynamic linking support in wasm2js') - @no_wasm64l("wasm64l doesn't support jspi") @with_asyncify_and_jspi def test_asyncify_main_module(self): self.set_setting('MAIN_MODULE', 2) @@ -9642,7 +9623,6 @@ def test_emscripten_async_call(self): self.do_run_in_out_file_test(test_file('core/test_emscripten_async_call.c')) @no_asan('asyncify stack operations confuse asan') - @no_wasm64('TODO: asyncify for wasm64') @parameterized({ '': ([],), 'no_dynamic_execution': (['-sDYNAMIC_EXECUTION=0'],) @@ -9660,7 +9640,6 @@ def test_embind_lib_with_asyncify(self, args): self.do_core_test('embind_lib_with_asyncify.cpp') @no_asan('asyncify stack operations confuse asan') - @no_wasm64l("wasm64l doesn't support jspi") @with_asyncify_and_jspi def test_em_async_js(self): self.uses_es6 = True @@ -9704,7 +9683,6 @@ def test_promise(self): self.set_setting('MIN_CHROME_VERSION', '85') self.do_core_test('test_promise.c') - @no_wasm64l("wasm64l doesn't support jspi") @with_asyncify_and_jspi def test_promise_await(self): self.do_core_test('test_promise_await.c') From 5c0799f08ca04a6601a56a43d4f28239f3da9212 Mon Sep 17 00:00:00 2001 From: SpaceManiac Date: Thu, 27 Jul 2023 15:17:13 -0700 Subject: [PATCH 0585/1523] Add depfile generation to file_packager (#18876) --- test/test_other.py | 18 ++++++++++++++++++ tools/file_packager.py | 30 ++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/test/test_other.py b/test/test_other.py index df7a85799d3ac..0f2a710bd2cc5 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -3109,6 +3109,24 @@ def test_file_packager_embed(self): output = self.run_js('a.out.js') self.assertContained('hello data', output) + def test_file_packager_depfile(self): + create_file('data1.txt', 'data1') + ensure_dir('subdir') + create_file('subdir/data2.txt', 'data2') + + self.run_process([FILE_PACKAGER, 'test.data', '--js-output=test.js', '--depfile=test.data.d', '--from-emcc', '--preload', '.']) + lines = read_file('test.data.d').splitlines() + split = lines.index(': \\') + before, after = set(lines[:split]), set(lines[split + 1:]) + # Set comparison used because depfile is not order-sensitive. + self.assertTrue('test.data \\' in before) + self.assertTrue('test.js \\' in before) + self.assertTrue(FILE_PACKAGER + '.py \\' in after) + self.assertTrue('. \\' in after) + self.assertTrue('./data1.txt \\' in after) + self.assertTrue('./subdir \\' in after) + self.assertTrue('./subdir/data2.txt \\' in after) + def test_sdl_headless(self): shutil.copyfile(test_file('screenshot.png'), 'example.png') self.do_other_test('test_sdl_headless.c', emcc_args=['-sHEADLESS']) diff --git a/tools/file_packager.py b/tools/file_packager.py index c934402971ddd..90e7dec88fb9a 100755 --- a/tools/file_packager.py +++ b/tools/file_packager.py @@ -35,6 +35,8 @@ --obj-output=FILE create an object file from embedded files, for direct linking into a wasm binary. + --depfile=FILE Writes a dependency list containing the list of directories and files walked, compatible with Make, Ninja, CMake, etc. + --wasm64 When used with `--obj-output` create a wasm64 object file --export-name=EXPORT_NAME Use custom export name (default is `Module`) @@ -96,6 +98,7 @@ excluded_patterns: List[str] = [] new_data_files = [] +walked = [] class Options: @@ -105,6 +108,7 @@ def __init__(self): self.has_embedded = False self.jsoutput = None self.obj_output = None + self.depfile = None self.from_emcc = False self.force = True # If set to True, IndexedDB (IDBFS in library_idbfs.js) is used to locally @@ -183,11 +187,13 @@ def add(mode, rootpathsrc, rootpathdst): rootpathdst: The name we want to make the source path available on the emscripten virtual FS. """ + walked.append(rootpathsrc) for dirpath, dirnames, filenames in os.walk(rootpathsrc): new_dirnames = [] for name in dirnames: fullname = os.path.join(dirpath, name) if not should_ignore(fullname): + walked.append(fullname) new_dirnames.append(name) elif DEBUG: err('Skipping directory "%s" from inclusion in the emscripten ' @@ -195,6 +201,7 @@ def add(mode, rootpathsrc, rootpathdst): for name in filenames: fullname = os.path.join(dirpath, name) if not should_ignore(fullname): + walked.append(fullname) # Convert source filename relative to root directory of target FS. dstpath = os.path.join(rootpathdst, os.path.relpath(fullname, rootpathsrc)) @@ -400,6 +407,9 @@ def main(): elif arg.startswith('--obj-output'): options.obj_output = arg.split('=', 1)[1] if '=' in arg else None leading = '' + elif arg.startswith('--depfile'): + options.depfile = arg.split('=', 1)[1] if '=' in arg else None + leading = '' elif arg == '--wasm64': options.wasm64 = True elif arg.startswith('--export-name'): @@ -457,11 +467,13 @@ def main(): err('error: TARGET should not be the same value of --js-output') return 1 + walked.append(__file__) for file_ in data_files: if not should_ignore(file_.srcpath): if os.path.isdir(file_.srcpath): add(file_.mode, file_.srcpath, file_.dstpath) else: + walked.append(file_.srcpath) new_data_files.append(file_) data_files = [file_ for file_ in new_data_files if not os.path.isdir(file_.srcpath)] @@ -563,9 +575,27 @@ def was_seen(name): if options.separate_metadata: utils.write_file(options.jsoutput + '.metadata', json.dumps(metadata, separators=(',', ':'))) + if options.depfile: + with open(options.depfile, 'w') as f: + for target in [data_target, options.jsoutput]: + if target: + f.write(escape_for_makefile(target)) + f.write(' \\\n') + f.write(': \\\n') + for dependency in walked: + f.write(escape_for_makefile(dependency)) + f.write(' \\\n') + return 0 +def escape_for_makefile(fpath): + # Escapes for CMake's "pathname" grammar as described here: + # https://cmake.org/cmake/help/latest/command/add_custom_command.html#grammar-token-depfile-pathname + # Which is congruent with how Ninja and GNU Make expect characters escaped. + return fpath.replace('$', '$$').replace('#', '\\#').replace(' ', '\\ ') + + def generate_js(data_target, data_files, metadata): # emcc will add this to the output itself, so it is only needed for # standalone calls From 759302f37fabf8ec8e6cff6e2a2b3ce6097cece2 Mon Sep 17 00:00:00 2001 From: Genki Takiuchi Date: Fri, 28 Jul 2023 07:32:01 +0900 Subject: [PATCH 0586/1523] Add FS_readFile to the exportable list (#19864) --- src/modules.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modules.js b/src/modules.js index f662d65b19dcf..3f47aa4ba21cc 100644 --- a/src/modules.js +++ b/src/modules.js @@ -375,6 +375,7 @@ function exportRuntime() { 'FS_createLazyFile', 'FS_createLink', 'FS_createDevice', + 'FS_readFile', 'FS_unlink', 'out', 'err', From 03ac6c55fc6aaeb955dfc8269f731f1743906907 Mon Sep 17 00:00:00 2001 From: jameshu15869 <55058507+jameshu15869@users.noreply.github.com> Date: Thu, 27 Jul 2023 19:04:51 -0400 Subject: [PATCH 0587/1523] WasmFS: Make wasmfs_readlink add a null-terminating byte (#19922) The syscall does not add a null terminator, so add one before returning to the JS that calls us. --- system/lib/wasmfs/js_api.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/system/lib/wasmfs/js_api.cpp b/system/lib/wasmfs/js_api.cpp index f2bd3069eb52f..6bbfb43fd420e 100644 --- a/system/lib/wasmfs/js_api.cpp +++ b/system/lib/wasmfs/js_api.cpp @@ -150,10 +150,11 @@ int _wasmfs_symlink(char* old_path, char* new_path) { intptr_t _wasmfs_readlink(char* path) { static thread_local void* readBuf = nullptr; readBuf = realloc(readBuf, PATH_MAX); - int err = __syscall_readlinkat(AT_FDCWD, (intptr_t)path, (intptr_t)readBuf, PATH_MAX); - if (err < 0) { - return err; + int bytes = __syscall_readlinkat(AT_FDCWD, (intptr_t)path, (intptr_t)readBuf, PATH_MAX); + if (bytes < 0) { + return bytes; } + ((char*)readBuf)[bytes] = '\0'; return (intptr_t)readBuf; } From 3cd9a380124bf17845f46819a895ec55a9e6ecf8 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Fri, 28 Jul 2023 01:15:58 +0200 Subject: [PATCH 0588/1523] Set INTERFACE_INCLUDE_DIRECTORIES property on SDL2 targets (#19780) This makes the targets more compatible with upstream SDL2. --- system/lib/cmake/SDL2/sdl2-config.cmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/system/lib/cmake/SDL2/sdl2-config.cmake b/system/lib/cmake/SDL2/sdl2-config.cmake index 82b1ec9465f05..fccc4a54ad08f 100644 --- a/system/lib/cmake/SDL2/sdl2-config.cmake +++ b/system/lib/cmake/SDL2/sdl2-config.cmake @@ -4,11 +4,13 @@ set(SDL2_LIBRARIES "-sUSE_SDL=2") if(NOT TARGET SDL2::SDL2) add_library(SDL2::SDL2 INTERFACE IMPORTED) set_target_properties(SDL2::SDL2 PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${SDL2_INCLUDE_DIRS}" INTERFACE_COMPILE_OPTIONS "-sUSE_SDL=2" INTERFACE_LINK_LIBRARIES "-sUSE_SDL=2") add_library(SDL2::SDL2-static INTERFACE IMPORTED) set_target_properties(SDL2::SDL2-static PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${SDL2_INCLUDE_DIRS}" INTERFACE_COMPILE_OPTIONS "-sUSE_SDL=2" INTERFACE_LINK_LIBRARIES "-sUSE_SDL=2") From 2bcdf0ab03dac43629ab931e67ff2c56967fa12b Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Sun, 30 Jul 2023 04:38:27 -0700 Subject: [PATCH 0589/1523] Fix applySignatureConversions under -O3. NFC (#19910) Prior to this change the applySignatureConversions function would not work when imports/exports are minified, which would cause wasm64 programs to fail when calling any native function that needs i64->i53 conversions. --- emcc.py | 2 +- emscripten.py | 13 ++++++++----- src/library.js | 4 ++-- src/postamble_minimal.js | 2 +- src/preamble.js | 2 +- test/optimizer/emitDCEGraph-output.js | 4 ++++ test/optimizer/emitDCEGraph.js | 5 +++++ test/test_other.py | 12 +++++++++--- tools/acorn-optimizer.js | 8 ++++++++ 9 files changed, 39 insertions(+), 13 deletions(-) diff --git a/emcc.py b/emcc.py index cbae8d913964a..085364cf9afb3 100755 --- a/emcc.py +++ b/emcc.py @@ -2427,7 +2427,7 @@ def phase_linker_setup(options, state, newargs): settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['$unSign'] if not settings.DECLARE_ASM_MODULE_EXPORTS: - settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['$exportAsmFunctions'] + settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['$exportWasmSymbols'] if settings.ALLOW_MEMORY_GROWTH: # Setting ALLOW_MEMORY_GROWTH turns off ABORTING_MALLOC, as in that mode we default to diff --git a/emscripten.py b/emscripten.py index 3856d855ccafb..cc14d0b1d61a8 100644 --- a/emscripten.py +++ b/emscripten.py @@ -755,7 +755,7 @@ def install_wrapper(sym): def create_receiving(function_exports): # When not declaring asm exports this section is empty and we instead programatically export - # symbols on the global object by calling exportAsmFunctions after initialization + # symbols on the global object by calling exportWasmSymbols after initialization if not settings.DECLARE_ASM_MODULE_EXPORTS: return '' @@ -884,9 +884,12 @@ def create_pointer_conversion_wrappers(metadata): } wrappers = ''' -function applySignatureConversions(exports) { +// Argument name here must shadow the `wasmExports` global so +// that it is recognised by metadce and minify-import-export-names +// passes. +function applySignatureConversions(wasmExports) { // First, make a copy of the incoming exports object - exports = Object.assign({}, exports); + wasmExports = Object.assign({}, wasmExports); ''' sigs_seen = set() @@ -907,8 +910,8 @@ def create_pointer_conversion_wrappers(metadata): for f in wrap_functions: sig = mapping[f] - wrappers += f"\n exports['{f}'] = makeWrapper_{sig}(exports['{f}']);" - wrappers += '\n return exports\n}' + wrappers += f"\n wasmExports['{f}'] = makeWrapper_{sig}(wasmExports['{f}']);" + wrappers += 'return wasmExports;\n}' return wrappers diff --git a/src/library.js b/src/library.js index 8f67fc3d2614d..95ee62d4e0d00 100644 --- a/src/library.js +++ b/src/library.js @@ -2972,8 +2972,8 @@ mergeInto(LibraryManager.library, { #if !DECLARE_ASM_MODULE_EXPORTS // When DECLARE_ASM_MODULE_EXPORTS is not set we export native symbols // at runtime rather than statically in JS code. - $exportAsmFunctions__deps: ['$asmjsMangle'], - $exportAsmFunctions: (wasmExports) => { + $exportWasmSymbols__deps: ['$asmjsMangle'], + $exportWasmSymbols: (wasmExports) => { #if ENVIRONMENT_MAY_BE_NODE && ENVIRONMENT_MAY_BE_WEB var global_object = (typeof process != "undefined" ? global : this); #elif ENVIRONMENT_MAY_BE_NODE diff --git a/src/postamble_minimal.js b/src/postamble_minimal.js index e72df02545984..cd515039c3883 100644 --- a/src/postamble_minimal.js +++ b/src/postamble_minimal.js @@ -183,7 +183,7 @@ WebAssembly.instantiate(Module['wasm'], imports).then((output) => { #endif #if !DECLARE_ASM_MODULE_EXPORTS - exportAsmFunctions(wasmExports); + exportWasmSymbols(wasmExports); #else <<< WASM_MODULE_EXPORTS >>> #endif diff --git a/src/preamble.js b/src/preamble.js index a3e428cf7ddaf..3de4637956760 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -1040,7 +1040,7 @@ function createWasm() { #if !DECLARE_ASM_MODULE_EXPORTS // If we didn't declare the asm exports as top level enties this function // is in charge of programatically exporting them on the global object. - exportAsmFunctions(exports); + exportWasmSymbols(exports); #endif #if PTHREADS || WASM_WORKERS diff --git a/test/optimizer/emitDCEGraph-output.js b/test/optimizer/emitDCEGraph-output.js index f8210ca84cf1e..1ed6d19b89c91 100644 --- a/test/optimizer/emitDCEGraph-output.js +++ b/test/optimizer/emitDCEGraph-output.js @@ -1,4 +1,8 @@ [ + { + "name": "emcc$defun$applySignatureConversions", + "reaches": [] + }, { "name": "emcc$defun$rootedFunc1", "reaches": [], diff --git a/test/optimizer/emitDCEGraph.js b/test/optimizer/emitDCEGraph.js index d9511afee2736..c36c85bfe793a 100644 --- a/test/optimizer/emitDCEGraph.js +++ b/test/optimizer/emitDCEGraph.js @@ -61,6 +61,11 @@ var expI4 = Module['expI4'] = () => (expI4 = Module['expI4'] = wasmExports['expI // Same as above but not export on the Module. var expI5 = () => (expI5 = wasmExports['expI5'])(); +function applySignatureConversions() { + // Wrapping functions should not constitute a usage + wasmExports['expI5'] = foo(wasmExports['expI5']); +} + // add uses for some of them expD1; Module['expD2']; diff --git a/test/test_other.py b/test/test_other.py index 0f2a710bd2cc5..1e6ce27ba1c73 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -12889,10 +12889,16 @@ def test_extended_const(self): # Smoketest for MEMORY64 setting. Most of the testing of MEMORY64 is by way of the wasm64 # variant of the core test suite. + @parameterized({ + 'O0': (['-O0'],), + 'O1': (['-O1'],), + 'O2': (['-O2'],), + 'O3': (['-O3'],), + 'Oz': (['-Oz'],), + }) @requires_wasm64 - def test_memory64(self): - for opt in ['-O0', '-O1', '-O2', '-O3']: - self.do_runf(test_file('hello_world.c'), 'hello, world', emcc_args=['-sMEMORY64', '-Wno-experimental', opt]) + def test_memory64(self, args): + self.do_run_in_out_file_test(test_file('core/test_hello_argc.c'), args=['hello', 'world'], emcc_args=['-sMEMORY64', '-Wno-experimental'] + args) # Verfy that MAIN_MODULE=1 (which includes all symbols from all libraries) # works with -sPROXY_POSIX_SOCKETS and -Oz, both of which affect linking of diff --git a/tools/acorn-optimizer.js b/tools/acorn-optimizer.js index 47e5ffbda2db2..5274f3114bc7a 100755 --- a/tools/acorn-optimizer.js +++ b/tools/acorn-optimizer.js @@ -687,6 +687,14 @@ function emitDCEGraph(ast) { }); foundWasmImportsAssign = true; emptyOut(node); // ignore this in the second pass; this does not root + } else if (node.type === 'AssignmentExpression') { + const target = node.left; + const value = node.right; + // Ignore assignment to the wasmExports object (as happens in + // applySignatureConversions). + if (isExportUse(target)) { + emptyOut(node); + } } else if (node.type === 'VariableDeclaration') { if (node.declarations.length === 1) { const item = node.declarations[0]; From 1691af2b50dec778cc01d8a9e8dd3cfaf732a1ad Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Sun, 30 Jul 2023 11:33:08 -0700 Subject: [PATCH 0590/1523] Remove some __sig attributes in favor of auto-generation. NFC (#19918) --- src/library.js | 4 ++-- src/library_browser.js | 2 -- src/library_exceptions.js | 15 +-------------- src/library_exports.js | 3 +-- src/library_html5.js | 1 - src/library_sigs.js | 19 +++++++++++++++++++ system/lib/libc/emscripten_internal.h | 4 ++++ tools/gen_sig_info.py | 13 ++++++++++--- 8 files changed, 37 insertions(+), 24 deletions(-) diff --git a/src/library.js b/src/library.js index 95ee62d4e0d00..4a7478d72b96f 100644 --- a/src/library.js +++ b/src/library.js @@ -3019,9 +3019,9 @@ mergeInto(LibraryManager.library, { } }, - _Unwind_GetIPInfo: () => abort('Unwind_GetIPInfo'), + _Unwind_GetIPInfo: (context, ipBefore) => abort('Unwind_GetIPInfo'), - _Unwind_FindEnclosingFunction: () => 0, // we cannot succeed + _Unwind_FindEnclosingFunction: (ip) => 0, // we cannot succeed _Unwind_RaiseException__deps: ['__cxa_throw'], _Unwind_RaiseException: (ex) => { diff --git a/src/library_browser.js b/src/library_browser.js index 31704c1336cbc..52ebe47fe9b05 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -1239,7 +1239,6 @@ var LibraryBrowser = { #if BUILD_AS_WORKER emscripten_worker_respond_provisionally__proxy: 'sync', - emscripten_worker_respond_provisionally__sig: 'vii', emscripten_worker_respond_provisionally: function(data, size) { if (workerResponded) throw 'already responded with final response!'; var transferObject = { @@ -1255,7 +1254,6 @@ var LibraryBrowser = { }, emscripten_worker_respond__proxy: 'sync', - emscripten_worker_respond__sig: 'vii', emscripten_worker_respond: function(data, size) { if (workerResponded) throw 'already responded with final response!'; workerResponded = true; diff --git a/src/library_exceptions.js b/src/library_exceptions.js index f4a481903c6ae..711576e7bb7a3 100644 --- a/src/library_exceptions.js +++ b/src/library_exceptions.js @@ -104,7 +104,6 @@ var LibraryExceptions = { // Here, we throw an exception after recording a couple of values that we need to remember // We also remember that it was the last exception thrown as we need to know that later. - __cxa_throw__sig: 'vppp', __cxa_throw__deps: ['$ExceptionInfo', '$exceptionLast', '$uncaughtExceptionCount'], __cxa_throw: function(ptr, type, destructor) { #if EXCEPTION_DEBUG @@ -122,7 +121,6 @@ var LibraryExceptions = { // we early-exit from end_catch when the exception has been rethrown, so // pop that here from the caught exceptions. __cxa_rethrow__deps: ['$exceptionCaught', '$exceptionLast', '$uncaughtExceptionCount'], - __cxa_rethrow__sig: 'v', __cxa_rethrow: function() { var info = exceptionCaught.pop(); if (!info) { @@ -144,14 +142,12 @@ var LibraryExceptions = { {{{ makeThrow('exceptionLast') }}} }, - llvm_eh_typeid_for__sig: 'ip', llvm_eh_typeid_for: function(type) { return type; }, __cxa_begin_catch__deps: ['$exceptionCaught', '__cxa_increment_exception_refcount', '$uncaughtExceptionCount'], - __cxa_begin_catch__sig: 'pp', __cxa_begin_catch: function(ptr) { var info = new ExceptionInfo(ptr); if (!info.get_caught()) { @@ -172,7 +168,6 @@ var LibraryExceptions = { // due to calling apply on undefined, that means that the destructor is // an invalid index into the FUNCTION_TABLE, so something has gone wrong. __cxa_end_catch__deps: ['$exceptionCaught', '$exceptionLast', '__cxa_decrement_exception_refcount', 'setThrew'], - __cxa_end_catch__sig: 'v', __cxa_end_catch: function() { // Clear state flag. _setThrew(0, 0); @@ -190,7 +185,6 @@ var LibraryExceptions = { }, __cxa_get_exception_ptr__deps: ['$ExceptionInfo'], - __cxa_get_exception_ptr__sig: 'pp', __cxa_get_exception_ptr: function(ptr) { var rtn = new ExceptionInfo(ptr).get_exception_ptr(); #if EXCEPTION_DEBUG @@ -205,15 +199,10 @@ var LibraryExceptions = { }, __cxa_call_unexpected: function(exception) { - err('Unexpected exception thrown, this is not properly supported - aborting'); -#if !MINIMAL_RUNTIME - ABORT = true; -#endif - throw exception; + abort('Unexpected exception thrown, this is not properly supported - aborting'); }, __cxa_current_primary_exception__deps: ['$exceptionCaught', '__cxa_increment_exception_refcount'], - __cxa_current_primary_exception__sig: 'p', __cxa_current_primary_exception: function() { if (!exceptionCaught.length) { return 0; @@ -224,7 +213,6 @@ var LibraryExceptions = { }, __cxa_rethrow_primary_exception__deps: ['$ExceptionInfo', '$exceptionCaught', '__cxa_rethrow'], - __cxa_rethrow_primary_exception__sig: 'vp', __cxa_rethrow_primary_exception: function(ptr) { if (!ptr) return; var info = new ExceptionInfo(ptr); @@ -293,7 +281,6 @@ var LibraryExceptions = { }, __resumeException__deps: ['$exceptionLast'], - __resumeException__sig: 'vp', __resumeException: function(ptr) { #if EXCEPTION_DEBUG dbg("__resumeException " + [ptrToString(ptr), exceptionLast]); diff --git a/src/library_exports.js b/src/library_exports.js index e9c875b9d47ea..c94f424c64647 100644 --- a/src/library_exports.js +++ b/src/library_exports.js @@ -5,8 +5,7 @@ */ mergeInto(LibraryManager.library, { - emscripten_get_exported_function__sig: 'pp', - emscripten_get_exported_function__deps: ['$addFunction'], + emscripten_get_exported_function__deps: ['$addFunction', '$UTF8ToString'], emscripten_get_exported_function: function(name) { name = UTF8ToString(name); // Wasm backend does not use C name mangling on exports, diff --git a/src/library_html5.js b/src/library_html5.js index 8e6837acd8c30..378621c5c0279 100644 --- a/src/library_html5.js +++ b/src/library_html5.js @@ -2420,7 +2420,6 @@ var LibraryHTML5 = { #endif $setCanvasElementSizeMainThread__proxy: 'sync', - $setCanvasElementSizeMainThread__sig: 'iiii', $setCanvasElementSizeMainThread__deps: ['$setCanvasElementSizeCallingThread'], $setCanvasElementSizeMainThread: function(target, width, height) { return setCanvasElementSizeCallingThread(target, width, height); diff --git a/src/library_sigs.js b/src/library_sigs.js index 71a8c65d0766a..4ef5995947b0d 100644 --- a/src/library_sigs.js +++ b/src/library_sigs.js @@ -208,14 +208,29 @@ sigs = { XSendEvent__sig: 'ippipp', XSetWMHints__sig: 'ippp', XStoreName__sig: 'ippp', + _Unwind_Backtrace__sig: 'ipp', + _Unwind_DeleteException__sig: 'vp', + _Unwind_FindEnclosingFunction__sig: 'pp', + _Unwind_GetIPInfo__sig: 'ppp', + _Unwind_RaiseException__sig: 'ip', __asctime_r__sig: 'ppp', __assert_fail__sig: 'vppip', __call_sighandler__sig: 'vpi', + __cxa_begin_catch__sig: 'pp', + __cxa_call_unexpected__sig: 'vp', + __cxa_current_primary_exception__sig: 'p', + __cxa_end_catch__sig: 'v', + __cxa_get_exception_ptr__sig: 'pp', + __cxa_rethrow__sig: 'v', + __cxa_rethrow_primary_exception__sig: 'vp', + __cxa_throw__sig: 'vppp', + __cxa_uncaught_exceptions__sig: 'i', __emscripten_init_main_thread_js__sig: 'vp', __emscripten_thread_cleanup__sig: 'vp', __handle_stack_overflow__sig: 'vp', __pthread_create_js__sig: 'ipppp', __pthread_kill_js__sig: 'ipi', + __resumeException__sig: 'vp', __syscall__newselect__sig: 'iipppp', __syscall_accept4__sig: 'iippiii', __syscall_bind__sig: 'iippiii', @@ -612,6 +627,7 @@ sigs = { emscripten_get_devicemotion_status__sig: 'ip', emscripten_get_deviceorientation_status__sig: 'ip', emscripten_get_element_css_size__sig: 'ippp', + emscripten_get_exported_function__sig: 'pp', emscripten_get_fullscreen_status__sig: 'ip', emscripten_get_gamepad_status__sig: 'iip', emscripten_get_heap_max__sig: 'p', @@ -921,6 +937,8 @@ sigs = { emscripten_websocket_set_onopen_callback_on_thread__sig: 'iippp', emscripten_wget__sig: 'ipp', emscripten_wget_data__sig: 'vpppp', + emscripten_worker_respond__sig: 'vpi', + emscripten_worker_respond_provisionally__sig: 'vpi', endprotoent__sig: 'v', environ_get__sig: 'ipp', environ_sizes_get__sig: 'ipp', @@ -1500,6 +1518,7 @@ sigs = { glutTimerFunc__sig: 'vipi', lineColor__sig: 'ipiiiii', lineRGBA__sig: 'ipiiiiiiii', + llvm_eh_typeid_for__sig: 'vp', pixelRGBA__sig: 'ipiiiiii', proc_exit__sig: 'vi', random_get__sig: 'ipp', diff --git a/system/lib/libc/emscripten_internal.h b/system/lib/libc/emscripten_internal.h index 50c16fb30d3cb..91887364cae13 100644 --- a/system/lib/libc/emscripten_internal.h +++ b/system/lib/libc/emscripten_internal.h @@ -136,6 +136,10 @@ EMSCRIPTEN_RESULT _emscripten_set_offscreencanvas_size(const char *target, int w // to perform the wasm worker creation. emscripten_wasm_worker_t _emscripten_create_wasm_worker(void *stackLowestAddress, uint32_t stackSize); +void __resumeException(void* exn); +void __cxa_call_unexpected(void* exn); +void llvm_eh_typeid_for(void* exn); + #ifdef __cplusplus } #endif diff --git a/tools/gen_sig_info.py b/tools/gen_sig_info.py index 3e0a212b67068..2d7293889a7d2 100755 --- a/tools/gen_sig_info.py +++ b/tools/gen_sig_info.py @@ -29,7 +29,7 @@ #define _GNU_SOURCE -// Public emscripen headers +// Public emscripten headers #include #include #include @@ -44,6 +44,7 @@ #include #include #include +#include #include // Internal emscripten headers @@ -104,7 +105,7 @@ cxx_header = '''/* Auto-generated by %s */ -// Public emscripen headers +// Public emscripten headers #include #include #include @@ -121,6 +122,8 @@ #include "js_impl_backend.h" // Public musl/libc headers +#include +#include #include #include #include @@ -130,6 +133,7 @@ #include using namespace emscripten::internal; +using namespace __cxxabiv1; ''' % os.path.basename(__file__) @@ -173,7 +177,7 @@ def ignore_symbol(s, cxx): if s in ('__stack_base', '__memory_base', '__table_base', '__global_base', '__heap_base', '__stack_pointer', '__stack_high', '__stack_low', '_load_secondary_module'): return True - if cxx and s in ('__asctime_r',): + if cxx and s in ('__asctime_r') or s.startswith('__cxa_find_matching_catch'): return True return False @@ -296,6 +300,7 @@ def extract_sig_info(sig_info, extra_settings=None, extra_cflags=None, cxx=False 'WASM_WORKERS': 1, 'JS_LIBRARIES': [ 'src/library_websocket.js', + 'src/library_exports.js', 'src/library_webaudio.js', 'src/library_fetch.js', 'src/library_pthread.js', @@ -375,6 +380,8 @@ def main(args): 'JS_LIBRARIES': [], 'USE_SDL': 0, 'MAX_WEBGL_VERSION': 0, + 'BUILD_AS_WORKER': 1, + 'LINK_AS_CXX': 1, 'AUTO_JS_LIBRARIES': 0}, cxx=True) extract_sig_info(sig_info, {'WASM_WORKERS': 1, 'JS_LIBRARIES': ['src/library_wasm_worker.js']}) extract_sig_info(sig_info, {'USE_GLFW': 3}, ['-DGLFW3']) From dd3eb0d6a7bfe53585357bdd23bd02cd9668fcbd Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 31 Jul 2023 07:29:04 -0700 Subject: [PATCH 0591/1523] Rebaseline codesize expectations. NFC --- test/other/metadce/test_metadce_cxx_ctors1.size | 2 +- test/other/metadce/test_metadce_cxx_ctors2.size | 2 +- test/other/metadce/test_metadce_cxx_except.size | 2 +- test/other/metadce/test_metadce_cxx_except_wasm.size | 2 +- test/other/metadce/test_metadce_cxx_mangle.size | 2 +- test/other/metadce/test_metadce_cxx_noexcept.size | 2 +- test/other/metadce/test_metadce_cxx_wasmfs.size | 2 +- test/other/metadce/test_metadce_files_wasmfs.size | 2 +- test/other/metadce/test_metadce_hello_O0.jssize | 2 +- test/other/metadce/test_metadce_minimal_O0.jssize | 2 +- test/other/test_unoptimized_code_size.js.size | 2 +- test/other/test_unoptimized_code_size.wasm.size | 2 +- test/other/test_unoptimized_code_size_no_asserts.wasm.size | 2 +- test/other/test_unoptimized_code_size_strict.js.size | 2 +- test/other/test_unoptimized_code_size_strict.wasm.size | 2 +- 15 files changed, 15 insertions(+), 15 deletions(-) diff --git a/test/other/metadce/test_metadce_cxx_ctors1.size b/test/other/metadce/test_metadce_cxx_ctors1.size index 058f4f6439b55..228e74f86ff4a 100644 --- a/test/other/metadce/test_metadce_cxx_ctors1.size +++ b/test/other/metadce/test_metadce_cxx_ctors1.size @@ -1 +1 @@ -123529 +123565 diff --git a/test/other/metadce/test_metadce_cxx_ctors2.size b/test/other/metadce/test_metadce_cxx_ctors2.size index 3a0f6f5d0aabe..ed64feb8e13e3 100644 --- a/test/other/metadce/test_metadce_cxx_ctors2.size +++ b/test/other/metadce/test_metadce_cxx_ctors2.size @@ -1 +1 @@ -123434 +123470 diff --git a/test/other/metadce/test_metadce_cxx_except.size b/test/other/metadce/test_metadce_cxx_except.size index 174744d2076e6..2e9ac712f802e 100644 --- a/test/other/metadce/test_metadce_cxx_except.size +++ b/test/other/metadce/test_metadce_cxx_except.size @@ -1 +1 @@ -166364 +166400 diff --git a/test/other/metadce/test_metadce_cxx_except_wasm.size b/test/other/metadce/test_metadce_cxx_except_wasm.size index 6748be003ac5e..77021e06e7988 100644 --- a/test/other/metadce/test_metadce_cxx_except_wasm.size +++ b/test/other/metadce/test_metadce_cxx_except_wasm.size @@ -1 +1 @@ -137157 +137189 diff --git a/test/other/metadce/test_metadce_cxx_mangle.size b/test/other/metadce/test_metadce_cxx_mangle.size index 264492efef7b6..1fc97313ee2f7 100644 --- a/test/other/metadce/test_metadce_cxx_mangle.size +++ b/test/other/metadce/test_metadce_cxx_mangle.size @@ -1 +1 @@ -221326 +221362 diff --git a/test/other/metadce/test_metadce_cxx_noexcept.size b/test/other/metadce/test_metadce_cxx_noexcept.size index f5cf2977dfdaf..14eb87d7a0c3f 100644 --- a/test/other/metadce/test_metadce_cxx_noexcept.size +++ b/test/other/metadce/test_metadce_cxx_noexcept.size @@ -1 +1 @@ -126333 +126369 diff --git a/test/other/metadce/test_metadce_cxx_wasmfs.size b/test/other/metadce/test_metadce_cxx_wasmfs.size index c04bb7574f6f2..312fc02536986 100644 --- a/test/other/metadce/test_metadce_cxx_wasmfs.size +++ b/test/other/metadce/test_metadce_cxx_wasmfs.size @@ -1 +1 @@ -164472 +164508 diff --git a/test/other/metadce/test_metadce_files_wasmfs.size b/test/other/metadce/test_metadce_files_wasmfs.size index 7d423ee08413d..1d7ac52661806 100644 --- a/test/other/metadce/test_metadce_files_wasmfs.size +++ b/test/other/metadce/test_metadce_files_wasmfs.size @@ -1 +1 @@ -52346 +52348 diff --git a/test/other/metadce/test_metadce_hello_O0.jssize b/test/other/metadce/test_metadce_hello_O0.jssize index b915817b43619..0dbe6809dd80a 100644 --- a/test/other/metadce/test_metadce_hello_O0.jssize +++ b/test/other/metadce/test_metadce_hello_O0.jssize @@ -1 +1 @@ -23662 +23674 diff --git a/test/other/metadce/test_metadce_minimal_O0.jssize b/test/other/metadce/test_metadce_minimal_O0.jssize index b48d260d639d5..2f6ad4ba8aa96 100644 --- a/test/other/metadce/test_metadce_minimal_O0.jssize +++ b/test/other/metadce/test_metadce_minimal_O0.jssize @@ -1 +1 @@ -20133 +20145 diff --git a/test/other/test_unoptimized_code_size.js.size b/test/other/test_unoptimized_code_size.js.size index fb626e1286469..45a63003d2ba8 100644 --- a/test/other/test_unoptimized_code_size.js.size +++ b/test/other/test_unoptimized_code_size.js.size @@ -1 +1 @@ -58325 +58342 diff --git a/test/other/test_unoptimized_code_size.wasm.size b/test/other/test_unoptimized_code_size.wasm.size index 8be8535efff58..4808bbca754f4 100644 --- a/test/other/test_unoptimized_code_size.wasm.size +++ b/test/other/test_unoptimized_code_size.wasm.size @@ -1 +1 @@ -12189 +12153 diff --git a/test/other/test_unoptimized_code_size_no_asserts.wasm.size b/test/other/test_unoptimized_code_size_no_asserts.wasm.size index 7230c6821ca4a..23da5c9c59435 100644 --- a/test/other/test_unoptimized_code_size_no_asserts.wasm.size +++ b/test/other/test_unoptimized_code_size_no_asserts.wasm.size @@ -1 +1 @@ -11636 +11600 diff --git a/test/other/test_unoptimized_code_size_strict.js.size b/test/other/test_unoptimized_code_size_strict.js.size index a517e768780f3..8416ee35bcea5 100644 --- a/test/other/test_unoptimized_code_size_strict.js.size +++ b/test/other/test_unoptimized_code_size_strict.js.size @@ -1 +1 @@ -57291 +57308 diff --git a/test/other/test_unoptimized_code_size_strict.wasm.size b/test/other/test_unoptimized_code_size_strict.wasm.size index 8be8535efff58..4808bbca754f4 100644 --- a/test/other/test_unoptimized_code_size_strict.wasm.size +++ b/test/other/test_unoptimized_code_size_strict.wasm.size @@ -1 +1 @@ -12189 +12153 From 43a1d18d7abd8c2a1c4574d9662a78c602e8bd6b Mon Sep 17 00:00:00 2001 From: Arthur Islamov Date: Mon, 31 Jul 2023 18:36:47 +0400 Subject: [PATCH 0592/1523] Signature conversions command-line flag (#19838) --- emscripten.py | 4 ++++ src/settings.js | 8 ++++++++ 2 files changed, 12 insertions(+) diff --git a/emscripten.py b/emscripten.py index cc14d0b1d61a8..fe9a6ba08d472 100644 --- a/emscripten.py +++ b/emscripten.py @@ -883,6 +883,10 @@ def create_pointer_conversion_wrappers(metadata): '__get_exception_message': '_ppp', } + for function in settings.SIGNATURE_CONVERSIONS: + sym, sig = function.split(':') + mapping[sym] = sig + wrappers = ''' // Argument name here must shadow the `wasmExports` global so // that it is recognised by metadce and minify-import-export-names diff --git a/src/settings.js b/src/settings.js index 456badb4fb4db..3777428d6fef1 100644 --- a/src/settings.js +++ b/src/settings.js @@ -2060,6 +2060,14 @@ var RUNTIME_DEBUG = false; // library symbol. var LEGACY_RUNTIME = false; +// User-defined functions to wrap with signature conversion, which take or return +// pointer argument. Only affects MEMORY64=1 builds, see create_pointer_conversion_wrappers +// in emscripten.py for details. +// Use _ for non-pointer arguments, p for pointer/i53 arguments, and P for optional pointer/i53 values. +// Example use -sSIGNATURE_CONVERSIONS=someFunction:_p,anotherFunction:p +// [link] +var SIGNATURE_CONVERSIONS = []; + //=========================================== // Internal, used for testing only, from here //=========================================== From 995ba815a9ac62b1de2d45b5bbb4b796f051cddb Mon Sep 17 00:00:00 2001 From: Bas Hendri Date: Mon, 31 Jul 2023 08:19:32 -0700 Subject: [PATCH 0593/1523] removes nullish-coalescing operator to increase compatibility (#19925) --- src/worker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/worker.js b/src/worker.js index 3e4760ca3ab63..42275d6f9ba97 100644 --- a/src/worker.js +++ b/src/worker.js @@ -99,7 +99,7 @@ Module['instantiateWasm'] = (info, receiveInstance) => { // Turn unhandled rejected promises into errors so that the main thread will be // notified about them. self.onunhandledrejection = (e) => { - throw e.reason ?? e; + throw e.reason || e; }; function handleMessage(e) { From 362944105647cde2ea71ebf42fea7d55b9b2c15c Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 31 Jul 2023 14:10:32 -0700 Subject: [PATCH 0594/1523] Avoid use of JS console.log/error/warning. NFC (#19936) Instead prefer the emscripten-specific `out`/`err`/`dbg` helpers which don't suffer from the same issues with workers and buffering that the console methods seem to under node. See #14804 --- system/lib/al.c | 4 ++-- system/lib/fetch/emscripten_fetch.c | 12 ++++++------ system/lib/gl/webgl1.c | 2 +- system/lib/libc/emscripten_syscall_stubs.c | 2 +- system/lib/wasmfs/js_api.cpp | 10 +++++----- system/lib/wasmfs/support.cpp | 6 +++--- system/lib/wasmfs/wasmfs.cpp | 4 ++-- test/other/metadce/test_metadce_cxx_wasmfs.imports | 1 - test/other/metadce/test_metadce_cxx_wasmfs.jssize | 2 +- test/other/metadce/test_metadce_cxx_wasmfs.sent | 1 - test/other/metadce/test_metadce_cxx_wasmfs.size | 2 +- test/other/metadce/test_metadce_files_wasmfs.exports | 2 +- test/other/metadce/test_metadce_files_wasmfs.imports | 1 - test/other/metadce/test_metadce_files_wasmfs.jssize | 2 +- test/other/metadce/test_metadce_files_wasmfs.sent | 1 - test/other/metadce/test_metadce_files_wasmfs.size | 2 +- 16 files changed, 25 insertions(+), 29 deletions(-) diff --git a/system/lib/al.c b/system/lib/al.c index ebbfe15e16d8b..49edf9b3ba4a3 100644 --- a/system/lib/al.c +++ b/system/lib/al.c @@ -62,7 +62,7 @@ void* alcGetProcAddress(ALCdevice *device, const ALCchar *name) { else if (!strcmp(name, "alcGetStringiSOFT")) { return emscripten_alcGetStringiSOFT; } else if (!strcmp(name, "alcResetDeviceSOFT")) { return emscripten_alcResetDeviceSOFT; } - emscripten_console_errorf("bad name in alcGetProcAddress: %s", name); + emscripten_errf("bad name in alcGetProcAddress: %s", name); return 0; } @@ -159,6 +159,6 @@ void* alGetProcAddress(const ALchar *name) { // Extensions - emscripten_console_errorf("bad name in alGetProcAddress: %s", name); + emscripten_errf("bad name in alGetProcAddress: %s", name); return 0; } diff --git a/system/lib/fetch/emscripten_fetch.c b/system/lib/fetch/emscripten_fetch.c index bc3287441bfd0..6c305d27bbf77 100644 --- a/system/lib/fetch/emscripten_fetch.c +++ b/system/lib/fetch/emscripten_fetch.c @@ -57,7 +57,7 @@ void emscripten_proxy_fetch(emscripten_fetch_t* fetch) { // TODO handle case when queue->numQueuedItems >= queue->queueSize queue->queuedOperations[queue->numQueuedItems++] = fetch; #ifdef FETCH_DEBUG - emscripten_console_logf("Queued fetch to fetch-worker to process. There are " + emscripten_dbgf("Queued fetch to fetch-worker to process. There are " "now %d operations in the queue.", queue->numQueuedItems); #endif // TODO: mutex unlock @@ -81,7 +81,7 @@ emscripten_fetch_t* emscripten_fetch(emscripten_fetch_attr_t* fetch_attr, const const bool performXhr = (fetch_attr->attributes & EMSCRIPTEN_FETCH_NO_DOWNLOAD) == 0; if (emscripten_is_main_browser_thread() && synchronous && (performXhr || readFromIndexedDB || writeToIndexedDB)) { #ifdef FETCH_DEBUG - emscripten_console_errorf("emscripten_fetch('%s') failed! Synchronous blocking XHRs and IndexedDB operations are not supported on the main browser thread. Try dropping the EMSCRIPTEN_FETCH_SYNCHRONOUS flag, or run with the linker flag --proxy-to-worker to decouple main C runtime thread from the main browser thread.", url); + emscripten_errf("emscripten_fetch('%s') failed! Synchronous blocking XHRs and IndexedDB operations are not supported on the main browser thread. Try dropping the EMSCRIPTEN_FETCH_SYNCHRONOUS flag, or run with the linker flag --proxy-to-worker to decouple main C runtime thread from the main browser thread.", url); #endif return NULL; } @@ -156,7 +156,7 @@ EMSCRIPTEN_RESULT emscripten_fetch_wait(emscripten_fetch_t* fetch, double timeou if (proxyState != 1) return EMSCRIPTEN_RESULT_INVALID_PARAM; // the fetch should be ongoing? #ifdef FETCH_DEBUG - emscripten_console_log("fetch: emscripten_fetch_wait.."); + emscripten_dbg("fetch: emscripten_fetch_wait.."); #endif if (timeoutMsecs <= 0) return EMSCRIPTEN_RESULT_TIMED_OUT; @@ -167,12 +167,12 @@ EMSCRIPTEN_RESULT emscripten_fetch_wait(emscripten_fetch_t* fetch, double timeou return EMSCRIPTEN_RESULT_TIMED_OUT; proxyState = fetch->__proxyState; } else { - emscripten_console_error("fetch: emscripten_fetch_wait failed: main thread cannot block to wait for long periods of time! Migrate the application to run in a worker to perform synchronous file IO, or switch to using asynchronous IO."); + emscripten_err("fetch: emscripten_fetch_wait failed: main thread cannot block to wait for long periods of time! Migrate the application to run in a worker to perform synchronous file IO, or switch to using asynchronous IO."); return EMSCRIPTEN_RESULT_FAILED; } } #ifdef FETCH_DEBUG - emscripten_console_log("fetch: emscripten_fetch_wait done.."); + emscripten_dbg("fetch: emscripten_fetch_wait done.."); #endif if (proxyState == 2) @@ -186,7 +186,7 @@ EMSCRIPTEN_RESULT emscripten_fetch_wait(emscripten_fetch_t* fetch, double timeou return EMSCRIPTEN_RESULT_TIMED_OUT /*Main thread testing completion with sleep=0msecs*/; else { #ifdef FETCH_DEBUG - emscripten_console_error("fetch: emscripten_fetch_wait() cannot stop to wait when building without pthreads!"); + emscripten_err("fetch: emscripten_fetch_wait() cannot stop to wait when building without pthreads!"); #endif return EMSCRIPTEN_RESULT_FAILED /*Main thread cannot block to wait*/; } diff --git a/system/lib/gl/webgl1.c b/system/lib/gl/webgl1.c index 1fa41d267d78e..bd761b5ec952f 100644 --- a/system/lib/gl/webgl1.c +++ b/system/lib/gl/webgl1.c @@ -27,7 +27,7 @@ EMSCRIPTEN_WEBGL_CONTEXT_HANDLE emscripten_webgl_create_context(const char *targ GL_FUNCTION_TRACE(__func__); if (!attributes) { - emscripten_console_error("emscripten_webgl_create_context: attributes pointer is null!"); + emscripten_err("emscripten_webgl_create_context: attributes pointer is null!"); return 0; } pthread_once(&tlsInit, InitWebGLTls); diff --git a/system/lib/libc/emscripten_syscall_stubs.c b/system/lib/libc/emscripten_syscall_stubs.c index 78d16e8792877..9cf6f1cc6a452 100644 --- a/system/lib/libc/emscripten_syscall_stubs.c +++ b/system/lib/libc/emscripten_syscall_stubs.c @@ -34,7 +34,7 @@ static mode_t g_umask = S_IRWXU | S_IRWXG | S_IRWXO; #define REPORT(name) #else #define REPORT(name) \ - emscripten_console_error("warning: unsupported syscall: __syscall_" #name "\n"); + emscripten_err("warning: unsupported syscall: __syscall_" #name "\n"); #endif #define UNIMPLEMENTED(name, args) \ diff --git a/system/lib/wasmfs/js_api.cpp b/system/lib/wasmfs/js_api.cpp index 6bbfb43fd420e..f63127bc3c875 100644 --- a/system/lib/wasmfs/js_api.cpp +++ b/system/lib/wasmfs/js_api.cpp @@ -34,7 +34,7 @@ void* _wasmfs_read_file(char* path) { int err = 0; err = stat(path, &file); if (err < 0) { - emscripten_console_error("Fatal error in FS.readFile"); + emscripten_err("Fatal error in FS.readFile"); abort(); } @@ -51,7 +51,7 @@ void* _wasmfs_read_file(char* path) { int fd = open(path, O_RDONLY); if (fd < 0) { - emscripten_console_error("Fatal error in FS.readFile"); + emscripten_err("Fatal error in FS.readFile"); abort(); } [[maybe_unused]] int numRead = pread(fd, result + sizeof(size), size, 0); @@ -60,7 +60,7 @@ void* _wasmfs_read_file(char* path) { assert(numRead == size); err = close(fd); if (err < 0) { - emscripten_console_error("Fatal error in FS.readFile"); + emscripten_err("Fatal error in FS.readFile"); abort(); } @@ -100,7 +100,7 @@ int _wasmfs_write_file(char* pathname, char* data, size_t data_size) { auto lockedFile = dataFile->locked(); int err = lockedFile.open(O_WRONLY); if (err < 0) { - emscripten_console_error("Fatal error in FS.writeFile"); + emscripten_err("Fatal error in FS.writeFile"); abort(); } @@ -112,7 +112,7 @@ int _wasmfs_write_file(char* pathname, char* data, size_t data_size) { err = lockedFile.close(); if (err < 0) { - emscripten_console_error("Fatal error in FS.writeFile"); + emscripten_err("Fatal error in FS.writeFile"); abort(); } diff --git a/system/lib/wasmfs/support.cpp b/system/lib/wasmfs/support.cpp index c4338297814d6..adf08aec37a47 100644 --- a/system/lib/wasmfs/support.cpp +++ b/system/lib/wasmfs/support.cpp @@ -18,11 +18,11 @@ void handle_unreachable(const char* msg, const char* file, unsigned line) { #ifndef NDEBUG #ifdef __EMSCRIPTEN__ if (msg) { - emscripten_console_error(msg); + emscripten_err(msg); } - emscripten_console_error("UNREACHABLE executed"); + emscripten_err("UNREACHABLE executed"); if (file) { - emscripten_console_errorf("at %s:%d", file, line); + emscripten_errf("at %s:%d", file, line); } #else // EMSCRIPTEN if (msg) { diff --git a/system/lib/wasmfs/wasmfs.cpp b/system/lib/wasmfs/wasmfs.cpp index a268868851973..90f78834512aa 100644 --- a/system/lib/wasmfs/wasmfs.cpp +++ b/system/lib/wasmfs/wasmfs.cpp @@ -161,7 +161,7 @@ void WasmFS::preloadFiles() { std::shared_ptr parentDir; if (parsed.getError() || !(parentDir = parsed.getFile()->dynCast())) { - emscripten_console_error( + emscripten_err( "Fatal error during directory creation in file preloading."); abort(); } @@ -188,7 +188,7 @@ void WasmFS::preloadFiles() { auto parsed = path::parseParent(fileName); if (parsed.getError()) { - emscripten_console_error("Fatal error during file preloading"); + emscripten_err("Fatal error during file preloading"); abort(); } auto& [parent, childName] = parsed.getParentChild(); diff --git a/test/other/metadce/test_metadce_cxx_wasmfs.imports b/test/other/metadce/test_metadce_cxx_wasmfs.imports index dd385d4916732..c825496d1cc33 100644 --- a/test/other/metadce/test_metadce_cxx_wasmfs.imports +++ b/test/other/metadce/test_metadce_cxx_wasmfs.imports @@ -10,7 +10,6 @@ env._wasmfs_get_preloaded_parent_path env._wasmfs_get_preloaded_path_name env._wasmfs_stdin_get_char env.abort -env.emscripten_console_error env.emscripten_date_now env.emscripten_err env.emscripten_memcpy_big diff --git a/test/other/metadce/test_metadce_cxx_wasmfs.jssize b/test/other/metadce/test_metadce_cxx_wasmfs.jssize index 6b5f7a5ee6607..99a37a4532ba5 100644 --- a/test/other/metadce/test_metadce_cxx_wasmfs.jssize +++ b/test/other/metadce/test_metadce_cxx_wasmfs.jssize @@ -1 +1 @@ -12731 +12681 diff --git a/test/other/metadce/test_metadce_cxx_wasmfs.sent b/test/other/metadce/test_metadce_cxx_wasmfs.sent index 901266de9f101..72ff0bd9e3aae 100644 --- a/test/other/metadce/test_metadce_cxx_wasmfs.sent +++ b/test/other/metadce/test_metadce_cxx_wasmfs.sent @@ -10,7 +10,6 @@ _wasmfs_get_preloaded_parent_path _wasmfs_get_preloaded_path_name _wasmfs_stdin_get_char abort -emscripten_console_error emscripten_date_now emscripten_err emscripten_get_now diff --git a/test/other/metadce/test_metadce_cxx_wasmfs.size b/test/other/metadce/test_metadce_cxx_wasmfs.size index 312fc02536986..3a52b254f9c39 100644 --- a/test/other/metadce/test_metadce_cxx_wasmfs.size +++ b/test/other/metadce/test_metadce_cxx_wasmfs.size @@ -1 +1 @@ -164508 +164473 diff --git a/test/other/metadce/test_metadce_files_wasmfs.exports b/test/other/metadce/test_metadce_files_wasmfs.exports index 16df2d145c61f..e689492db2cfe 100644 --- a/test/other/metadce/test_metadce_files_wasmfs.exports +++ b/test/other/metadce/test_metadce_files_wasmfs.exports @@ -1,4 +1,4 @@ +r s t u -v diff --git a/test/other/metadce/test_metadce_files_wasmfs.imports b/test/other/metadce/test_metadce_files_wasmfs.imports index cca17b666c5d2..ac4ee2d44f8ad 100644 --- a/test/other/metadce/test_metadce_files_wasmfs.imports +++ b/test/other/metadce/test_metadce_files_wasmfs.imports @@ -15,4 +15,3 @@ a.n a.o a.p a.q -a.r diff --git a/test/other/metadce/test_metadce_files_wasmfs.jssize b/test/other/metadce/test_metadce_files_wasmfs.jssize index 7b5514dfe63ca..13484b6dc0ddd 100644 --- a/test/other/metadce/test_metadce_files_wasmfs.jssize +++ b/test/other/metadce/test_metadce_files_wasmfs.jssize @@ -1 +1 @@ -7242 +7215 diff --git a/test/other/metadce/test_metadce_files_wasmfs.sent b/test/other/metadce/test_metadce_files_wasmfs.sent index c010d5bedf25b..f6c3b87f767e8 100644 --- a/test/other/metadce/test_metadce_files_wasmfs.sent +++ b/test/other/metadce/test_metadce_files_wasmfs.sent @@ -15,4 +15,3 @@ n o p q -r diff --git a/test/other/metadce/test_metadce_files_wasmfs.size b/test/other/metadce/test_metadce_files_wasmfs.size index 1d7ac52661806..6d51b8b12bc62 100644 --- a/test/other/metadce/test_metadce_files_wasmfs.size +++ b/test/other/metadce/test_metadce_files_wasmfs.size @@ -1 +1 @@ -52348 +52341 From b36547769f5652caf2cfa3f9b1f7cc60ca35766f Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 31 Jul 2023 14:12:12 -0700 Subject: [PATCH 0595/1523] Disable USE_GLFW by default in -sSTRICT mode (#19935) This fixes `-sSTRICT` + `-sINCLUDE_FULL_LIBRARY`. Fixes: #19926 --- emcc.py | 1 + src/settings.js | 3 ++- test/test_other.py | 6 ++++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/emcc.py b/emcc.py index 085364cf9afb3..4310998df057a 100755 --- a/emcc.py +++ b/emcc.py @@ -2010,6 +2010,7 @@ def phase_linker_setup(options, state, newargs): if settings.STRICT: if not settings.MODULARIZE and not settings.EXPORT_ES6: default_setting('STRICT_JS', 1) + default_setting('USE_GLFW', 0) default_setting('AUTO_JS_LIBRARIES', 0) default_setting('AUTO_NATIVE_LIBRARIES', 0) default_setting('AUTO_ARCHIVE_INDEXES', 0) diff --git a/src/settings.js b/src/settings.js index 3777428d6fef1..67a415b0360f0 100644 --- a/src/settings.js +++ b/src/settings.js @@ -1114,6 +1114,7 @@ var LINKABLE = false; // * AUTO_NATIVE_LIBRARIES is disabled. // * AUTO_ARCHIVE_INDEXES is disabled. // * DEFAULT_TO_CXX is disabled. +// * USE_GLFW is set to 0 rather than 2 by default. // * ALLOW_UNIMPLEMENTED_SYSCALLS is disabled. // [compile+link] var STRICT = false; @@ -1305,7 +1306,7 @@ var EMSCRIPTEN_TRACING = false; // Specify the GLFW version that is being linked against. Only relevant, if you // are linking against the GLFW library. Valid options are 2 for GLFW2 and 3 // for GLFW3. -// In MINIMAL_RUNTIME builds, this option defaults to 0. +// This defaults to 0 in either MINIMAL_RUNTIME or STRICT modes. // [link] var USE_GLFW = 2; diff --git a/test/test_other.py b/test/test_other.py index 1e6ce27ba1c73..31ab4c322b282 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -10295,11 +10295,13 @@ def test_jsmath(self): def test_strict_mode_hello_world(self): # Verify that strict mode can be used for simple hello world program both # via the environment EMCC_STRICT=1 and from the command line `-sSTRICT` - cmd = [EMCC, test_file('hello_world.c'), '-sSTRICT'] - self.run_process(cmd) + self.do_runf(test_file('hello_world.c'), emcc_args=['-sSTRICT']) with env_modify({'EMCC_STRICT': '1'}): self.do_runf(test_file('hello_world.c'), 'hello, world!') + def test_strict_mode_full_library(self): + self.do_runf(test_file('hello_world.c'), emcc_args=['-sSTRICT', '-sINCLUDE_FULL_LIBRARY']) + def test_legacy_settings(self): cmd = [EMCC, test_file('hello_world.c'), '-sSPLIT_MEMORY=0'] From e39a8bd8ddb65be122d0e70cd8e272369d80e716 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 31 Jul 2023 16:53:16 -0700 Subject: [PATCH 0596/1523] Rebaseline codesize expectations. NFC --- test/other/test_unoptimized_code_size_strict.js.size | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/other/test_unoptimized_code_size_strict.js.size b/test/other/test_unoptimized_code_size_strict.js.size index 8416ee35bcea5..569d2facfd859 100644 --- a/test/other/test_unoptimized_code_size_strict.js.size +++ b/test/other/test_unoptimized_code_size_strict.js.size @@ -1 +1 @@ -57308 +57281 From 2817cd7b6d60192e9359e895222161fa78cf5812 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 31 Jul 2023 17:42:04 -0700 Subject: [PATCH 0597/1523] Fix test_file_packager_depfile under windows (#19931) Mark the test as @crossplatform so it run on windows. Fix the test by always writing paths with unix-style separators when writing the deps file. Also unify all the places where we do this unix-style path normalization. --- emcc.py | 2 +- test/common.py | 6 +++--- test/test_browser.py | 8 ++++---- test/test_other.py | 16 ++++++++++------ tools/building.py | 2 +- tools/file_packager.py | 9 +++------ tools/utils.py | 11 +++++++++++ tools/wasm-sourcemap.py | 8 ++------ 8 files changed, 35 insertions(+), 27 deletions(-) diff --git a/emcc.py b/emcc.py index 4310998df057a..618072987aa3d 100755 --- a/emcc.py +++ b/emcc.py @@ -4297,7 +4297,7 @@ def replacement(self): def is_valid_abspath(options, path_name): # Any path that is underneath the emscripten repository root must be ok. - if utils.path_from_root().replace('\\', '/') in path_name.replace('\\', '/'): + if utils.normalize_path(path_name).startswith(utils.normalize_path(utils.path_from_root())): return True def in_directory(root, child): diff --git a/test/common.py b/test/common.py index c59356294f47f..9015a190f5bfb 100644 --- a/test/common.py +++ b/test/common.py @@ -902,7 +902,7 @@ def verify_es5(self, filename): inputfile = os.path.abspath(filename) # For some reason es-check requires unix paths, even on windows if WINDOWS: - inputfile = inputfile.replace('\\', '/') + inputfile = utils.normalize_path(inputfile) try: # es-check prints the details of the errors to stdout, but it also prints # stuff in the case there are no errors: @@ -1114,8 +1114,8 @@ def assertNotExists(self, filename, msg=None): # Tests that the given two paths are identical, modulo path delimiters. E.g. "C:/foo" is equal to "C:\foo". def assertPathsIdentical(self, path1, path2): - path1 = path1.replace('\\', '/') - path2 = path2.replace('\\', '/') + path1 = utils.normalize_path(path1) + path2 = utils.normalize_path(path2) return self.assertIdentical(path1, path2) # Tests that the given two multiline text content are identical, modulo line diff --git a/test/test_browser.py b/test/test_browser.py index c73689fcd3d6c..2b784780c8fb8 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -380,13 +380,13 @@ def make_main(path): # Test subdirectory handling with asset packaging. delete_dir('assets') - ensure_dir('assets/sub/asset1/'.replace('\\', '/')) - ensure_dir('assets/sub/asset1/.git'.replace('\\', '/')) # Test adding directory that shouldn't exist. - ensure_dir('assets/sub/asset2/'.replace('\\', '/')) + ensure_dir('assets/sub/asset1') + ensure_dir('assets/sub/asset1/.git') # Test adding directory that shouldn't exist. + ensure_dir('assets/sub/asset2') create_file('assets/sub/asset1/file1.txt', '''load me right before running the code please''') create_file('assets/sub/asset1/.git/shouldnt_be_embedded.txt', '''this file should not get embedded''') create_file('assets/sub/asset2/file2.txt', '''load me right before running the code please''') - absolute_assets_src_path = 'assets'.replace('\\', '/') + absolute_assets_src_path = 'assets' def make_main_two_files(path1, path2, nonexistingpath): create_file('main.cpp', r''' diff --git a/test/test_other.py b/test/test_other.py index 31ab4c322b282..ae56f890d81a2 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -3109,19 +3109,22 @@ def test_file_packager_embed(self): output = self.run_js('a.out.js') self.assertContained('hello data', output) + @crossplatform def test_file_packager_depfile(self): create_file('data1.txt', 'data1') ensure_dir('subdir') create_file('subdir/data2.txt', 'data2') self.run_process([FILE_PACKAGER, 'test.data', '--js-output=test.js', '--depfile=test.data.d', '--from-emcc', '--preload', '.']) - lines = read_file('test.data.d').splitlines() + output = read_file('test.data.d') + file_packager = utils.normalize_path(shared.replace_suffix(FILE_PACKAGER, '.py')) + lines = output.splitlines() split = lines.index(': \\') before, after = set(lines[:split]), set(lines[split + 1:]) # Set comparison used because depfile is not order-sensitive. self.assertTrue('test.data \\' in before) self.assertTrue('test.js \\' in before) - self.assertTrue(FILE_PACKAGER + '.py \\' in after) + self.assertTrue(file_packager + ' \\' in after) self.assertTrue('. \\' in after) self.assertTrue('./data1.txt \\' in after) self.assertTrue('./subdir \\' in after) @@ -4691,6 +4694,7 @@ def test_init_file_at_offset(self): def test_unlink(self): self.do_other_test('test_unlink.cpp') + @crossplatform def test_argv0_node(self): create_file('code.c', r''' #include @@ -4700,8 +4704,8 @@ def test_argv0_node(self): } ''') - self.run_process([EMCC, 'code.c']) - self.assertContained('I am ' + os.path.realpath(self.get_dir()).replace('\\', '/') + '/a.out.js', self.run_js('a.out.js').replace('\\', '/')) + output = self.do_runf('code.c') + self.assertContained('I am ' + utils.normalize_path(os.path.realpath(self.get_dir())) + '/code.js', utils.normalize_path(output)) @parameterized({ 'no_exit_runtime': [True], @@ -13160,7 +13164,7 @@ def test_reproduce(self): self.assertExists('foo.tar') names = [] root = os.path.splitdrive(path_from_root())[1][1:] - root = root.replace('\\', '/') + root = utils.normalize_path(root) print('root: %s' % root) with tarfile.open('foo.tar') as f: for name in f.getnames(): @@ -13179,7 +13183,7 @@ def test_reproduce(self): /test/hello_world.c ''' response = read_file('foo/response.txt') - response = response.replace('\\', '/') + response = utils.normalize_path(response) response = response.replace(root, '') self.assertTextDataIdentical(expected, response) diff --git a/tools/building.py b/tools/building.py index 49412409a0a6e..56d5842c75f45 100644 --- a/tools/building.py +++ b/tools/building.py @@ -944,7 +944,7 @@ def emit_debug_on_side(wasm_file): embedded_path = os.path.relpath(wasm_file_with_dwarf, os.path.dirname(wasm_file)) # normalize the path to use URL-style separators, per the spec - embedded_path = embedded_path.replace('\\', '/').replace('//', '/') + embedded_path = utils.normalize_path(embedded_path) shutil.move(wasm_file, wasm_file_with_dwarf) strip(wasm_file_with_dwarf, wasm_file, debug=True) diff --git a/tools/file_packager.py b/tools/file_packager.py index 90e7dec88fb9a..a4e4459ba185b 100755 --- a/tools/file_packager.py +++ b/tools/file_packager.py @@ -142,10 +142,6 @@ def err(*args): print(*args, file=sys.stderr) -def to_unix_path(p): - return p.replace(os.path.sep, '/') - - def base64_encode(b): b64 = base64.b64encode(b) return b64.decode('ascii') @@ -281,7 +277,7 @@ def generate_object_file(data_files): size = os.path.getsize(f.srcpath) dstpath = to_asm_string(f.dstpath) - srcpath = to_unix_path(f.srcpath) + srcpath = utils.normalize_path(f.srcpath) out.write(dedent(f''' .section .rodata.{f.c_symbol_name},"",@ @@ -514,7 +510,7 @@ def main(): for file_ in data_files: # name in the filesystem, native and emulated - file_.dstpath = to_unix_path(file_.dstpath) + file_.dstpath = utils.normalize_path(file_.dstpath) # If user has submitted a directory name as the destination but omitted # the destination filename, use the filename from source file if file_.dstpath.endswith('/'): @@ -593,6 +589,7 @@ def escape_for_makefile(fpath): # Escapes for CMake's "pathname" grammar as described here: # https://cmake.org/cmake/help/latest/command/add_custom_command.html#grammar-token-depfile-pathname # Which is congruent with how Ninja and GNU Make expect characters escaped. + fpath = utils.normalize_path(fpath) return fpath.replace('$', '$$').replace('#', '\\#').replace(' ', '\\ ') diff --git a/tools/utils.py b/tools/utils.py index f3b8294195237..7e1e771902b8b 100644 --- a/tools/utils.py +++ b/tools/utils.py @@ -25,6 +25,17 @@ def path_from_root(*pathelems): return str(Path(__rootpath__, *pathelems)) +def normalize_path(path): + """Normalize path separators to UNIX-style forward slashes. + + This can be useful when converting paths to URLs or JS strings, + or when trying to generate consistent output file contents + across all platforms. In most cases UNIX-style separators work + fine on windows. + """ + return path.replace('\\', '/').replace('//', '/') + + def safe_ensure_dirs(dirname): os.makedirs(dirname, exist_ok=True) diff --git a/tools/wasm-sourcemap.py b/tools/wasm-sourcemap.py index 3f0003ff3d0bd..a2b4685eaea6c 100755 --- a/tools/wasm-sourcemap.py +++ b/tools/wasm-sourcemap.py @@ -251,10 +251,6 @@ def read_dwarf_entries(wasm, options): return sorted(entries, key=lambda entry: entry['address']) -def normalize_path(path): - return path.replace('\\', '/').replace('//', '/') - - def build_sourcemap(entries, code_section_offset, prefixes, collect_sources, base_path): sources = [] sources_content = [] if collect_sources else None @@ -275,7 +271,7 @@ def build_sourcemap(entries, code_section_offset, prefixes, collect_sources, bas column = 1 address = entry['address'] + code_section_offset file_name = entry['file'] - file_name = normalize_path(file_name) + file_name = utils.normalize_path(file_name) # if prefixes were provided, we use that; otherwise, we emit a relative # path if prefixes.provided(): @@ -285,7 +281,7 @@ def build_sourcemap(entries, code_section_offset, prefixes, collect_sources, bas file_name = os.path.relpath(file_name, base_path) except ValueError: file_name = os.path.abspath(file_name) - file_name = normalize_path(file_name) + file_name = utils.normalize_path(file_name) source_name = file_name if source_name not in sources_map: source_id = len(sources) From 0ac2d7d40b88a56398f6551ed4da0b320fe5d232 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Mon, 31 Jul 2023 18:03:20 -0700 Subject: [PATCH 0598/1523] More use of JS method syntax. NFC (#19906) --- src/library.js | 4 +- src/library_async.js | 38 ++-- src/library_browser.js | 50 ++--- src/library_dylink.js | 2 +- src/library_egl.js | 4 +- src/library_fs.js | 198 +++++++++--------- src/library_glemu.js | 6 +- src/library_nodefs.js | 48 ++--- src/library_pthread.js | 30 ++- src/library_syscall.js | 8 +- src/library_tty.js | 32 +-- src/library_wasmfs.js | 50 ++--- src/library_wget.js | 2 +- src/library_workerfs.js | 4 +- .../metadce/test_metadce_cxx_ctors1.jssize | 2 +- .../metadce/test_metadce_cxx_ctors2.jssize | 2 +- .../metadce/test_metadce_cxx_except.jssize | 2 +- .../test_metadce_cxx_except_wasm.jssize | 2 +- .../metadce/test_metadce_cxx_mangle.jssize | 2 +- .../metadce/test_metadce_cxx_noexcept.jssize | 2 +- .../metadce/test_metadce_files_js_fs.jssize | 2 +- .../test_metadce_minimal_pthreads.jssize | 2 +- 22 files changed, 245 insertions(+), 247 deletions(-) diff --git a/src/library.js b/src/library.js index 4a7478d72b96f..31901ce36e4c8 100644 --- a/src/library.js +++ b/src/library.js @@ -1755,7 +1755,7 @@ mergeInto(LibraryManager.library, { names: {} }, - lookup_name: (name) => { + lookup_name(name) { // If the name is already a valid ipv4 / ipv6 address, don't generate a fake one. var res = inetPton4(name); if (res !== null) { @@ -1784,7 +1784,7 @@ mergeInto(LibraryManager.library, { return addr; }, - lookup_addr: (addr) => { + lookup_addr(addr) { if (DNS.address_map.names[addr]) { return DNS.address_map.names[addr]; } diff --git a/src/library_async.js b/src/library_async.js index c694352c425ab..75ee8bb6ecfe9 100644 --- a/src/library_async.js +++ b/src/library_async.js @@ -37,7 +37,7 @@ mergeInto(LibraryManager.library, { #if ASYNCIFY == 1 && MEMORY64 rewindArguments: {}, #endif - instrumentWasmImports: function(imports) { + instrumentWasmImports(imports) { #if ASYNCIFY_DEBUG dbg('asyncify instrumenting imports'); #endif @@ -108,14 +108,14 @@ mergeInto(LibraryManager.library, { } }, #if ASYNCIFY == 1 && MEMORY64 - saveOrRestoreRewindArguments: function(funcName, passedArguments) { + saveOrRestoreRewindArguments(funcName, passedArguments) { if (passedArguments.length === 0) { return Asyncify.rewindArguments[funcName] || [] } return Asyncify.rewindArguments[funcName] = Array.from(passedArguments) }, #endif - instrumentWasmExports: function(exports) { + instrumentWasmExports(exports) { #if ASYNCIFY_DEBUG dbg('asyncify instrumenting exports'); #endif @@ -205,7 +205,7 @@ mergeInto(LibraryManager.library, { asyncPromiseHandlers: null, // { resolve, reject } pair for when *all* asynchronicity is done sleepCallbacks: [], // functions to call every time we sleep - getCallStackId: function(funcName) { + getCallStackId(funcName) { var id = Asyncify.callStackNameToId[funcName]; if (id === undefined) { id = Asyncify.callStackId++; @@ -215,7 +215,7 @@ mergeInto(LibraryManager.library, { return id; }, - maybeStopUnwind: function() { + maybeStopUnwind() { #if ASYNCIFY_DEBUG dbg('ASYNCIFY: maybe stop unwind', Asyncify.exportCallStack); #endif @@ -240,7 +240,7 @@ mergeInto(LibraryManager.library, { } }, - whenDone: function() { + whenDone() { #if ASSERTIONS assert(Asyncify.currData, 'Tried to wait for an async operation when none is in progress.'); assert(!Asyncify.asyncPromiseHandlers, 'Cannot have multiple async operations in flight at once'); @@ -250,7 +250,7 @@ mergeInto(LibraryManager.library, { }); }, - allocateData: function() { + allocateData() { // An asyncify data structure has three fields: // 0 current stack pos // 4 max stack pos @@ -265,12 +265,12 @@ mergeInto(LibraryManager.library, { return ptr; }, - setDataHeader: function(ptr, stack, stackSize) { + setDataHeader(ptr, stack, stackSize) { {{{ makeSetValue('ptr', C_STRUCTS.asyncify_data_s.stack_ptr, 'stack', '*') }}}; {{{ makeSetValue('ptr', C_STRUCTS.asyncify_data_s.stack_limit, 'stack + stackSize', '*') }}}; }, - setDataRewindFunc: function(ptr) { + setDataRewindFunc(ptr) { var bottomOfCallStack = Asyncify.exportCallStack[0]; #if ASYNCIFY_DEBUG >= 2 dbg('ASYNCIFY: setDataRewindFunc('+ptr+'), bottomOfCallStack is', bottomOfCallStack, new Error().stack); @@ -282,7 +282,7 @@ mergeInto(LibraryManager.library, { #if RELOCATABLE getDataRewindFunc__deps: [ '$resolveGlobalSymbol' ], #endif - getDataRewindFunc: function(ptr) { + getDataRewindFunc(ptr) { var id = {{{ makeGetValue('ptr', C_STRUCTS.asyncify_data_s.rewind_id, 'i32') }}}; var name = Asyncify.callStackIdToName[id]; var func = wasmExports[name]; @@ -296,7 +296,7 @@ mergeInto(LibraryManager.library, { return func; }, - doRewind: function(ptr) { + doRewind(ptr) { var start = Asyncify.getDataRewindFunc(ptr); #if ASYNCIFY_DEBUG dbg('ASYNCIFY: start:', start); @@ -310,7 +310,7 @@ mergeInto(LibraryManager.library, { // This receives a function to call to start the async operation, and // handles everything else for the user of this API. See emscripten_sleep() // and other async methods for simple examples of usage. - handleSleep: function(startAsync) { + handleSleep(startAsync) { #if ASSERTIONS assert(Asyncify.state !== Asyncify.State.Disabled, 'Asyncify cannot be done during or after the runtime exits'); #endif @@ -424,7 +424,7 @@ mergeInto(LibraryManager.library, { // // This is particularly useful for native JS `async` functions where the // returned value will "just work" and be passed back to C++. - handleAsync: function(startAsync) { + handleAsync(startAsync) { return Asyncify.handleSleep((wakeUp) => { // TODO: add error handling as a second param when handleSleep implements it. startAsync().then(wakeUp); @@ -439,10 +439,10 @@ mergeInto(LibraryManager.library, { // Stores all the exported raw Wasm functions that are wrapped with async // WebAssembly.Functions. asyncExports: null, - isAsyncExport: function(func) { + isAsyncExport(func) { return Asyncify.asyncExports && Asyncify.asyncExports.has(func); }, - handleSleep: function(startAsync) { + handleSleep(startAsync) { {{{ runtimeKeepalivePush(); }}} var promise = new Promise((resolve) => { startAsync(resolve); @@ -452,13 +452,13 @@ mergeInto(LibraryManager.library, { }); return promise; }, - handleAsync: function(startAsync) { + handleAsync(startAsync) { return Asyncify.handleSleep((wakeUp) => { // TODO: add error handling as a second param when handleSleep implements it. startAsync().then(wakeUp); }); }, - makeAsyncFunction: function(original) { + makeAsyncFunction(original) { #if ASYNCIFY_DEBUG dbg('asyncify: returnPromiseOnSuspend for', original); #endif @@ -553,7 +553,7 @@ mergeInto(LibraryManager.library, { $Fibers: { nextFiber: 0, trampolineRunning: false, - trampoline: function() { + trampoline() { if (!Fibers.trampolineRunning && Fibers.nextFiber) { Fibers.trampolineRunning = true; do { @@ -570,7 +570,7 @@ mergeInto(LibraryManager.library, { /* * NOTE: This function is the asynchronous part of emscripten_fiber_swap. */ - finishContextSwitch: function(newFiber) { + finishContextSwitch(newFiber) { var stack_base = {{{ makeGetValue('newFiber', C_STRUCTS.emscripten_fiber_s.stack_base, '*') }}}; var stack_max = {{{ makeGetValue('newFiber', C_STRUCTS.emscripten_fiber_s.stack_limit, '*') }}}; _emscripten_stack_set_limits(stack_base, stack_max); diff --git a/src/library_browser.js b/src/library_browser.js index 52ebe47fe9b05..7863b243cd2bc 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -54,12 +54,12 @@ var LibraryBrowser = { timingValue: 0, currentFrameNumber: 0, queue: [], - pause: function() { + pause() { Browser.mainLoop.scheduler = null; // Incrementing this signals the previous main loop that it's now become old, and it must return. Browser.mainLoop.currentlyRunningMainloop++; }, - resume: function() { + resume() { Browser.mainLoop.currentlyRunningMainloop++; var timingMode = Browser.mainLoop.timingMode; var timingValue = Browser.mainLoop.timingValue; @@ -70,7 +70,7 @@ var LibraryBrowser = { _emscripten_set_main_loop_timing(timingMode, timingValue); Browser.mainLoop.scheduler(); }, - updateStatus: function() { + updateStatus() { if (Module['setStatus']) { var message = Module['statusMessage'] || 'Please wait...'; var remaining = Browser.mainLoop.remainingBlockers; @@ -86,7 +86,7 @@ var LibraryBrowser = { } } }, - runIter: function(func) { + runIter(func) { if (ABORT) return; if (Module['preMainLoop']) { var preRet = Module['preMainLoop'](); @@ -103,7 +103,7 @@ var LibraryBrowser = { moduleContextCreatedCallbacks: [], workers: [], - init: function() { + init() { if (Browser.initted) return; Browser.initted = true; @@ -255,7 +255,7 @@ var LibraryBrowser = { } }, - createContext: function(/** @type {HTMLCanvasElement} */ canvas, useWebGL, setInModule, webGLContextAttributes) { + createContext(/** @type {HTMLCanvasElement} */ canvas, useWebGL, setInModule, webGLContextAttributes) { if (useWebGL && Module.ctx && canvas == Module.canvas) return Module.ctx; // no need to recreate GL context if it's already been created for this canvas. var ctx; @@ -307,12 +307,12 @@ var LibraryBrowser = { return ctx; }, - destroyContext: function(canvas, useWebGL, setInModule) {}, + destroyContext(canvas, useWebGL, setInModule) {}, fullscreenHandlersInstalled: false, lockPointer: undefined, resizeCanvas: undefined, - requestFullscreen: function(lockPointer, resizeCanvas) { + requestFullscreen(lockPointer, resizeCanvas) { Browser.lockPointer = lockPointer; Browser.resizeCanvas = resizeCanvas; if (typeof Browser.lockPointer == 'undefined') Browser.lockPointer = true; @@ -372,12 +372,12 @@ var LibraryBrowser = { }, #if ASSERTIONS - requestFullScreen: function() { + requestFullScreen() { abort('Module.requestFullScreen has been replaced by Module.requestFullscreen (without a capital S)'); }, #endif - exitFullscreen: function() { + exitFullscreen() { // This is workaround for chrome. Trying to exit from fullscreen // not in fullscreen state will cause "TypeError: Document not active" // in chrome. See https://github.com/emscripten-core/emscripten/pull/8236 @@ -397,7 +397,7 @@ var LibraryBrowser = { nextRAF: 0, - fakeRequestAnimationFrame: function(func) { + fakeRequestAnimationFrame(func) { // try to keep 60fps between calls to here var now = Date.now(); if (Browser.nextRAF === 0) { @@ -411,7 +411,7 @@ var LibraryBrowser = { setTimeout(func, delay); }, - requestAnimationFrame: function(func) { + requestAnimationFrame(func) { if (typeof requestAnimationFrame == 'function') { requestAnimationFrame(func); return; @@ -432,13 +432,13 @@ var LibraryBrowser = { // abort and pause-aware versions TODO: build main loop on top of this? - safeSetTimeout: function(func, timeout) { + safeSetTimeout(func, timeout) { // Legacy function, this is used by the SDL2 port so we need to keep it // around at least until that is updated. // See https://github.com/libsdl-org/SDL/pull/6304 return safeSetTimeout(func, timeout); }, - safeRequestAnimationFrame: function(func) { + safeRequestAnimationFrame(func) { {{{ runtimeKeepalivePush() }}} return Browser.requestAnimationFrame(() => { {{{ runtimeKeepalivePop() }}} @@ -446,7 +446,7 @@ var LibraryBrowser = { }); }, - getMimetype: function(name) { + getMimetype(name) { return { 'jpg': 'image/jpeg', 'jpeg': 'image/jpeg', @@ -458,7 +458,7 @@ var LibraryBrowser = { }[name.substr(name.lastIndexOf('.')+1)]; }, - getUserMedia: function(func) { + getUserMedia(func) { if (!window.getUserMedia) { window.getUserMedia = navigator['getUserMedia'] || navigator['mozGetUserMedia']; @@ -467,14 +467,14 @@ var LibraryBrowser = { }, - getMovementX: function(event) { + getMovementX(event) { return event['movementX'] || event['mozMovementX'] || event['webkitMovementX'] || 0; }, - getMovementY: function(event) { + getMovementY(event) { return event['movementY'] || event['mozMovementY'] || event['webkitMovementY'] || @@ -490,7 +490,7 @@ var LibraryBrowser = { // this as an integer, don't simply cast to int, or you may receive scroll events for wheel delta == 0. // NOTE: We convert all units returned by events into steps, i.e. individual wheel notches. // These conversions are only approximations. Changing browsers, operating systems, or even settings can change the values. - getMouseWheelDelta: function(event) { + getMouseWheelDelta(event) { var delta = 0; switch (event.type) { case 'DOMMouseScroll': @@ -533,7 +533,7 @@ var LibraryBrowser = { touches: {}, lastTouches: {}, - calculateMouseEvent: function(event) { // event should be mousemove, mousedown or mouseup + calculateMouseEvent(event) { // event should be mousemove, mousedown or mouseup if (Browser.pointerLock) { // When the pointer is locked, calculate the coordinates // based on the movement of the mouse. @@ -618,12 +618,12 @@ var LibraryBrowser = { resizeListeners: [], - updateResizeListeners: function() { + updateResizeListeners() { var canvas = Module['canvas']; Browser.resizeListeners.forEach((listener) => listener(canvas.width, canvas.height)); }, - setCanvasSize: function(width, height, noUpdates) { + setCanvasSize(width, height, noUpdates) { var canvas = Module['canvas']; Browser.updateCanvasDimensions(canvas, width, height); if (!noUpdates) Browser.updateResizeListeners(); @@ -631,7 +631,7 @@ var LibraryBrowser = { windowedWidth: 0, windowedHeight: 0, - setFullscreenCanvasSize: function() { + setFullscreenCanvasSize() { // check if SDL is available if (typeof SDL != "undefined") { var flags = {{{ makeGetValue('SDL.screen', '0', 'u32') }}}; @@ -642,7 +642,7 @@ var LibraryBrowser = { Browser.updateResizeListeners(); }, - setWindowedCanvasSize: function() { + setWindowedCanvasSize() { // check if SDL is available if (typeof SDL != "undefined") { var flags = {{{ makeGetValue('SDL.screen', '0', 'u32') }}}; @@ -653,7 +653,7 @@ var LibraryBrowser = { Browser.updateResizeListeners(); }, - updateCanvasDimensions : function(canvas, wNative, hNative) { + updateCanvasDimensions(canvas, wNative, hNative) { if (wNative && hNative) { canvas.widthNative = wNative; canvas.heightNative = hNative; diff --git a/src/library_dylink.js b/src/library_dylink.js index d95f87a67cb91..9d0beac9f200a 100644 --- a/src/library_dylink.js +++ b/src/library_dylink.js @@ -331,7 +331,7 @@ var LibraryDylink = { loadedLibsByName: {}, // handle -> dso; Used by dlsym loadedLibsByHandle: {}, - init: () => { + init() { #if ASSERTIONS // This function needs to run after the initial wasmImports object // as been created. diff --git a/src/library_egl.js b/src/library_egl.js index 01b5ec4736bed..c78b3fa972bb3 100644 --- a/src/library_egl.js +++ b/src/library_egl.js @@ -34,11 +34,11 @@ var LibraryEGL = { stringCache: {}, - setErrorCode: function(code) { + setErrorCode(code) { EGL.errorCode = code; }, - chooseConfig: function(display, attribList, config, config_size, numConfigs) { + chooseConfig(display, attribList, config, config_size, numConfigs) { if (display != 62000 /* Magic ID for Emscripten 'default display' */) { EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); return 0; diff --git a/src/library_fs.js b/src/library_fs.js index 5994dc2ce9cbc..c19be6b53bf60 100644 --- a/src/library_fs.js +++ b/src/library_fs.js @@ -33,7 +33,7 @@ mergeInto(LibraryManager.library, { #if ASSERTIONS && !MINIMAL_RUNTIME '$demangleAll', #endif - ], + ], $FS__postset: function() { // TODO: do we need noFSInit? addAtInit(` @@ -121,7 +121,7 @@ FS.staticInit();` + // // paths // - lookupPath: (path, opts = {}) => { + lookupPath(path, opts = {}) { path = PATH_FS.resolve(path); if (!path) return { path: '', node: null }; @@ -180,7 +180,7 @@ FS.staticInit();` + return { path: current_path, node: current }; }, - getPath: (node) => { + getPath(node) { var path; while (true) { if (FS.isRoot(node)) { @@ -196,7 +196,7 @@ FS.staticInit();` + // // nodes // - hashName: (parentid, name) => { + hashName(parentid, name) { var hash = 0; #if CASE_INSENSITIVE_FS @@ -208,12 +208,12 @@ FS.staticInit();` + } return ((parentid + hash) >>> 0) % FS.nameTable.length; }, - hashAddNode: (node) => { + hashAddNode(node) { var hash = FS.hashName(node.parent.id, node.name); node.name_next = FS.nameTable[hash]; FS.nameTable[hash] = node; }, - hashRemoveNode: (node) => { + hashRemoveNode(node) { var hash = FS.hashName(node.parent.id, node.name); if (FS.nameTable[hash] === node) { FS.nameTable[hash] = node.name_next; @@ -228,7 +228,7 @@ FS.staticInit();` + } } }, - lookupNode: (parent, name) => { + lookupNode(parent, name) { var errCode = FS.mayLookup(parent); if (errCode) { throw new FS.ErrnoError(errCode, parent); @@ -249,7 +249,7 @@ FS.staticInit();` + // if we failed to find it in the cache, call into the VFS return FS.lookup(parent, name); }, - createNode: (parent, name, mode, rdev) => { + createNode(parent, name, mode, rdev) { #if ASSERTIONS assert(typeof parent == 'object') #endif @@ -259,34 +259,34 @@ FS.staticInit();` + return node; }, - destroyNode: (node) => { + destroyNode(node) { FS.hashRemoveNode(node); }, - isRoot: (node) => { + isRoot(node) { return node === node.parent; }, - isMountpoint: (node) => { + isMountpoint(node) { return !!node.mounted; }, - isFile: (mode) => { + isFile(mode) { return (mode & {{{ cDefs.S_IFMT }}}) === {{{ cDefs.S_IFREG }}}; }, - isDir: (mode) => { + isDir(mode) { return (mode & {{{ cDefs.S_IFMT }}}) === {{{ cDefs.S_IFDIR }}}; }, - isLink: (mode) => { + isLink(mode) { return (mode & {{{ cDefs.S_IFMT }}}) === {{{ cDefs.S_IFLNK }}}; }, - isChrdev: (mode) => { + isChrdev(mode) { return (mode & {{{ cDefs.S_IFMT }}}) === {{{ cDefs.S_IFCHR }}}; }, - isBlkdev: (mode) => { + isBlkdev(mode) { return (mode & {{{ cDefs.S_IFMT }}}) === {{{ cDefs.S_IFBLK }}}; }, - isFIFO: (mode) => { + isFIFO(mode) { return (mode & {{{ cDefs.S_IFMT }}}) === {{{ cDefs.S_IFIFO }}}; }, - isSocket: (mode) => { + isSocket(mode) { return (mode & {{{ cDefs.S_IFSOCK }}}) === {{{ cDefs.S_IFSOCK }}}; }, @@ -294,14 +294,14 @@ FS.staticInit();` + // permissions // // convert O_* bitmask to a string for nodePermissions - flagsToPermissionString: (flag) => { + flagsToPermissionString(flag) { var perms = ['r', 'w', 'rw'][flag & 3]; if ((flag & {{{ cDefs.O_TRUNC }}})) { perms += 'w'; } return perms; }, - nodePermissions: (node, perms) => { + nodePermissions(node, perms) { if (FS.ignorePermissions) { return 0; } @@ -315,13 +315,13 @@ FS.staticInit();` + } return 0; }, - mayLookup: (dir) => { + mayLookup(dir) { var errCode = FS.nodePermissions(dir, 'x'); if (errCode) return errCode; if (!dir.node_ops.lookup) return {{{ cDefs.EACCES }}}; return 0; }, - mayCreate: (dir, name) => { + mayCreate(dir, name) { try { var node = FS.lookupNode(dir, name); return {{{ cDefs.EEXIST }}}; @@ -329,7 +329,7 @@ FS.staticInit();` + } return FS.nodePermissions(dir, 'wx'); }, - mayDelete: (dir, name, isdir) => { + mayDelete(dir, name, isdir) { var node; try { node = FS.lookupNode(dir, name); @@ -354,7 +354,7 @@ FS.staticInit();` + } return 0; }, - mayOpen: (node, flags) => { + mayOpen(node, flags) { if (!node) { return {{{ cDefs.ENOENT }}}; } @@ -373,7 +373,7 @@ FS.staticInit();` + // streams // MAX_OPEN_FDS: 4096, - nextfd: () => { + nextfd() { for (var fd = 0; fd <= FS.MAX_OPEN_FDS; fd++) { if (!FS.streams[fd]) { return fd; @@ -381,7 +381,7 @@ FS.staticInit();` + } throw new FS.ErrnoError({{{ cDefs.EMFILE }}}); }, - getStreamChecked: (fd) => { + getStreamChecked(fd) { var stream = FS.getStream(fd); if (!stream) { throw new FS.ErrnoError({{{ cDefs.EBADF }}}); @@ -392,7 +392,7 @@ FS.staticInit();` + // TODO parameterize this function such that a stream // object isn't directly passed in. not possible until // SOCKFS is completed. - createStream: (stream, fd = -1) => { + createStream(stream, fd = -1) { if (!FS.FSStream) { FS.FSStream = /** @constructor */ function() { this.shared = { }; @@ -440,7 +440,7 @@ FS.staticInit();` + FS.streams[fd] = stream; return stream; }, - closeStream: (fd) => { + closeStream(fd) { FS.streams[fd] = null; }, @@ -454,7 +454,7 @@ FS.staticInit();` + // however, once opened, the stream's operations are overridden with // the operations of the device its underlying node maps back to. chrdev_stream_ops: { - open: (stream) => { + open(stream) { var device = FS.getDevice(stream.node.rdev); // override node's stream ops with the device's stream.stream_ops = device.stream_ops; @@ -463,14 +463,14 @@ FS.staticInit();` + stream.stream_ops.open(stream); } }, - llseek: () => { + llseek() { throw new FS.ErrnoError({{{ cDefs.ESPIPE }}}); } }, major: (dev) => ((dev) >> 8), minor: (dev) => ((dev) & 0xff), makedev: (ma, mi) => ((ma) << 8 | (mi)), - registerDevice: (dev, ops) => { + registerDevice(dev, ops) { FS.devices[dev] = { stream_ops: ops }; }, getDevice: (dev) => FS.devices[dev], @@ -478,7 +478,7 @@ FS.staticInit();` + // // core // - getMounts: (mount) => { + getMounts(mount) { var mounts = []; var check = [mount]; @@ -492,7 +492,7 @@ FS.staticInit();` + return mounts; }, - syncfs: (populate, callback) => { + syncfs(populate, callback) { if (typeof populate == 'function') { callback = populate; populate = false; @@ -536,7 +536,7 @@ FS.staticInit();` + mount.type.syncfs(mount, populate, done); }); }, - mount: (type, opts, mountpoint) => { + mount(type, opts, mountpoint) { #if ASSERTIONS if (typeof type == 'string') { // The filesystem was not included, and instead we have an error @@ -591,7 +591,7 @@ FS.staticInit();` + return mountRoot; }, - unmount: (mountpoint) => { + unmount(mountpoint) { var lookup = FS.lookupPath(mountpoint, { follow_mount: false }); if (!FS.isMountpoint(lookup.node)) { @@ -627,11 +627,11 @@ FS.staticInit();` + #endif node.mount.mounts.splice(idx, 1); }, - lookup: (parent, name) => { + lookup(parent, name) { return parent.node_ops.lookup(parent, name); }, // generic function for all node creation - mknod: (path, mode, dev) => { + mknod(path, mode, dev) { var lookup = FS.lookupPath(path, { parent: true }); var parent = lookup.node; var name = PATH.basename(path); @@ -648,13 +648,13 @@ FS.staticInit();` + return parent.node_ops.mknod(parent, name, mode, dev); }, // helpers to create specific types of nodes - create: (path, mode) => { + create(path, mode) { mode = mode !== undefined ? mode : 438 /* 0666 */; mode &= {{{ cDefs.S_IALLUGO }}}; mode |= {{{ cDefs.S_IFREG }}}; return FS.mknod(path, mode, 0); }, - mkdir: (path, mode) => { + mkdir(path, mode) { mode = mode !== undefined ? mode : 511 /* 0777 */; mode &= {{{ cDefs.S_IRWXUGO }}} | {{{ cDefs.S_ISVTX }}}; mode |= {{{ cDefs.S_IFDIR }}}; @@ -666,7 +666,7 @@ FS.staticInit();` + return FS.mknod(path, mode, 0); }, // Creates a whole directory tree chain if it doesn't yet exist - mkdirTree: (path, mode) => { + mkdirTree(path, mode) { var dirs = path.split('/'); var d = ''; for (var i = 0; i < dirs.length; ++i) { @@ -679,7 +679,7 @@ FS.staticInit();` + } } }, - mkdev: (path, mode, dev) => { + mkdev(path, mode, dev) { if (typeof dev == 'undefined') { dev = mode; mode = 438 /* 0666 */; @@ -687,7 +687,7 @@ FS.staticInit();` + mode |= {{{ cDefs.S_IFCHR }}}; return FS.mknod(path, mode, dev); }, - symlink: (oldpath, newpath) => { + symlink(oldpath, newpath) { if (!PATH_FS.resolve(oldpath)) { throw new FS.ErrnoError({{{ cDefs.ENOENT }}}); } @@ -711,7 +711,7 @@ FS.staticInit();` + #endif return parent.node_ops.symlink(parent, newname, oldpath); }, - rename: (old_path, new_path) => { + rename(old_path, new_path) { var old_dirname = PATH.dirname(old_path); var new_dirname = PATH.dirname(new_path); var old_name = PATH.basename(old_path); @@ -803,7 +803,7 @@ FS.staticInit();` + } #endif }, - rmdir: (path) => { + rmdir(path) { var lookup = FS.lookupPath(path, { parent: true }); var parent = lookup.node; var name = PATH.basename(path); @@ -831,7 +831,7 @@ FS.staticInit();` + } #endif }, - readdir: (path) => { + readdir(path) { var lookup = FS.lookupPath(path, { follow: true }); var node = lookup.node; if (!node.node_ops.readdir) { @@ -839,7 +839,7 @@ FS.staticInit();` + } return node.node_ops.readdir(node); }, - unlink: (path) => { + unlink(path) { var lookup = FS.lookupPath(path, { parent: true }); var parent = lookup.node; if (!parent) { @@ -873,7 +873,7 @@ FS.staticInit();` + } #endif }, - readlink: (path) => { + readlink(path) { var lookup = FS.lookupPath(path); var link = lookup.node; if (!link) { @@ -884,7 +884,7 @@ FS.staticInit();` + } return PATH_FS.resolve(FS.getPath(link.parent), link.node_ops.readlink(link)); }, - stat: (path, dontFollow) => { + stat(path, dontFollow) { var lookup = FS.lookupPath(path, { follow: !dontFollow }); var node = lookup.node; if (!node) { @@ -895,10 +895,10 @@ FS.staticInit();` + } return node.node_ops.getattr(node); }, - lstat: (path) => { + lstat(path) { return FS.stat(path, true); }, - chmod: (path, mode, dontFollow) => { + chmod(path, mode, dontFollow) { var node; if (typeof path == 'string') { var lookup = FS.lookupPath(path, { follow: !dontFollow }); @@ -914,14 +914,14 @@ FS.staticInit();` + timestamp: Date.now() }); }, - lchmod: (path, mode) => { + lchmod(path, mode) { FS.chmod(path, mode, true); }, - fchmod: (fd, mode) => { + fchmod(fd, mode) { var stream = FS.getStreamChecked(fd); FS.chmod(stream.node, mode); }, - chown: (path, uid, gid, dontFollow) => { + chown(path, uid, gid, dontFollow) { var node; if (typeof path == 'string') { var lookup = FS.lookupPath(path, { follow: !dontFollow }); @@ -937,14 +937,14 @@ FS.staticInit();` + // we ignore the uid / gid for now }); }, - lchown: (path, uid, gid) => { + lchown(path, uid, gid) { FS.chown(path, uid, gid, true); }, - fchown: (fd, uid, gid) => { + fchown(fd, uid, gid) { var stream = FS.getStreamChecked(fd); FS.chown(stream.node, uid, gid); }, - truncate: (path, len) => { + truncate(path, len) { if (len < 0) { throw new FS.ErrnoError({{{ cDefs.EINVAL }}}); } @@ -973,21 +973,21 @@ FS.staticInit();` + timestamp: Date.now() }); }, - ftruncate: (fd, len) => { + ftruncate(fd, len) { var stream = FS.getStreamChecked(fd); if ((stream.flags & {{{ cDefs.O_ACCMODE }}}) === {{{ cDefs.O_RDONLY}}}) { throw new FS.ErrnoError({{{ cDefs.EINVAL }}}); } FS.truncate(stream.node, len); }, - utime: (path, atime, mtime) => { + utime(path, atime, mtime) { var lookup = FS.lookupPath(path, { follow: true }); var node = lookup.node; node.node_ops.setattr(node, { timestamp: Math.max(atime, mtime) }); }, - open: (path, flags, mode) => { + open(path, flags, mode) { if (path === "") { throw new FS.ErrnoError({{{ cDefs.ENOENT }}}); } @@ -1088,7 +1088,7 @@ FS.staticInit();` + #endif return stream; }, - close: (stream) => { + close(stream) { if (FS.isClosed(stream)) { throw new FS.ErrnoError({{{ cDefs.EBADF }}}); } @@ -1109,10 +1109,10 @@ FS.staticInit();` + } #endif }, - isClosed: (stream) => { + isClosed(stream) { return stream.fd === null; }, - llseek: (stream, offset, whence) => { + llseek(stream, offset, whence) { if (FS.isClosed(stream)) { throw new FS.ErrnoError({{{ cDefs.EBADF }}}); } @@ -1131,7 +1131,7 @@ FS.staticInit();` + #endif return stream.position; }, - read: (stream, buffer, offset, length, position) => { + read(stream, buffer, offset, length, position) { #if ASSERTIONS assert(offset >= 0); #endif @@ -1165,7 +1165,7 @@ FS.staticInit();` + #endif return bytesRead; }, - write: (stream, buffer, offset, length, position, canOwn) => { + write(stream, buffer, offset, length, position, canOwn) { #if ASSERTIONS assert(offset >= 0); #endif @@ -1203,7 +1203,7 @@ FS.staticInit();` + #endif return bytesWritten; }, - allocate: (stream, offset, length) => { + allocate(stream, offset, length) { if (FS.isClosed(stream)) { throw new FS.ErrnoError({{{ cDefs.EBADF }}}); } @@ -1221,7 +1221,7 @@ FS.staticInit();` + } stream.stream_ops.allocate(stream, offset, length); }, - mmap: (stream, length, position, prot, flags) => { + mmap(stream, length, position, prot, flags) { // User requests writing to file (prot & PROT_WRITE != 0). // Checking if we have permissions to write to the file unless // MAP_PRIVATE flag is set. According to POSIX spec it is possible @@ -1241,7 +1241,7 @@ FS.staticInit();` + } return stream.stream_ops.mmap(stream, length, position, prot, flags); }, - msync: (stream, buffer, offset, length, mmapFlags) => { + msync(stream, buffer, offset, length, mmapFlags) { #if ASSERTIONS assert(offset >= 0); #endif @@ -1251,13 +1251,13 @@ FS.staticInit();` + return stream.stream_ops.msync(stream, buffer, offset, length, mmapFlags); }, munmap: (stream) => 0, - ioctl: (stream, cmd, arg) => { + ioctl(stream, cmd, arg) { if (!stream.stream_ops.ioctl) { throw new FS.ErrnoError({{{ cDefs.ENOTTY }}}); } return stream.stream_ops.ioctl(stream, cmd, arg); }, - readFile: (path, opts = {}) => { + readFile(path, opts = {}) { opts.flags = opts.flags || {{{ cDefs.O_RDONLY }}}; opts.encoding = opts.encoding || 'binary'; if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') { @@ -1277,7 +1277,7 @@ FS.staticInit();` + FS.close(stream); return ret; }, - writeFile: (path, data, opts = {}) => { + writeFile(path, data, opts = {}) { opts.flags = opts.flags || {{{ cDefs.O_TRUNC | cDefs.O_CREAT | cDefs.O_WRONLY }}}; var stream = FS.open(path, opts.flags, opts.mode); if (typeof data == 'string') { @@ -1296,7 +1296,7 @@ FS.staticInit();` + // module-level FS code // cwd: () => FS.currentPath, - chdir: (path) => { + chdir(path) { var lookup = FS.lookupPath(path, { follow: true }); if (lookup.node === null) { throw new FS.ErrnoError({{{ cDefs.ENOENT }}}); @@ -1310,12 +1310,12 @@ FS.staticInit();` + } FS.currentPath = lookup.path; }, - createDefaultDirectories: () => { + createDefaultDirectories() { FS.mkdir('/tmp'); FS.mkdir('/home'); FS.mkdir('/home/web_user'); }, - createDefaultDevices: () => { + createDefaultDevices() { // create /dev FS.mkdir('/dev'); // setup /dev/null @@ -1347,17 +1347,17 @@ FS.staticInit();` + FS.mkdir('/dev/shm'); FS.mkdir('/dev/shm/tmp'); }, - createSpecialDirectories: () => { + createSpecialDirectories() { // create /proc/self/fd which allows /proc/self/fd/6 => readlink gives the // name of the stream for fd 6 (see test_unistd_ttyname) FS.mkdir('/proc'); var proc_self = FS.mkdir('/proc/self'); FS.mkdir('/proc/self/fd'); FS.mount({ - mount: () => { + mount() { var node = FS.createNode(proc_self, 'fd', {{{ cDefs.S_IFDIR }}} | 511 /* 0777 */, {{{ cDefs.S_IXUGO }}}); node.node_ops = { - lookup: (parent, name) => { + lookup(parent, name) { var fd = +name; var stream = FS.getStreamChecked(fd); var ret = { @@ -1373,7 +1373,7 @@ FS.staticInit();` + } }, {}, '/proc/self/fd'); }, - createStandardStreams: () => { + createStandardStreams() { // TODO deprecate the old functionality of a single // input / output callback and that utilizes FS.createDevice // and instead require a unique set of stream ops @@ -1408,7 +1408,7 @@ FS.staticInit();` + assert(stderr.fd === 2, `invalid handle for stderr (${stderr.fd})`); #endif }, - ensureErrnoError: () => { + ensureErrnoError() { if (FS.ErrnoError) return; FS.ErrnoError = /** @this{Object} */ function ErrnoError(errno, node) { // We set the `name` property to be able to identify `FS.ErrnoError` @@ -1455,7 +1455,7 @@ FS.staticInit();` + FS.genericErrors[code].stack = ''; }); }, - staticInit: () => { + staticInit() { FS.ensureErrnoError(); FS.nameTable = new Array(4096); @@ -1482,7 +1482,7 @@ FS.staticInit();` + #endif }; }, - init: (input, output, error) => { + init(input, output, error) { #if ASSERTIONS assert(!FS.init.initialized, 'FS.init was previously called. If you want to initialize later with custom parameters, remove any earlier calls (note that one is automatically added to the generated code)'); #endif @@ -1497,7 +1497,7 @@ FS.staticInit();` + FS.createStandardStreams(); }, - quit: () => { + quit() { FS.init.initialized = false; // force-flush all streams, so we get musl std streams printed out #if hasExportedSymbol('fflush') @@ -1516,14 +1516,14 @@ FS.staticInit();` + // // old v1 compatibility functions // - findObject: (path, dontResolveLastLink) => { + findObject(path, dontResolveLastLink) { var ret = FS.analyzePath(path, dontResolveLastLink); if (!ret.exists) { return null; } return ret.object; }, - analyzePath: (path, dontResolveLastLink) => { + analyzePath(path, dontResolveLastLink) { // operate from within the context of the symlink's target try { var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink }); @@ -1551,7 +1551,7 @@ FS.staticInit();` + }; return ret; }, - createPath: (parent, path, canRead, canWrite) => { + createPath(parent, path, canRead, canWrite) { parent = typeof parent == 'string' ? parent : FS.getPath(parent); var parts = path.split('/').reverse(); while (parts.length) { @@ -1567,12 +1567,12 @@ FS.staticInit();` + } return current; }, - createFile: (parent, name, properties, canRead, canWrite) => { + createFile(parent, name, properties, canRead, canWrite) { var path = PATH.join2(typeof parent == 'string' ? parent : FS.getPath(parent), name); var mode = FS_getMode(canRead, canWrite); return FS.create(path, mode); }, - createDataFile: (parent, name, data, canRead, canWrite, canOwn) => { + createDataFile(parent, name, data, canRead, canWrite, canOwn) { var path = name; if (parent) { parent = typeof parent == 'string' ? parent : FS.getPath(parent); @@ -1595,7 +1595,7 @@ FS.staticInit();` + } return node; }, - createDevice: (parent, name, input, output) => { + createDevice(parent, name, input, output) { var path = PATH.join2(typeof parent == 'string' ? parent : FS.getPath(parent), name); var mode = FS_getMode(!!input, !!output); if (!FS.createDevice.major) FS.createDevice.major = 64; @@ -1603,16 +1603,16 @@ FS.staticInit();` + // Create a fake device that a set of stream ops to emulate // the old behavior. FS.registerDevice(dev, { - open: (stream) => { + open(stream) { stream.seekable = false; }, - close: (stream) => { + close(stream) { // flush any pending line data if (output && output.buffer && output.buffer.length) { output({{{ charCode('\n') }}}); } }, - read: (stream, buffer, offset, length, pos /* ignored */) => { + read(stream, buffer, offset, length, pos /* ignored */) { var bytesRead = 0; for (var i = 0; i < length; i++) { var result; @@ -1633,7 +1633,7 @@ FS.staticInit();` + } return bytesRead; }, - write: (stream, buffer, offset, length, pos) => { + write(stream, buffer, offset, length, pos) { for (var i = 0; i < length; i++) { try { output(buffer[offset+i]); @@ -1651,7 +1651,7 @@ FS.staticInit();` + }, // Makes sure a file's contents are loaded. Returns whether the file has // been loaded successfully. No-op for files that have been loaded already. - forceLoadFile: (obj) => { + forceLoadFile(obj) { if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true; if (typeof XMLHttpRequest != 'undefined') { throw new Error("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread."); @@ -1672,7 +1672,7 @@ FS.staticInit();` + // Creates a file record for lazy-loading from a URL. XXX This requires a synchronous // XHR, which is not possible in browsers except in a web worker! Use preloading, // either --preload-file in emcc or FS.createPreloadedFile - createLazyFile: (parent, name, url, canRead, canWrite) => { + createLazyFile(parent, name, url, canRead, canWrite) { // Lazy chunked Uint8Array (implements get and length from Uint8Array). Actual getting is abstracted away for eventual reuse. /** @constructor */ function LazyUint8Array() { @@ -1849,22 +1849,22 @@ FS.staticInit();` + // Removed v1 functions #if ASSERTIONS - absolutePath: () => { + absolutePath() { abort('FS.absolutePath has been removed; use PATH_FS.resolve instead'); }, - createFolder: () => { + createFolder() { abort('FS.createFolder has been removed; use FS.mkdir instead'); }, - createLink: () => { + createLink() { abort('FS.createLink has been removed; use FS.symlink instead'); }, - joinPath: () => { + joinPath() { abort('FS.joinPath has been removed; use PATH.join instead'); }, - mmapAlloc: () => { + mmapAlloc() { abort('FS.mmapAlloc has been replaced by the top level function mmapAlloc'); }, - standardizePath: () => { + standardizePath() { abort('FS.standardizePath has been removed; use PATH.normalize instead'); }, #endif diff --git a/src/library_glemu.js b/src/library_glemu.js index c7e2c753763de..01e3f7d9dafa6 100644 --- a/src/library_glemu.js +++ b/src/library_glemu.js @@ -95,7 +95,7 @@ var LibraryGLEmulation = { hasRunInit: false, // Find a token in a shader source string - findToken: function(source, token) { + findToken(source, token) { function isIdentChar(ch) { if (ch >= 48 && ch <= 57) // 0-9 return true; @@ -123,7 +123,7 @@ var LibraryGLEmulation = { return false; }, - init: function() { + init() { // Do not activate immediate/emulation code (e.g. replace glDrawElements) when in FULL_ES2 mode. // We do not need full emulation, we instead emulate client-side arrays etc. in FULL_ES2 code in // a straightforward manner, and avoid not having a bound buffer be ambiguous between es2 emulation @@ -698,7 +698,7 @@ var LibraryGLEmulation = { }; }, - getAttributeFromCapability: function(cap) { + getAttributeFromCapability(cap) { var attrib = null; switch (cap) { case 0xDE1: // GL_TEXTURE_2D - XXX not according to spec, and not in desktop GL, but works in some GLES1.x apparently, so support it diff --git a/src/library_nodefs.js b/src/library_nodefs.js index 7686dfd519a10..a9d73751da139 100644 --- a/src/library_nodefs.js +++ b/src/library_nodefs.js @@ -9,7 +9,7 @@ mergeInto(LibraryManager.library, { $NODEFS__postset: 'if (ENVIRONMENT_IS_NODE) { NODEFS.staticInit(); }', $NODEFS: { isWindows: false, - staticInit: () => { + staticInit() { NODEFS.isWindows = !!process.platform.match(/^win/); var flags = process.binding("constants"); // Node.js 4 compatibility: it has no namespaces for constants @@ -34,20 +34,20 @@ mergeInto(LibraryManager.library, { assert(NODEFS.flagsForNodeMap["0"] === 0); #endif }, - convertNodeCode: (e) => { + convertNodeCode(e) { var code = e.code; #if ASSERTIONS assert(code in ERRNO_CODES, `unexpected node error code: ${code} (${e})`); #endif return ERRNO_CODES[code]; }, - mount: (mount) => { + mount(mount) { #if ASSERTIONS assert(ENVIRONMENT_IS_NODE); #endif return NODEFS.createNode(null, '/', NODEFS.getMode(mount.opts.root), 0); }, - createNode: (parent, name, mode, dev) => { + createNode(parent, name, mode, dev) { if (!FS.isDir(mode) && !FS.isFile(mode) && !FS.isLink(mode)) { throw new FS.ErrnoError({{{ cDefs.EINVAL }}}); } @@ -56,7 +56,7 @@ mergeInto(LibraryManager.library, { node.stream_ops = NODEFS.stream_ops; return node; }, - getMode: (path) => { + getMode(path) { var stat; try { stat = fs.lstatSync(path); @@ -71,7 +71,7 @@ mergeInto(LibraryManager.library, { } return stat.mode; }, - realPath: (node) => { + realPath(node) { var parts = []; while (node.parent !== node) { parts.push(node.name); @@ -83,7 +83,7 @@ mergeInto(LibraryManager.library, { }, // This maps the integer permission modes from http://linux.die.net/man/3/open // to node.js-specific file open permission strings at http://nodejs.org/api/fs.html#fs_fs_open_path_flags_mode_callback - flagsForNode: (flags) => { + flagsForNode(flags) { flags &= ~{{{ cDefs.O_PATH }}}; // Ignore this flag from musl, otherwise node.js fails to open the file. flags &= ~{{{ cDefs.O_NONBLOCK }}}; // Ignore this flag from musl, otherwise node.js fails to open the file. flags &= ~{{{ cDefs.O_LARGEFILE }}}; // Ignore this flag from musl, otherwise node.js fails to open the file. @@ -102,7 +102,7 @@ mergeInto(LibraryManager.library, { return newFlags; }, node_ops: { - getattr: (node) => { + getattr(node) { var path = NODEFS.realPath(node); var stat; try { @@ -135,7 +135,7 @@ mergeInto(LibraryManager.library, { blocks: stat.blocks }; }, - setattr: (node, attr) => { + setattr(node, attr) { var path = NODEFS.realPath(node); try { if (attr.mode !== undefined) { @@ -155,12 +155,12 @@ mergeInto(LibraryManager.library, { throw new FS.ErrnoError(NODEFS.convertNodeCode(e)); } }, - lookup: (parent, name) => { + lookup(parent, name) { var path = PATH.join2(NODEFS.realPath(parent), name); var mode = NODEFS.getMode(path); return NODEFS.createNode(parent, name, mode); }, - mknod: (parent, name, mode, dev) => { + mknod(parent, name, mode, dev) { var node = NODEFS.createNode(parent, name, mode, dev); // create the backing node for this in the fs root as well var path = NODEFS.realPath(node); @@ -176,7 +176,7 @@ mergeInto(LibraryManager.library, { } return node; }, - rename: (oldNode, newDir, newName) => { + rename(oldNode, newDir, newName) { var oldPath = NODEFS.realPath(oldNode); var newPath = PATH.join2(NODEFS.realPath(newDir), newName); try { @@ -187,7 +187,7 @@ mergeInto(LibraryManager.library, { } oldNode.name = newName; }, - unlink: (parent, name) => { + unlink(parent, name) { var path = PATH.join2(NODEFS.realPath(parent), name); try { fs.unlinkSync(path); @@ -196,7 +196,7 @@ mergeInto(LibraryManager.library, { throw new FS.ErrnoError(NODEFS.convertNodeCode(e)); } }, - rmdir: (parent, name) => { + rmdir(parent, name) { var path = PATH.join2(NODEFS.realPath(parent), name); try { fs.rmdirSync(path); @@ -205,7 +205,7 @@ mergeInto(LibraryManager.library, { throw new FS.ErrnoError(NODEFS.convertNodeCode(e)); } }, - readdir: (node) => { + readdir(node) { var path = NODEFS.realPath(node); try { return fs.readdirSync(path); @@ -214,7 +214,7 @@ mergeInto(LibraryManager.library, { throw new FS.ErrnoError(NODEFS.convertNodeCode(e)); } }, - symlink: (parent, newName, oldPath) => { + symlink(parent, newName, oldPath) { var newPath = PATH.join2(NODEFS.realPath(parent), newName); try { fs.symlinkSync(oldPath, newPath); @@ -223,7 +223,7 @@ mergeInto(LibraryManager.library, { throw new FS.ErrnoError(NODEFS.convertNodeCode(e)); } }, - readlink: (node) => { + readlink(node) { var path = NODEFS.realPath(node); try { path = fs.readlinkSync(path); @@ -239,7 +239,7 @@ mergeInto(LibraryManager.library, { }, }, stream_ops: { - open: (stream) => { + open(stream) { var path = NODEFS.realPath(stream.node); try { if (FS.isFile(stream.node.mode)) { @@ -250,7 +250,7 @@ mergeInto(LibraryManager.library, { throw new FS.ErrnoError(NODEFS.convertNodeCode(e)); } }, - close: (stream) => { + close(stream) { try { if (FS.isFile(stream.node.mode) && stream.nfd) { fs.closeSync(stream.nfd); @@ -260,7 +260,7 @@ mergeInto(LibraryManager.library, { throw new FS.ErrnoError(NODEFS.convertNodeCode(e)); } }, - read: (stream, buffer, offset, length, position) => { + read(stream, buffer, offset, length, position) { // Node.js < 6 compatibility: node errors on 0 length reads if (length === 0) return 0; try { @@ -269,14 +269,14 @@ mergeInto(LibraryManager.library, { throw new FS.ErrnoError(NODEFS.convertNodeCode(e)); } }, - write: (stream, buffer, offset, length, position) => { + write(stream, buffer, offset, length, position) { try { return fs.writeSync(stream.nfd, Buffer.from(buffer.buffer), offset, length, position); } catch (e) { throw new FS.ErrnoError(NODEFS.convertNodeCode(e)); } }, - llseek: (stream, offset, whence) => { + llseek(stream, offset, whence) { var position = offset; if (whence === {{{ cDefs.SEEK_CUR }}}) { position += stream.position; @@ -297,7 +297,7 @@ mergeInto(LibraryManager.library, { return position; }, - mmap: (stream, length, position, prot, flags) => { + mmap(stream, length, position, prot, flags) { if (!FS.isFile(stream.node.mode)) { throw new FS.ErrnoError({{{ cDefs.ENODEV }}}); } @@ -307,7 +307,7 @@ mergeInto(LibraryManager.library, { NODEFS.stream_ops.read(stream, HEAP8, ptr, length, position); return { ptr, allocated: true }; }, - msync: (stream, buffer, offset, length, mmapFlags) => { + msync(stream, buffer, offset, length, mmapFlags) { NODEFS.stream_ops.write(stream, buffer, 0, length, offset, false); // should we check if bytesWritten and length are the same? return 0; diff --git a/src/library_pthread.js b/src/library_pthread.js index ac1505428216a..c4c13f23e1304 100644 --- a/src/library_pthread.js +++ b/src/library_pthread.js @@ -57,7 +57,7 @@ var LibraryPThread = { pthreads: {}, #if ASSERTIONS nextWorkerID: 1, - debugInit: function() { + debugInit() { function pthreadLogPrefix() { var t = 0; if (runtimeInitialized && typeof _pthread_self != 'undefined' @@ -80,7 +80,7 @@ var LibraryPThread = { #endif }, #endif - init: function() { + init() { #if ASSERTIONS PThread.debugInit(); #endif @@ -94,7 +94,7 @@ var LibraryPThread = { PThread.initMainThread(); } }, - initMainThread: function() { + initMainThread() { #if PTHREAD_POOL_SIZE var pthreadPoolSize = {{{ PTHREAD_POOL_SIZE }}}; // Start loading up the Worker pool, if requested. @@ -118,7 +118,7 @@ var LibraryPThread = { #endif }, - initWorker: function() { + initWorker() { #if USE_CLOSURE_COMPILER // worker.js is not compiled together with us, and must access certain // things. @@ -142,13 +142,13 @@ var LibraryPThread = { }, #if PTHREADS_PROFILING - getThreadName: function(pthreadPtr) { + getThreadName(pthreadPtr) { var profilerBlock = {{{ makeGetValue('pthreadPtr', C_STRUCTS.pthread.profilerBlock, POINTER_TYPE) }}}; if (!profilerBlock) return ""; return UTF8ToString(profilerBlock + {{{ C_STRUCTS.thread_profiler_block.name }}}); }, - threadStatusToString: function(threadStatus) { + threadStatusToString(threadStatus) { switch (threadStatus) { case 0: return "not yet started"; case 1: return "running"; @@ -161,7 +161,7 @@ var LibraryPThread = { } }, - threadStatusAsString: function(pthreadPtr) { + threadStatusAsString(pthreadPtr) { var profilerBlock = {{{ makeGetValue('pthreadPtr', C_STRUCTS.pthread.profilerBlock, POINTER_TYPE) }}}; var status = (profilerBlock == 0) ? 0 : Atomics.load(HEAPU32, (profilerBlock + {{{ C_STRUCTS.thread_profiler_block.threadStatus }}} ) >> 2); return PThread.threadStatusToString(status); @@ -230,7 +230,7 @@ var LibraryPThread = { // linear memory. __emscripten_thread_free_data(pthread_ptr); }, - receiveObjectTransfer: function(data) { + receiveObjectTransfer(data) { #if OFFSCREENCANVAS_SUPPORT if (typeof GL != 'undefined') { Object.assign(GL.offscreenCanvases, data.offscreenCanvases); @@ -242,7 +242,7 @@ var LibraryPThread = { #endif }, // Called by worker.js each time a thread is started. - threadInitTLS: function() { + threadInitTLS() { #if PTHREADS_DEBUG dbg('threadInitTLS'); #endif @@ -406,7 +406,7 @@ var LibraryPThread = { }); }), - loadWasmModuleToAllWorkers: function(onMaybeReady) { + loadWasmModuleToAllWorkers(onMaybeReady) { #if !PTHREAD_POOL_SIZE onMaybeReady(); #else @@ -435,7 +435,7 @@ var LibraryPThread = { }, // Creates a new web Worker and places it in the unused worker pool to wait for its use. - allocateUnusedWorker: function() { + allocateUnusedWorker() { var worker; #if MINIMAL_RUNTIME var pthreadMainJs = Module['worker']; @@ -452,9 +452,7 @@ var LibraryPThread = { var p = trustedTypes.createPolicy( 'emscripten#workerPolicy1', { - createScriptURL: function(ignored) { - return new URL('{{{ PTHREAD_WORKER_FILE }}}', import.meta.url); - } + createScriptURL: (ignored) => new URL('{{{ PTHREAD_WORKER_FILE }}}', import.meta.url); } ); worker = new Worker(p.createScriptURL('ignored')); @@ -474,7 +472,7 @@ var LibraryPThread = { #if TRUSTED_TYPES // Use Trusted Types compatible wrappers. if (typeof trustedTypes != 'undefined' && trustedTypes.createPolicy) { - var p = trustedTypes.createPolicy('emscripten#workerPolicy2', { createScriptURL: function(ignored) { return pthreadMainJs } }); + var p = trustedTypes.createPolicy('emscripten#workerPolicy2', { createScriptURL: (ignored) => pthreadMainJs }); worker = new Worker(p.createScriptURL('ignored')); } else #endif @@ -485,7 +483,7 @@ var LibraryPThread = { PThread.unusedWorkers.push(worker); }, - getNewWorker: function() { + getNewWorker() { if (PThread.unusedWorkers.length == 0) { // PTHREAD_POOL_SIZE_STRICT should show a warning and, if set to level `2`, return from the function. #if (PTHREAD_POOL_SIZE_STRICT && ASSERTIONS) || PTHREAD_POOL_SIZE_STRICT == 2 diff --git a/src/library_syscall.js b/src/library_syscall.js index fc2bd1d4b0a32..1dc3dfc1dfdde 100644 --- a/src/library_syscall.js +++ b/src/library_syscall.js @@ -20,7 +20,7 @@ var SyscallsLibrary = { DEFAULT_POLLMASK: {{{ cDefs.POLLIN }}} | {{{ cDefs.POLLOUT }}}, // shared utilities - calculateAt: function(dirfd, path, allowEmpty) { + calculateAt(dirfd, path, allowEmpty) { if (PATH.isAbs(path)) { return path; } @@ -41,7 +41,7 @@ var SyscallsLibrary = { return PATH.join2(dir, path); }, - doStat: function(func, path, buf) { + doStat(func, path, buf) { try { var stat = func(path); } catch (e) { @@ -72,7 +72,7 @@ var SyscallsLibrary = { {{{ makeSetValue('buf', C_STRUCTS.stat.st_ino, 'stat.ino', 'i64') }}}; return 0; }, - doMsync: function(addr, stream, len, flags, offset) { + doMsync(addr, stream, len, flags, offset) { if (!FS.isFile(stream.node.mode)) { throw new FS.ErrnoError({{{ cDefs.ENODEV }}}); } @@ -109,7 +109,7 @@ var SyscallsLibrary = { }, #if SYSCALLS_REQUIRE_FILESYSTEM // Just like `FS.getStream` but will throw EBADF if stream is undefined. - getStreamFromFD: function(fd) { + getStreamFromFD(fd) { var stream = FS.getStreamChecked(fd); #if SYSCALL_DEBUG dbg(` (stream: "${stream.path}")`); diff --git a/src/library_tty.js b/src/library_tty.js index 413176dfc4e60..97c584e4028ca 100644 --- a/src/library_tty.js +++ b/src/library_tty.js @@ -18,7 +18,7 @@ mergeInto(LibraryManager.library, { #endif $TTY: { ttys: [], - init: function () { + init() { // https://github.com/emscripten-core/emscripten/pull/1555 // if (ENVIRONMENT_IS_NODE) { // // currently, FS.init does not distinguish if process.stdin is a file or TTY @@ -28,7 +28,7 @@ mergeInto(LibraryManager.library, { // process.stdin.setEncoding('utf8'); // } }, - shutdown: function() { + shutdown() { // https://github.com/emscripten-core/emscripten/pull/1555 // if (ENVIRONMENT_IS_NODE) { // // inolen: any idea as to why node -e 'process.stdin.read()' wouldn't exit immediately (with process.stdin being a tty)? @@ -39,12 +39,12 @@ mergeInto(LibraryManager.library, { // process.stdin.pause(); // } }, - register: function(dev, ops) { + register(dev, ops) { TTY.ttys[dev] = { input: [], output: [], ops: ops }; FS.registerDevice(dev, TTY.stream_ops); }, stream_ops: { - open: function(stream) { + open(stream) { var tty = TTY.ttys[stream.node.rdev]; if (!tty) { throw new FS.ErrnoError({{{ cDefs.ENODEV }}}); @@ -52,14 +52,14 @@ mergeInto(LibraryManager.library, { stream.tty = tty; stream.seekable = false; }, - close: function(stream) { + close(stream) { // flush any pending line data stream.tty.ops.fsync(stream.tty); }, - fsync: function(stream) { + fsync(stream) { stream.tty.ops.fsync(stream.tty); }, - read: function(stream, buffer, offset, length, pos /* ignored */) { + read(stream, buffer, offset, length, pos /* ignored */) { if (!stream.tty || !stream.tty.ops.get_char) { throw new FS.ErrnoError({{{ cDefs.ENXIO }}}); } @@ -83,7 +83,7 @@ mergeInto(LibraryManager.library, { } return bytesRead; }, - write: function(stream, buffer, offset, length, pos) { + write(stream, buffer, offset, length, pos) { if (!stream.tty || !stream.tty.ops.put_char) { throw new FS.ErrnoError({{{ cDefs.ENXIO }}}); } @@ -101,10 +101,10 @@ mergeInto(LibraryManager.library, { } }, default_tty_ops: { - get_char: function(tty) { + get_char(tty) { return FS_stdin_getChar(); }, - put_char: function(tty, val) { + put_char(tty, val) { if (val === null || val === {{{ charCode('\n') }}}) { out(UTF8ArrayToString(tty.output, 0)); tty.output = []; @@ -112,13 +112,13 @@ mergeInto(LibraryManager.library, { if (val != 0) tty.output.push(val); // val == 0 would cut text output off in the middle. } }, - fsync: function(tty) { + fsync(tty) { if (tty.output && tty.output.length > 0) { out(UTF8ArrayToString(tty.output, 0)); tty.output = []; } }, - ioctl_tcgets: function(tty) { + ioctl_tcgets(tty) { // typical setting return { c_iflag: {{{ cDefs.ICRNL | cDefs.IXON | cDefs.IMAXBEL | cDefs.IUTF8 }}}, @@ -132,16 +132,16 @@ mergeInto(LibraryManager.library, { ] }; }, - ioctl_tcsets: function(tty, optional_actions, data) { + ioctl_tcsets(tty, optional_actions, data) { // currently just ignore return 0; }, - ioctl_tiocgwinsz: function(tty) { + ioctl_tiocgwinsz(tty) { return [24, 80]; } }, default_tty1_ops: { - put_char: function(tty, val) { + put_char(tty, val) { if (val === null || val === {{{ charCode('\n') }}}) { err(UTF8ArrayToString(tty.output, 0)); tty.output = []; @@ -149,7 +149,7 @@ mergeInto(LibraryManager.library, { if (val != 0) tty.output.push(val); } }, - fsync: function(tty) { + fsync(tty) { if (tty.output && tty.output.length > 0) { err(UTF8ArrayToString(tty.output, 0)); tty.output = []; diff --git a/src/library_wasmfs.js b/src/library_wasmfs.js index 970520c9d2a4a..56e1ec3dd4483 100644 --- a/src/library_wasmfs.js +++ b/src/library_wasmfs.js @@ -40,11 +40,11 @@ FS.createPreloadedFile = FS_createPreloadedFile; #endif ], $FS : { - init: () => { + init() { FS.ensureErrnoError(); }, ErrnoError: null, - handleError: (returnValue) => { + handleError(returnValue) { // Assume errors correspond to negative returnValues // since some functions like _wasmfs_open() return positive // numbers on success (some callers of this function may need to negate the parameter). @@ -54,7 +54,7 @@ FS.createPreloadedFile = FS_createPreloadedFile; return returnValue; }, - ensureErrnoError: () => { + ensureErrnoError() { if (FS.ErrnoError) return; FS.ErrnoError = /** @this{Object} */ function ErrnoError(code) { this.errno = code; @@ -64,7 +64,7 @@ FS.createPreloadedFile = FS_createPreloadedFile; FS.ErrnoError.prototype = new Error(); FS.ErrnoError.prototype.constructor = FS.ErrnoError; }, - createDataFile: (parent, name, fileData, canRead, canWrite, canOwn) => { + createDataFile(parent, name, fileData, canRead, canWrite, canOwn) { var pathName = name ? parent + '/' + name : parent; var mode = FS_getMode(canRead, canWrite); @@ -79,7 +79,7 @@ FS.createPreloadedFile = FS_createPreloadedFile; FS.writeFile(pathName, fileData); } }, - createPath: (parent, path, canRead, canWrite) => { + createPath(parent, path, canRead, canWrite) { // Cache file path directory names. var parts = path.split('/').reverse(); while (parts.length) { @@ -102,7 +102,7 @@ FS.createPreloadedFile = FS_createPreloadedFile; // we'd error anyhow). This depends // on other code including the // __wasmfs_* method properly. - readFile: (path, opts = {}) => { + readFile(path, opts = {}) { opts.encoding = opts.encoding || 'binary'; if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') { throw new Error('Invalid encoding type "' + opts.encoding + '"'); @@ -132,7 +132,7 @@ FS.createPreloadedFile = FS_createPreloadedFile; #if FORCE_FILESYSTEM || INCLUDE_FULL_LIBRARY // see comment above // Full JS API support - analyzePath: (path) => { + analyzePath(path) { // TODO: Consider simplifying this API, which for now matches the JS FS. var exists = !!FS.findObject(path); return { @@ -150,7 +150,7 @@ FS.createPreloadedFile = FS_createPreloadedFile; var buffer = stringToUTF8OnStack(path); return __wasmfs_mkdir(buffer, mode); })), - mkdirTree: (path, mode) => { + mkdirTree(path, mode) { var dirs = path.split('/'); var d = ''; for (var i = 0; i < dirs.length; ++i) { @@ -173,7 +173,7 @@ FS.createPreloadedFile = FS_createPreloadedFile; var fd = FS.handleError(__wasmfs_open(buffer, flags, mode)); return { fd : fd }; }), - create: (path, mode) => { + create(path, mode) { // Default settings copied from the legacy JS FS API. mode = mode !== undefined ? mode : 438 /* 0666 */; mode &= {{{ cDefs.S_IALLUGO }}}; @@ -189,7 +189,7 @@ FS.createPreloadedFile = FS_createPreloadedFile; var buffer = stringToUTF8OnStack(path); return __wasmfs_chdir(buffer); }), - read: (stream, buffer, offset, length, position) => { + read(stream, buffer, offset, length, position) { var seeking = typeof position != 'undefined'; var dataBuffer = _malloc(length); @@ -210,7 +210,7 @@ FS.createPreloadedFile = FS_createPreloadedFile; return bytesRead; }, // Note that canOwn is an optimization that we ignore for now in WasmFS. - write: (stream, buffer, offset, length, position, canOwn) => { + write(stream, buffer, offset, length, position, canOwn) { var seeking = typeof position != 'undefined'; var dataBuffer = _malloc(length); @@ -229,7 +229,7 @@ FS.createPreloadedFile = FS_createPreloadedFile; return bytesRead; }, - allocate: (stream, offset, length) => { + allocate(stream, offset, length) { return FS.handleError(__wasmfs_allocate(stream.fd, {{{ splitI64('offset') }}}, {{{ splitI64('length') }}})); }, // TODO: mmap @@ -256,11 +256,11 @@ FS.createPreloadedFile = FS_createPreloadedFile; symlink: (target, linkpath) => withStackSave(() => ( __wasmfs_symlink(stringToUTF8OnStack(target), stringToUTF8OnStack(linkpath)) )), - readlink: (path) => { + readlink(path) { var readBuffer = FS.handleError(withStackSave(() => __wasmfs_readlink(stringToUTF8OnStack(path)))); return UTF8ToString(readBuffer); }, - statBufToObject : (statBuf) => { + statBufToObject(statBuf) { // i53/u53 are enough for times and ino in practice. return { dev: {{{ makeGetValue('statBuf', C_STRUCTS.stat.st_dev, "u32") }}}, @@ -278,7 +278,7 @@ FS.createPreloadedFile = FS_createPreloadedFile; ino: {{{ makeGetValue('statBuf', C_STRUCTS.stat.st_ino, "u53") }}} } }, - stat: (path) => { + stat(path) { var statBuf = _malloc({{{ C_STRUCTS.stat.__size__ }}}); FS.handleError(withStackSave(() => { return __wasmfs_stat(stringToUTF8OnStack(path), statBuf); @@ -288,7 +288,7 @@ FS.createPreloadedFile = FS_createPreloadedFile; return stats; }, - lstat: (path) => { + lstat(path) { var statBuf = _malloc({{{ C_STRUCTS.stat.__size__ }}}); FS.handleError(withStackSave(() => { return __wasmfs_lstat(stringToUTF8OnStack(path), statBuf); @@ -298,19 +298,19 @@ FS.createPreloadedFile = FS_createPreloadedFile; return stats; }, - chmod: (path, mode) => { + chmod(path, mode) { return FS.handleError(withStackSave(() => { var buffer = stringToUTF8OnStack(path); return __wasmfs_chmod(buffer, mode); })); }, - lchmod: (path, mode) => { + lchmod(path, mode) { return FS.handleError(withStackSave(() => { var buffer = stringToUTF8OnStack(path); return __wasmfs_lchmod(buffer, mode); })); }, - fchmod: (fd, mode) => { + fchmod(fd, mode) { return FS.handleError(__wasmfs_fchmod(fd, mode)); }, utime: (path, atime, mtime) => ( @@ -318,13 +318,13 @@ FS.createPreloadedFile = FS_createPreloadedFile; __wasmfs_utime(stringToUTF8OnStack(path), atime, mtime) ))) ), - truncate: (path, len) => { + truncate(path, len) { return FS.handleError(withStackSave(() => (__wasmfs_truncate(stringToUTF8OnStack(path), {{{ splitI64('len') }}})))); }, - ftruncate: (fd, len) => { + ftruncate(fd, len) { return FS.handleError(__wasmfs_ftruncate(fd, {{{ splitI64('len') }}})); }, - findObject: (path) => { + findObject(path) { var result = withStackSave(() => __wasmfs_identify(stringToUTF8OnStack(path))); if (result == {{{ cDefs.ENOENT }}}) { return null; @@ -352,14 +352,14 @@ FS.createPreloadedFile = FS_createPreloadedFile; // TODO: mount // TODO: unmount // TODO: lookup - mknod: (path, mode, dev) => { + mknod(path, mode, dev) { return FS.handleError(withStackSave(() => { var pathBuffer = stringToUTF8OnStack(path); return __wasmfs_mknod(pathBuffer, mode, dev); })); }, // TODO: mkdev - rename: (oldPath, newPath) => { + rename(oldPath, newPath) { return FS.handleError(withStackSave(() => { var oldPathBuffer = stringToUTF8OnStack(oldPath); var newPathBuffer = stringToUTF8OnStack(newPath); @@ -367,7 +367,7 @@ FS.createPreloadedFile = FS_createPreloadedFile; })); }, // TODO: syncfs - llseek: (stream, offset, whence) => { + llseek(stream, offset, whence) { return FS.handleError(__wasmfs_llseek(stream.fd, {{{ splitI64('offset') }}}, whence)); } // TODO: ioctl diff --git a/src/library_wget.js b/src/library_wget.js index 91e024d33ee23..fb9781d2b3960 100644 --- a/src/library_wget.js +++ b/src/library_wget.js @@ -9,7 +9,7 @@ var LibraryWget = { wgetRequests: {}, nextWgetRequestHandle: 0, - getNextWgetRequestHandle: function() { + getNextWgetRequestHandle() { var handle = wget.nextWgetRequestHandle; wget.nextWgetRequestHandle++; return handle; diff --git a/src/library_workerfs.js b/src/library_workerfs.js index 10bb58f0e5ba8..1109fe7fcd186 100644 --- a/src/library_workerfs.js +++ b/src/library_workerfs.js @@ -10,7 +10,7 @@ mergeInto(LibraryManager.library, { DIR_MODE: {{{ cDefs.S_IFDIR }}} | 511 /* 0777 */, FILE_MODE: {{{ cDefs.S_IFREG }}} | 511 /* 0777 */, reader: null, - mount (mount) { + mount(mount) { assert(ENVIRONMENT_IS_WORKER); if (!WORKERFS.reader) WORKERFS.reader = new FileReaderSync(); var root = WORKERFS.createNode(null, '/', WORKERFS.DIR_MODE, 0); @@ -54,7 +54,7 @@ mergeInto(LibraryManager.library, { }); return root; }, - createNode (parent, name, mode, dev, contents, mtime) { + createNode(parent, name, mode, dev, contents, mtime) { var node = FS.createNode(parent, name, mode); node.mode = mode; node.node_ops = WORKERFS.node_ops; diff --git a/test/other/metadce/test_metadce_cxx_ctors1.jssize b/test/other/metadce/test_metadce_cxx_ctors1.jssize index 4d08dc5b9f967..f97f06f642373 100644 --- a/test/other/metadce/test_metadce_cxx_ctors1.jssize +++ b/test/other/metadce/test_metadce_cxx_ctors1.jssize @@ -1 +1 @@ -25125 +25094 diff --git a/test/other/metadce/test_metadce_cxx_ctors2.jssize b/test/other/metadce/test_metadce_cxx_ctors2.jssize index 72f6e6531f550..e1e82040b12d4 100644 --- a/test/other/metadce/test_metadce_cxx_ctors2.jssize +++ b/test/other/metadce/test_metadce_cxx_ctors2.jssize @@ -1 +1 @@ -25093 +25062 diff --git a/test/other/metadce/test_metadce_cxx_except.jssize b/test/other/metadce/test_metadce_cxx_except.jssize index 283e578e1bd30..89093bce90250 100644 --- a/test/other/metadce/test_metadce_cxx_except.jssize +++ b/test/other/metadce/test_metadce_cxx_except.jssize @@ -1 +1 @@ -29302 +29270 diff --git a/test/other/metadce/test_metadce_cxx_except_wasm.jssize b/test/other/metadce/test_metadce_cxx_except_wasm.jssize index 3c31c02beb627..8d5ddfc010c36 100644 --- a/test/other/metadce/test_metadce_cxx_except_wasm.jssize +++ b/test/other/metadce/test_metadce_cxx_except_wasm.jssize @@ -1 +1 @@ -24893 +24862 diff --git a/test/other/metadce/test_metadce_cxx_mangle.jssize b/test/other/metadce/test_metadce_cxx_mangle.jssize index 7e268fce81768..85f2b2d016743 100644 --- a/test/other/metadce/test_metadce_cxx_mangle.jssize +++ b/test/other/metadce/test_metadce_cxx_mangle.jssize @@ -1 +1 @@ -29301 +29269 diff --git a/test/other/metadce/test_metadce_cxx_noexcept.jssize b/test/other/metadce/test_metadce_cxx_noexcept.jssize index 4d08dc5b9f967..f97f06f642373 100644 --- a/test/other/metadce/test_metadce_cxx_noexcept.jssize +++ b/test/other/metadce/test_metadce_cxx_noexcept.jssize @@ -1 +1 @@ -25125 +25094 diff --git a/test/other/metadce/test_metadce_files_js_fs.jssize b/test/other/metadce/test_metadce_files_js_fs.jssize index b92677edb9566..912f6d1e5bf4f 100644 --- a/test/other/metadce/test_metadce_files_js_fs.jssize +++ b/test/other/metadce/test_metadce_files_js_fs.jssize @@ -1 +1 @@ -20000 +19963 diff --git a/test/other/metadce/test_metadce_minimal_pthreads.jssize b/test/other/metadce/test_metadce_minimal_pthreads.jssize index 947d39415a098..e91fdc3e1243d 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.jssize +++ b/test/other/metadce/test_metadce_minimal_pthreads.jssize @@ -1 +1 @@ -14534 +14374 From 71c72a28f4344013bd049ccb2d481a2b31674b42 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 1 Aug 2023 09:41:29 -0700 Subject: [PATCH 0599/1523] Remove a stray print. Followup to #19916 (#19919) --- emcc.py | 1 - 1 file changed, 1 deletion(-) diff --git a/emcc.py b/emcc.py index 618072987aa3d..c6d5c7a7fd065 100755 --- a/emcc.py +++ b/emcc.py @@ -819,7 +819,6 @@ def process_dynamic_libs(dylibs, lib_dirs): while to_process: dylib = to_process.pop() dylink = webassembly.parse_dylink_section(dylib) - print(dylink) for needed in dylink.needed: if needed in seen: continue From 25bec4748989b0869ac36a676e326518f64ee3ae Mon Sep 17 00:00:00 2001 From: Brendan Dahl Date: Tue, 1 Aug 2023 11:32:39 -0700 Subject: [PATCH 0600/1523] embind: Generate TS definitions from static class methods. (#19895) --- src/embind/embind_ts.js | 25 ++++++++++++++++++++++++- test/other/embind_tsgen.cpp | 3 +++ test/other/embind_tsgen.d.ts | 2 +- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/embind/embind_ts.js b/src/embind/embind_ts.js index 26487f99e09dc..80e3ee4beebca 100644 --- a/src/embind/embind_ts.js +++ b/src/embind/embind_ts.js @@ -42,12 +42,12 @@ var LibraryEmbind = { printFunction(nameMap, out) { out.push(`${this.name}`); this.printSignature(nameMap, out); - out.push(';\n'); } printModuleEntry(nameMap, out) { out.push(' '); this.printFunction(nameMap, out); + out.push(';\n'); } }, $ClassDefinition: class ClassDefinition { @@ -55,6 +55,7 @@ var LibraryEmbind = { this.typeId = typeId; this.name = name; this.methods = []; + this.staticMethods = []; this.constructors = [ new FunctionDefinition('default', this, []) ]; @@ -75,6 +76,7 @@ var LibraryEmbind = { for (const method of this.methods) { out.push(' '); method.printFunction(nameMap, out); + out.push(';\n'); } out.push(' delete(): void;\n'); out.push('}\n\n'); @@ -85,6 +87,10 @@ var LibraryEmbind = { // TODO Handle constructor overloading const constructor = this.constructors[this.constructors.length > 1 ? 1 : 0]; constructor.printSignature(nameMap, out); + for (const method of this.staticMethods) { + out.push('; '); + method.printFunction(nameMap, out); + } out.push('};\n'); } }, @@ -376,6 +382,23 @@ var LibraryEmbind = { return []; }); }, + _embind_register_class_class_function__deps: ['$createFunctionDefinition'], + _embind_register_class_class_function: function(rawClassType, + methodName, + argCount, + rawArgTypesAddr, + invokerSignature, + rawInvoker, + fn, + isAsync) { + whenDependentTypesAreResolved([], [rawClassType], function(classType) { + classType = classType[0]; + createFunctionDefinition(methodName, argCount, rawArgTypesAddr, false, (funcDef) => { + classType.staticMethods.push(funcDef); + }); + return []; + }); + }, _embind_register_enum__deps: ['$readLatin1String', '$EnumDefinition', '$moduleDefinitions'], _embind_register_enum: function(rawType, name, size, isSigned) { name = readLatin1String(name); diff --git a/test/other/embind_tsgen.cpp b/test/other/embind_tsgen.cpp index f9ba1345fb809..5141e525431f8 100644 --- a/test/other/embind_tsgen.cpp +++ b/test/other/embind_tsgen.cpp @@ -16,6 +16,8 @@ class Test { int getX() const { return x; } void setX(int x_) { x = x_; } + static int static_function(int x) { return 1; } + private: int x; }; @@ -84,6 +86,7 @@ EMSCRIPTEN_BINDINGS(Test) { .function("functionFour", &Test::function_four) .function("constFn", &Test::const_fn) .property("x", &Test::getX, &Test::setX) + .class_function("staticFunction", &Test::static_function) ; function("class_returning_fn", &class_returning_fn); diff --git a/test/other/embind_tsgen.d.ts b/test/other/embind_tsgen.d.ts index 5f7816a697487..2f26fc5702292 100644 --- a/test/other/embind_tsgen.d.ts +++ b/test/other/embind_tsgen.d.ts @@ -57,7 +57,7 @@ export interface DerivedClass extends BaseClass { export type ValArr = [ number, number, number ]; export interface MainModule { - Test: {new(): Test}; + Test: {new(): Test; staticFunction(_0: number): number}; class_returning_fn(): Test; class_unique_ptr_returning_fn(): Test; a_class_instance: Test; From b840dc7f840f9d2dc259e884651a83bb5d911f7f Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 1 Aug 2023 12:11:55 -0700 Subject: [PATCH 0601/1523] Rename internal JS proxying function. NFC (#19945) I renamed the existing `_emscripten_run_in_main_runtime_thread_js` to the simpler `_emscripten_run_in_main_thread_js` to match other things such as `$proxyToMainThread`. I don't believe is ambiguous. There is no way this function could be referring to the main browser thread and not the main runtime thread since if the main browser thread ever exists in the system it is by definition also the main runtime thread. This change is laying the groundwork for a larger change which to move JS function proxying over to the new proxying system. --- emcc.py | 2 +- emscripten.py | 2 +- src/library_pthread.js | 25 ++++++++++--------- src/library_sigs.js | 2 +- system/lib/pthread/library_pthread.c | 4 +-- system/lib/pthread/threading_internal.h | 2 +- .../test_metadce_minimal_pthreads.funcs | 2 +- 7 files changed, 20 insertions(+), 19 deletions(-) diff --git a/emcc.py b/emcc.py index c6d5c7a7fd065..3eb04d0bf866c 100755 --- a/emcc.py +++ b/emcc.py @@ -1710,7 +1710,7 @@ def setup_pthreads(target): '_emscripten_thread_free_data', 'emscripten_main_runtime_thread_id', 'emscripten_main_thread_process_queued_calls', - '_emscripten_run_in_main_runtime_thread_js', + '_emscripten_run_on_main_thread_js', 'emscripten_stack_set_limits', ] diff --git a/emscripten.py b/emscripten.py index fe9a6ba08d472..560a0fbc59c4d 100644 --- a/emscripten.py +++ b/emscripten.py @@ -866,7 +866,7 @@ def create_pointer_conversion_wrappers(metadata): '__cxa_decrement_exception_refcount': '_p', '_wasmfs_write_file': '_ppp', '__dl_seterr': '_pp', - '_emscripten_run_in_main_runtime_thread_js': '___p_', + '_emscripten_run_on_main_thread_js': '___p_', '_emscripten_proxy_execute_task_queue': '_p', '_emscripten_thread_exit': '_p', '_emscripten_thread_init': '_p_____', diff --git a/src/library_pthread.js b/src/library_pthread.js index c4c13f23e1304..82510f53479e9 100644 --- a/src/library_pthread.js +++ b/src/library_pthread.js @@ -955,7 +955,7 @@ var LibraryPThread = { _exit(returnCode); }, - $proxyToMainThread__deps: ['$withStackSave', '_emscripten_run_in_main_runtime_thread_js'], + $proxyToMainThread__deps: ['$withStackSave', '_emscripten_run_on_main_thread_js'], $proxyToMainThread__docs: '/** @type{function(number, (number|boolean), ...(number|boolean))} */', $proxyToMainThread: function(index, sync) { // Additional arguments are passed after those two, which are the actual @@ -998,16 +998,17 @@ var LibraryPThread = { HEAPF64[b + i] = arg; #endif } - return __emscripten_run_in_main_runtime_thread_js(index, serializedNumCallArgs, args, sync); + return __emscripten_run_on_main_thread_js(index, serializedNumCallArgs, args, sync); }); }, - $emscripten_receive_on_main_thread_js_callArgs: '=[]', + // Reuse global JS array to avoid creating JS garbage for each proxied call + $proxiedJSCallArgs: '=[]', - emscripten_receive_on_main_thread_js__deps: [ + _emscripten_receive_on_main_thread_js__deps: [ '$proxyToMainThread', - '$emscripten_receive_on_main_thread_js_callArgs'], - emscripten_receive_on_main_thread_js: function(index, callingThread, numCallArgs, args) { + '$proxiedJSCallArgs'], + _emscripten_receive_on_main_thread_js: function(index, callingThread, numCallArgs, args) { // Sometimes we need to backproxy events to the calling thread (e.g. // HTML5 DOM events handlers such as // emscripten_set_mousemove_callback()), so keep track in a globally @@ -1016,19 +1017,19 @@ var LibraryPThread = { #if WASM_BIGINT numCallArgs /= 2; #endif - emscripten_receive_on_main_thread_js_callArgs.length = numCallArgs; + proxiedJSCallArgs.length = numCallArgs; var b = args >> 3; for (var i = 0; i < numCallArgs; i++) { #if WASM_BIGINT if (HEAP64[b + 2*i]) { // It's a BigInt. - emscripten_receive_on_main_thread_js_callArgs[i] = HEAP64[b + 2*i + 1]; + proxiedJSCallArgs[i] = HEAP64[b + 2*i + 1]; } else { // It's a Number. - emscripten_receive_on_main_thread_js_callArgs[i] = HEAPF64[b + 2*i + 1]; + proxiedJSCallArgs[i] = HEAPF64[b + 2*i + 1]; } #else - emscripten_receive_on_main_thread_js_callArgs[i] = HEAPF64[b + i]; + proxiedJSCallArgs[i] = HEAPF64[b + i]; #endif } // Proxied JS library funcs are encoded as positive values, and @@ -1040,9 +1041,9 @@ var LibraryPThread = { var func = proxiedFunctionTable[index]; #endif #if ASSERTIONS - assert(func.length == numCallArgs, 'Call args mismatch in emscripten_receive_on_main_thread_js'); + assert(func.length == numCallArgs, 'Call args mismatch in _emscripten_receive_on_main_thread_js'); #endif - return func.apply(null, emscripten_receive_on_main_thread_js_callArgs); + return func.apply(null, proxiedJSCallArgs); }, $establishStackSpace__internal: true, diff --git a/src/library_sigs.js b/src/library_sigs.js index 4ef5995947b0d..7d3f4c5e8d03e 100644 --- a/src/library_sigs.js +++ b/src/library_sigs.js @@ -325,6 +325,7 @@ sigs = { _emscripten_notify_mailbox_postmessage__sig: 'vppp', _emscripten_push_main_loop_blocker__sig: 'vppp', _emscripten_push_uncounted_main_loop_blocker__sig: 'vppp', + _emscripten_receive_on_main_thread_js__sig: 'dipip', _emscripten_set_offscreencanvas_size__sig: 'ipii', _emscripten_thread_exit_joinable__sig: 'vp', _emscripten_thread_mailbox_await__sig: 'vp', @@ -712,7 +713,6 @@ sigs = { emscripten_promise_resolve__sig: 'vpip', emscripten_promise_then__sig: 'ppppp', emscripten_random__sig: 'f', - emscripten_receive_on_main_thread_js__sig: 'dipip', emscripten_request_animation_frame__sig: 'ipp', emscripten_request_animation_frame_loop__sig: 'vpp', emscripten_request_fullscreen__sig: 'ipi', diff --git a/system/lib/pthread/library_pthread.c b/system/lib/pthread/library_pthread.c index c4b25a031291c..4a5ca5de788c6 100644 --- a/system/lib/pthread/library_pthread.c +++ b/system/lib/pthread/library_pthread.c @@ -188,7 +188,7 @@ static void _do_call(void* arg) { break; case EM_PROXIED_JS_FUNCTION: q->returnValue.d = - emscripten_receive_on_main_thread_js((intptr_t)q->functionPtr, q->callingThread, q->args[0].i, &q->args[1].d); + _emscripten_receive_on_main_thread_js((intptr_t)q->functionPtr, q->callingThread, q->args[0].i, &q->args[1].d); break; case EM_FUNC_SIG_V: ((em_func_v)q->functionPtr)(); @@ -420,7 +420,7 @@ int emscripten_sync_run_in_main_runtime_thread_(EM_FUNC_SIGNATURE sig, void* fun return q.returnValue.i; } -double _emscripten_run_in_main_runtime_thread_js(int index, int num_args, int64_t* buffer, int sync) { +double _emscripten_run_on_main_thread_js(int index, int num_args, int64_t* buffer, int sync) { em_queued_call q; em_queued_call *c; if (sync) { diff --git a/system/lib/pthread/threading_internal.h b/system/lib/pthread/threading_internal.h index 7d0899e2b8cea..245db45baf52a 100644 --- a/system/lib/pthread/threading_internal.h +++ b/system/lib/pthread/threading_internal.h @@ -167,4 +167,4 @@ int __pthread_create_js(struct __pthread *thread, const pthread_attr_t *attr, vo int _emscripten_default_pthread_stack_size(); void __set_thread_state(pthread_t ptr, int is_main, int is_runtime, int can_block); -double emscripten_receive_on_main_thread_js(int functionIndex, pthread_t callingThread, int numCallArgs, double* args); +double _emscripten_receive_on_main_thread_js(int functionIndex, pthread_t callingThread, int numCallArgs, double* args); diff --git a/test/other/metadce/test_metadce_minimal_pthreads.funcs b/test/other/metadce/test_metadce_minimal_pthreads.funcs index b73e40caf9df9..e4e874250750f 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.funcs +++ b/test/other/metadce/test_metadce_minimal_pthreads.funcs @@ -25,7 +25,7 @@ $__wasm_init_tls $_do_call $_emscripten_check_mailbox $_emscripten_proxy_main -$_emscripten_run_in_main_runtime_thread_js +$_emscripten_run_on_main_thread_js $_emscripten_thread_crashed $_emscripten_thread_exit $_emscripten_thread_free_data From 6f5b680ce616055dc889c02064226ebc2ece236c Mon Sep 17 00:00:00 2001 From: Kai Ninomiya Date: Tue, 1 Aug 2023 12:21:50 -0700 Subject: [PATCH 0602/1523] WebGPU: fix missed handling of sentinel values (#19929) Sentinel values come in as -1, but we were still incorrectly assuming WGPU_WHOLE_MAP_SIZE would come in as 0xFFFFFFFF. --- src/library_webgpu.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/library_webgpu.js b/src/library_webgpu.js index 2c88f7ac9be15..51f99304b7084 100644 --- a/src/library_webgpu.js +++ b/src/library_webgpu.js @@ -75,7 +75,6 @@ wgpu${type}Release: function(id) { WebGPU.mgr${type}.release(id) },`; // Must be in sync with webgpu.h. COPY_STRIDE_UNDEFINED: 0xFFFFFFFF, LIMIT_U32_UNDEFINED: 0xFFFFFFFF, - WHOLE_MAP_SIZE: 0xFFFFFFFF, // use 32-bit uint max MIP_LEVEL_COUNT_UNDEFINED: 0xFFFFFFFF, ARRAY_LAYER_COUNT_UNDEFINED: 0xFFFFFFFF, AdapterType: { @@ -1842,7 +1841,7 @@ var LibraryWebGPU = { if (size === 0) warnOnce('getMappedRange size=0 no longer means WGPU_WHOLE_MAP_SIZE'); - if (size === {{{ gpu.WHOLE_MAP_SIZE }}}) size = undefined; + {{{ gpu.convertSentinelToUndefined('size') }}} var mapped; try { @@ -1875,7 +1874,7 @@ var LibraryWebGPU = { if (size === 0) warnOnce('getMappedRange size=0 no longer means WGPU_WHOLE_MAP_SIZE'); - if (size === {{{ gpu.WHOLE_MAP_SIZE }}}) size = undefined; + {{{ gpu.convertSentinelToUndefined('size') }}} if (bufferWrapper.mapMode !== {{{ gpu.MapMode.Write }}}) { #if ASSERTIONS @@ -1915,7 +1914,7 @@ var LibraryWebGPU = { bufferWrapper.onUnmap = []; var buffer = bufferWrapper.object; - if (size === {{{ gpu.WHOLE_MAP_SIZE }}}) size = undefined; + {{{ gpu.convertSentinelToUndefined('size') }}} // `callback` takes (WGPUBufferMapAsyncStatus status, void * userdata) From 48e8a04805e1b255309fcb61f37958a15837aa46 Mon Sep 17 00:00:00 2001 From: jameshu15869 <55058507+jameshu15869@users.noreply.github.com> Date: Tue, 1 Aug 2023 16:22:07 -0400 Subject: [PATCH 0603/1523] WasmFS JS API: Implement mount and unmount (#19825) This PR implements FS.mount and FS.unmount. There were existing tests, so I just added some additional test cases to those files. Tests that now pass in WasmFS mode were also added to CI. There are some differences in the behavior of the WasmFS mount and the legacy API. For example, WasmFS mount will create a new directory to mount to if one does not already exist. Existing directories must be nonempty, since WasmFS will unlink the directory before creating a new directory with the specified backend. Currently, WasmFS does not support mounting IDBFS, WORKERFS, and PROXYFS, although those may be added in the future using a bridge to legacy backends (#18935) --- .circleci/config.yml | 17 +++++ emcc.py | 2 + src/library_fetchfs.js | 18 +++++ src/library_icasefs.js | 22 ++++++ src/library_idbfs.js | 4 ++ src/library_jsfilefs.js | 18 +++++ src/library_nodefs.js | 9 +++ src/library_opfs.js | 18 +++++ src/library_proxyfs.js | 4 ++ src/library_wasmfs.js | 38 +++++++++- src/library_workerfs.js | 4 ++ src/shell.js | 5 ++ system/include/emscripten/wasmfs.h | 9 ++- .../wasmfs/backends/ignore_case_backend.cpp | 8 +-- system/lib/wasmfs/js_api.cpp | 25 ++++++- system/lib/wasmfs/syscalls.cpp | 33 +++++++++ test/fs/test_fs_js_api.c | 7 ++ test/fs/test_mount.c | 70 +++++++++++++++++-- test/test_core.py | 11 +++ 19 files changed, 308 insertions(+), 14 deletions(-) create mode 100644 src/library_fetchfs.js create mode 100644 src/library_icasefs.js create mode 100644 src/library_jsfilefs.js create mode 100644 src/library_opfs.js diff --git a/.circleci/config.yml b/.circleci/config.yml index 8e6f5f9b27b87..68d21ef24089d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -544,6 +544,21 @@ jobs: wasmfs.test_readdir_unlink wasmfs.test_unistd_pipe wasmfs.test_fs_write + wasmfs.test_fs_writev + wasmfs.test_fs_writev_rawfs + wasmfs.test_fs_writeFile + wasmfs.test_fs_writeFile_rawfs + wasmfs.test_fs_readv + wasmfs.test_fs_write + wasmfs.test_fs_readv_rawfs + wasmfs.test_fs_nodefs_nofollow + wasmfs.test_fs_nodefs_readdir + wasmfs.test_fs_nodefs_home + wasmfs.test_fs_nodefs_cloexec + wasmfs.test_fs_nodefs_cloexec_rawfs + wasmfs.test_fs_errorstack + wasmfs.test_fs_errorstack_rawfs + wasmfs.test_fs_emptyPath wasmfs.test_webidl wasmfs.test_dlfcn_self wasmfs.test_dlfcn_unique_sig @@ -551,6 +566,7 @@ jobs: wasmfs.test_exit_status wasmfs.test_minimal_runtime_memorygrowth wasmfs.test_mmap_anon* + wasmfs.test_mount wasmfs.test_getcwd_with_non_ascii_name wasmfs.test_stat wasmfs.test_fstatat @@ -559,6 +575,7 @@ jobs: wasmfs.test_fcntl_open wasmfs.test_fs_js_api wasmfs.test_fs_llseek + wasmfs.test_fs_llseek_rawfs wasmfs.test_freetype" test-wasm2js1: environment: diff --git a/emcc.py b/emcc.py index 3eb04d0bf866c..f362afb9c4cd7 100755 --- a/emcc.py +++ b/emcc.py @@ -2339,6 +2339,8 @@ def phase_linker_setup(options, state, newargs): # included, as the entire JS library can refer to things that require # these exports.) settings.REQUIRED_EXPORTS += [ + '_wasmfs_mount', + '_wasmfs_unmount', '_wasmfs_read_file', '_wasmfs_write_file', '_wasmfs_open', diff --git a/src/library_fetchfs.js b/src/library_fetchfs.js new file mode 100644 index 0000000000000..e91ba34d02fdc --- /dev/null +++ b/src/library_fetchfs.js @@ -0,0 +1,18 @@ +/** + * @license + * Copyright 2023 The Emscripten Authors + * SPDX-License-Identifier: MIT + */ + +mergeInto(LibraryManager.library, { + $FETCHFS__deps: ['$stringToUTF8OnStack', 'wasmfs_create_fetch_backend'], + $FETCHFS: { + createBackend(opts) { + return _wasmfs_create_fetch_backend(stringToUTF8OnStack(opts.base_url)); + } + }, +}); + +if (!WASMFS) { + error("using -lfetchfs.js requires using WasmFS (-sWASMFS)"); +} diff --git a/src/library_icasefs.js b/src/library_icasefs.js new file mode 100644 index 0000000000000..f4e95c67ea1cd --- /dev/null +++ b/src/library_icasefs.js @@ -0,0 +1,22 @@ +/** + * @license + * Copyright 2023 The Emscripten Authors + * SPDX-License-Identifier: MIT + */ + +mergeInto(LibraryManager.library, { + $ICASEFS__deps: ['wasmfs_create_icase_backend'], + $ICASEFS: { + createBackend(opts) { + if (typeof opts.backend === "undefined") { + throw new Error("Underlying backend is not valid."); + } + var underlyingBackend = opts.backend.createBackend(opts); + return _wasmfs_create_icase_backend(underlyingBackend); + } + }, +}); + +if (!WASMFS) { + error("using -licasefs.js requires using WasmFS (-sWASMFS)"); +} diff --git a/src/library_idbfs.js b/src/library_idbfs.js index 18e514fd99b31..d6ff1a9682782 100644 --- a/src/library_idbfs.js +++ b/src/library_idbfs.js @@ -312,3 +312,7 @@ mergeInto(LibraryManager.library, { } } }); + +if (WASMFS) { + error("using -lidbfs is not currently supported in WasmFS."); +} diff --git a/src/library_jsfilefs.js b/src/library_jsfilefs.js new file mode 100644 index 0000000000000..11cc04ee5d3be --- /dev/null +++ b/src/library_jsfilefs.js @@ -0,0 +1,18 @@ +/** + * @license + * Copyright 2023 The Emscripten Authors + * SPDX-License-Identifier: MIT + */ + +mergeInto(LibraryManager.library, { + $JSFILEFS__deps: ['wasmfs_create_js_file_backend'], + $JSFILEFS: { + createBackend(opts) { + return _wasmfs_create_js_file_backend(); + } + }, +}); + +if (!WASMFS) { + error("using -ljsfile.js requires using WasmFS (-sWASMFS)"); +} diff --git a/src/library_nodefs.js b/src/library_nodefs.js index a9d73751da139..677fa8ea00bb4 100644 --- a/src/library_nodefs.js +++ b/src/library_nodefs.js @@ -5,6 +5,14 @@ */ mergeInto(LibraryManager.library, { +#if WASMFS + $NODEFS__deps: ['$stringToUTF8OnStack', 'wasmfs_create_node_backend'], + $NODEFS: { + createBackend(opts) { + return _wasmfs_create_node_backend(stringToUTF8OnStack(opts.root)); + } + } +#else $NODEFS__deps: ['$FS', '$PATH', '$ERRNO_CODES', '$mmapAlloc'], $NODEFS__postset: 'if (ENVIRONMENT_IS_NODE) { NODEFS.staticInit(); }', $NODEFS: { @@ -314,4 +322,5 @@ mergeInto(LibraryManager.library, { } } } +#endif }); diff --git a/src/library_opfs.js b/src/library_opfs.js new file mode 100644 index 0000000000000..b4ca7829d2bf3 --- /dev/null +++ b/src/library_opfs.js @@ -0,0 +1,18 @@ +/** + * @license + * Copyright 2023 The Emscripten Authors + * SPDX-License-Identifier: MIT + */ + +mergeInto(LibraryManager.library, { + $OPFS__deps: ['wasmfs_create_opfs_backend'], + $OPFS: { + createBackend(opts) { + return _wasmfs_create_opfs_backend(); + } + }, +}); + +if (!WASMFS) { + error("using -lopfs.js requires using WasmFS (-sWASMFS)"); +} diff --git a/src/library_proxyfs.js b/src/library_proxyfs.js index bec3f65d7cb10..90d03a00370d8 100644 --- a/src/library_proxyfs.js +++ b/src/library_proxyfs.js @@ -218,3 +218,7 @@ mergeInto(LibraryManager.library, { } } }); + +if (WASMFS) { + error("using -lproxyfs is not currently supported in WasmFS."); +} diff --git a/src/library_wasmfs.js b/src/library_wasmfs.js index 56e1ec3dd4483..63c7232088beb 100644 --- a/src/library_wasmfs.js +++ b/src/library_wasmfs.js @@ -5,6 +5,12 @@ */ mergeInto(LibraryManager.library, { + $MEMFS__deps: ['wasmfs_create_memory_backend'], + $MEMFS: { + createBackend(opts) { + return _wasmfs_create_memory_backend(); + } + }, $wasmFSPreloadedFiles: [], $wasmFSPreloadedDirs: [], // We must note when preloading has been "flushed", that is, the time at which @@ -18,6 +24,7 @@ FS.init(); FS.createPreloadedFile = FS_createPreloadedFile; `, $FS__deps: [ + '$MEMFS', '$wasmFSPreloadedFiles', '$wasmFSPreloadedDirs', '$wasmFSPreloadingFlushed', @@ -35,6 +42,21 @@ FS.createPreloadedFile = FS_createPreloadedFile; // up requiring all of our code // here. '$FS_modeStringToFlags', +#if LibraryManager.has('library_icasefs.js') + '$ICASEFS', +#endif +#if LibraryManager.has('library_nodefs.js') + '$NODEFS', +#endif +#if LibraryManager.has('library_opfs.js') + '$OPFS', +#endif +#if LibraryManager.has('library_jsfilefs.js') + '$JSFILEFS', +#endif +#if LibraryManager.has('library_fetchfs.js') + '$FETCHFS', +#endif 'malloc', 'free', #endif @@ -349,8 +371,20 @@ FS.createPreloadedFile = FS_createPreloadedFile; __wasmfs_readdir_finish(state); return entries; }), - // TODO: mount - // TODO: unmount + mount: (type, opts, mountpoint) => { +#if ASSERTIONS + if (typeof type == 'string') { + // The filesystem was not included, and instead we have an error + // message stored in the variable. + throw type; + } +#endif + var backendPointer = type.createBackend(opts); + return FS.handleError(withStackSave(() => __wasmfs_mount(stringToUTF8OnStack(mountpoint), backendPointer))); + }, + unmount: (mountpoint) => ( + FS.handleError(withStackSave(() => __wasmfs_unmount(stringToUTF8OnStack(mountpoint)))) + ), // TODO: lookup mknod(path, mode, dev) { return FS.handleError(withStackSave(() => { diff --git a/src/library_workerfs.js b/src/library_workerfs.js index 1109fe7fcd186..9fef354d16efd 100644 --- a/src/library_workerfs.js +++ b/src/library_workerfs.js @@ -156,3 +156,7 @@ mergeInto(LibraryManager.library, { }, }, }); + +if (WASMFS) { + error("using -lworkerfs is not currently supported in WasmFS."); +} diff --git a/src/shell.js b/src/shell.js index 2663771873874..09f184f7c858f 100644 --- a/src/shell.js +++ b/src/shell.js @@ -485,6 +485,11 @@ assert(typeof Module['TOTAL_MEMORY'] == 'undefined', 'Module.TOTAL_MEMORY has be {{{ makeRemovedFSAssert('IDBFS') }}} {{{ makeRemovedFSAssert('PROXYFS') }}} {{{ makeRemovedFSAssert('WORKERFS') }}} +{{{ makeRemovedFSAssert('FETCHFS') }}} +{{{ makeRemovedFSAssert('ICASEFS') }}} +{{{ makeRemovedFSAssert('JSFILEFS') }}} +{{{ makeRemovedFSAssert('OPFS') }}} + #if !NODERAWFS {{{ makeRemovedFSAssert('NODEFS') }}} #endif diff --git a/system/include/emscripten/wasmfs.h b/system/include/emscripten/wasmfs.h index 974ebba98c00e..03ba4e76854aa 100644 --- a/system/include/emscripten/wasmfs.h +++ b/system/include/emscripten/wasmfs.h @@ -26,12 +26,18 @@ backend_t wasmfs_get_backend_by_fd(int fd); // Returns the file descriptor for the new file like `open`. Returns a negative // value on error. TODO: It might be worth returning a more specialized type // like __wasi_fd_t here. +// TODO: Remove this function so that only directories can be mounted. int wasmfs_create_file(const char* pathname __attribute__((nonnull)), mode_t mode, backend_t backend); // Creates a new directory in the new file system under a specific backend. // Returns 0 on success like `mkdir`, or a negative value on error. +// TODO: Add an alias with wasmfs_mount. int wasmfs_create_directory(const char* path __attribute__((nonnull)), mode_t mode, backend_t backend); +// Unmounts the directory (Which must be a valid mountpoint) at a specific path. +// Returns 0 on success, or a negative value on error. +int wasmfs_unmount(intptr_t path); + // Backend creation // Creates a JSFile Backend in the new file system. @@ -66,8 +72,7 @@ backend_t wasmfs_create_node_backend(const char* root __attribute__((nonnull))); // thread. backend_t wasmfs_create_opfs_backend(void); -backend_t wasmfs_create_icase_backend(backend_constructor_t create_backend, - void* arg); +backend_t wasmfs_create_icase_backend(backend_t backend); // Similar to fflush(0), but also flushes all internal buffers inside WasmFS. // This is necessary because in a Web environment we must buffer at an diff --git a/system/lib/wasmfs/backends/ignore_case_backend.cpp b/system/lib/wasmfs/backends/ignore_case_backend.cpp index 8675de6cd8e1a..7cf2856e5f2b8 100644 --- a/system/lib/wasmfs/backends/ignore_case_backend.cpp +++ b/system/lib/wasmfs/backends/ignore_case_backend.cpp @@ -234,11 +234,11 @@ backend_t createIgnoreCaseBackend(std::function createBackend) { extern "C" { -// C API for creating ignore case backend. -backend_t wasmfs_create_icase_backend(backend_constructor_t create_backend, - void* arg) { +// C API FOR creating an ignore case backend by supplying a pointer to another backend. +backend_t wasmfs_create_icase_backend(backend_t backend) { return createIgnoreCaseBackend( - [create_backend, arg]() { return create_backend(arg); }); + [backend]() { return backend; } + ); } } // extern "C" diff --git a/system/lib/wasmfs/js_api.cpp b/system/lib/wasmfs/js_api.cpp index f63127bc3c875..523a60ec9b05e 100644 --- a/system/lib/wasmfs/js_api.cpp +++ b/system/lib/wasmfs/js_api.cpp @@ -22,11 +22,16 @@ using namespace wasmfs; extern "C" { +// TODO: Replace forward declarations with #include and +// resolve wasmfs::backend_t namespace conflicts. __wasi_fd_t wasmfs_create_file(char* pathname, mode_t mode, backend_t backend); +int wasmfs_create_directory(char* path, int mode, backend_t backend); +int wasmfs_unmount(intptr_t path); // Copy the file specified by the pathname into JS. // Return a pointer to the JS buffer in HEAPU8. // The buffer will also contain the file length. +// TODO: Use WasmFS ErrnoError handling instead of aborting on failure. void* _wasmfs_read_file(char* path) { static_assert(sizeof(off_t) == 8, "File offset type must be 64-bit"); @@ -207,7 +212,7 @@ int _wasmfs_llseek(int fd, off_t offset, int whence) { int _wasmfs_rename(char* oldpath, char* newpath) { return __syscall_renameat(AT_FDCWD, (intptr_t)oldpath, AT_FDCWD, (intptr_t)newpath); -}; +} int _wasmfs_read(int fd, void *buf, size_t count) { __wasi_iovec_t iovs[1]; @@ -265,6 +270,24 @@ int _wasmfs_lstat(char* path, struct stat* statBuf) { return __syscall_lstat64((intptr_t)path, (intptr_t)statBuf); } +// The legacy JS API requires a mountpoint to already exist, so WasmFS will attempt to remove +// the target directory if it exists before replacing it with a mounted directory. +int _wasmfs_mount(char* path, wasmfs::backend_t created_backend) { + int err = __syscall_rmdir((intptr_t)path); + + // The legacy JS API mount requires the directory to already exist, but we will also allow it to be missing. + if (err && err != -ENOENT) { + return err; + } + + return wasmfs_create_directory(path, 0777, created_backend); +} + +// WasmFS will always remove the mounted directory, regardless of if the directory existed before. +int _wasmfs_unmount(char* path) { + return wasmfs_unmount((intptr_t)path); +} + // Helper method that identifies what a path is: // ENOENT - if nothing exists there // EISDIR - if it is a directory diff --git a/system/lib/wasmfs/syscalls.cpp b/system/lib/wasmfs/syscalls.cpp index 261b4aead7ddc..b78b2829eec33 100644 --- a/system/lib/wasmfs/syscalls.cpp +++ b/system/lib/wasmfs/syscalls.cpp @@ -861,6 +861,39 @@ int __syscall_rmdir(intptr_t path) { return __syscall_unlinkat(AT_FDCWD, path, AT_REMOVEDIR); } +// wasmfs_unmount is similar to __syscall_unlinkat, but assumes AT_REMOVEDIR is true +// and will only unlink mountpoints (Empty and nonempty). +int wasmfs_unmount(intptr_t path) { + auto parsed = path::parseParent((char*)path, AT_FDCWD); + if (auto err = parsed.getError()) { + return err; + } + auto& [parent, childNameView] = parsed.getParentChild(); + std::string childName(childNameView); + auto lockedParent = parent->locked(); + auto file = lockedParent.getChild(childName); + if (!file) { + return -ENOENT; + } + // Disallow removing the root directory, even if it is empty. + if (file == wasmFS.getRootDirectory()) { + return -EBUSY; + } + + if (auto dir = file->dynCast()) { + if (parent->getBackend() == dir->getBackend()) { + // The child is not a valid mountpoint. + return -EINVAL; + } + } else { + // A normal file or symlink. + return -ENOTDIR; + } + + // Input is valid, perform the unlink. + return lockedParent.removeChild(childName); +} + int __syscall_getdents64(int fd, intptr_t dirp, size_t count) { dirent* result = (dirent*)dirp; diff --git a/test/fs/test_fs_js_api.c b/test/fs/test_fs_js_api.c index 6d03c13a08a2c..d0fe6a2dc2c02 100644 --- a/test/fs/test_fs_js_api.c +++ b/test/fs/test_fs_js_api.c @@ -1,3 +1,10 @@ +/* + * Copyright 2023 The Emscripten Authors. All rights reserved. + * Emscripten is available under two separate licenses, the MIT license and the + * University of Illinois/NCSA Open Source License. Both these licenses can be + * found in the LICENSE file. + */ + #include #include #include diff --git a/test/fs/test_mount.c b/test/fs/test_mount.c index 8626eb1741f70..80d532f7a1056 100644 --- a/test/fs/test_mount.c +++ b/test/fs/test_mount.c @@ -26,13 +26,29 @@ int main() { contents = FS.readFile('/working/waka.txt', { encoding: 'utf8' }); assert(contents === 'az'); - // mount to a missing directory +#if !defined(WASMFS) + // the legacy API requires a mount directory to exist, while WasmFS will create the directory. try { FS.mount(MEMFS, {}, '/missing'); } catch (e) { ex = e; } - assert(ex instanceof FS.ErrnoError && ex.errno === 44); // ENOENT + assert(ex.name === 'ErrnoError' && ex.errno === 44); // ENOENT + ex = null; +#endif + +#if WASMFS + // WasmFS will throw an error if a directory to mount to is not empty, while the legacy API will not. + try { + FS.mkdir("/test"); + FS.writeFile("/test/hi.txt", "abc"); + FS.mount(MEMFS, {}, '/test'); + } catch (e) { + ex = e; + } + assert(ex.name === 'ErrnoError' && ex.errno === 55); // ENOTEMPTY + ex = null; +#endif // mount to an existing mountpoint try { @@ -40,7 +56,23 @@ int main() { } catch (e) { ex = e; } - assert(ex instanceof FS.ErrnoError && ex.errno === 10); // EBUSY +#if WASMFS + // WasmFS returns ENOTEMPTY instead of EBUSY in exchange for a simpler implementation. + assert(ex.name === 'ErrnoError' && ex.errno === 55); // ENOTEMPTY +#else + assert(ex.name === 'ErrnoError' && ex.errno === 10); // EBUSY +#endif + ex = null; + + // attempt to unmount a non-mountpoint directory inside a mountpoint + FS.mkdir('/working/unmountable'); + try { + FS.unmount('/working/unmountable'); + } catch (e) { + ex = e; + } + assert(ex.name === 'ErrnoError' && ex.errno === 28); // EINVAL + ex = null; // unmount FS.unmount('/working'); @@ -51,23 +83,51 @@ int main() { } catch (e) { ex = e; } - assert(ex instanceof FS.ErrnoError && ex.errno === 28); // EINVAL +#if WASMFS + // WasmFS will remove a directory on unmount, regardless of if a directory existed before. + assert(ex.name === 'ErrnoError' && ex.errno === 44); // ENOENT +#else + assert(ex.name === 'ErrnoError' && ex.errno === 28); // EINVAL +#endif + ex = null; // mount and unmount again FS.mount(MEMFS, {}, '/working'); FS.unmount('/working'); + ex = null; // try to read the file from the old mount try { FS.readFile('/working/waka.txt', { encoding: 'utf8' }); } catch (e) { ex = e; } - assert(ex instanceof FS.ErrnoError && ex.errno === 44); // ENOENT +#if !defined(WASMFS) + // WasmFS readFile aborts on failure, instead throwing an ErrnoError. + assert(ex.name === 'ErrnoError' && ex.errno === 44); // ENOENT +#else + assert(ex); +#endif + ex = null; // check the safe file contents = FS.readFile('/safe.txt', { encoding: 'utf8' }); assert(contents === 'abc'); + +#if WASMFS + // test JS_FILE backend + FS.mount(JSFILEFS, {}, "/jsfile"); + FS.writeFile("/jsfile/jsfile.txt", "a=1"); + assert(FS.readFile("/jsfile/jsfile.txt", { encoding: 'utf8' }) === 'a=1'); + FS.unmount("/jsfile"); + + // test ICASE backend + FS.mount(ICASEFS, { backend: MEMFS }, "/icase"); + FS.writeFile("/icase/IGNORE.txt", "a=1"); + assert(FS.readFile("/icase/Ignore.txt", { encoding: 'utf8' }) === 'a=1'); + assert(FS.readFile("/icase/ignore.TXT", { encoding: 'utf8' }) === 'a=1'); + FS.unmount("/icase"); +#endif ); puts("success"); diff --git a/test/test_core.py b/test/test_core.py index 72414079c8a62..31dba36241cd4 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -5634,6 +5634,9 @@ def clean(out): def test_mount(self): self.set_setting('FORCE_FILESYSTEM') + if self.get_setting('WASMFS'): + self.emcc_args += ['-licasefs.js'] + self.emcc_args += ['-ljsfilefs.js'] self.do_runf(test_file('fs/test_mount.c'), 'success') def test_getdents64(self): @@ -5941,6 +5944,8 @@ def test_fs_nodefs_rw(self): @also_with_noderawfs @requires_node def test_fs_nodefs_cloexec(self): + if self.get_setting('WASMFS'): + self.set_setting('FORCE_FILESYSTEM') self.emcc_args += ['-lnodefs.js'] self.do_runf(test_file('fs/test_nodefs_cloexec.c'), 'success') @@ -5952,12 +5957,16 @@ def test_fs_nodefs_home(self): @requires_node def test_fs_nodefs_nofollow(self): + if self.get_setting('WASMFS'): + self.set_setting('FORCE_FILESYSTEM') self.emcc_args += ['-lnodefs.js'] self.do_runf(test_file('fs/test_nodefs_nofollow.c'), 'success') @requires_node def test_fs_nodefs_readdir(self): # externally setup an existing folder structure: existing/a + if self.get_setting('WASMFS'): + self.set_setting('FORCE_FILESYSTEM') os.makedirs(os.path.join(self.working_dir, 'existing', 'a')) self.emcc_args += ['-lnodefs.js'] self.do_runf(test_file('fs/test_nodefs_readdir.c'), 'success') @@ -5978,6 +5987,8 @@ def test_fs_trackingdelegate(self): @also_with_noderawfs @also_with_wasmfs_js def test_fs_writeFile(self): + if self.get_setting('WASMFS'): + self.set_setting("FORCE_FILESYSTEM") self.do_run_in_out_file_test('fs/test_writeFile.cpp') def test_fs_js_api(self): From 505f49be0fb74d8d89d6016602af22cd52ba7392 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 1 Aug 2023 13:48:06 -0700 Subject: [PATCH 0604/1523] Fix EM_CALLBACK_THREAD_CONTEXT_CALLING_THREAD when used on the main thread. (#19943) Back in #19691 I tried to fix EM_CALLBACK_THREAD_CONTEXT_CALLING_THREAD but I broken the case where it was used in pthread applications but on the main thread itself. We were not previously testing this case because most of our testing was don't using PROXY_TO_PTHREAD, so the calls we originating from a non-main thread. Fixes: #19921 --- src/library_html5.js | 8 +++----- src/library_pthread.js | 6 ++++-- .../metadce/test_metadce_minimal_pthreads.jssize | 2 +- test/test_browser.py | 3 ++- test/test_interactive.py | 16 ++++++++++------ 5 files changed, 20 insertions(+), 15 deletions(-) diff --git a/src/library_html5.js b/src/library_html5.js index 378621c5c0279..3562ff07710c2 100644 --- a/src/library_html5.js +++ b/src/library_html5.js @@ -225,11 +225,9 @@ var LibraryHTML5 = { case {{{ cDefs.EM_CALLBACK_THREAD_CONTEXT_CALLING_THREAD }}}: // The event callback for the current event should be backproxied to // the thread that is registering the event. -#if ASSERTIONS - // If we get here PThread.currentProxiedOperationCallerThread should - // be set to the calling thread. - assert(PThread.currentProxiedOperationCallerThread); -#endif + // This can be 0 in the case that the caller uses + // EM_CALLBACK_THREAD_CONTEXT_CALLING_THREAD but on the main thread + // itself. return PThread.currentProxiedOperationCallerThread; default: // The event callback for the current event should be proxied to the diff --git a/src/library_pthread.js b/src/library_pthread.js index 82510f53479e9..ac740b0b523d5 100644 --- a/src/library_pthread.js +++ b/src/library_pthread.js @@ -1013,7 +1013,6 @@ var LibraryPThread = { // HTML5 DOM events handlers such as // emscripten_set_mousemove_callback()), so keep track in a globally // accessible variable about the thread that initiated the proxying. - PThread.currentProxiedOperationCallerThread = callingThread; #if WASM_BIGINT numCallArgs /= 2; #endif @@ -1043,7 +1042,10 @@ var LibraryPThread = { #if ASSERTIONS assert(func.length == numCallArgs, 'Call args mismatch in _emscripten_receive_on_main_thread_js'); #endif - return func.apply(null, proxiedJSCallArgs); + PThread.currentProxiedOperationCallerThread = callingThread; + var rtn = func.apply(null, proxiedFunctionTable); + PThread.currentProxiedOperationCallerThread = 0; + return rtn; }, $establishStackSpace__internal: true, diff --git a/test/other/metadce/test_metadce_minimal_pthreads.jssize b/test/other/metadce/test_metadce_minimal_pthreads.jssize index e91fdc3e1243d..16c2210899b3e 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.jssize +++ b/test/other/metadce/test_metadce_minimal_pthreads.jssize @@ -1 +1 @@ -14374 +14391 diff --git a/test/test_browser.py b/test/test_browser.py index 2b784780c8fb8..0b0d331c9f9c8 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -2636,7 +2636,8 @@ def test_doublestart_bug(self): @parameterized({ '': ([],), 'closure': (['-O2', '-g1', '--closure=1', '-sHTML5_SUPPORT_DEFERRING_USER_SENSITIVE_REQUESTS=0'],), - 'pthread': (['-pthread', '-sPROXY_TO_PTHREAD'],), + 'pthread': (['-pthread'],), + 'proxy_to_pthread': (['-pthread', '-sPROXY_TO_PTHREAD'],), 'legacy': (['-sMIN_FIREFOX_VERSION=0', '-sMIN_SAFARI_VERSION=0', '-sMIN_IE_VERSION=0', '-sMIN_EDGE_VERSION=0', '-sMIN_CHROME_VERSION=0', '-Wno-transpile'],) }) @requires_threads diff --git a/test/test_interactive.py b/test/test_interactive.py index 4e1e04d51dede..9a0bc0d61067d 100644 --- a/test/test_interactive.py +++ b/test/test_interactive.py @@ -237,13 +237,17 @@ def test_html5_callbacks_on_calling_thread(self): for args in [[], ['-DTEST_SYNC_BLOCKING_LOOP=1']]: self.btest('html5_callbacks_on_calling_thread.c', expected='1', args=args + ['-sDISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR', '-pthread', '-sPROXY_TO_PTHREAD']) - # Test that it is possible to register HTML5 event callbacks on either main browser thread, or application main thread, - # and that the application can manually proxy the event from main browser thread to the application main thread, to - # implement event suppression capabilities. - def test_html5_callback_on_two_threads(self): + # Test that it is possible to register HTML5 event callbacks on either main browser thread, or + # application main thread, and that the application can manually proxy the event from main browser + # thread to the application main thread, to implement event suppression capabilities. + @parameterized({ + '': ([],), + 'pthread': (['-pthread'],), + 'proxy_to_pthread': (['-pthread', '-sPROXY_TO_PTHREAD'],), + }) + def test_html5_event_callback_in_two_threads(self, args): # TODO: Make this automatic by injecting enter key press in e.g. shell html file. - for args in [[], ['-pthread', '-sPROXY_TO_PTHREAD']]: - self.btest('html5_event_callback_in_two_threads.c', expected='1', args=args) + self.btest('html5_event_callback_in_two_threads.c', expected='1', args=args) # Test that emscripten_hide_mouse() is callable from pthreads (and proxies to main thread to obtain the proper window.devicePixelRatio value). def test_emscripten_hide_mouse(self): From 5b962fef48080b94b4c96cebe8ee68d1844327db Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 1 Aug 2023 13:48:19 -0700 Subject: [PATCH 0605/1523] Update library_idbstore.js to use runtimeKeepalivePush/Pop. NFC (#19940) --- src/library_idbstore.js | 88 ++++++++++++++++++++++-------------- test/browser/test_idbstore.c | 29 +++--------- test/test_browser.py | 2 + 3 files changed, 63 insertions(+), 56 deletions(-) diff --git a/src/library_idbstore.js b/src/library_idbstore.js index 49cc6004c80d1..ea4c07397addd 100644 --- a/src/library_idbstore.js +++ b/src/library_idbstore.js @@ -7,51 +7,73 @@ #include "IDBStore.js" var LibraryIDBStore = { - // A simple IDB-backed storage mechanism. Suitable for saving and loading large files asynchronously. This does - // *NOT* use the emscripten filesystem, intentionally, to avoid overhead. It lets you application define whatever - // filesystem-like layer you want, with the overhead 100% controlled by you. At the extremes, you could either - // just store large files, with almost no extra code; or you could implement a file b-tree using posix-compliant + // A simple IDB-backed storage mechanism. Suitable for saving and loading + // large files asynchronously. This does *NOT* use the emscripten filesystem, + // intentionally, to avoid overhead. It lets you application define whatever + // filesystem-like layer you want, with the overhead 100% controlled by you. + // At the extremes, you could either just store large files, with almost no + // extra code; or you could implement a file b-tree using posix-compliant // filesystem on top. $IDBStore: IDBStore, - emscripten_idb_async_load__deps: ['$UTF8ToString', 'malloc', 'free'], + emscripten_idb_async_load__deps: ['$UTF8ToString', '$callUserCallback', 'malloc', 'free'], emscripten_idb_async_load: function(db, id, arg, onload, onerror) { - IDBStore.getFile(UTF8ToString(db), UTF8ToString(id), function(error, byteArray) { - if (error) { - if (onerror) {{{ makeDynCall('vi', 'onerror') }}}(arg); - return; - } - var buffer = _malloc(byteArray.length); - HEAPU8.set(byteArray, buffer); - {{{ makeDynCall('viii', 'onload') }}}(arg, buffer, byteArray.length); - _free(buffer); + {{{ runtimeKeepalivePush() }}}; + IDBStore.getFile(UTF8ToString(db), UTF8ToString(id), (error, byteArray) => { + {{{ runtimeKeepalivePop() }}} + callUserCallback(() => { + if (error) { + if (onerror) {{{ makeDynCall('vp', 'onerror') }}}(arg); + return; + } + var buffer = _malloc(byteArray.length); + HEAPU8.set(byteArray, buffer); + {{{ makeDynCall('vppi', 'onload') }}}(arg, buffer, byteArray.length); + _free(buffer); + }); }); }, + emscripten_idb_async_store__deps: ['$UTF8ToString', 'free', '$callUserCallback'], emscripten_idb_async_store: function(db, id, ptr, num, arg, onstore, onerror) { - // note that we copy the data here, as these are async operatins - changes to HEAPU8 meanwhile should not affect us! - IDBStore.setFile(UTF8ToString(db), UTF8ToString(id), new Uint8Array(HEAPU8.subarray(ptr, ptr+num)), function(error) { - if (error) { - if (onerror) {{{ makeDynCall('vi', 'onerror') }}}(arg); - return; - } - if (onstore) {{{ makeDynCall('vi', 'onstore') }}}(arg); + // note that we copy the data here, as these are async operatins - changes + // to HEAPU8 meanwhile should not affect us! + {{{ runtimeKeepalivePush() }}}; + IDBStore.setFile(UTF8ToString(db), UTF8ToString(id), new Uint8Array(HEAPU8.subarray(ptr, ptr+num)), (error) => { + {{{ runtimeKeepalivePop() }}} + callUserCallback(() => { + if (error) { + if (onerror) {{{ makeDynCall('vp', 'onerror') }}}(arg); + return; + } + if (onstore) {{{ makeDynCall('vp', 'onstore') }}}(arg); + }); }); }, + emscripten_idb_async_delete__deps: ['$UTF8ToString', '$callUserCallback'], emscripten_idb_async_delete: function(db, id, arg, ondelete, onerror) { - IDBStore.deleteFile(UTF8ToString(db), UTF8ToString(id), function(error) { - if (error) { - if (onerror) {{{ makeDynCall('vi', 'onerror') }}}(arg); - return; - } - if (ondelete) {{{ makeDynCall('vi', 'ondelete') }}}(arg); + {{{ runtimeKeepalivePush() }}}; + IDBStore.deleteFile(UTF8ToString(db), UTF8ToString(id), (error) => { + {{{ runtimeKeepalivePop() }}} + callUserCallback(() => { + if (error) { + if (onerror) {{{ makeDynCall('vp', 'onerror') }}}(arg); + return; + } + if (ondelete) {{{ makeDynCall('vp', 'ondelete') }}}(arg); + }); }); }, + emscripten_idb_async_exists__deps: ['$UTF8ToString', '$callUserCallback'], emscripten_idb_async_exists: function(db, id, arg, oncheck, onerror) { - IDBStore.existsFile(UTF8ToString(db), UTF8ToString(id), function(error, exists) { - if (error) { - if (onerror) {{{ makeDynCall('vi', 'onerror') }}}(arg); - return; - } - if (oncheck) {{{ makeDynCall('vii', 'oncheck') }}}(arg, exists); + {{{ runtimeKeepalivePush() }}}; + IDBStore.existsFile(UTF8ToString(db), UTF8ToString(id), (error, exists) => { + {{{ runtimeKeepalivePop() }}} + callUserCallback(() => { + if (error) { + if (onerror) {{{ makeDynCall('vp', 'onerror') }}}(arg); + return; + } + if (oncheck) {{{ makeDynCall('vpi', 'oncheck') }}}(arg, exists); + }); }); }, diff --git a/test/browser/test_idbstore.c b/test/browser/test_idbstore.c index d1efb4cf193c3..e41e476d8dda9 100644 --- a/test/browser/test_idbstore.c +++ b/test/browser/test_idbstore.c @@ -20,51 +20,37 @@ long expected; int result; -void doExit(void* userData) { - emscripten_force_exit(0); -} - -void ok(void* arg) -{ +void ok(void* arg) { assert(expected == (long)arg); - emscripten_set_timeout(doExit, 0, 0); } -void onerror(void* arg) -{ +void onerror(void* arg) { assert(expected == (long)arg); assert(false); } -void onload(void* arg, void* ptr, int num) -{ +void onload(void* arg, void* ptr, int num) { assert(expected == (long)arg); printf("loaded %s\n", (char*)ptr); assert(num == strlen(SECRET)+1); assert(strcmp(ptr, SECRET) == 0); - emscripten_set_timeout(doExit, 0, 0); } -void onbadload(void* arg, void* ptr, int num) -{ +void onbadload(void* arg, void* ptr, int num) { printf("load failed, surprising\n"); assert(false); } -void oncheck(void* arg, int exists) -{ +void oncheck(void* arg, int exists) { assert(expected == (long)arg); printf("exists? %d\n", exists); assert(exists); - emscripten_set_timeout(doExit, 0, 0); } -void onchecknope(void* arg, int exists) -{ +void onchecknope(void* arg, int exists) { assert(expected == (long)arg); printf("exists (hopefully not)? %d\n", exists); assert(!exists); - emscripten_set_timeout(doExit, 0, 0); } int main() { @@ -94,8 +80,5 @@ int main() { #else assert(0); #endif - - emscripten_exit_with_live_runtime(); - __builtin_trap(); } diff --git a/test/test_browser.py b/test/test_browser.py index 0b0d331c9f9c8..e55b3cd53ea76 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -1498,6 +1498,7 @@ def test_separate_metadata_later(self): self.run_process([FILE_PACKAGER, 'more.data', '--preload', 'data.dat', '--separate-metadata', '--js-output=more.js']) self.btest(Path('browser/separate_metadata_later.cpp'), '1', args=['-sFORCE_FILESYSTEM']) + @also_with_wasm64 def test_idbstore(self): secret = str(time.time()) for stage in [0, 1, 2, 3, 0, 1, 2, 0, 0, 1, 4, 2, 5]: @@ -1506,6 +1507,7 @@ def test_idbstore(self): args=['-lidbstore.js', f'-DSTAGE={stage}', f'-DSECRET="{secret}"'], output_basename=f'idbstore_{stage}') + @also_with_wasm64 def test_idbstore_sync(self): secret = str(time.time()) self.btest(test_file('browser/test_idbstore_sync.c'), '6', args=['-lidbstore.js', f'-DSECRET="{secret}"', '-O3', '-g2', '-sASYNCIFY']) From f14f0294538d307c8a5253502ec6c550767f2886 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 1 Aug 2023 13:52:48 -0700 Subject: [PATCH 0606/1523] Move legacy thread proxying system into seperate source and header. NFC (#19946) This is the first step towards removing the internal use of the old proxying system. The primary user of which is the JS library proxying system. The legacy proxying system is already layered on top of the new proxying system so removing it should be pure win. --- system/include/emscripten/threading.h | 183 +------ system/include/emscripten/threading_legacy.h | 201 +++++++ system/lib/pthread/library_pthread.c | 438 ---------------- system/lib/pthread/proxying_legacy.c | 519 +++++++++++++++++++ system/lib/pthread/threading_internal.h | 68 --- tools/system_libs.py | 1 + 6 files changed, 724 insertions(+), 686 deletions(-) create mode 100644 system/include/emscripten/threading_legacy.h create mode 100644 system/lib/pthread/proxying_legacy.c diff --git a/system/include/emscripten/threading.h b/system/include/emscripten/threading.h index 362cd561aa4c4..1d3f41df2fc29 100644 --- a/system/include/emscripten/threading.h +++ b/system/include/emscripten/threading.h @@ -9,11 +9,13 @@ #include #include -#include #include // for EMSCRIPTEN_RESULT #include +// Legacy proxying functions. See proxying.h for the new proxying system. +#include "threading_legacy.h" + #ifdef __cplusplus extern "C" { #endif @@ -44,182 +46,6 @@ int emscripten_futex_wait(volatile void/*uint32_t*/ * _Nonnull addr, uint32_t va // Returns -EINVAL if addr is null. int emscripten_futex_wake(volatile void/*uint32_t*/ * _Nonnull addr, int count); -typedef struct em_queued_call em_queued_call; - -// Encode function signatures into a single uint32_t integer. -// N.B. This encoding scheme is internal to the implementation, and can change -// in the future. Do not depend on the exact numbers in this scheme. -#define EM_FUNC_SIGNATURE unsigned int - -// The encoding scheme is as follows: -// - highest three bits identify the type of the return value -#define EM_FUNC_SIG_RETURN_VALUE_MASK (0x7U << 29) - -#define EM_FUNC_SIG_RETURN_VALUE_V 0 -#define EM_FUNC_SIG_RETURN_VALUE_I (0x1U << 29) -#define EM_FUNC_SIG_RETURN_VALUE_I64 (0x2U << 29) -#define EM_FUNC_SIG_RETURN_VALUE_F (0x3U << 29) -#define EM_FUNC_SIG_RETURN_VALUE_D (0x4U << 29) - -// - next highest four bits specify the number of input parameters to the -// function (allowed values are 0-12, inclusively) -#define EM_FUNC_SIG_NUM_PARAMETERS_SHIFT 25 -#define EM_FUNC_SIG_NUM_PARAMETERS_MASK (0xFU << EM_FUNC_SIG_NUM_PARAMETERS_SHIFT) -#define EM_FUNC_SIG_WITH_N_PARAMETERS(x) (((EM_FUNC_SIGNATURE)(x)) << EM_FUNC_SIG_NUM_PARAMETERS_SHIFT) - -// - starting from the lowest bits upwards, each pair of two subsequent bits -// specifies the type of an input parameter. -// That is, bits 1:0 encode the type of the first input, bits 3:2 encode the -// type of the second input, and so on. -#define EM_FUNC_SIG_ARGUMENTS_TYPE_MASK (~(EM_FUNC_SIG_RETURN_VALUE_MASK | EM_FUNC_SIG_NUM_PARAMETERS_MASK)) -#define EM_FUNC_SIG_ARGUMENT_TYPE_SIZE_MASK 0x3U -#define EM_FUNC_SIG_ARGUMENT_TYPE_SIZE_SHIFT 2 - -#define EM_FUNC_SIG_PARAM_I 0 -#define EM_FUNC_SIG_PARAM_I64 0x1U -#define EM_FUNC_SIG_PARAM_F 0x2U -#define EM_FUNC_SIG_PARAM_D 0x3U -#define EM_FUNC_SIG_SET_PARAM(i, type) ((EM_FUNC_SIGNATURE)(type) << (2*i)) - -// Extra types used in WebGL glGet*() calls (not used in proxying) -#define EM_FUNC_SIG_PARAM_B 0x4U -#define EM_FUNC_SIG_PARAM_F2I 0x5U - -// In total, the above encoding scheme gives the following 32-bit structure for -// the proxied function signatures (highest -> lowest bit order): -// RRRiiiiSbbaa99887766554433221100 -// where RRR is return type -// iiii is the number of inputs -// S denotes a special function (internal proxying mechanism for functions -// related to built-in threading APIs, like thread creation itself) -// 00-bb encode the type of up to 12 function parameters - -#define EM_FUNC_SIG_V (EM_FUNC_SIG_RETURN_VALUE_V | EM_FUNC_SIG_WITH_N_PARAMETERS(0)) -#define EM_FUNC_SIG_D (EM_FUNC_SIG_RETURN_VALUE_D | EM_FUNC_SIG_WITH_N_PARAMETERS(0)) -#define EM_FUNC_SIG_VI (EM_FUNC_SIG_RETURN_VALUE_V | EM_FUNC_SIG_WITH_N_PARAMETERS(1) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I)) -#define EM_FUNC_SIG_VF (EM_FUNC_SIG_RETURN_VALUE_V | EM_FUNC_SIG_WITH_N_PARAMETERS(1) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_F)) -#define EM_FUNC_SIG_FI (EM_FUNC_SIG_RETURN_VALUE_F | EM_FUNC_SIG_WITH_N_PARAMETERS(1) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I)) -#define EM_FUNC_SIG_DI (EM_FUNC_SIG_RETURN_VALUE_D | EM_FUNC_SIG_WITH_N_PARAMETERS(1) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I)) -#define EM_FUNC_SIG_VII (EM_FUNC_SIG_RETURN_VALUE_V | EM_FUNC_SIG_WITH_N_PARAMETERS(2) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_I)) -#define EM_FUNC_SIG_VIF (EM_FUNC_SIG_RETURN_VALUE_V | EM_FUNC_SIG_WITH_N_PARAMETERS(2) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_F)) -#define EM_FUNC_SIG_VFF (EM_FUNC_SIG_RETURN_VALUE_V | EM_FUNC_SIG_WITH_N_PARAMETERS(2) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_F) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_F)) -#define EM_FUNC_SIG_VIII (EM_FUNC_SIG_RETURN_VALUE_V | EM_FUNC_SIG_WITH_N_PARAMETERS(3) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_I)) -#define EM_FUNC_SIG_VIIF (EM_FUNC_SIG_RETURN_VALUE_V | EM_FUNC_SIG_WITH_N_PARAMETERS(3) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_F)) -#define EM_FUNC_SIG_VIFF (EM_FUNC_SIG_RETURN_VALUE_V | EM_FUNC_SIG_WITH_N_PARAMETERS(3) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_F) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_F)) -#define EM_FUNC_SIG_VFFF (EM_FUNC_SIG_RETURN_VALUE_V | EM_FUNC_SIG_WITH_N_PARAMETERS(3) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_F) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_F) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_F)) -#define EM_FUNC_SIG_VIIII (EM_FUNC_SIG_RETURN_VALUE_V | EM_FUNC_SIG_WITH_N_PARAMETERS(4) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(3, EM_FUNC_SIG_PARAM_I)) -#define EM_FUNC_SIG_VIIFI (EM_FUNC_SIG_RETURN_VALUE_V | EM_FUNC_SIG_WITH_N_PARAMETERS(4) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_F) | EM_FUNC_SIG_SET_PARAM(3, EM_FUNC_SIG_PARAM_I)) -#define EM_FUNC_SIG_VIFFF (EM_FUNC_SIG_RETURN_VALUE_V | EM_FUNC_SIG_WITH_N_PARAMETERS(4) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_F) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_F) | EM_FUNC_SIG_SET_PARAM(3, EM_FUNC_SIG_PARAM_F)) -#define EM_FUNC_SIG_VFFFF (EM_FUNC_SIG_RETURN_VALUE_V | EM_FUNC_SIG_WITH_N_PARAMETERS(4) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_F) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_F) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_F) | EM_FUNC_SIG_SET_PARAM(3, EM_FUNC_SIG_PARAM_F)) -#define EM_FUNC_SIG_IIFFF (EM_FUNC_SIG_RETURN_VALUE_I | EM_FUNC_SIG_WITH_N_PARAMETERS(4) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_F) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_F) | EM_FUNC_SIG_SET_PARAM(3, EM_FUNC_SIG_PARAM_F)) -#define EM_FUNC_SIG_VIIIII (EM_FUNC_SIG_RETURN_VALUE_V | EM_FUNC_SIG_WITH_N_PARAMETERS(5) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(3, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(4, EM_FUNC_SIG_PARAM_I)) -#define EM_FUNC_SIG_VIFFFF (EM_FUNC_SIG_RETURN_VALUE_V | EM_FUNC_SIG_WITH_N_PARAMETERS(5) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_F) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_F) | EM_FUNC_SIG_SET_PARAM(3, EM_FUNC_SIG_PARAM_F) | EM_FUNC_SIG_SET_PARAM(4, EM_FUNC_SIG_PARAM_F)) -#define EM_FUNC_SIG_VIIIIII (EM_FUNC_SIG_RETURN_VALUE_V | EM_FUNC_SIG_WITH_N_PARAMETERS(6) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(3, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(4, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(5, EM_FUNC_SIG_PARAM_I)) -#define EM_FUNC_SIG_VIIIIIII (EM_FUNC_SIG_RETURN_VALUE_V | EM_FUNC_SIG_WITH_N_PARAMETERS(7) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(3, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(4, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(5, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(6, EM_FUNC_SIG_PARAM_I)) -#define EM_FUNC_SIG_VIIIIIIII (EM_FUNC_SIG_RETURN_VALUE_V | EM_FUNC_SIG_WITH_N_PARAMETERS(8) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(3, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(4, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(5, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(6, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(7, EM_FUNC_SIG_PARAM_I)) -#define EM_FUNC_SIG_VIIIIIIIII (EM_FUNC_SIG_RETURN_VALUE_V | EM_FUNC_SIG_WITH_N_PARAMETERS(9) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(3, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(4, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(5, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(6, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(7, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(8, EM_FUNC_SIG_PARAM_I)) -#define EM_FUNC_SIG_VIIIIIIIIII (EM_FUNC_SIG_RETURN_VALUE_V | EM_FUNC_SIG_WITH_N_PARAMETERS(10) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(3, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(4, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(5, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(6, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(7, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(8, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(9, EM_FUNC_SIG_PARAM_I)) -#define EM_FUNC_SIG_VIIIIIIIIIII (EM_FUNC_SIG_RETURN_VALUE_V | EM_FUNC_SIG_WITH_N_PARAMETERS(11) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(3, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(4, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(5, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(6, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(7, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(8, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(9, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(10, EM_FUNC_SIG_PARAM_I)) -#define EM_FUNC_SIG_I (EM_FUNC_SIG_RETURN_VALUE_I | EM_FUNC_SIG_WITH_N_PARAMETERS(0)) -#define EM_FUNC_SIG_II (EM_FUNC_SIG_RETURN_VALUE_I | EM_FUNC_SIG_WITH_N_PARAMETERS(1) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I)) -#define EM_FUNC_SIG_III (EM_FUNC_SIG_RETURN_VALUE_I | EM_FUNC_SIG_WITH_N_PARAMETERS(2) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_I)) -#define EM_FUNC_SIG_IIII (EM_FUNC_SIG_RETURN_VALUE_I | EM_FUNC_SIG_WITH_N_PARAMETERS(3) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_I)) -#define EM_FUNC_SIG_IIIII (EM_FUNC_SIG_RETURN_VALUE_I | EM_FUNC_SIG_WITH_N_PARAMETERS(4) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(3, EM_FUNC_SIG_PARAM_I)) -#define EM_FUNC_SIG_IIIIII (EM_FUNC_SIG_RETURN_VALUE_I | EM_FUNC_SIG_WITH_N_PARAMETERS(5) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(3, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(4, EM_FUNC_SIG_PARAM_I)) -#define EM_FUNC_SIG_IIIIIII (EM_FUNC_SIG_RETURN_VALUE_I | EM_FUNC_SIG_WITH_N_PARAMETERS(6) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(3, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(4, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(5, EM_FUNC_SIG_PARAM_I)) -#define EM_FUNC_SIG_IIIIIIII (EM_FUNC_SIG_RETURN_VALUE_I | EM_FUNC_SIG_WITH_N_PARAMETERS(7) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(3, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(4, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(5, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(6, EM_FUNC_SIG_PARAM_I)) -#define EM_FUNC_SIG_IIIIIIIII (EM_FUNC_SIG_RETURN_VALUE_I | EM_FUNC_SIG_WITH_N_PARAMETERS(8) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(3, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(4, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(5, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(6, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(7, EM_FUNC_SIG_PARAM_I)) -#define EM_FUNC_SIG_IIIIIIIIII (EM_FUNC_SIG_RETURN_VALUE_I | EM_FUNC_SIG_WITH_N_PARAMETERS(9) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(3, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(4, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(5, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(6, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(7, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(8, EM_FUNC_SIG_PARAM_I)) - -#define EM_FUNC_SIG_NUM_FUNC_ARGUMENTS(x) ((((EM_FUNC_SIGNATURE)x) & EM_FUNC_SIG_NUM_PARAMETERS_MASK) >> EM_FUNC_SIG_NUM_PARAMETERS_SHIFT) - -// There are some built-in special proxied functions, that embed the signatures -// inside the above encoding scheme -#define EM_FUNC_SIG_SPECIAL_INTERNAL (1 << 24) -#define EM_PROXIED_FUNC_SPECIAL(x) (EM_FUNC_SIG_SPECIAL_INTERNAL | ((x) << 20)) - -#define EM_PROXIED_RESIZE_OFFSCREENCANVAS (EM_PROXIED_FUNC_SPECIAL(0) | EM_FUNC_SIG_IIII) -#define EM_PROXIED_JS_FUNCTION (EM_PROXIED_FUNC_SPECIAL(1) | EM_FUNC_SIG_D) - -// Runs the given function synchronously on the main Emscripten runtime thread. -// If this thread is the main thread, the operation is immediately performed, -// and the result is returned. -// If the current thread is not the main Emscripten runtime thread (but a -// pthread), the function -// will be proxied to be called by the main thread. -// - Calling emscripten_sync_* functions requires that the application was -// compiled with pthreads support enabled (-pthread) and that the -// browser supports SharedArrayBuffer specification. -int emscripten_sync_run_in_main_runtime_thread_(EM_FUNC_SIGNATURE sig, void *func_ptr __attribute__((nonnull)), ...); - -// The 'async' variant of the run_in_main_thread functions are otherwise the -// same as the synchronous ones, except that the operation is performed in a -// fire and forget manner. The call is placed to the command queue of the main -// Emscripten runtime thread, but its completion is not waited for. As a result, -// if the function did have a return value, the return value is not received. -// - Note that multiple asynchronous commands from a single pthread/Worker are -// guaranteed to be executed on the main thread in the program order they -// were called in. -void emscripten_async_run_in_main_runtime_thread_(EM_FUNC_SIGNATURE sig, void *func_ptr __attribute__((nonnull)), ...); - -// The 'async_waitable' variant of the run_in_main_runtime_thread functions run -// like the 'async' variants, except that while the operation starts off -// asynchronously, the result is then later waited upon to receive the return -// value. -// - The object returned by this function call is dynamically allocated, and -// should be freed up via a call to emscripten_async_waitable_close() after -// the wait has been performed. -em_queued_call *emscripten_async_waitable_run_in_main_runtime_thread_(EM_FUNC_SIGNATURE sig, void *func_ptr __attribute__((nonnull)), ...); - -// Since we can't validate the function pointer type, allow implicit casting of -// functions to void* without complaining. -#define emscripten_sync_run_in_main_runtime_thread(sig, func_ptr, ...) emscripten_sync_run_in_main_runtime_thread_((sig), (void*)(func_ptr),##__VA_ARGS__) -#define emscripten_async_run_in_main_runtime_thread(sig, func_ptr, ...) emscripten_async_run_in_main_runtime_thread_((sig), (void*)(func_ptr),##__VA_ARGS__) -#define emscripten_async_waitable_run_in_main_runtime_thread(sig, func_ptr, ...) emscripten_async_waitable_run_in_main_runtime_thread_((sig), (void*)(func_ptr),##__VA_ARGS__) - -EMSCRIPTEN_RESULT emscripten_wait_for_call_v(em_queued_call *call __attribute__((nonnull)), double timeoutMSecs); -EMSCRIPTEN_RESULT emscripten_wait_for_call_i(em_queued_call *call __attribute__((nonnull)), double timeoutMSecs, int *outResult); - -void emscripten_async_waitable_close(em_queued_call *call __attribute__((nonnull))); - -// Runs the given function on the specified thread. If we are currently on -// that target thread then we just execute the call synchronously; otherwise it -// is queued on that thread to execute asynchronously. -// Returns 1 if it executed the code (i.e., it was on the target thread), and 0 -// otherwise. -int emscripten_dispatch_to_thread_args(pthread_t target_thread, - EM_FUNC_SIGNATURE sig, - void* func_ptr __attribute__((nonnull)), - void* satellite, - va_list args); -int emscripten_dispatch_to_thread_(pthread_t target_thread, - EM_FUNC_SIGNATURE sig, - void* func_ptr __attribute__((nonnull)), - void* satellite, - ...); -#define emscripten_dispatch_to_thread( \ - target_thread, sig, func_ptr, satellite, ...) \ - emscripten_dispatch_to_thread_( \ - (target_thread), (sig), (void*)(func_ptr), (satellite), ##__VA_ARGS__) - -// Similar to emscripten_dispatch_to_thread, but always runs the -// function asynchronously, even if on the same thread. This is less efficient -// but may be simpler to reason about in some cases. -int emscripten_dispatch_to_thread_async_args(pthread_t target_thread, - EM_FUNC_SIGNATURE sig, - void* func_ptr __attribute__((nonnull)), - void* satellite, - va_list args); -int emscripten_dispatch_to_thread_async_(pthread_t target_thread, - EM_FUNC_SIGNATURE sig, - void* func_ptr __attribute__((nonnull)), - void* satellite, - ...); -#define emscripten_dispatch_to_thread_async( \ - target_thread, sig, func_ptr, satellite, ...) \ - emscripten_dispatch_to_thread_async_( \ - (target_thread), (sig), (void*)(func_ptr), (satellite), ##__VA_ARGS__) - // Returns 1 if the current thread is the thread that hosts the Emscripten // runtime. int emscripten_is_main_runtime_thread(void); @@ -241,9 +67,6 @@ void emscripten_current_thread_process_queued_calls(void); // Returns the thread ID of the thread that hosts the Emscripten runtime. pthread_t emscripten_main_runtime_thread_id(void); -#define emscripten_main_browser_thread_id() emscripten_main_runtime_thread_id() -#pragma clang deprecated(emscripten_main_browser_thread_id, "use emscripten_main_runtime_thread_id instead") - // Synchronously sleeps the calling thread for the given number of milliseconds. // Note: Calling this on the main browser thread is _very_ _very_ bad for // application logic throttling, because it does not save any battery, it will diff --git a/system/include/emscripten/threading_legacy.h b/system/include/emscripten/threading_legacy.h new file mode 100644 index 0000000000000..3bc9a0d2027a8 --- /dev/null +++ b/system/include/emscripten/threading_legacy.h @@ -0,0 +1,201 @@ +/* + * Copyright 2015 The Emscripten Authors. All rights reserved. + * Emscripten is available under two separate licenses, the MIT license and the + * University of Illinois/NCSA Open Source License. Both these licenses can be + * found in the LICENSE file. + * + * Legacy proxying functions. See proxying.h for the new proxying system. + */ + +#pragma once + +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define emscripten_main_browser_thread_id() emscripten_main_runtime_thread_id() +#pragma clang deprecated(emscripten_main_browser_thread_id, "use emscripten_main_runtime_thread_id instead") + +typedef struct em_queued_call em_queued_call; + +// Encode function signatures into a single uint32_t integer. +// N.B. This encoding scheme is internal to the implementation, and can change +// in the future. Do not depend on the exact numbers in this scheme. +#define EM_FUNC_SIGNATURE unsigned int + +// The encoding scheme is as follows: +// - highest three bits identify the type of the return value +#define EM_FUNC_SIG_RETURN_VALUE_MASK (0x7U << 29) + +#define EM_FUNC_SIG_RETURN_VALUE_V 0 +#define EM_FUNC_SIG_RETURN_VALUE_I (0x1U << 29) +#define EM_FUNC_SIG_RETURN_VALUE_I64 (0x2U << 29) +#define EM_FUNC_SIG_RETURN_VALUE_F (0x3U << 29) +#define EM_FUNC_SIG_RETURN_VALUE_D (0x4U << 29) + +// - next highest four bits specify the number of input parameters to the +// function (allowed values are 0-12, inclusively) +#define EM_FUNC_SIG_NUM_PARAMETERS_SHIFT 25 +#define EM_FUNC_SIG_NUM_PARAMETERS_MASK (0xFU << EM_FUNC_SIG_NUM_PARAMETERS_SHIFT) +#define EM_FUNC_SIG_WITH_N_PARAMETERS(x) (((EM_FUNC_SIGNATURE)(x)) << EM_FUNC_SIG_NUM_PARAMETERS_SHIFT) + +// - starting from the lowest bits upwards, each pair of two subsequent bits +// specifies the type of an input parameter. +// That is, bits 1:0 encode the type of the first input, bits 3:2 encode the +// type of the second input, and so on. +#define EM_FUNC_SIG_ARGUMENTS_TYPE_MASK (~(EM_FUNC_SIG_RETURN_VALUE_MASK | EM_FUNC_SIG_NUM_PARAMETERS_MASK)) +#define EM_FUNC_SIG_ARGUMENT_TYPE_SIZE_MASK 0x3U +#define EM_FUNC_SIG_ARGUMENT_TYPE_SIZE_SHIFT 2 + +#define EM_FUNC_SIG_PARAM_I 0 +#define EM_FUNC_SIG_PARAM_I64 0x1U +#define EM_FUNC_SIG_PARAM_F 0x2U +#define EM_FUNC_SIG_PARAM_D 0x3U +#define EM_FUNC_SIG_SET_PARAM(i, type) ((EM_FUNC_SIGNATURE)(type) << (2*i)) + +// Extra types used in WebGL glGet*() calls (not used in proxying) +#define EM_FUNC_SIG_PARAM_B 0x4U +#define EM_FUNC_SIG_PARAM_F2I 0x5U + +// In total, the above encoding scheme gives the following 32-bit structure for +// the proxied function signatures (highest -> lowest bit order): +// RRRiiiiSbbaa99887766554433221100 +// where RRR is return type +// iiii is the number of inputs +// S denotes a special function (internal proxying mechanism for functions +// related to built-in threading APIs, like thread creation itself) +// 00-bb encode the type of up to 12 function parameters + +#define EM_FUNC_SIG_V (EM_FUNC_SIG_RETURN_VALUE_V | EM_FUNC_SIG_WITH_N_PARAMETERS(0)) +#define EM_FUNC_SIG_D (EM_FUNC_SIG_RETURN_VALUE_D | EM_FUNC_SIG_WITH_N_PARAMETERS(0)) +#define EM_FUNC_SIG_VI (EM_FUNC_SIG_RETURN_VALUE_V | EM_FUNC_SIG_WITH_N_PARAMETERS(1) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I)) +#define EM_FUNC_SIG_VF (EM_FUNC_SIG_RETURN_VALUE_V | EM_FUNC_SIG_WITH_N_PARAMETERS(1) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_F)) +#define EM_FUNC_SIG_FI (EM_FUNC_SIG_RETURN_VALUE_F | EM_FUNC_SIG_WITH_N_PARAMETERS(1) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I)) +#define EM_FUNC_SIG_DI (EM_FUNC_SIG_RETURN_VALUE_D | EM_FUNC_SIG_WITH_N_PARAMETERS(1) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I)) +#define EM_FUNC_SIG_VII (EM_FUNC_SIG_RETURN_VALUE_V | EM_FUNC_SIG_WITH_N_PARAMETERS(2) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_I)) +#define EM_FUNC_SIG_VIF (EM_FUNC_SIG_RETURN_VALUE_V | EM_FUNC_SIG_WITH_N_PARAMETERS(2) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_F)) +#define EM_FUNC_SIG_VFF (EM_FUNC_SIG_RETURN_VALUE_V | EM_FUNC_SIG_WITH_N_PARAMETERS(2) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_F) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_F)) +#define EM_FUNC_SIG_VIII (EM_FUNC_SIG_RETURN_VALUE_V | EM_FUNC_SIG_WITH_N_PARAMETERS(3) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_I)) +#define EM_FUNC_SIG_VIIF (EM_FUNC_SIG_RETURN_VALUE_V | EM_FUNC_SIG_WITH_N_PARAMETERS(3) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_F)) +#define EM_FUNC_SIG_VIFF (EM_FUNC_SIG_RETURN_VALUE_V | EM_FUNC_SIG_WITH_N_PARAMETERS(3) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_F) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_F)) +#define EM_FUNC_SIG_VFFF (EM_FUNC_SIG_RETURN_VALUE_V | EM_FUNC_SIG_WITH_N_PARAMETERS(3) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_F) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_F) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_F)) +#define EM_FUNC_SIG_VIIII (EM_FUNC_SIG_RETURN_VALUE_V | EM_FUNC_SIG_WITH_N_PARAMETERS(4) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(3, EM_FUNC_SIG_PARAM_I)) +#define EM_FUNC_SIG_VIIFI (EM_FUNC_SIG_RETURN_VALUE_V | EM_FUNC_SIG_WITH_N_PARAMETERS(4) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_F) | EM_FUNC_SIG_SET_PARAM(3, EM_FUNC_SIG_PARAM_I)) +#define EM_FUNC_SIG_VIFFF (EM_FUNC_SIG_RETURN_VALUE_V | EM_FUNC_SIG_WITH_N_PARAMETERS(4) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_F) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_F) | EM_FUNC_SIG_SET_PARAM(3, EM_FUNC_SIG_PARAM_F)) +#define EM_FUNC_SIG_VFFFF (EM_FUNC_SIG_RETURN_VALUE_V | EM_FUNC_SIG_WITH_N_PARAMETERS(4) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_F) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_F) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_F) | EM_FUNC_SIG_SET_PARAM(3, EM_FUNC_SIG_PARAM_F)) +#define EM_FUNC_SIG_IIFFF (EM_FUNC_SIG_RETURN_VALUE_I | EM_FUNC_SIG_WITH_N_PARAMETERS(4) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_F) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_F) | EM_FUNC_SIG_SET_PARAM(3, EM_FUNC_SIG_PARAM_F)) +#define EM_FUNC_SIG_VIIIII (EM_FUNC_SIG_RETURN_VALUE_V | EM_FUNC_SIG_WITH_N_PARAMETERS(5) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(3, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(4, EM_FUNC_SIG_PARAM_I)) +#define EM_FUNC_SIG_VIFFFF (EM_FUNC_SIG_RETURN_VALUE_V | EM_FUNC_SIG_WITH_N_PARAMETERS(5) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_F) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_F) | EM_FUNC_SIG_SET_PARAM(3, EM_FUNC_SIG_PARAM_F) | EM_FUNC_SIG_SET_PARAM(4, EM_FUNC_SIG_PARAM_F)) +#define EM_FUNC_SIG_VIIIIII (EM_FUNC_SIG_RETURN_VALUE_V | EM_FUNC_SIG_WITH_N_PARAMETERS(6) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(3, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(4, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(5, EM_FUNC_SIG_PARAM_I)) +#define EM_FUNC_SIG_VIIIIIII (EM_FUNC_SIG_RETURN_VALUE_V | EM_FUNC_SIG_WITH_N_PARAMETERS(7) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(3, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(4, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(5, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(6, EM_FUNC_SIG_PARAM_I)) +#define EM_FUNC_SIG_VIIIIIIII (EM_FUNC_SIG_RETURN_VALUE_V | EM_FUNC_SIG_WITH_N_PARAMETERS(8) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(3, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(4, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(5, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(6, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(7, EM_FUNC_SIG_PARAM_I)) +#define EM_FUNC_SIG_VIIIIIIIII (EM_FUNC_SIG_RETURN_VALUE_V | EM_FUNC_SIG_WITH_N_PARAMETERS(9) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(3, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(4, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(5, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(6, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(7, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(8, EM_FUNC_SIG_PARAM_I)) +#define EM_FUNC_SIG_VIIIIIIIIII (EM_FUNC_SIG_RETURN_VALUE_V | EM_FUNC_SIG_WITH_N_PARAMETERS(10) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(3, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(4, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(5, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(6, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(7, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(8, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(9, EM_FUNC_SIG_PARAM_I)) +#define EM_FUNC_SIG_VIIIIIIIIIII (EM_FUNC_SIG_RETURN_VALUE_V | EM_FUNC_SIG_WITH_N_PARAMETERS(11) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(3, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(4, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(5, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(6, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(7, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(8, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(9, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(10, EM_FUNC_SIG_PARAM_I)) +#define EM_FUNC_SIG_I (EM_FUNC_SIG_RETURN_VALUE_I | EM_FUNC_SIG_WITH_N_PARAMETERS(0)) +#define EM_FUNC_SIG_II (EM_FUNC_SIG_RETURN_VALUE_I | EM_FUNC_SIG_WITH_N_PARAMETERS(1) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I)) +#define EM_FUNC_SIG_III (EM_FUNC_SIG_RETURN_VALUE_I | EM_FUNC_SIG_WITH_N_PARAMETERS(2) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_I)) +#define EM_FUNC_SIG_IIII (EM_FUNC_SIG_RETURN_VALUE_I | EM_FUNC_SIG_WITH_N_PARAMETERS(3) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_I)) +#define EM_FUNC_SIG_IIIII (EM_FUNC_SIG_RETURN_VALUE_I | EM_FUNC_SIG_WITH_N_PARAMETERS(4) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(3, EM_FUNC_SIG_PARAM_I)) +#define EM_FUNC_SIG_IIIIII (EM_FUNC_SIG_RETURN_VALUE_I | EM_FUNC_SIG_WITH_N_PARAMETERS(5) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(3, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(4, EM_FUNC_SIG_PARAM_I)) +#define EM_FUNC_SIG_IIIIIII (EM_FUNC_SIG_RETURN_VALUE_I | EM_FUNC_SIG_WITH_N_PARAMETERS(6) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(3, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(4, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(5, EM_FUNC_SIG_PARAM_I)) +#define EM_FUNC_SIG_IIIIIIII (EM_FUNC_SIG_RETURN_VALUE_I | EM_FUNC_SIG_WITH_N_PARAMETERS(7) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(3, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(4, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(5, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(6, EM_FUNC_SIG_PARAM_I)) +#define EM_FUNC_SIG_IIIIIIIII (EM_FUNC_SIG_RETURN_VALUE_I | EM_FUNC_SIG_WITH_N_PARAMETERS(8) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(3, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(4, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(5, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(6, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(7, EM_FUNC_SIG_PARAM_I)) +#define EM_FUNC_SIG_IIIIIIIIII (EM_FUNC_SIG_RETURN_VALUE_I | EM_FUNC_SIG_WITH_N_PARAMETERS(9) | EM_FUNC_SIG_SET_PARAM(0, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(1, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(2, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(3, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(4, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(5, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(6, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(7, EM_FUNC_SIG_PARAM_I) | EM_FUNC_SIG_SET_PARAM(8, EM_FUNC_SIG_PARAM_I)) + +#define EM_FUNC_SIG_NUM_FUNC_ARGUMENTS(x) ((((EM_FUNC_SIGNATURE)x) & EM_FUNC_SIG_NUM_PARAMETERS_MASK) >> EM_FUNC_SIG_NUM_PARAMETERS_SHIFT) + +// There are some built-in special proxied functions, that embed the signatures +// inside the above encoding scheme +#define EM_FUNC_SIG_SPECIAL_INTERNAL (1 << 24) +#define EM_PROXIED_FUNC_SPECIAL(x) (EM_FUNC_SIG_SPECIAL_INTERNAL | ((x) << 20)) + +#define EM_PROXIED_RESIZE_OFFSCREENCANVAS (EM_PROXIED_FUNC_SPECIAL(0) | EM_FUNC_SIG_IIII) +#define EM_PROXIED_JS_FUNCTION (EM_PROXIED_FUNC_SPECIAL(1) | EM_FUNC_SIG_D) + +// Runs the given function synchronously on the main Emscripten runtime thread. +// If this thread is the main thread, the operation is immediately performed, +// and the result is returned. +// If the current thread is not the main Emscripten runtime thread (but a +// pthread), the function +// will be proxied to be called by the main thread. +// - Calling emscripten_sync_* functions requires that the application was +// compiled with pthreads support enabled (-pthread) and that the +// browser supports SharedArrayBuffer specification. +int emscripten_sync_run_in_main_runtime_thread_(EM_FUNC_SIGNATURE sig, void *func_ptr __attribute__((nonnull)), ...); + +// The 'async' variant of the run_in_main_thread functions are otherwise the +// same as the synchronous ones, except that the operation is performed in a +// fire and forget manner. The call is placed to the command queue of the main +// Emscripten runtime thread, but its completion is not waited for. As a result, +// if the function did have a return value, the return value is not received. +// - Note that multiple asynchronous commands from a single pthread/Worker are +// guaranteed to be executed on the main thread in the program order they +// were called in. +void emscripten_async_run_in_main_runtime_thread_(EM_FUNC_SIGNATURE sig, void *func_ptr __attribute__((nonnull)), ...); + +// The 'async_waitable' variant of the run_in_main_runtime_thread functions run +// like the 'async' variants, except that while the operation starts off +// asynchronously, the result is then later waited upon to receive the return +// value. +// - The object returned by this function call is dynamically allocated, and +// should be freed up via a call to emscripten_async_waitable_close() after +// the wait has been performed. +em_queued_call *emscripten_async_waitable_run_in_main_runtime_thread_(EM_FUNC_SIGNATURE sig, void *func_ptr __attribute__((nonnull)), ...); + +// Since we can't validate the function pointer type, allow implicit casting of +// functions to void* without complaining. +#define emscripten_sync_run_in_main_runtime_thread(sig, func_ptr, ...) emscripten_sync_run_in_main_runtime_thread_((sig), (void*)(func_ptr),##__VA_ARGS__) +#define emscripten_async_run_in_main_runtime_thread(sig, func_ptr, ...) emscripten_async_run_in_main_runtime_thread_((sig), (void*)(func_ptr),##__VA_ARGS__) +#define emscripten_async_waitable_run_in_main_runtime_thread(sig, func_ptr, ...) emscripten_async_waitable_run_in_main_runtime_thread_((sig), (void*)(func_ptr),##__VA_ARGS__) + +EMSCRIPTEN_RESULT emscripten_wait_for_call_v(em_queued_call *call __attribute__((nonnull)), double timeoutMSecs); +EMSCRIPTEN_RESULT emscripten_wait_for_call_i(em_queued_call *call __attribute__((nonnull)), double timeoutMSecs, int *outResult); + +void emscripten_async_waitable_close(em_queued_call *call __attribute__((nonnull))); + +// Runs the given function on the specified thread. If we are currently on +// that target thread then we just execute the call synchronously; otherwise it +// is queued on that thread to execute asynchronously. +// Returns 1 if it executed the code (i.e., it was on the target thread), and 0 +// otherwise. +int emscripten_dispatch_to_thread_args(pthread_t target_thread, + EM_FUNC_SIGNATURE sig, + void* func_ptr __attribute__((nonnull)), + void* satellite, + va_list args); +int emscripten_dispatch_to_thread_(pthread_t target_thread, + EM_FUNC_SIGNATURE sig, + void* func_ptr __attribute__((nonnull)), + void* satellite, + ...); +#define emscripten_dispatch_to_thread( \ + target_thread, sig, func_ptr, satellite, ...) \ + emscripten_dispatch_to_thread_( \ + (target_thread), (sig), (void*)(func_ptr), (satellite), ##__VA_ARGS__) + +// Similar to emscripten_dispatch_to_thread, but always runs the +// function asynchronously, even if on the same thread. This is less efficient +// but may be simpler to reason about in some cases. +int emscripten_dispatch_to_thread_async_args(pthread_t target_thread, + EM_FUNC_SIGNATURE sig, + void* func_ptr __attribute__((nonnull)), + void* satellite, + va_list args); +int emscripten_dispatch_to_thread_async_(pthread_t target_thread, + EM_FUNC_SIGNATURE sig, + void* func_ptr __attribute__((nonnull)), + void* satellite, + ...); +#define emscripten_dispatch_to_thread_async( \ + target_thread, sig, func_ptr, satellite, ...) \ + emscripten_dispatch_to_thread_async_( \ + (target_thread), (sig), (void*)(func_ptr), (satellite), ##__VA_ARGS__) + +#ifdef __cplusplus +} +#endif diff --git a/system/lib/pthread/library_pthread.c b/system/lib/pthread/library_pthread.c index 4a5ca5de788c6..773e086681821 100644 --- a/system/lib/pthread/library_pthread.c +++ b/system/lib/pthread/library_pthread.c @@ -12,12 +12,9 @@ #include #include #include -#include #include #include -#include #include -#include #include #include #include @@ -116,290 +113,12 @@ void emscripten_thread_sleep(double msecs) { EM_THREAD_STATUS_SLEEPING, EM_THREAD_STATUS_RUNNING); } -// Allocator and deallocator for em_queued_call objects. -static em_queued_call* em_queued_call_malloc() { - em_queued_call* call = (em_queued_call*)malloc(sizeof(em_queued_call)); - assert(call); // Not a programming error, but use assert() in debug builds to catch OOM scenarios. - if (call) { - call->operationDone = 0; - call->functionPtr = 0; - call->satelliteData = 0; - } - return call; -} - -static void em_queued_call_free(em_queued_call* call) { - if (call) - free(call->satelliteData); - free(call); -} - -static void init_em_queued_call_args(em_queued_call* q, - EM_FUNC_SIGNATURE sig, - va_list args) { - EM_FUNC_SIGNATURE argumentsType = sig & EM_FUNC_SIG_ARGUMENTS_TYPE_MASK; - int numArguments = EM_FUNC_SIG_NUM_FUNC_ARGUMENTS(sig); - for (int i = 0; i < numArguments; ++i) { - switch ((argumentsType & EM_FUNC_SIG_ARGUMENT_TYPE_SIZE_MASK)) { - case EM_FUNC_SIG_PARAM_I: - q->args[i].i = va_arg(args, int); - break; - case EM_FUNC_SIG_PARAM_I64: - q->args[i].i64 = va_arg(args, int64_t); - break; - case EM_FUNC_SIG_PARAM_F: - q->args[i].f = (float)va_arg(args, double); - break; - case EM_FUNC_SIG_PARAM_D: - q->args[i].d = va_arg(args, double); - break; - } - argumentsType >>= EM_FUNC_SIG_ARGUMENT_TYPE_SIZE_SHIFT; - } -} - -static em_queued_call* em_queued_call_create(EM_FUNC_SIGNATURE sig, - void* func, - void* satellite, - va_list args) { - em_queued_call* call = em_queued_call_malloc(); - if (call) { - call->functionEnum = sig; - call->functionPtr = func; - call->satelliteData = satellite; - init_em_queued_call_args(call, sig, args); - } - return call; -} - -void emscripten_async_waitable_close(em_queued_call* call) { - assert(call->operationDone); - em_queued_call_free(call); -} - -static void _do_call(void* arg) { - em_queued_call* q = (em_queued_call*)arg; - // C function pointer - assert(EM_FUNC_SIG_NUM_FUNC_ARGUMENTS(q->functionEnum) <= EM_QUEUED_CALL_MAX_ARGS); - switch (q->functionEnum) { - case EM_PROXIED_RESIZE_OFFSCREENCANVAS: - q->returnValue.i = - _emscripten_set_offscreencanvas_size(q->args[0].cp, q->args[1].i, q->args[2].i); - break; - case EM_PROXIED_JS_FUNCTION: - q->returnValue.d = - _emscripten_receive_on_main_thread_js((intptr_t)q->functionPtr, q->callingThread, q->args[0].i, &q->args[1].d); - break; - case EM_FUNC_SIG_V: - ((em_func_v)q->functionPtr)(); - break; - case EM_FUNC_SIG_VI: - ((em_func_vi)q->functionPtr)(q->args[0].i); - break; - case EM_FUNC_SIG_VF: - ((em_func_vf)q->functionPtr)(q->args[0].f); - break; - case EM_FUNC_SIG_VII: - ((em_func_vii)q->functionPtr)(q->args[0].i, q->args[1].i); - break; - case EM_FUNC_SIG_VIF: - ((em_func_vif)q->functionPtr)(q->args[0].i, q->args[1].f); - break; - case EM_FUNC_SIG_VFF: - ((em_func_vff)q->functionPtr)(q->args[0].f, q->args[1].f); - break; - case EM_FUNC_SIG_VIII: - ((em_func_viii)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].i); - break; - case EM_FUNC_SIG_VIIF: - ((em_func_viif)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].f); - break; - case EM_FUNC_SIG_VIFF: - ((em_func_viff)q->functionPtr)(q->args[0].i, q->args[1].f, q->args[2].f); - break; - case EM_FUNC_SIG_VFFF: - ((em_func_vfff)q->functionPtr)(q->args[0].f, q->args[1].f, q->args[2].f); - break; - case EM_FUNC_SIG_VIIII: - ((em_func_viiii)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].i, q->args[3].i); - break; - case EM_FUNC_SIG_VIIFI: - ((em_func_viifi)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].f, q->args[3].i); - break; - case EM_FUNC_SIG_VIFFF: - ((em_func_vifff)q->functionPtr)(q->args[0].i, q->args[1].f, q->args[2].f, q->args[3].f); - break; - case EM_FUNC_SIG_VFFFF: - ((em_func_vffff)q->functionPtr)(q->args[0].f, q->args[1].f, q->args[2].f, q->args[3].f); - break; - case EM_FUNC_SIG_VIIIII: - ((em_func_viiiii)q->functionPtr)( - q->args[0].i, q->args[1].i, q->args[2].i, q->args[3].i, q->args[4].i); - break; - case EM_FUNC_SIG_VIFFFF: - ((em_func_viffff)q->functionPtr)( - q->args[0].i, q->args[1].f, q->args[2].f, q->args[3].f, q->args[4].f); - break; - case EM_FUNC_SIG_VIIIIII: - ((em_func_viiiiii)q->functionPtr)( - q->args[0].i, q->args[1].i, q->args[2].i, q->args[3].i, q->args[4].i, q->args[5].i); - break; - case EM_FUNC_SIG_VIIIIIII: - ((em_func_viiiiiii)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].i, q->args[3].i, - q->args[4].i, q->args[5].i, q->args[6].i); - break; - case EM_FUNC_SIG_VIIIIIIII: - ((em_func_viiiiiiii)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].i, q->args[3].i, - q->args[4].i, q->args[5].i, q->args[6].i, q->args[7].i); - break; - case EM_FUNC_SIG_VIIIIIIIII: - ((em_func_viiiiiiiii)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].i, q->args[3].i, - q->args[4].i, q->args[5].i, q->args[6].i, q->args[7].i, q->args[8].i); - break; - case EM_FUNC_SIG_VIIIIIIIIII: - ((em_func_viiiiiiiiii)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].i, - q->args[3].i, q->args[4].i, q->args[5].i, q->args[6].i, q->args[7].i, q->args[8].i, - q->args[9].i); - break; - case EM_FUNC_SIG_VIIIIIIIIIII: - ((em_func_viiiiiiiiiii)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].i, - q->args[3].i, q->args[4].i, q->args[5].i, q->args[6].i, q->args[7].i, q->args[8].i, - q->args[9].i, q->args[10].i); - break; - case EM_FUNC_SIG_I: - q->returnValue.i = ((em_func_i)q->functionPtr)(); - break; - case EM_FUNC_SIG_II: - q->returnValue.i = ((em_func_ii)q->functionPtr)(q->args[0].i); - break; - case EM_FUNC_SIG_III: - q->returnValue.i = ((em_func_iii)q->functionPtr)(q->args[0].i, q->args[1].i); - break; - case EM_FUNC_SIG_IIII: - q->returnValue.i = ((em_func_iiii)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].i); - break; - case EM_FUNC_SIG_IIIII: - q->returnValue.i = - ((em_func_iiiii)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].i, q->args[3].i); - break; - case EM_FUNC_SIG_IIIIII: - q->returnValue.i = ((em_func_iiiiii)q->functionPtr)( - q->args[0].i, q->args[1].i, q->args[2].i, q->args[3].i, q->args[4].i); - break; - case EM_FUNC_SIG_IIIIIII: - q->returnValue.i = ((em_func_iiiiiii)q->functionPtr)( - q->args[0].i, q->args[1].i, q->args[2].i, q->args[3].i, q->args[4].i, q->args[5].i); - break; - case EM_FUNC_SIG_IIIIIIII: - q->returnValue.i = ((em_func_iiiiiiii)q->functionPtr)(q->args[0].i, q->args[1].i, - q->args[2].i, q->args[3].i, q->args[4].i, q->args[5].i, q->args[6].i); - break; - case EM_FUNC_SIG_IIIIIIIII: - q->returnValue.i = ((em_func_iiiiiiiii)q->functionPtr)(q->args[0].i, q->args[1].i, - q->args[2].i, q->args[3].i, q->args[4].i, q->args[5].i, q->args[6].i, q->args[7].i); - break; - case EM_FUNC_SIG_IIIIIIIIII: - q->returnValue.i = - ((em_func_iiiiiiiiii)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].i, - q->args[3].i, q->args[4].i, q->args[5].i, q->args[6].i, q->args[7].i, q->args[8].i); - break; - default: - assert(0 && "Invalid Emscripten pthread _do_call opcode!"); - } - - // If the caller is detached from this operation, it is the main thread's responsibility to free - // up the call object. - if (q->calleeDelete) { - em_queued_call_free(q); - // No need to wake a listener, nothing is listening to this since the call object is detached. - } else { - // The caller owns this call object, it is listening to it and will free it up. - q->operationDone = 1; - emscripten_futex_wake(&q->operationDone, INT_MAX); - } -} - -EMSCRIPTEN_RESULT emscripten_wait_for_call_v(em_queued_call* call, double timeoutMSecs) { - int r; - - int done = atomic_load(&call->operationDone); - if (!done) { - double now = emscripten_get_now(); - double waitEndTime = now + timeoutMSecs; - emscripten_set_current_thread_status(EM_THREAD_STATUS_WAITPROXY); - while (!done && now < waitEndTime) { - r = emscripten_futex_wait(&call->operationDone, 0, waitEndTime - now); - done = atomic_load(&call->operationDone); - now = emscripten_get_now(); - } - emscripten_set_current_thread_status(EM_THREAD_STATUS_RUNNING); - } - if (done) - return EMSCRIPTEN_RESULT_SUCCESS; - else - return EMSCRIPTEN_RESULT_TIMED_OUT; -} - -EMSCRIPTEN_RESULT emscripten_wait_for_call_i( - em_queued_call* call, double timeoutMSecs, int* outResult) { - EMSCRIPTEN_RESULT res = emscripten_wait_for_call_v(call, timeoutMSecs); - if (res == EMSCRIPTEN_RESULT_SUCCESS && outResult) - *outResult = call->returnValue.i; - return res; -} - static struct pthread __main_pthread; pthread_t emscripten_main_runtime_thread_id() { return &__main_pthread; } -static pthread_t normalize_thread(pthread_t target_thread) { - assert(target_thread); - if (target_thread == EM_CALLBACK_THREAD_CONTEXT_MAIN_RUNTIME_THREAD) { - return emscripten_main_runtime_thread_id(); - } - if (target_thread == EM_CALLBACK_THREAD_CONTEXT_CALLING_THREAD) { - return pthread_self(); - } - return target_thread; -} - -// Execute `call` and return 1 only if already on the `target_thread`. Otherwise -// return 0. -static int maybe_call_on_current_thread(pthread_t target_thread, - em_queued_call* call) { - if (pthread_equal(target_thread, pthread_self())) { - _do_call(call); - return 1; - } - return 0; -} - -// Execute or proxy `call`. Return 1 if the work was executed or otherwise -// return 0. -static int do_dispatch_to_thread(pthread_t target_thread, - em_queued_call* call) { - target_thread = normalize_thread(target_thread); - if (maybe_call_on_current_thread(target_thread, call)) { - return 1; - } - emscripten_proxy_async( - emscripten_proxy_get_system_queue(), target_thread, _do_call, call); - return 0; -} - -void emscripten_async_run_in_main_thread(em_queued_call* call) { - do_dispatch_to_thread(emscripten_main_runtime_thread_id(), call); -} - -static void sync_run_in_main_thread(em_queued_call* call) { - emscripten_async_run_in_main_thread(call); - - // Enter to wait for the operation to complete. - emscripten_wait_for_call_v(call, INFINITY); -} - void emscripten_current_thread_process_queued_calls() { emscripten_proxy_execute_queue(emscripten_proxy_get_system_queue()); } @@ -409,163 +128,6 @@ void emscripten_main_thread_process_queued_calls() { emscripten_current_thread_process_queued_calls(); } -int emscripten_sync_run_in_main_runtime_thread_(EM_FUNC_SIGNATURE sig, void* func_ptr, ...) { - em_queued_call q = {sig, func_ptr}; - - va_list args; - va_start(args, func_ptr); - init_em_queued_call_args(&q, sig, args); - va_end(args); - sync_run_in_main_thread(&q); - return q.returnValue.i; -} - -double _emscripten_run_on_main_thread_js(int index, int num_args, int64_t* buffer, int sync) { - em_queued_call q; - em_queued_call *c; - if (sync) { - q.operationDone = 0; - q.satelliteData = 0; - c = &q; - } else { - c = em_queued_call_malloc(); - } - c->calleeDelete = !sync; - c->functionEnum = EM_PROXIED_JS_FUNCTION; - // Index not needed to ever be more than 32-bit. - c->functionPtr = (void*)(intptr_t)index; - c->callingThread = pthread_self(); - assert(num_args+1 <= EM_QUEUED_JS_CALL_MAX_ARGS); - // The types are only known at runtime in these calls, so we store values that - // must be able to contain any valid JS value, including a 64-bit BigInt if - // BigInt support is enabled. We store to an i64, which can contain both a - // BigInt and a JS Number which is a 64-bit double. - c->args[0].i = num_args; - for (int i = 0; i < num_args; i++) { - c->args[i+1].i64 = buffer[i]; - } - - if (sync) { - sync_run_in_main_thread(&q); - // TODO: support BigInt return values somehow. - return q.returnValue.d; - } else { - // 'async' runs are fire and forget, where the caller detaches itself from the call object after - // returning here, and it is the callee's responsibility to free up the memory after the call - // has been performed. - emscripten_async_run_in_main_thread(c); - return 0; - } -} - -void emscripten_async_run_in_main_runtime_thread_(EM_FUNC_SIGNATURE sig, void* func_ptr, ...) { - em_queued_call* q = em_queued_call_malloc(); - if (!q) - return; - q->functionEnum = sig; - q->functionPtr = func_ptr; - - va_list args; - va_start(args, func_ptr); - init_em_queued_call_args(q, sig, args); - va_end(args); - // 'async' runs are fire and forget, where the caller detaches itself from the call object after - // returning here, and it is the callee's responsibility to free up the memory after the call has - // been performed. - q->calleeDelete = 1; - emscripten_async_run_in_main_thread(q); -} - -em_queued_call* emscripten_async_waitable_run_in_main_runtime_thread_( - EM_FUNC_SIGNATURE sig, void* func_ptr, ...) { - em_queued_call* q = em_queued_call_malloc(); - if (!q) - return NULL; - q->functionEnum = sig; - q->functionPtr = func_ptr; - - va_list args; - va_start(args, func_ptr); - init_em_queued_call_args(q, sig, args); - va_end(args); - // 'async waitable' runs are waited on by the caller, so the call object needs to remain alive for - // the caller to access it after the operation is done. The caller is responsible in cleaning up - // the object after done. - q->calleeDelete = 0; - emscripten_async_run_in_main_thread(q); - return q; -} - -int emscripten_dispatch_to_thread_args(pthread_t target_thread, - EM_FUNC_SIGNATURE sig, - void* func_ptr, - void* satellite, - va_list args) { - em_queued_call* q = em_queued_call_create(sig, func_ptr, satellite, args); - assert(q); - // TODO: handle errors in a better way, this pattern appears in several places - // in this file. The current behavior makes the calling thread hang as - // it waits (for synchronous calls). - // If we failed to allocate, return 0 which means we did not execute anything - // (we also never will in that case). - if (!q) - return 0; - - // `q` will not be used after it is called, so let the call clean it up. - q->calleeDelete = 1; - return do_dispatch_to_thread(target_thread, q); -} - -int emscripten_dispatch_to_thread_(pthread_t target_thread, - EM_FUNC_SIGNATURE sig, - void* func_ptr, - void* satellite, - ...) { - va_list args; - va_start(args, satellite); - int ret = emscripten_dispatch_to_thread_args( - target_thread, sig, func_ptr, satellite, args); - va_end(args); - return ret; -} - -int emscripten_dispatch_to_thread_async_args(pthread_t target_thread, - EM_FUNC_SIGNATURE sig, - void* func_ptr, - void* satellite, - va_list args) { - // Check if we are already on the target thread. - if (pthread_equal(target_thread, pthread_self())) { - // Setup is the same as in emscripten_dispatch_to_thread_args. - em_queued_call* q = em_queued_call_create(sig, func_ptr, satellite, args); - assert(q); - if (!q) - return 0; - q->calleeDelete = 1; - - // Schedule the call to run later on this thread. - emscripten_set_timeout(_do_call, 0, q); - return 0; - } - - // Otherwise, dispatch as usual. - return emscripten_dispatch_to_thread_args( - target_thread, sig, func_ptr, satellite, args); -} - -int emscripten_dispatch_to_thread_async_(pthread_t target_thread, - EM_FUNC_SIGNATURE sig, - void* func_ptr, - void* satellite, - ...) { - va_list args; - va_start(args, satellite); - int ret = emscripten_dispatch_to_thread_async_args( - target_thread, sig, func_ptr, satellite, args); - va_end(args); - return ret; -} - int _emscripten_thread_is_valid(pthread_t thread) { return thread->self == thread; } diff --git a/system/lib/pthread/proxying_legacy.c b/system/lib/pthread/proxying_legacy.c new file mode 100644 index 0000000000000..bf9294fa0474c --- /dev/null +++ b/system/lib/pthread/proxying_legacy.c @@ -0,0 +1,519 @@ +/* + * Copyright 2023 The Emscripten Authors. All rights reserved. + * Emscripten is available under two separate licenses, the MIT license and the + * University of Illinois/NCSA Open Source License. Both these licenses can be + * found in the LICENSE file. + */ +#include +#include +#include + +#include + +#include "../internal/pthread_impl.h" + +#include "threading_internal.h" +#include "emscripten_internal.h" + +typedef union em_variant_val { + int i; + int64_t i64; + float f; + double d; + void *vp; + char *cp; +} em_variant_val; + +typedef struct em_queued_call { + int functionEnum; + void *functionPtr; + _Atomic uint32_t operationDone; + em_variant_val args[EM_QUEUED_JS_CALL_MAX_ARGS]; + em_variant_val returnValue; + + // Sets the PThread.currentProxiedOperationCallerThread global for the + // duration of the proxied call. + pthread_t callingThread; + + // An optional pointer to a secondary data block that should be free()d when + // this queued call is freed. + void *satelliteData; + + // If true, the caller has "detached" itself from this call object and the + // Emscripten main runtime thread should free up this em_queued_call object + // after it has been executed. If false, the caller is in control of the + // memory. + int calleeDelete; +} em_queued_call; + +// Proxied C/C++ functions support at most this many arguments. Dispatch is +// static/strongly typed by signature. +#define EM_QUEUED_CALL_MAX_ARGS 11 + +typedef void (*em_func_v)(void); +typedef void (*em_func_vi)(int); +typedef void (*em_func_vf)(float); +typedef void (*em_func_vii)(int, int); +typedef void (*em_func_vif)(int, float); +typedef void (*em_func_vff)(float, float); +typedef void (*em_func_viii)(int, int, int); +typedef void (*em_func_viif)(int, int, float); +typedef void (*em_func_viff)(int, float, float); +typedef void (*em_func_vfff)(float, float, float); +typedef void (*em_func_viiii)(int, int, int, int); +typedef void (*em_func_viifi)(int, int, float, int); +typedef void (*em_func_vifff)(int, float, float, float); +typedef void (*em_func_vffff)(float, float, float, float); +typedef void (*em_func_viiiii)(int, int, int, int, int); +typedef void (*em_func_viffff)(int, float, float, float, float); +typedef void (*em_func_viiiiii)(int, int, int, int, int, int); +typedef void (*em_func_viiiiiii)(int, int, int, int, int, int, int); +typedef void (*em_func_viiiiiiii)(int, int, int, int, int, int, int, int); +typedef void (*em_func_viiiiiiiii)(int, int, int, int, int, int, int, int, int); +typedef void (*em_func_viiiiiiiiii)(int, int, int, int, int, int, int, int, int, int); +typedef void (*em_func_viiiiiiiiiii)(int, int, int, int, int, int, int, int, int, int, int); +typedef int (*em_func_i)(void); +typedef int (*em_func_ii)(int); +typedef int (*em_func_iii)(int, int); +typedef int (*em_func_iiii)(int, int, int); +typedef int (*em_func_iiiii)(int, int, int, int); +typedef int (*em_func_iiiiii)(int, int, int, int, int); +typedef int (*em_func_iiiiiii)(int, int, int, int, int, int); +typedef int (*em_func_iiiiiiii)(int, int, int, int, int, int, int); +typedef int (*em_func_iiiiiiiii)(int, int, int, int, int, int, int, int); +typedef int (*em_func_iiiiiiiiii)(int, int, int, int, int, int, int, int, int); + +// Allocator and deallocator for em_queued_call objects. +static em_queued_call* em_queued_call_malloc() { + em_queued_call* call = (em_queued_call*)malloc(sizeof(em_queued_call)); + assert(call); // Not a programming error, but use assert() in debug builds to catch OOM scenarios. + if (call) { + call->operationDone = 0; + call->functionPtr = 0; + call->satelliteData = 0; + } + return call; +} + +static void em_queued_call_free(em_queued_call* call) { + if (call) + free(call->satelliteData); + free(call); +} + +static void init_em_queued_call_args(em_queued_call* q, + EM_FUNC_SIGNATURE sig, + va_list args) { + EM_FUNC_SIGNATURE argumentsType = sig & EM_FUNC_SIG_ARGUMENTS_TYPE_MASK; + int numArguments = EM_FUNC_SIG_NUM_FUNC_ARGUMENTS(sig); + for (int i = 0; i < numArguments; ++i) { + switch ((argumentsType & EM_FUNC_SIG_ARGUMENT_TYPE_SIZE_MASK)) { + case EM_FUNC_SIG_PARAM_I: + q->args[i].i = va_arg(args, int); + break; + case EM_FUNC_SIG_PARAM_I64: + q->args[i].i64 = va_arg(args, int64_t); + break; + case EM_FUNC_SIG_PARAM_F: + q->args[i].f = (float)va_arg(args, double); + break; + case EM_FUNC_SIG_PARAM_D: + q->args[i].d = va_arg(args, double); + break; + } + argumentsType >>= EM_FUNC_SIG_ARGUMENT_TYPE_SIZE_SHIFT; + } +} + +static em_queued_call* em_queued_call_create(EM_FUNC_SIGNATURE sig, + void* func, + void* satellite, + va_list args) { + em_queued_call* call = em_queued_call_malloc(); + if (call) { + call->functionEnum = sig; + call->functionPtr = func; + call->satelliteData = satellite; + init_em_queued_call_args(call, sig, args); + } + return call; +} + +void emscripten_async_waitable_close(em_queued_call* call) { + assert(call->operationDone); + em_queued_call_free(call); +} + +static void _do_call(void* arg) { + em_queued_call* q = (em_queued_call*)arg; + // C function pointer + assert(EM_FUNC_SIG_NUM_FUNC_ARGUMENTS(q->functionEnum) <= EM_QUEUED_CALL_MAX_ARGS); + switch (q->functionEnum) { + case EM_PROXIED_RESIZE_OFFSCREENCANVAS: + q->returnValue.i = + _emscripten_set_offscreencanvas_size(q->args[0].cp, q->args[1].i, q->args[2].i); + break; + case EM_PROXIED_JS_FUNCTION: + q->returnValue.d = + _emscripten_receive_on_main_thread_js((intptr_t)q->functionPtr, q->callingThread, q->args[0].i, &q->args[1].d); + break; + case EM_FUNC_SIG_V: + ((em_func_v)q->functionPtr)(); + break; + case EM_FUNC_SIG_VI: + ((em_func_vi)q->functionPtr)(q->args[0].i); + break; + case EM_FUNC_SIG_VF: + ((em_func_vf)q->functionPtr)(q->args[0].f); + break; + case EM_FUNC_SIG_VII: + ((em_func_vii)q->functionPtr)(q->args[0].i, q->args[1].i); + break; + case EM_FUNC_SIG_VIF: + ((em_func_vif)q->functionPtr)(q->args[0].i, q->args[1].f); + break; + case EM_FUNC_SIG_VFF: + ((em_func_vff)q->functionPtr)(q->args[0].f, q->args[1].f); + break; + case EM_FUNC_SIG_VIII: + ((em_func_viii)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].i); + break; + case EM_FUNC_SIG_VIIF: + ((em_func_viif)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].f); + break; + case EM_FUNC_SIG_VIFF: + ((em_func_viff)q->functionPtr)(q->args[0].i, q->args[1].f, q->args[2].f); + break; + case EM_FUNC_SIG_VFFF: + ((em_func_vfff)q->functionPtr)(q->args[0].f, q->args[1].f, q->args[2].f); + break; + case EM_FUNC_SIG_VIIII: + ((em_func_viiii)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].i, q->args[3].i); + break; + case EM_FUNC_SIG_VIIFI: + ((em_func_viifi)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].f, q->args[3].i); + break; + case EM_FUNC_SIG_VIFFF: + ((em_func_vifff)q->functionPtr)(q->args[0].i, q->args[1].f, q->args[2].f, q->args[3].f); + break; + case EM_FUNC_SIG_VFFFF: + ((em_func_vffff)q->functionPtr)(q->args[0].f, q->args[1].f, q->args[2].f, q->args[3].f); + break; + case EM_FUNC_SIG_VIIIII: + ((em_func_viiiii)q->functionPtr)( + q->args[0].i, q->args[1].i, q->args[2].i, q->args[3].i, q->args[4].i); + break; + case EM_FUNC_SIG_VIFFFF: + ((em_func_viffff)q->functionPtr)( + q->args[0].i, q->args[1].f, q->args[2].f, q->args[3].f, q->args[4].f); + break; + case EM_FUNC_SIG_VIIIIII: + ((em_func_viiiiii)q->functionPtr)( + q->args[0].i, q->args[1].i, q->args[2].i, q->args[3].i, q->args[4].i, q->args[5].i); + break; + case EM_FUNC_SIG_VIIIIIII: + ((em_func_viiiiiii)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].i, q->args[3].i, + q->args[4].i, q->args[5].i, q->args[6].i); + break; + case EM_FUNC_SIG_VIIIIIIII: + ((em_func_viiiiiiii)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].i, q->args[3].i, + q->args[4].i, q->args[5].i, q->args[6].i, q->args[7].i); + break; + case EM_FUNC_SIG_VIIIIIIIII: + ((em_func_viiiiiiiii)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].i, q->args[3].i, + q->args[4].i, q->args[5].i, q->args[6].i, q->args[7].i, q->args[8].i); + break; + case EM_FUNC_SIG_VIIIIIIIIII: + ((em_func_viiiiiiiiii)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].i, + q->args[3].i, q->args[4].i, q->args[5].i, q->args[6].i, q->args[7].i, q->args[8].i, + q->args[9].i); + break; + case EM_FUNC_SIG_VIIIIIIIIIII: + ((em_func_viiiiiiiiiii)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].i, + q->args[3].i, q->args[4].i, q->args[5].i, q->args[6].i, q->args[7].i, q->args[8].i, + q->args[9].i, q->args[10].i); + break; + case EM_FUNC_SIG_I: + q->returnValue.i = ((em_func_i)q->functionPtr)(); + break; + case EM_FUNC_SIG_II: + q->returnValue.i = ((em_func_ii)q->functionPtr)(q->args[0].i); + break; + case EM_FUNC_SIG_III: + q->returnValue.i = ((em_func_iii)q->functionPtr)(q->args[0].i, q->args[1].i); + break; + case EM_FUNC_SIG_IIII: + q->returnValue.i = ((em_func_iiii)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].i); + break; + case EM_FUNC_SIG_IIIII: + q->returnValue.i = + ((em_func_iiiii)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].i, q->args[3].i); + break; + case EM_FUNC_SIG_IIIIII: + q->returnValue.i = ((em_func_iiiiii)q->functionPtr)( + q->args[0].i, q->args[1].i, q->args[2].i, q->args[3].i, q->args[4].i); + break; + case EM_FUNC_SIG_IIIIIII: + q->returnValue.i = ((em_func_iiiiiii)q->functionPtr)( + q->args[0].i, q->args[1].i, q->args[2].i, q->args[3].i, q->args[4].i, q->args[5].i); + break; + case EM_FUNC_SIG_IIIIIIII: + q->returnValue.i = ((em_func_iiiiiiii)q->functionPtr)(q->args[0].i, q->args[1].i, + q->args[2].i, q->args[3].i, q->args[4].i, q->args[5].i, q->args[6].i); + break; + case EM_FUNC_SIG_IIIIIIIII: + q->returnValue.i = ((em_func_iiiiiiiii)q->functionPtr)(q->args[0].i, q->args[1].i, + q->args[2].i, q->args[3].i, q->args[4].i, q->args[5].i, q->args[6].i, q->args[7].i); + break; + case EM_FUNC_SIG_IIIIIIIIII: + q->returnValue.i = + ((em_func_iiiiiiiiii)q->functionPtr)(q->args[0].i, q->args[1].i, q->args[2].i, + q->args[3].i, q->args[4].i, q->args[5].i, q->args[6].i, q->args[7].i, q->args[8].i); + break; + default: + assert(0 && "Invalid Emscripten pthread _do_call opcode!"); + } + + // If the caller is detached from this operation, it is the main thread's responsibility to free + // up the call object. + if (q->calleeDelete) { + em_queued_call_free(q); + // No need to wake a listener, nothing is listening to this since the call object is detached. + } else { + // The caller owns this call object, it is listening to it and will free it up. + q->operationDone = 1; + emscripten_futex_wake(&q->operationDone, INT_MAX); + } +} + +static pthread_t normalize_thread(pthread_t target_thread) { + assert(target_thread); + if (target_thread == EM_CALLBACK_THREAD_CONTEXT_MAIN_RUNTIME_THREAD) { + return emscripten_main_runtime_thread_id(); + } + if (target_thread == EM_CALLBACK_THREAD_CONTEXT_CALLING_THREAD) { + return pthread_self(); + } + return target_thread; +} + +// Execute `call` and return 1 only if already on the `target_thread`. Otherwise +// return 0. +static int maybe_call_on_current_thread(pthread_t target_thread, + em_queued_call* call) { + if (pthread_equal(target_thread, pthread_self())) { + _do_call(call); + return 1; + } + return 0; +} + +// Execute or proxy `call`. Return 1 if the work was executed or otherwise +// return 0. +static int do_dispatch_to_thread(pthread_t target_thread, + em_queued_call* call) { + target_thread = normalize_thread(target_thread); + if (maybe_call_on_current_thread(target_thread, call)) { + return 1; + } + emscripten_proxy_async( + emscripten_proxy_get_system_queue(), target_thread, _do_call, call); + return 0; +} + +int emscripten_dispatch_to_thread_args(pthread_t target_thread, + EM_FUNC_SIGNATURE sig, + void* func_ptr, + void* satellite, + va_list args) { + em_queued_call* q = em_queued_call_create(sig, func_ptr, satellite, args); + assert(q); + // TODO: handle errors in a better way, this pattern appears in several places + // in this file. The current behavior makes the calling thread hang as + // it waits (for synchronous calls). + // If we failed to allocate, return 0 which means we did not execute anything + // (we also never will in that case). + if (!q) + return 0; + + // `q` will not be used after it is called, so let the call clean it up. + q->calleeDelete = 1; + return do_dispatch_to_thread(target_thread, q); +} + +void emscripten_async_run_in_main_thread(em_queued_call* call) { + do_dispatch_to_thread(emscripten_main_runtime_thread_id(), call); +} + +int emscripten_dispatch_to_thread_(pthread_t target_thread, + EM_FUNC_SIGNATURE sig, + void* func_ptr, + void* satellite, + ...) { + va_list args; + va_start(args, satellite); + int ret = emscripten_dispatch_to_thread_args( + target_thread, sig, func_ptr, satellite, args); + va_end(args); + return ret; +} + +int emscripten_dispatch_to_thread_async_args(pthread_t target_thread, + EM_FUNC_SIGNATURE sig, + void* func_ptr, + void* satellite, + va_list args) { + // Check if we are already on the target thread. + if (pthread_equal(target_thread, pthread_self())) { + // Setup is the same as in emscripten_dispatch_to_thread_args. + em_queued_call* q = em_queued_call_create(sig, func_ptr, satellite, args); + assert(q); + if (!q) + return 0; + q->calleeDelete = 1; + + // Schedule the call to run later on this thread. + emscripten_set_timeout(_do_call, 0, q); + return 0; + } + + // Otherwise, dispatch as usual. + return emscripten_dispatch_to_thread_args( + target_thread, sig, func_ptr, satellite, args); +} + +int emscripten_dispatch_to_thread_async_(pthread_t target_thread, + EM_FUNC_SIGNATURE sig, + void* func_ptr, + void* satellite, + ...) { + va_list args; + va_start(args, satellite); + int ret = emscripten_dispatch_to_thread_async_args( + target_thread, sig, func_ptr, satellite, args); + va_end(args); + return ret; +} + +static void sync_run_in_main_thread(em_queued_call* call) { + emscripten_async_run_in_main_thread(call); + + // Enter to wait for the operation to complete. + emscripten_wait_for_call_v(call, INFINITY); +} + +int emscripten_sync_run_in_main_runtime_thread_(EM_FUNC_SIGNATURE sig, void* func_ptr, ...) { + em_queued_call q = {sig, func_ptr}; + + va_list args; + va_start(args, func_ptr); + init_em_queued_call_args(&q, sig, args); + va_end(args); + sync_run_in_main_thread(&q); + return q.returnValue.i; +} + +double _emscripten_run_on_main_thread_js(int index, int num_args, int64_t* buffer, int sync) { + em_queued_call q; + em_queued_call *c; + if (sync) { + q.operationDone = 0; + q.satelliteData = 0; + c = &q; + } else { + c = em_queued_call_malloc(); + } + c->calleeDelete = !sync; + c->functionEnum = EM_PROXIED_JS_FUNCTION; + // Index not needed to ever be more than 32-bit. + c->functionPtr = (void*)(intptr_t)index; + c->callingThread = pthread_self(); + assert(num_args+1 <= EM_QUEUED_JS_CALL_MAX_ARGS); + // The types are only known at runtime in these calls, so we store values that + // must be able to contain any valid JS value, including a 64-bit BigInt if + // BigInt support is enabled. We store to an i64, which can contain both a + // BigInt and a JS Number which is a 64-bit double. + c->args[0].i = num_args; + for (int i = 0; i < num_args; i++) { + c->args[i+1].i64 = buffer[i]; + } + + if (sync) { + sync_run_in_main_thread(&q); + // TODO: support BigInt return values somehow. + return q.returnValue.d; + } else { + // 'async' runs are fire and forget, where the caller detaches itself from the call object after + // returning here, and it is the callee's responsibility to free up the memory after the call + // has been performed. + emscripten_async_run_in_main_thread(c); + return 0; + } +} + +void emscripten_async_run_in_main_runtime_thread_(EM_FUNC_SIGNATURE sig, void* func_ptr, ...) { + em_queued_call* q = em_queued_call_malloc(); + if (!q) + return; + q->functionEnum = sig; + q->functionPtr = func_ptr; + + va_list args; + va_start(args, func_ptr); + init_em_queued_call_args(q, sig, args); + va_end(args); + // 'async' runs are fire and forget, where the caller detaches itself from the call object after + // returning here, and it is the callee's responsibility to free up the memory after the call has + // been performed. + q->calleeDelete = 1; + emscripten_async_run_in_main_thread(q); +} + +em_queued_call* emscripten_async_waitable_run_in_main_runtime_thread_( + EM_FUNC_SIGNATURE sig, void* func_ptr, ...) { + em_queued_call* q = em_queued_call_malloc(); + if (!q) + return NULL; + q->functionEnum = sig; + q->functionPtr = func_ptr; + + va_list args; + va_start(args, func_ptr); + init_em_queued_call_args(q, sig, args); + va_end(args); + // 'async waitable' runs are waited on by the caller, so the call object needs to remain alive for + // the caller to access it after the operation is done. The caller is responsible in cleaning up + // the object after done. + q->calleeDelete = 0; + emscripten_async_run_in_main_thread(q); + return q; +} + +EMSCRIPTEN_RESULT emscripten_wait_for_call_v(em_queued_call* call, double timeoutMSecs) { + int r; + + int done = atomic_load(&call->operationDone); + if (!done) { + double now = emscripten_get_now(); + double waitEndTime = now + timeoutMSecs; + emscripten_set_current_thread_status(EM_THREAD_STATUS_WAITPROXY); + while (!done && now < waitEndTime) { + r = emscripten_futex_wait(&call->operationDone, 0, waitEndTime - now); + done = atomic_load(&call->operationDone); + now = emscripten_get_now(); + } + emscripten_set_current_thread_status(EM_THREAD_STATUS_RUNNING); + } + if (done) + return EMSCRIPTEN_RESULT_SUCCESS; + else + return EMSCRIPTEN_RESULT_TIMED_OUT; +} + +EMSCRIPTEN_RESULT emscripten_wait_for_call_i( + em_queued_call* call, double timeoutMSecs, int* outResult) { + EMSCRIPTEN_RESULT res = emscripten_wait_for_call_v(call, timeoutMSecs); + if (res == EMSCRIPTEN_RESULT_SUCCESS && outResult) + *outResult = call->returnValue.i; + return res; +} diff --git a/system/lib/pthread/threading_internal.h b/system/lib/pthread/threading_internal.h index 245db45baf52a..a2b6f01f3f73d 100644 --- a/system/lib/pthread/threading_internal.h +++ b/system/lib/pthread/threading_internal.h @@ -9,78 +9,10 @@ #include -typedef union em_variant_val { - int i; - int64_t i64; - float f; - double d; - void *vp; - char *cp; -} em_variant_val; - // Proxied JS function can support a few more arguments than proxied C/C++ // functions, because the dispatch is variadic and signature independent. #define EM_QUEUED_JS_CALL_MAX_ARGS 20 -// Proxied C/C++ functions support at most this many arguments. Dispatch is -// static/strongly typed by signature. -#define EM_QUEUED_CALL_MAX_ARGS 11 - -typedef struct em_queued_call { - int functionEnum; - void *functionPtr; - _Atomic uint32_t operationDone; - em_variant_val args[EM_QUEUED_JS_CALL_MAX_ARGS]; - em_variant_val returnValue; - - // Sets the PThread.currentProxiedOperationCallerThread global for the - // duration of the proxied call. - pthread_t callingThread; - - // An optional pointer to a secondary data block that should be free()d when - // this queued call is freed. - void *satelliteData; - - // If true, the caller has "detached" itself from this call object and the - // Emscripten main runtime thread should free up this em_queued_call object - // after it has been executed. If false, the caller is in control of the - // memory. - int calleeDelete; -} em_queued_call; - -typedef void (*em_func_v)(void); -typedef void (*em_func_vi)(int); -typedef void (*em_func_vf)(float); -typedef void (*em_func_vii)(int, int); -typedef void (*em_func_vif)(int, float); -typedef void (*em_func_vff)(float, float); -typedef void (*em_func_viii)(int, int, int); -typedef void (*em_func_viif)(int, int, float); -typedef void (*em_func_viff)(int, float, float); -typedef void (*em_func_vfff)(float, float, float); -typedef void (*em_func_viiii)(int, int, int, int); -typedef void (*em_func_viifi)(int, int, float, int); -typedef void (*em_func_vifff)(int, float, float, float); -typedef void (*em_func_vffff)(float, float, float, float); -typedef void (*em_func_viiiii)(int, int, int, int, int); -typedef void (*em_func_viffff)(int, float, float, float, float); -typedef void (*em_func_viiiiii)(int, int, int, int, int, int); -typedef void (*em_func_viiiiiii)(int, int, int, int, int, int, int); -typedef void (*em_func_viiiiiiii)(int, int, int, int, int, int, int, int); -typedef void (*em_func_viiiiiiiii)(int, int, int, int, int, int, int, int, int); -typedef void (*em_func_viiiiiiiiii)(int, int, int, int, int, int, int, int, int, int); -typedef void (*em_func_viiiiiiiiiii)(int, int, int, int, int, int, int, int, int, int, int); -typedef int (*em_func_i)(void); -typedef int (*em_func_ii)(int); -typedef int (*em_func_iii)(int, int); -typedef int (*em_func_iiii)(int, int, int); -typedef int (*em_func_iiiii)(int, int, int, int); -typedef int (*em_func_iiiiii)(int, int, int, int, int); -typedef int (*em_func_iiiiiii)(int, int, int, int, int, int); -typedef int (*em_func_iiiiiiii)(int, int, int, int, int, int, int); -typedef int (*em_func_iiiiiiiii)(int, int, int, int, int, int, int, int); -typedef int (*em_func_iiiiiiiiii)(int, int, int, int, int, int, int, int, int); - #define EM_THREAD_NAME_MAX 32 #define EM_THREAD_STATUS int diff --git a/tools/system_libs.py b/tools/system_libs.py index 3ae3d59ad8651..8eadd8a749b09 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -1058,6 +1058,7 @@ def get_files(self): 'library_pthread.c', 'em_task_queue.c', 'proxying.c', + 'proxying_legacy.c', 'thread_mailbox.c', 'pthread_create.c', 'pthread_kill.c', From d4040572441e3920c9cea56fd63c806163e0fe82 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 1 Aug 2023 13:58:50 -0700 Subject: [PATCH 0607/1523] Rebaseline codesize expectations. NFC --- test/other/metadce/test_metadce_minimal_pthreads.jssize | 2 +- test/other/test_unoptimized_code_size.js.size | 2 +- test/other/test_unoptimized_code_size_strict.js.size | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/other/metadce/test_metadce_minimal_pthreads.jssize b/test/other/metadce/test_metadce_minimal_pthreads.jssize index 16c2210899b3e..6fa45cd1fd746 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.jssize +++ b/test/other/metadce/test_metadce_minimal_pthreads.jssize @@ -1 +1 @@ -14391 +14352 diff --git a/test/other/test_unoptimized_code_size.js.size b/test/other/test_unoptimized_code_size.js.size index 45a63003d2ba8..cbbf26eb097fc 100644 --- a/test/other/test_unoptimized_code_size.js.size +++ b/test/other/test_unoptimized_code_size.js.size @@ -1 +1 @@ -58342 +58669 diff --git a/test/other/test_unoptimized_code_size_strict.js.size b/test/other/test_unoptimized_code_size_strict.js.size index 569d2facfd859..0b2c8106dbec3 100644 --- a/test/other/test_unoptimized_code_size_strict.js.size +++ b/test/other/test_unoptimized_code_size_strict.js.size @@ -1 +1 @@ -57281 +57608 From dea387566c9a8a4cca135ec6da462244110dd389 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 1 Aug 2023 16:19:15 -0700 Subject: [PATCH 0608/1523] Fix typo from #19943 (#19949) --- src/library_pthread.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/library_pthread.js b/src/library_pthread.js index ac740b0b523d5..088624f7364fa 100644 --- a/src/library_pthread.js +++ b/src/library_pthread.js @@ -1043,7 +1043,7 @@ var LibraryPThread = { assert(func.length == numCallArgs, 'Call args mismatch in _emscripten_receive_on_main_thread_js'); #endif PThread.currentProxiedOperationCallerThread = callingThread; - var rtn = func.apply(null, proxiedFunctionTable); + var rtn = func.apply(null, proxiedJSCallArgs); PThread.currentProxiedOperationCallerThread = 0; return rtn; }, From e929196ccaaddd5f0a2afce19cce4e4213c5590b Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 1 Aug 2023 17:20:15 -0700 Subject: [PATCH 0609/1523] Disable asan.test_sse2. NFC (#19948) --- test/test_core.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test_core.py b/test/test_core.py index 31dba36241cd4..59b0b0f20c917 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -6713,6 +6713,7 @@ def test_sse1(self): @no_safe_heap('has unaligned 64-bit operations in wasm') @is_slow_test @no_ubsan('https://github.com/emscripten-core/emscripten/issues/19688') + @no_asan('local count too large') def test_sse2(self): src = test_file('sse/test_sse2.cpp') self.run_process([shared.CLANG_CXX, src, '-msse2', '-Wno-argument-outside-range', '-o', 'test_sse2', '-D_CRT_SECURE_NO_WARNINGS=1'] + clang_native.get_clang_native_args(), stdout=PIPE) From b3c0304953ced0a8a6941f286a469a470c2a9690 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 2 Aug 2023 10:49:35 -0700 Subject: [PATCH 0610/1523] Add .git-blame-ignore-revs file (#19956) Include a couple of obvious reformatting-only revisions to get it started and test is out. --- .git-blame-ignore-revs | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .git-blame-ignore-revs diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 0000000000000..f9435e6588f08 --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,12 @@ +# This file contains a list of commits that are not likely what you +# are looking for in a blame, such as mass reformatting or renaming. +# You can set this file as a default ignore file for blame by running +# the following command. +# +# $ git config blame.ignoreRevsFile .git-blame-ignore-revs + +# Remove tabs and fix formatting in test/sse/. NFC (#18245) +3cd47cff5da467ae7ca2a29490d8b04af897023f + +# [embind docs] Reformat and cleanup whitespace. +9b1a5910c4f31cff4949541a42ac956ba45e4701 From f4398806c0afa2b8dc50a0a73d57e38588b77223 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 2 Aug 2023 11:58:47 -0700 Subject: [PATCH 0611/1523] Add wasm64_gb test config (#19957) This test configuration sets GLOBAL_BASE to 4gb meaning that all memory addresses used by emscripten will be larger then 4gb --- .circleci/config.yml | 1 + test/test_core.py | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 68d21ef24089d..c2c7e53d8722c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -606,6 +606,7 @@ jobs: title: "wasm64" test_targets: " wasm64 + wasm64_4gb.test_hello_world wasm64l.test_bigswitch other.test_memory64_proxies other.test_failing_growth_wasm64" diff --git a/test/test_core.py b/test/test_core.py index 59b0b0f20c917..4167f4d74625a 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -9800,6 +9800,13 @@ def setUp(self): settings={'MEMORY64': 1}, require_wasm64=True, require_node=True) wasm64_v8 = make_run('wasm64_v8', emcc_args=['-Wno-experimental', '--profiling-funcs'], settings={'MEMORY64': 1}, require_wasm64=True, require_v8=True) +# Run the wasm64 tests with all memory offsets > 4gb. Be careful running this test +# suite with any kind of parallelism. +wasm64_4gb = make_run('wasm64_4gb', emcc_args=['-Wno-experimental', '--profiling-funcs'], + settings={'MEMORY64': 1, 'INITIAL_MEMORY': '4200mb', + 'MAXIMUM_MEMORY': '4200mb', # TODO(sbc): should not be needed + 'GLOBAL_BASE': '4gb'}, + require_wasm64=True) # MEMORY64=2, or "lowered" wasm64l = make_run('wasm64l', emcc_args=['-O1', '-Wno-experimental', '--profiling-funcs'], settings={'MEMORY64': 2}, From bf2fcc29683b9418cb139aab4584a1cf7b54d559 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 2 Aug 2023 13:58:29 -0700 Subject: [PATCH 0612/1523] Rebaseline codesize expectations. NFC --- test/other/metadce/test_metadce_cxx_ctors1.size | 2 +- test/other/metadce/test_metadce_cxx_ctors2.size | 2 +- test/other/metadce/test_metadce_cxx_except.size | 2 +- test/other/metadce/test_metadce_cxx_except_wasm.size | 2 +- test/other/metadce/test_metadce_cxx_mangle.size | 2 +- test/other/metadce/test_metadce_cxx_noexcept.size | 2 +- test/other/metadce/test_metadce_cxx_wasmfs.size | 2 +- test/other/metadce/test_metadce_minimal_pthreads.jssize | 2 +- test/other/metadce/test_metadce_minimal_pthreads.size | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/test/other/metadce/test_metadce_cxx_ctors1.size b/test/other/metadce/test_metadce_cxx_ctors1.size index 228e74f86ff4a..4626b38c492cb 100644 --- a/test/other/metadce/test_metadce_cxx_ctors1.size +++ b/test/other/metadce/test_metadce_cxx_ctors1.size @@ -1 +1 @@ -123565 +123556 diff --git a/test/other/metadce/test_metadce_cxx_ctors2.size b/test/other/metadce/test_metadce_cxx_ctors2.size index ed64feb8e13e3..922b7b6070ff7 100644 --- a/test/other/metadce/test_metadce_cxx_ctors2.size +++ b/test/other/metadce/test_metadce_cxx_ctors2.size @@ -1 +1 @@ -123470 +123461 diff --git a/test/other/metadce/test_metadce_cxx_except.size b/test/other/metadce/test_metadce_cxx_except.size index 2e9ac712f802e..436352a6c3032 100644 --- a/test/other/metadce/test_metadce_cxx_except.size +++ b/test/other/metadce/test_metadce_cxx_except.size @@ -1 +1 @@ -166400 +166391 diff --git a/test/other/metadce/test_metadce_cxx_except_wasm.size b/test/other/metadce/test_metadce_cxx_except_wasm.size index 77021e06e7988..9527613dc508a 100644 --- a/test/other/metadce/test_metadce_cxx_except_wasm.size +++ b/test/other/metadce/test_metadce_cxx_except_wasm.size @@ -1 +1 @@ -137189 +137174 diff --git a/test/other/metadce/test_metadce_cxx_mangle.size b/test/other/metadce/test_metadce_cxx_mangle.size index 1fc97313ee2f7..ffeb33286ee63 100644 --- a/test/other/metadce/test_metadce_cxx_mangle.size +++ b/test/other/metadce/test_metadce_cxx_mangle.size @@ -1 +1 @@ -221362 +221356 diff --git a/test/other/metadce/test_metadce_cxx_noexcept.size b/test/other/metadce/test_metadce_cxx_noexcept.size index 14eb87d7a0c3f..08ab488d6854f 100644 --- a/test/other/metadce/test_metadce_cxx_noexcept.size +++ b/test/other/metadce/test_metadce_cxx_noexcept.size @@ -1 +1 @@ -126369 +126360 diff --git a/test/other/metadce/test_metadce_cxx_wasmfs.size b/test/other/metadce/test_metadce_cxx_wasmfs.size index 3a52b254f9c39..b6365d636f5f6 100644 --- a/test/other/metadce/test_metadce_cxx_wasmfs.size +++ b/test/other/metadce/test_metadce_cxx_wasmfs.size @@ -1 +1 @@ -164473 +164464 diff --git a/test/other/metadce/test_metadce_minimal_pthreads.jssize b/test/other/metadce/test_metadce_minimal_pthreads.jssize index 6fa45cd1fd746..16c2210899b3e 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.jssize +++ b/test/other/metadce/test_metadce_minimal_pthreads.jssize @@ -1 +1 @@ -14352 +14391 diff --git a/test/other/metadce/test_metadce_minimal_pthreads.size b/test/other/metadce/test_metadce_minimal_pthreads.size index dd9bd2b18e1b9..686ddd583747b 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.size +++ b/test/other/metadce/test_metadce_minimal_pthreads.size @@ -1 +1 @@ -18969 +18965 From d482a46b335c830924e113ca3da0335c965dc6a5 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 2 Aug 2023 16:45:37 -0700 Subject: [PATCH 0613/1523] Add parameter names to GL Emulation functions to fix 4GB mode link error (#19962) Without this, we hit error: handleI64Signatures: missing name for argument 1 in glGetTexLevelParameteriv Fixes #19944 --- src/library_glemu.js | 16 ++++++++-------- test/glgettexenv.c | 3 ++- test/test_other.py | 3 ++- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/library_glemu.js b/src/library_glemu.js index 01e3f7d9dafa6..76e8845ab7c87 100644 --- a/src/library_glemu.js +++ b/src/library_glemu.js @@ -3810,18 +3810,18 @@ var LibraryGLEmulation = { } }, - glTexGeni: function() { throw 'glTexGeni: TODO' }, - glTexGenfv: function() { throw 'glTexGenfv: TODO' }, - glTexEnvi: function() { warnOnce('glTexEnvi: TODO') }, - glTexEnvf: function() { warnOnce('glTexEnvf: TODO') }, - glTexEnvfv: function() { warnOnce('glTexEnvfv: TODO') }, + glTexGeni: function(coord, pname, param) { throw 'glTexGeni: TODO' }, + glTexGenfv: function(coord, pname, param) { throw 'glTexGenfv: TODO' }, + glTexEnvi: function(target, pname, params) { warnOnce('glTexEnvi: TODO') }, + glTexEnvf: function(target, pname, params) { warnOnce('glTexEnvf: TODO') }, + glTexEnvfv: function(target, pname, params) { warnOnce('glTexEnvfv: TODO') }, glGetTexEnviv: function(target, pname, param) { throw 'GL emulation not initialized!'; }, glGetTexEnvfv: function(target, pname, param) { throw 'GL emulation not initialized!'; }, - glTexImage1D: function() { throw 'glTexImage1D: TODO' }, - glTexCoord3f: function() { throw 'glTexCoord3f: TODO' }, - glGetTexLevelParameteriv: function() { throw 'glGetTexLevelParameteriv: TODO' }, + glTexImage1D: function(target, level, internalformat, width, border, format, type, data) { throw 'glTexImage1D: TODO' }, + glTexCoord3f: function(target, level, internalformat, width, border, format, type, data) { throw 'glTexCoord3f: TODO' }, + glGetTexLevelParameteriv: function(target, level, pname, params) { throw 'glGetTexLevelParameteriv: TODO' }, glShadeModel: function() { warnOnce('TODO: glShadeModel') }, diff --git a/test/glgettexenv.c b/test/glgettexenv.c index 68702cf52d8b1..d33a576abb82b 100644 --- a/test/glgettexenv.c +++ b/test/glgettexenv.c @@ -68,8 +68,9 @@ int main(int argc, char *argv[]) assert(colora[1] == colorb[1]); assert(colora[2] == colorb[2]); assert(colora[3] == colorb[3]); + SDL_Quit(); - + #ifdef REPORT_RESULT REPORT_RESULT(1); #endif diff --git a/test/test_other.py b/test/test_other.py index ae56f890d81a2..5d6677758783c 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -8774,7 +8774,8 @@ def test(check, extra): @parameterized({ '': ([],), 'asyncify': (['-sASYNCIFY'],), - 'gl_emu': (['-sLEGACY_GL_EMULATION'],), + # set max_memory to 4GB to test handleI64Signatures() with GL emulation + 'gl_emu': (['-sLEGACY_GL_EMULATION', '-sMAXIMUM_MEMORY=4GB', '-sALLOW_MEMORY_GROWTH'],), 'no_exception_throwing': (['-sDISABLE_EXCEPTION_THROWING'],), 'minimal_runtime': (['-sMINIMAL_RUNTIME'],), }) From cdfc80c909ddd544d583b8204872ac8a31841e61 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 3 Aug 2023 09:39:55 -0700 Subject: [PATCH 0614/1523] Remove test_inlinejs and test_inlinejs2. NFC (#19967) I believe these date back to before fastcomp! --- test/core/test_inlinejs.c | 34 ---------------------------------- test/core/test_inlinejs.out | 2 -- test/core/test_inlinejs2.c | 25 ------------------------- test/core/test_inlinejs2.out | 3 --- test/test_core.py | 26 ++------------------------ 5 files changed, 2 insertions(+), 88 deletions(-) delete mode 100644 test/core/test_inlinejs.c delete mode 100644 test/core/test_inlinejs.out delete mode 100644 test/core/test_inlinejs2.c delete mode 100644 test/core/test_inlinejs2.out diff --git a/test/core/test_inlinejs.c b/test/core/test_inlinejs.c deleted file mode 100644 index be22a2bd9cb98..0000000000000 --- a/test/core/test_inlinejs.c +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2016 The Emscripten Authors. All rights reserved. - * Emscripten is available under two separate licenses, the MIT license and the - * University of Illinois/NCSA Open Source License. Both these licenses can be - * found in the LICENSE file. - */ - -#include - -double get() { - double ret = 0; - __asm __volatile__("Math.abs(-12/3.3)" : "=r"(ret)); // write to a variable - asm("#comment1"); - asm volatile("#comment2"); - asm volatile( - "#comment3\n" - "#comment4\n"); - return ret; -} - -int main() { - asm("out('Inline JS is very cool')"); - printf("%.2f\n", get()); - - // Test that passing multiple input and output variables works. - int src1 = 1, src2 = 2, src3 = 3; - int dst1 = 0, dst2 = 0, dst3 = 0; - // TODO asm("out(%3); out(%4); out(%5); %0 = %3; %1 - // = %4; %2 = %5;" : "=r"(dst1),"=r"(dst2),"=r"(dst3): - // "r"(src1),"r"(src2),"r"(src3)); - // TODO printf("%d\n%d\n%d\n", dst1, dst2, dst3); - - return 0; -} diff --git a/test/core/test_inlinejs.out b/test/core/test_inlinejs.out deleted file mode 100644 index 1838ef2e9c78c..0000000000000 --- a/test/core/test_inlinejs.out +++ /dev/null @@ -1,2 +0,0 @@ -Inline JS is very cool -3.64 diff --git a/test/core/test_inlinejs2.c b/test/core/test_inlinejs2.c deleted file mode 100644 index b3b201bc9fd34..0000000000000 --- a/test/core/test_inlinejs2.c +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2016 The Emscripten Authors. All rights reserved. - * Emscripten is available under two separate licenses, the MIT license and the - * University of Illinois/NCSA Open Source License. Both these licenses can be - * found in the LICENSE file. - */ - -#include - -int mix(int x, int y) { - int ret; - asm("Math.pow(2, %0+%1+1)" : "=r"(ret) : "r"(x), "r"(y)); // read and write - return ret; -} - -void mult() { - asm("var $_$1 = Math.abs(-100); $_$1 *= 2; out($_$1)"); // multiline - asm __volatile__("out('done')"); -} - -int main(int argc, char **argv) { - printf("%d\n", mix(argc, argc / 2)); - mult(); - return 0; -} diff --git a/test/core/test_inlinejs2.out b/test/core/test_inlinejs2.out deleted file mode 100644 index 68dd9b641cf09..0000000000000 --- a/test/core/test_inlinejs2.out +++ /dev/null @@ -1,3 +0,0 @@ -4 -200 -done diff --git a/test/test_core.py b/test/test_core.py index 4167f4d74625a..3290519b04356 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -2114,34 +2114,12 @@ def test_emscripten_has_asyncify(self): self.set_setting('ASYNCIFY') self.do_run(src, '1') - # TODO: test only worked in non-fastcomp - def test_inlinejs(self): - self.skipTest('non-fastcomp is deprecated and fails in 3.5') # only supports EM_ASM - - self.do_core_test('test_inlinejs.c') - - if self.emcc_args == []: - # opts will eliminate the comments - out = read_file('src.js') - for i in range(1, 5): - assert ('comment%d' % i) in out - - # TODO: test only worked in non-fastcomp - def test_inlinejs2(self): - self.skipTest('non-fastcomp is deprecated and fails in 3.5') # only supports EM_ASM - - self.do_core_test('test_inlinejs2.c') - def test_inlinejs3(self): - if self.is_wasm(): - self.skipTest('wasm requires a proper asm module') - - src = test_file('core/test_inlinejs3.c') - output = shared.unsuffixed(src) + '.out' - self.do_core_test('test_inlinejs3.c') print('no debugger, check validation') + src = test_file('core/test_inlinejs3.c') + output = test_file('core/test_inlinejs3.out') src = read_file(src).replace('emscripten_debugger();', '') self.do_run(src, read_file(output)) From bb233ad5c04a988a5b06b4c100177057ab691f80 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 3 Aug 2023 11:17:46 -0700 Subject: [PATCH 0615/1523] Make more use of emscripten_out/emscripten_err in test code. NFC (#19524) Using these emscripten wrappers has some advantages. In particular, with workers we have seen issues with writes to console.log/console.error being lost in some cases. --- test/core/test_em_asm.cpp | 12 +- test/core/test_em_asm_2.cpp | 184 +++++++++--------- test/core/test_em_asm_types.cpp | 8 +- test/core/test_em_js_i64.c | 8 +- test/core/test_get_exported_function.cpp | 7 +- test/embind/embind_jspi_test.cpp | 4 +- test/embind/test_float_constants.cpp | 14 +- test/embind/test_negative_constants.cpp | 12 +- test/fetch/sync_xhr.cpp | 2 +- test/pthread/hello_thread.c | 4 +- test/pthread/test_pthread_64bit_atomics.cpp | 17 +- test/pthread/test_pthread_atomics.cpp | 12 +- test/pthread/test_pthread_cancel.cpp | 10 +- .../test_pthread_condition_variable.cpp | 40 ++-- test/pthread/test_pthread_create.cpp | 7 +- test/pthread/test_pthread_create_pthread.cpp | 6 +- test/pthread/test_pthread_file_io.cpp | 4 +- .../test_pthread_global_data_initialization.c | 12 +- .../test_pthread_hardware_concurrency.cpp | 12 +- test/pthread/test_pthread_join.cpp | 11 +- test/pthread/test_pthread_malloc.cpp | 6 +- test/pthread/test_pthread_mutex.cpp | 5 +- .../test_pthread_preallocates_workers.cpp | 3 +- test/pthread/test_pthread_sbrk.cpp | 2 +- test/test_browser.py | 2 +- test/test_closure_warning.c | 2 +- test/test_core.py | 28 +-- test/test_other.py | 33 ++-- test/test_webgl2_runtime_no_context.cpp | 4 +- test/test_webgl_context_attributes_common.c | 9 +- test/wasm_worker/c11__Thread_local.c | 4 +- test/wasm_worker/cpp11_thread_local.cpp | 4 +- test/wasm_worker/gcc___Thread.c | 4 +- test/wasm_worker/lock_waitinf_acquire.c | 6 +- test/wasm_worker/thread_stack.c | 10 +- test/wasm_worker/wasm_worker_and_pthread.c | 5 +- test/wasmfs/wasmfs_opfs_errors.c | 6 +- 37 files changed, 261 insertions(+), 258 deletions(-) diff --git a/test/core/test_em_asm.cpp b/test/core/test_em_asm.cpp index ccd62ce73be75..74494233cd457 100644 --- a/test/core/test_em_asm.cpp +++ b/test/core/test_em_asm.cpp @@ -12,7 +12,7 @@ int main() { unsigned long p = 8; EM_ASM({ - console.log("int types:"); + out("int types:"); out(" char : " + $0); out(" signed char : " + $1); out("unsigned char : " + $2); @@ -71,35 +71,35 @@ int main() { // Test mixing ints and doubles EM_ASM({ - console.log("idii"); + out("idii"); out("a " + $0); out("b " + $1); out("c " + $2); out("d " + $3); }, 1, 3.14159, 3, 4); EM_ASM({ - console.log("diii"); + out("diii"); out("a " + $0); out("b " + $1); out("c " + $2); out("d " + $3); }, 3.14159, 2, 3, 4); EM_ASM({ - console.log("iidi"); + out("iidi"); out("a " + $0); out("b " + $1); out("c " + $2); out("d " + $3); }, 1, 2, 3.14159, 4); EM_ASM({ - console.log("ddii"); + out("ddii"); out("a " + $0); out("b " + $1); out("c " + $2); out("d " + $3); }, 3.14159, 2.1828, 3, 4); EM_ASM({ - console.log("iddi"); + out("iddi"); out("a " + $0); out("b " + $1); out("c " + $2); diff --git a/test/core/test_em_asm_2.cpp b/test/core/test_em_asm_2.cpp index 92721ad11eaa7..2012af88d05ea 100644 --- a/test/core/test_em_asm_2.cpp +++ b/test/core/test_em_asm_2.cpp @@ -9,97 +9,97 @@ int main() { printf("EM_ASM: Simple expression without trailing semicolon\n"); - EM_ASM(console.log('1. expression without trailing semicolon')); - EM_ASM("console.log('2. expression without trailing semicolon')"); - EM_ASM({"console.log('3. expression without trailing semicolon')"}); - EM_ASM({console.log('4. expression without trailing semicolon')}); - EM_ASM("{console.log('5. expression without trailing semicolon')}"); + EM_ASM(out('1. expression without trailing semicolon')); + EM_ASM("out('2. expression without trailing semicolon')"); + EM_ASM({"out('3. expression without trailing semicolon')"}); + EM_ASM({out('4. expression without trailing semicolon')}); + EM_ASM("{out('5. expression without trailing semicolon')}"); printf("\nEM_ASM: Double quotes\n"); - EM_ASM(console.log("1. string in double quotes")); - EM_ASM("console.log(\"2. string in double quotes\")"); - EM_ASM({"console.log(\"3. string in double quotes\")"}); - EM_ASM({console.log("4. string in double quotes")}); - EM_ASM("{console.log(\"5. string in double quotes\")}"); + EM_ASM(out("1. string in double quotes")); + EM_ASM("out(\"2. string in double quotes\")"); + EM_ASM({"out(\"3. string in double quotes\")"}); + EM_ASM({out("4. string in double quotes")}); + EM_ASM("{out(\"5. string in double quotes\")}"); printf("\nEM_ASM: Double quotes inside a string\n"); - EM_ASM(console.log('1. this is \"double\" \"quotes\"')); - EM_ASM(console.log('2. this is "double" "quotes" without escaping')); - EM_ASM("console.log('3. this is \"double\" \"quotes\"')"); - EM_ASM({"console.log('4. this is \"double\" \"quotes\"')"}); - EM_ASM({console.log('5. this is \"double\" \"quotes\"')}); - EM_ASM({console.log('6. this is "double" "quotes" without esacping')}); - EM_ASM("{console.log('7. this is \"double\" \"quotes\"')}"); + EM_ASM(out('1. this is \"double\" \"quotes\"')); + EM_ASM(out('2. this is "double" "quotes" without escaping')); + EM_ASM("out('3. this is \"double\" \"quotes\"')"); + EM_ASM({"out('4. this is \"double\" \"quotes\"')"}); + EM_ASM({out('5. this is \"double\" \"quotes\"')}); + EM_ASM({out('6. this is "double" "quotes" without esacping')}); + EM_ASM("{out('7. this is \"double\" \"quotes\"')}"); printf("\nEM_ASM: Pass a string\n"); - EM_ASM(console.log('1. hello ' + UTF8ToString($0)), "world!"); - EM_ASM("console.log('2. hello ' + UTF8ToString($0))", "world!"); - EM_ASM({"console.log('3. hello ' + UTF8ToString($0))"}, "world!"); - EM_ASM({console.log('4. hello ' + UTF8ToString($0))}, "world!"); - EM_ASM("{console.log('5. hello ' + UTF8ToString($0))}", "world!"); + EM_ASM(out('1. hello ' + UTF8ToString($0)), "world!"); + EM_ASM("out('2. hello ' + UTF8ToString($0))", "world!"); + EM_ASM({"out('3. hello ' + UTF8ToString($0))"}, "world!"); + EM_ASM({out('4. hello ' + UTF8ToString($0))}, "world!"); + EM_ASM("{out('5. hello ' + UTF8ToString($0))}", "world!"); printf("\nEM_ASM: Simple expression without trailing semicolon, wrap code block in extra parentheses\n"); - EM_ASM((console.log('1. expression without trailing semicolon, in parentheses'))); - EM_ASM(("console.log('2. expression without trailing semicolon, in parentheses')")); - EM_ASM(({"console.log('3. expression without trailing semicolon, in parentheses')"})); - EM_ASM(({console.log('4. expression without trailing semicolon, in parentheses')})); - EM_ASM(("{console.log('5. expression without trailing semicolon, in parentheses')}")); + EM_ASM((out('1. expression without trailing semicolon, in parentheses'))); + EM_ASM(("out('2. expression without trailing semicolon, in parentheses')")); + EM_ASM(({"out('3. expression without trailing semicolon, in parentheses')"})); + EM_ASM(({out('4. expression without trailing semicolon, in parentheses')})); + EM_ASM(("{out('5. expression without trailing semicolon, in parentheses')}")); printf("\nEM_ASM: Two statements, separated with a semicolon\n"); - EM_ASM(console.log('1. two'); console.log('1. statements');); - EM_ASM("console.log('2. two'); console.log('2. statements 2');"); - EM_ASM({"console.log('3. two'); console.log('3. statements 3');"}); - EM_ASM({console.log('4. two'); console.log('4. statements 4');}); - EM_ASM("{console.log('5. two'); console.log('5. statements 5');}"); + EM_ASM(out('1. two'); out('1. statements');); + EM_ASM("out('2. two'); out('2. statements 2');"); + EM_ASM({"out('3. two'); out('3. statements 3');"}); + EM_ASM({out('4. two'); out('4. statements 4');}); + EM_ASM("{out('5. two'); out('5. statements 5');}"); printf("\nEM_ASM: Pass an integer\n"); - EM_ASM(console.log('1. int ' + $0), 42); - EM_ASM("console.log('2. int ' + $0)", 43); - EM_ASM({"console.log('3. int ' + $0)"}, 44); - EM_ASM({console.log('4. int ' + $0)}, 45); - EM_ASM("{console.log('5. int ' + $0)}", 46); + EM_ASM(out('1. int ' + $0), 42); + EM_ASM("out('2. int ' + $0)", 43); + EM_ASM({"out('3. int ' + $0)"}, 44); + EM_ASM({out('4. int ' + $0)}, 45); + EM_ASM("{out('5. int ' + $0)}", 46); printf("\nEM_ASM: Evaluate an anonymous function\n"); - EM_ASM((function() {console.log('1. evaluating anonymous function ' + $0)})(), 42); - EM_ASM("(function() {console.log('2. evaluating anonymous function ' + $0)})()", 42); - EM_ASM({"(function() {console.log('3. evaluating anonymous function ' + $0)})()"}, 42); - EM_ASM({(function() {console.log('4. evaluating anonymous function ' + $0)})()}, 42); - EM_ASM("{(function() {console.log('5. evaluating anonymous function ' + $0)})()}", 42); + EM_ASM((function() {out('1. evaluating anonymous function ' + $0)})(), 42); + EM_ASM("(function() {out('2. evaluating anonymous function ' + $0)})()", 42); + EM_ASM({"(function() {out('3. evaluating anonymous function ' + $0)})()"}, 42); + EM_ASM({(function() {out('4. evaluating anonymous function ' + $0)})()}, 42); + EM_ASM("{(function() {out('5. evaluating anonymous function ' + $0)})()}", 42); printf("\nEM_ASM: Pass an integer and a double\n"); - EM_ASM(console.log('1. int and double ' + $0 + ' ' + $1), 42, 43.5); - EM_ASM("console.log('2. int and double ' + $0 + ' ' + $1)", 42, 43.5); - EM_ASM({"console.log('3. int and double ' + $0 + ' ' + $1)"}, 42, 43.5); - EM_ASM({console.log('4. int and double ' + $0 + ' ' + $1)}, 42, 43.5); - EM_ASM("{console.log('5. int and double ' + $0 + ' ' + $1)}", 42, 43.5); + EM_ASM(out('1. int and double ' + $0 + ' ' + $1), 42, 43.5); + EM_ASM("out('2. int and double ' + $0 + ' ' + $1)", 42, 43.5); + EM_ASM({"out('3. int and double ' + $0 + ' ' + $1)"}, 42, 43.5); + EM_ASM({out('4. int and double ' + $0 + ' ' + $1)}, 42, 43.5); + EM_ASM("{out('5. int and double ' + $0 + ' ' + $1)}", 42, 43.5); int i; printf("\nEM_ASM_INT: Pass an integer, return an integer back\n"); - i = EM_ASM_INT(console.log('1. got int ' + $0); return 3.5;, 42); printf("1. returned int %d\n", i); - i = EM_ASM_INT("console.log('2. got int ' + $0); return 4.5;", 42); printf("2. returned int %d\n", i); - i = EM_ASM_INT({"console.log('3. got int ' + $0); return 5.5;"}, 42); printf("3. returned int %d\n", i); - i = EM_ASM_INT({console.log('4. got int ' + $0); return 6.5;}, 42); printf("4. returned int %d\n", i); - i = EM_ASM_INT("{console.log('5. got int ' + $0); return 7.5;}", 42); printf("5. returned int %d\n", i); + i = EM_ASM_INT(out('1. got int ' + $0); return 3.5;, 42); printf("1. returned int %d\n", i); + i = EM_ASM_INT("out('2. got int ' + $0); return 4.5;", 42); printf("2. returned int %d\n", i); + i = EM_ASM_INT({"out('3. got int ' + $0); return 5.5;"}, 42); printf("3. returned int %d\n", i); + i = EM_ASM_INT({out('4. got int ' + $0); return 6.5;}, 42); printf("4. returned int %d\n", i); + i = EM_ASM_INT("{out('5. got int ' + $0); return 7.5;}", 42); printf("5. returned int %d\n", i); printf("\nEM_ASM_INT: Pass an integer, return an integer back, wrap code block in extra parentheses\n"); - i = EM_ASM_INT((console.log('1. got int, extra parentheses ' + $0); return 3.5;), 42); printf("1. returned int, extra parentheses %d\n", i); - i = EM_ASM_INT(("console.log('2. got int, extra parentheses ' + $0); return 4.5;"), 42); printf("2. returned int, extra parentheses %d\n", i); - i = EM_ASM_INT(({"console.log('3. got int, extra parentheses ' + $0); return 5.5;"}), 42); printf("3. returned int, extra parentheses %d\n", i); - i = EM_ASM_INT(({console.log('4. got int, extra parentheses ' + $0); return 6.5;}), 42); printf("4. returned int, extra parentheses %d\n", i); - i = EM_ASM_INT(("{console.log('5. got int, extra parentheses ' + $0); return 7.5;}"), 42); printf("5. returned int, extra parentheses %d\n", i); + i = EM_ASM_INT((out('1. got int, extra parentheses ' + $0); return 3.5;), 42); printf("1. returned int, extra parentheses %d\n", i); + i = EM_ASM_INT(("out('2. got int, extra parentheses ' + $0); return 4.5;"), 42); printf("2. returned int, extra parentheses %d\n", i); + i = EM_ASM_INT(({"out('3. got int, extra parentheses ' + $0); return 5.5;"}), 42); printf("3. returned int, extra parentheses %d\n", i); + i = EM_ASM_INT(({out('4. got int, extra parentheses ' + $0); return 6.5;}), 42); printf("4. returned int, extra parentheses %d\n", i); + i = EM_ASM_INT(("{out('5. got int, extra parentheses ' + $0); return 7.5;}"), 42); printf("5. returned int, extra parentheses %d\n", i); printf("\nEM_ASM_INT: More imaginable ways for user to wrap in extra parentheses\n"); - i = EM_ASM_INT({("console.log('1. got int, extra extra parentheses ' + $0); return 5.5;")}, 42); printf("1. returned int, extra extra parentheses %d\n", i); - i = EM_ASM_INT({(console.log('2. got int, extra extra parentheses ' + $0); return 6.5;)}, 42); printf("2. returned int, extra extra parentheses %d\n", i); - i = EM_ASM_INT(((((((((((console.log('3. got int, extra extra extra parentheses ' + $0); return 6.5;)))))))))), 42); printf("3. returned int, extra extra extra parentheses %d\n", i); + i = EM_ASM_INT({("out('1. got int, extra extra parentheses ' + $0); return 5.5;")}, 42); printf("1. returned int, extra extra parentheses %d\n", i); + i = EM_ASM_INT({(out('2. got int, extra extra parentheses ' + $0); return 6.5;)}, 42); printf("2. returned int, extra extra parentheses %d\n", i); + i = EM_ASM_INT(((((((((((out('3. got int, extra extra extra parentheses ' + $0); return 6.5;)))))))))), 42); printf("3. returned int, extra extra extra parentheses %d\n", i); printf("\nEM_ASM_INT: Return an integer back.\n"); - i = EM_ASM_INT(console.log('1. got int ' + $0); return 3.5;, 42); printf("1. returned int %d\n", i); - i = EM_ASM_INT("console.log('2. got int ' + $0); return 4.5;", 42); printf("2. returned int %d\n", i); - i = EM_ASM_INT({"console.log('3. got int ' + $0); return 5.5;"}, 42); printf("3. returned int %d\n", i); - i = EM_ASM_INT({console.log('4. got int ' + $0); return 6.5;}, 42); printf("4. returned int %d\n", i); - i = EM_ASM_INT("{console.log('5. got int ' + $0); return 7.5;}", 42); printf("5. returned int %d\n", i); + i = EM_ASM_INT(out('1. got int ' + $0); return 3.5;, 42); printf("1. returned int %d\n", i); + i = EM_ASM_INT("out('2. got int ' + $0); return 4.5;", 42); printf("2. returned int %d\n", i); + i = EM_ASM_INT({"out('3. got int ' + $0); return 5.5;"}, 42); printf("3. returned int %d\n", i); + i = EM_ASM_INT({out('4. got int ' + $0); return 6.5;}, 42); printf("4. returned int %d\n", i); + i = EM_ASM_INT("{out('5. got int ' + $0); return 7.5;}", 42); printf("5. returned int %d\n", i); printf("\nEM_ASM_INT: Return an integer in a single brief statement.\n"); i = EM_ASM_INT(return 42); printf("1. returned statement %d\n", i); @@ -114,39 +114,39 @@ int main() double d; printf("\nEM_ASM_DOUBLE: Pass no parameters, return a double.\n"); - d = EM_ASM_DOUBLE(console.log('1. returning double'); return 3.5;); printf("1. got double %f\n", d); - d = EM_ASM_DOUBLE("console.log('2. returning double'); return 4.5;"); printf("2. got double %f\n", d); - d = EM_ASM_DOUBLE({"console.log('3. returning double'); return 5.5;"}); printf("3. got double %f\n", d); - d = EM_ASM_DOUBLE({console.log('4. returning double'); return 6.5;}); printf("4. got double %f\n", d); - d = EM_ASM_DOUBLE("{console.log('5. returning double'); return 7.5;}"); printf("5. got double %f\n", d); + d = EM_ASM_DOUBLE(out('1. returning double'); return 3.5;); printf("1. got double %f\n", d); + d = EM_ASM_DOUBLE("out('2. returning double'); return 4.5;"); printf("2. got double %f\n", d); + d = EM_ASM_DOUBLE({"out('3. returning double'); return 5.5;"}); printf("3. got double %f\n", d); + d = EM_ASM_DOUBLE({out('4. returning double'); return 6.5;}); printf("4. got double %f\n", d); + d = EM_ASM_DOUBLE("{out('5. returning double'); return 7.5;}"); printf("5. got double %f\n", d); printf("\nEM_ASM_DOUBLE: Pass an integer, return a double.\n"); - d = EM_ASM_DOUBLE(console.log('1. got int ' + $0); return 3.5;, 42); printf("1. returned double %f\n", d); - d = EM_ASM_DOUBLE("console.log('2. got int ' + $0); return 4.5;", 42); printf("2. returned double %f\n", d); - d = EM_ASM_DOUBLE({"console.log('3. got int ' + $0); return 5.5;"}, 42); printf("3. returned double %f\n", d); - d = EM_ASM_DOUBLE({console.log('4. got int ' + $0); return 6.5;}, 42); printf("4. returned double %f\n", d); - d = EM_ASM_DOUBLE("{console.log('5. got int ' + $0); return 7.5;}", 42); printf("5. returned double %f\n", d); + d = EM_ASM_DOUBLE(out('1. got int ' + $0); return 3.5;, 42); printf("1. returned double %f\n", d); + d = EM_ASM_DOUBLE("out('2. got int ' + $0); return 4.5;", 42); printf("2. returned double %f\n", d); + d = EM_ASM_DOUBLE({"out('3. got int ' + $0); return 5.5;"}, 42); printf("3. returned double %f\n", d); + d = EM_ASM_DOUBLE({out('4. got int ' + $0); return 6.5;}, 42); printf("4. returned double %f\n", d); + d = EM_ASM_DOUBLE("{out('5. got int ' + $0); return 7.5;}", 42); printf("5. returned double %f\n", d); printf("\nEM_ASM_DOUBLE: Pass a double and an integer, return a double.\n"); - d = EM_ASM_DOUBLE(console.log('1. got double and int ' + $0 + ' ' + $1); return 3.5;, 5.5, 42); printf("1. returned double %f\n", d); - d = EM_ASM_DOUBLE("console.log('2. got double and int ' + $0 + ' ' + $1); return 4.5;", 5.5, 42); printf("2. returned double %f\n", d); - d = EM_ASM_DOUBLE({"console.log('3. got double and int ' + $0 + ' ' + $1); return 5.5;"}, 5.5, 42); printf("3. returned double %f\n", d); - d = EM_ASM_DOUBLE({console.log('4. got double and int ' + $0 + ' ' + $1); return 6.5;}, 5.5, 42); printf("4. returned double %f\n", d); - d = EM_ASM_DOUBLE("{console.log('5. got double and int ' + $0 + ' ' + $1); return 7.5;}", 5.5, 42); printf("5. returned double %f\n", d); + d = EM_ASM_DOUBLE(out('1. got double and int ' + $0 + ' ' + $1); return 3.5;, 5.5, 42); printf("1. returned double %f\n", d); + d = EM_ASM_DOUBLE("out('2. got double and int ' + $0 + ' ' + $1); return 4.5;", 5.5, 42); printf("2. returned double %f\n", d); + d = EM_ASM_DOUBLE({"out('3. got double and int ' + $0 + ' ' + $1); return 5.5;"}, 5.5, 42); printf("3. returned double %f\n", d); + d = EM_ASM_DOUBLE({out('4. got double and int ' + $0 + ' ' + $1); return 6.5;}, 5.5, 42); printf("4. returned double %f\n", d); + d = EM_ASM_DOUBLE("{out('5. got double and int ' + $0 + ' ' + $1); return 7.5;}", 5.5, 42); printf("5. returned double %f\n", d); printf("\nEM_ASM_INT: A comma character (,) inside the code block may need extra parentheses\n"); -// i = EM_ASM_INT(console.log('1. comma in em_asm'); var foo = { a: 5, b: $0 }; return foo.a + foo.b, 10); printf("1. returned %d\n", i); // This would not compile: use of undeclared identifier 'b' - i = EM_ASM_INT((console.log('1. comma in em_asm'); var foo = { a: 5, b: $0 }; return foo.a + foo.b), 10); printf("1. returned %d\n", i); // However by wrapping the code block inside parentheses, it will be ok - i = EM_ASM_INT("console.log('2. comma in em_asm'); var foo = { a: 5, b: $0 }; return foo.a + foo.b", 10); printf("2. returned %d\n", i); - i = EM_ASM_INT({"console.log('3. comma in em_asm'); var foo = { a: 5, b: $0 }; return foo.a + foo.b"}, 10); printf("3. returned %d\n", i); -// i = EM_ASM_INT({console.log('4. comma in em_asm'); var foo = { a: 5, b: $0 }; return foo.a + foo.b}, 10); printf("4. returned %d\n", i); // This would also not compile: use of undeclared identifier 'b' - i = EM_ASM_INT(({console.log('4. comma in em_asm'); var foo = { a: 5, b: $0 }; return foo.a + foo.b}), 10); printf("4. returned %d\n", i); // Again by wrapping the code block inside parentheses, it will work - i = EM_ASM_INT("{console.log('5. comma in em_asm'); var foo = { a: 5, b: $0 }; return foo.a + foo.b}", 10); printf("5. returned %d\n", i); +// i = EM_ASM_INT(out('1. comma in em_asm'); var foo = { a: 5, b: $0 }; return foo.a + foo.b, 10); printf("1. returned %d\n", i); // This would not compile: use of undeclared identifier 'b' + i = EM_ASM_INT((out('1. comma in em_asm'); var foo = { a: 5, b: $0 }; return foo.a + foo.b), 10); printf("1. returned %d\n", i); // However by wrapping the code block inside parentheses, it will be ok + i = EM_ASM_INT("out('2. comma in em_asm'); var foo = { a: 5, b: $0 }; return foo.a + foo.b", 10); printf("2. returned %d\n", i); + i = EM_ASM_INT({"out('3. comma in em_asm'); var foo = { a: 5, b: $0 }; return foo.a + foo.b"}, 10); printf("3. returned %d\n", i); +// i = EM_ASM_INT({out('4. comma in em_asm'); var foo = { a: 5, b: $0 }; return foo.a + foo.b}, 10); printf("4. returned %d\n", i); // This would also not compile: use of undeclared identifier 'b' + i = EM_ASM_INT(({out('4. comma in em_asm'); var foo = { a: 5, b: $0 }; return foo.a + foo.b}), 10); printf("4. returned %d\n", i); // Again by wrapping the code block inside parentheses, it will work + i = EM_ASM_INT("{out('5. comma in em_asm'); var foo = { a: 5, b: $0 }; return foo.a + foo.b}", 10); printf("5. returned %d\n", i); printf("\nEM_ASM: Expression contains a tab character\n"); - EM_ASM(console.log('1. the following word is delimited by tab characters: H\tE\tL\tL\tO\tT\tA\tB\tS')); - EM_ASM("console.log('2. the following word is delimited by tab characters: H\tE\tL\tL\tO\tT\tA\tB\tS')"); - EM_ASM({"console.log('3. the following word is delimited by tab characters: H\tE\tL\tL\tO\tT\tA\tB\tS')"}); - EM_ASM({console.log('4. the following word is delimited by tab characters: H\tE\tL\tL\tO\tT\tA\tB\tS')}); - EM_ASM("{console.log('5. the following word is delimited by tab characters: H\tE\tL\tL\tO\tT\tA\tB\tS')}"); + EM_ASM(out('1. the following word is delimited by tab characters: H\tE\tL\tL\tO\tT\tA\tB\tS')); + EM_ASM("out('2. the following word is delimited by tab characters: H\tE\tL\tL\tO\tT\tA\tB\tS')"); + EM_ASM({"out('3. the following word is delimited by tab characters: H\tE\tL\tL\tO\tT\tA\tB\tS')"}); + EM_ASM({out('4. the following word is delimited by tab characters: H\tE\tL\tL\tO\tT\tA\tB\tS')}); + EM_ASM("{out('5. the following word is delimited by tab characters: H\tE\tL\tL\tO\tT\tA\tB\tS')}"); } diff --git a/test/core/test_em_asm_types.cpp b/test/core/test_em_asm_types.cpp index 7bbcfa36fb52d..cd18494e21339 100644 --- a/test/core/test_em_asm_types.cpp +++ b/test/core/test_em_asm_types.cpp @@ -16,7 +16,7 @@ int main(int argc, char **argv) { // Promotions of arrays, function/member pointers and objects implicitly // convertible to numbers are excluded because they will not be translated // to corresponding JS objects. -#define TEST_TYPE(type, value) EM_ASM({console.log(#type, Number($0));}, (type)(value)); +#define TEST_TYPE(type, value) EM_ASM({out(#type, Number($0));}, (type)(value)); TEST_TYPE(int*, 0); TEST_TYPE(float, 1.5f); TEST_TYPE(double, 2.5); @@ -39,14 +39,14 @@ int main(int argc, char **argv) { struct WithBitField w; w.x = 3; - EM_ASM({ console.log('bit field', $0); }, w.x); + EM_ASM({ out('bit field', $0); }, w.x); #ifdef __cplusplus TEST_TYPE(bool, true); TEST_TYPE(wchar_t, 50); #else - EM_ASM({console.log('bool 1')}); - EM_ASM({console.log('wchar_t 50')}); + EM_ASM({out('bool 1')}); + EM_ASM({out('wchar_t 50')}); #endif TEST_TYPE(enum SomeEnum, SIXTY); diff --git a/test/core/test_em_js_i64.c b/test/core/test_em_js_i64.c index 513ee2c8a8f6a..6319f6fffa88a 100644 --- a/test/core/test_em_js_i64.c +++ b/test/core/test_em_js_i64.c @@ -2,11 +2,11 @@ #include EM_JS(void, foo, (uint64_t a, int64_t b), { - console.log(typeof a); - console.log(typeof b); + out(typeof a); + out(typeof b); - console.log('a:' + a); - console.log('b:' + b); + out('a:' + a); + out('b:' + b); }) int main() { diff --git a/test/core/test_get_exported_function.cpp b/test/core/test_get_exported_function.cpp index 7fc1165d921a9..b2ac54f258c40 100644 --- a/test/core/test_get_exported_function.cpp +++ b/test/core/test_get_exported_function.cpp @@ -1,4 +1,5 @@ -#include +#include +#include #include extern "C" EMSCRIPTEN_KEEPALIVE int foo() @@ -17,10 +18,10 @@ int main() { intfunc f = (intfunc)emscripten_get_exported_function("_foo"); intfunc b = (intfunc)emscripten_get_exported_function("_bar"); - EM_ASM(console.log($0 + ' ' + $1), f(), b()); + emscripten_outf("%d %d", f(), b()); // Obtaining the same function pointer twice should return the // same address. intfunc b2 = (intfunc)emscripten_get_exported_function("_bar"); - EM_ASM(console.log($0), b == b2); + emscripten_outf("%d", b == b2); } diff --git a/test/embind/embind_jspi_test.cpp b/test/embind/embind_jspi_test.cpp index b3e161f4ed3f8..0799fdb2de6c4 100644 --- a/test/embind/embind_jspi_test.cpp +++ b/test/embind/embind_jspi_test.cpp @@ -97,9 +97,9 @@ EM_ASYNC_JS(void, test, (), { setTimeout(Module.unsuspend); await Module.suspend(); - console.log('done'); + out('done'); } catch (e) { - console.log('Failed: ' + e.stack); + out('Failed: ' + e.stack); } }); diff --git a/test/embind/test_float_constants.cpp b/test/embind/test_float_constants.cpp index 4dbfb070b32a4..f55395008f8dc 100644 --- a/test/embind/test_float_constants.cpp +++ b/test/embind/test_float_constants.cpp @@ -19,10 +19,10 @@ EMSCRIPTEN_BINDINGS(constants) { } int main() { - EM_ASM( - console.log("PI (as double) = " + Module['PI']); - console.log("EULER = " + Module['EULER']); - console.log("pi (as float) = " + Module['pi']); - console.log("euler = " + Module['euler']); - ); -} \ No newline at end of file + EM_ASM( + out("PI (as double) = " + Module['PI']); + out("EULER = " + Module['EULER']); + out("pi (as float) = " + Module['pi']); + out("euler = " + Module['euler']); + ); +} diff --git a/test/embind/test_negative_constants.cpp b/test/embind/test_negative_constants.cpp index 08c77de3fb230..998e1697397a2 100644 --- a/test/embind/test_negative_constants.cpp +++ b/test/embind/test_negative_constants.cpp @@ -22,10 +22,10 @@ EMSCRIPTEN_BINDINGS(constants) { int main() { EM_ASM( - console.log("NEGATIVE_FLOAT_NUM = " + Module['NEGATIVE_FLOAT_NUM']); - console.log("NEGATIVE_INT_NUM = " + Module['NEGATIVE_INT_NUM']); - console.log("negative_float_num = " + Module['negative_float_num']); - console.log("negative_double_num = " + Module['negative_double_num']); - console.log("negative_int_num = " + Module['negative_int_num']); + out("NEGATIVE_FLOAT_NUM = " + Module['NEGATIVE_FLOAT_NUM']); + out("NEGATIVE_INT_NUM = " + Module['NEGATIVE_INT_NUM']); + out("negative_float_num = " + Module['negative_float_num']); + out("negative_double_num = " + Module['negative_double_num']); + out("negative_int_num = " + Module['negative_int_num']); ); -} \ No newline at end of file +} diff --git a/test/fetch/sync_xhr.cpp b/test/fetch/sync_xhr.cpp index a79566674a70d..a77c9aa2f37cd 100644 --- a/test/fetch/sync_xhr.cpp +++ b/test/fetch/sync_xhr.cpp @@ -17,7 +17,7 @@ int main() // If an exception is thrown from the user callback, it bubbles up to self.onerror but is otherwise completely // swallowed by xhr.send. EM_ASM({self.onerror = function() { - console.log('Got error'); + out('Got error'); HEAP32[$0 >> 2] = 2; };}, &result); emscripten_fetch_attr_t attr; diff --git a/test/pthread/hello_thread.c b/test/pthread/hello_thread.c index 3e040cbfd415a..ac5ea51387728 100644 --- a/test/pthread/hello_thread.c +++ b/test/pthread/hello_thread.c @@ -7,11 +7,11 @@ #include #include -#include +#include void *thread_main(void *arg) { - EM_ASM(out('hello from thread!')); + emscripten_out("hello from thread!"); emscripten_force_exit(0); __builtin_trap(); } diff --git a/test/pthread/test_pthread_64bit_atomics.cpp b/test/pthread/test_pthread_64bit_atomics.cpp index 3817e29fbb4c1..207a2383a8532 100644 --- a/test/pthread/test_pthread_64bit_atomics.cpp +++ b/test/pthread/test_pthread_64bit_atomics.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #define NUM_THREADS 8 @@ -39,7 +40,7 @@ void *ThreadMain(void *arg) assert(globalDouble == 5.0); assert(globalU64 == 5); struct Test *t = (struct Test*)arg; - EM_ASM(out('Thread ' + $0 + ' for test ' + $1 + ': starting computation.'), t->threadId, t->op); + emscripten_outf("Thread %d for test %d: starting computation", t->threadId, t->op); for(int i = 0; i < 99999; ++i) for(int j = 0; j < N; ++j) @@ -80,7 +81,7 @@ void *ThreadMain(void *arg) break; } } - EM_ASM(out('Thread ' + $0 + ' for test ' + $1 + ': finished, exit()ing.'), t->threadId, t->op); + emscripten_outf("Thread %d for test %d: finished, exit()ing", t->threadId, t->op); pthread_exit(0); } @@ -93,7 +94,7 @@ void RunTest(int test) pthread_attr_init(&attr); pthread_attr_setstacksize(&attr, 4*1024); - printf("Main thread has thread ID %ld\n", pthread_self()); + emscripten_outf("Main thread has thread ID %ld\n", pthread_self()); assert(pthread_self() != 0); switch(test) @@ -103,7 +104,7 @@ void RunTest(int test) default: memset(sharedData, 0, sizeof(sharedData)); break; } - EM_ASM(out('Main: Starting test ' + $0), test); + emscripten_outf("Main: Starting test %d", test); for(int i = 0; i < NUM_THREADS; ++i) { @@ -124,7 +125,7 @@ void RunTest(int test) } int val = sharedData[0]; - EM_ASM(out('Main: Test ' + $0 + ' finished. Result: ' + $1), test, val); + emscripten_outf("Main: Test %d finished. Result: %d", test, val); if (test != 6) { for(int i = 1; i < N; ++i) @@ -152,10 +153,10 @@ int main() for(int i = 0; i < N; ++i) totalRead += sharedData[i]; if (totalRead == totalWritten) - printf("totalRead: %llu, totalWritten: %llu\n", totalRead, totalWritten); + emscripten_outf("totalRead: %llu, totalWritten: %llu\n", totalRead, totalWritten); else - printf("64-bit CAS test failed! totalRead != totalWritten (%llu != %llu)\n", totalRead, totalWritten); + emscripten_outf("64-bit CAS test failed! totalRead != totalWritten (%llu != %llu)\n", totalRead, totalWritten); assert(totalRead == totalWritten); - EM_ASM(out('Main: Test successfully finished.')); + emscripten_outf("Main: Test successfully finished"); return 0; } diff --git a/test/pthread/test_pthread_atomics.cpp b/test/pthread/test_pthread_atomics.cpp index f9961853367cd..afd27b7a005c5 100644 --- a/test/pthread/test_pthread_atomics.cpp +++ b/test/pthread/test_pthread_atomics.cpp @@ -43,7 +43,7 @@ int rand_32() void *ThreadMain(void *arg) { // Do some stdio to test proxying to the main thread. - printf("pthread %p starting\n", arg); + emscripten_outf("pthread %p starting\n", arg); assert(pthread_self() != 0); assert(globalUchar == 5); @@ -52,7 +52,7 @@ void *ThreadMain(void *arg) assert(globalFloat == 5.0f); assert(globalDouble == 5.0); struct Test *t = (struct Test*)arg; - EM_ASM(out('Thread ' + $0 + ' for test ' + $1 + ': starting computation.'), t->threadId, t->op); + emscripten_outf("Thread %d for test %d: starting computation", t->threadId, t->op); for(int i = 0; i < 99999; ++i) for(int j = 0; j < N; ++j) @@ -92,7 +92,7 @@ void *ThreadMain(void *arg) break; } } - EM_ASM(out('Thread ' + $0 + ' for test ' + $1 + ': finished, exit()ing.'), t->threadId, t->op); + emscripten_outf("Thread %d for test %d: finished, exit()ing", t->threadId, t->op); pthread_exit(0); } @@ -105,7 +105,7 @@ void RunTest(int test) pthread_attr_init(&attr); pthread_attr_setstacksize(&attr, 4*1024); - printf("Main thread has thread ID %d\n", (int)pthread_self()); + emscripten_outf("Main thread has thread ID %d\n", (int)pthread_self()); assert(pthread_self() != 0); switch(test) @@ -115,7 +115,7 @@ void RunTest(int test) default: memset(sharedData, 0, sizeof(sharedData)); break; } - EM_ASM(out('Main: Starting test ' + $0), test); + emscripten_outf("Main: Starting test %d", test); for(int i = 0; i < NUM_THREADS; ++i) { @@ -136,7 +136,7 @@ void RunTest(int test) } int val = sharedData[0]; - EM_ASM(out('Main: Test ' + $0 + ' finished. Result: ' + $1), test, val); + emscripten_outf("Main: Test %d finished. Result: %d", test, val); if (test != 6) { for(int i = 1; i < N; ++i) diff --git a/test/pthread/test_pthread_cancel.cpp b/test/pthread/test_pthread_cancel.cpp index 4113049ff8116..9781136e1e594 100644 --- a/test/pthread/test_pthread_cancel.cpp +++ b/test/pthread/test_pthread_cancel.cpp @@ -10,12 +10,12 @@ #include #include #include -#include +#include _Atomic long res = 43; static void cleanup_handler(void *arg) { - EM_ASM(out('Called clean-up handler with arg ' + $0), arg); + emscripten_outf("Called clean-up handler with arg %p", arg); long a = (long)arg; res -= a; } @@ -23,7 +23,7 @@ static void cleanup_handler(void *arg) static void *thread_start(void *arg) { pthread_cleanup_push(cleanup_handler, (void*)42); - EM_ASM(out('Thread started!')); + emscripten_out("Thread started!"); for(;;) { pthread_testcancel(); @@ -38,7 +38,7 @@ int main() { int s = pthread_create(&thr, NULL, thread_start, (void*)0); assert(s == 0); - EM_ASM(out('Canceling thread..');); + emscripten_out("Canceling thread.."); s = pthread_cancel(thr); assert(s == 0); @@ -47,7 +47,7 @@ int main() int result = res; if (result == 1) { - EM_ASM_INT( { out('After canceling, shared variable = ' + $0 + '.'); }, result); + emscripten_outf("After canceling, shared variable = %d", result); return 0; } } diff --git a/test/pthread/test_pthread_condition_variable.cpp b/test/pthread/test_pthread_condition_variable.cpp index e2aec583cde66..02c72c41e14e1 100644 --- a/test/pthread/test_pthread_condition_variable.cpp +++ b/test/pthread/test_pthread_condition_variable.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #define NUM_THREADS 3 #define TCOUNT 10 @@ -17,7 +18,7 @@ int thread_ids[3] = {0,1,2}; pthread_mutex_t count_mutex; pthread_cond_t count_threshold_cv; -void *inc_count(void *t) +void *inc_count(void *t) { int i; long my_id = (long)t; @@ -26,50 +27,43 @@ void *inc_count(void *t) pthread_mutex_lock(&count_mutex); count++; - /* + /* Check the value of count and signal waiting thread when condition is - reached. Note that this occurs while mutex is locked. + reached. Note that this occurs while mutex is locked. */ if (count == COUNT_LIMIT) { pthread_cond_signal(&count_threshold_cv); - // printf("inc_count(): thread %ld, count = %d Threshold reached.\n", - // my_id, count); - EM_ASM(out('inc_count(): thread ' + $0 + ', count = ' + $1 + ', Threshold reached.'), my_id, count); - } -// printf("inc_count(): thread %ld, count = %d, unlocking mutex\n", -// my_id, count); - EM_ASM(out('inc_count(): thread ' + $0 + ', count = ' + $1 + ', unlocking mutex.'), my_id, count); + emscripten_outf("inc_count(): thread %ld, count = %d Threshold reached.\n", my_id, count); + } + emscripten_outf("inc_count(): thread %ld, count = %d, unlocking mutex\n", my_id, count); pthread_mutex_unlock(&count_mutex); /* Do some "work" so threads can alternate on mutex lock */ //sleep(1); - } + } pthread_exit(NULL); } -void *watch_count(void *t) +void *watch_count(void *t) { long my_id = (long)t; -// printf("Starting watch_count(): thread %ld\n", my_id); - EM_ASM(out('Starting watch_count(): thread ' + $0), my_id); + emscripten_outf("Starting watch_count(): thread %ld\n", my_id); /* - Lock mutex and wait for signal. Note that the pthread_cond_wait - routine will automatically and atomically unlock mutex while it waits. + Lock mutex and wait for signal. Note that the pthread_cond_wait + routine will automatically and atomically unlock mutex while it waits. Also, note that if COUNT_LIMIT is reached before this routine is run by the waiting thread, the loop will be skipped to prevent pthread_cond_wait - from never returning. + from never returning. */ pthread_mutex_lock(&count_mutex); while (count -#include +#include #include #include #include @@ -13,14 +13,14 @@ volatile int result = 0; static void *thread2_start(void *arg) { - EM_ASM(out('thread2_start!')); + emscripten_out("thread2_start!"); ++result; return NULL; } static void *thread1_start(void *arg) { - EM_ASM(out('thread1_start!')); + emscripten_out("thread1_start!"); pthread_t thr; int rtn = pthread_create(&thr, NULL, thread2_start, NULL); #ifdef SMALL_POOL diff --git a/test/pthread/test_pthread_file_io.cpp b/test/pthread/test_pthread_file_io.cpp index f0f54f9bf8924..2150350763235 100644 --- a/test/pthread/test_pthread_file_io.cpp +++ b/test/pthread/test_pthread_file_io.cpp @@ -4,7 +4,7 @@ // found in the LICENSE file. #include -#include +#include #include #include #include @@ -12,7 +12,7 @@ static void *thread1_start(void *arg) { - EM_ASM(out('thread1_start!')); + emscripten_out("thread1_start!"); FILE *handle = fopen("file1.txt", "r"); assert(handle); diff --git a/test/pthread/test_pthread_global_data_initialization.c b/test/pthread/test_pthread_global_data_initialization.c index 041573ce1d324..592bb36ed5a33 100644 --- a/test/pthread/test_pthread_global_data_initialization.c +++ b/test/pthread/test_pthread_global_data_initialization.c @@ -7,35 +7,35 @@ #include #include -#include +#include int globalData = 1; void *thread_main(void *arg) { - EM_ASM(out('hello from pthread 1: ' + $0), globalData); + emscripten_outf("hello from pthread 1: %d", globalData); assert(globalData == 10); globalData = 20; - EM_ASM(out('hello from pthread 2: ' + $0), globalData); + emscripten_outf("hello from pthread 2: %d", globalData); assert(globalData == 20); return 0; } int main() { - EM_ASM(out('hello from main 1: ' + $0), globalData); + emscripten_outf("hello from main 1: %d", globalData); assert(globalData == 1); globalData = 10; - EM_ASM(out('hello from main 2: ' + $0), globalData); + emscripten_outf("hello from main 2: %d", globalData); assert(globalData == 10); pthread_t thread; pthread_create(&thread, NULL, thread_main, NULL); pthread_join(thread, 0); - EM_ASM(out('hello from main 3: ' + $0), globalData); + emscripten_outf("hello from main 3: %d", globalData); assert(globalData == 20); return 0; } diff --git a/test/pthread/test_pthread_hardware_concurrency.cpp b/test/pthread/test_pthread_hardware_concurrency.cpp index 848efe5851330..b33aeecf41a10 100644 --- a/test/pthread/test_pthread_hardware_concurrency.cpp +++ b/test/pthread/test_pthread_hardware_concurrency.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include @@ -19,7 +19,7 @@ struct Test void *ThreadMain(void *arg) { - EM_ASM(out('Thread ' + $0 + ' finished, exit()ing.'), ((Test*)arg)->threadId); + emscripten_outf("Thread %d finished, exit()ing", ((Test*)arg)->threadId); pthread_exit(0); } @@ -28,7 +28,7 @@ void RunTest(int test) int NUM_THREADS = std::thread::hardware_concurrency(); assert(NUM_THREADS > 0); - EM_ASM(out('Main: Test ' + $0 + ' starting, with num cores: ' + $1), test, NUM_THREADS); + emscripten_outf("Main: Test %d starting, with num cores: %d", test, NUM_THREADS); struct Test t[NUM_THREADS]; pthread_t thread[NUM_THREADS]; @@ -37,10 +37,10 @@ void RunTest(int test) pthread_attr_init(&attr); pthread_attr_setstacksize(&attr, 4*1024); - printf("Main thread has thread ID %ld\n", (long)pthread_self()); + emscripten_outf("Main thread has thread ID %ld", pthread_self()); assert(pthread_self() != 0); - EM_ASM(out('Main: Starting test ' + $0), test); + emscripten_outf("Main: Starting test %d", test); for(int i = 0; i < NUM_THREADS; ++i) { @@ -59,7 +59,7 @@ void RunTest(int test) assert(status == 0); } - EM_ASM(out('Main: Test ' + $0 + ' finished.'), test); + emscripten_outf("Main: Test %d finished", test); } int main() diff --git a/test/pthread/test_pthread_join.cpp b/test/pthread/test_pthread_join.cpp index 9c6ba464b10ba..16b5f1d48db13 100644 --- a/test/pthread/test_pthread_join.cpp +++ b/test/pthread/test_pthread_join.cpp @@ -11,6 +11,7 @@ #include #include #include +#include long fib(long n) { @@ -22,9 +23,9 @@ long fib(long n) static void *thread_start(void *arg) { long n = (long)arg; - EM_ASM(out('Thread: Computing fib('+$0+')...'), n); + emscripten_outf("Thread: Computing fib(%ld)...", n); long fibn = fib(n); - EM_ASM(out('Thread: Computation done. fib('+$0+') = '+$1+'.'), n, fibn); + emscripten_outf("Thread: Computation done. fib(%ld) = %ld", n, fibn); pthread_exit((void*)fibn); } @@ -40,10 +41,10 @@ int main() assert(EM_ASM_INT(return PThread.unusedWorkers.length) == 8); // This test should be run with a prepopulated pool of size 8. int n = 20; - EM_ASM(out('Main: Spawning thread to compute fib('+$0+')...'), n); + emscripten_outf("Main: Spawning thread to compute fib(%d)...", n); int s = pthread_create(&thr, NULL, thread_start, (void*)n); assert(s == 0); - EM_ASM(out('Main: Waiting for thread to join.')); + emscripten_out("Main: Waiting for thread to join"); int result = 0; assert(EM_ASM_INT(return PThread.runningWorkers.length) == 1); @@ -51,7 +52,7 @@ int main() s = pthread_join(thr, (void**)&result); assert(s == 0); - EM_ASM(out('Main: Thread joined with result: '+$0+'.'), result); + emscripten_outf("Main: Thread joined with result: %d", result); assert(EM_ASM_INT(return PThread.runningWorkers.length) == 0); assert(EM_ASM_INT(return PThread.unusedWorkers.length) == 8); diff --git a/test/pthread/test_pthread_malloc.cpp b/test/pthread/test_pthread_malloc.cpp index 14510bdfd83e8..6da2b5712c105 100644 --- a/test/pthread/test_pthread_malloc.cpp +++ b/test/pthread/test_pthread_malloc.cpp @@ -4,7 +4,7 @@ // found in the LICENSE file. #include -#include +#include #include #include #include @@ -26,14 +26,14 @@ static void *thread_start(void *arg) long k = *mem[i]; if (k != n+i) { - EM_ASM(console.error('Memory corrupted! mem[i]: ' + $0 + ', i: ' + $1 + ', n: ' + $2), k, i, n); + emscripten_errf("Memory corrupted! mem[i]: %ld, i: %ld, n: %ld", k, i, n); pthread_exit((void*)1); } assert(*mem[i] == n+i); free(mem[i]); } - EM_ASM(console.log('Worker with task number ' + $0 + ' finished.'), n); + emscripten_outf("Worker with task number %ld finished", n); pthread_exit(0); } diff --git a/test/pthread/test_pthread_mutex.cpp b/test/pthread/test_pthread_mutex.cpp index 60183449fcd57..eec94e00ff6d3 100644 --- a/test/pthread/test_pthread_mutex.cpp +++ b/test/pthread/test_pthread_mutex.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #define NUM_THREADS 8 @@ -82,9 +83,9 @@ EM_BOOL WaitToJoin(double time, void *userData) if (!threadsRunning) { if (counter == numThreadsToCreateTotal) - EM_ASM(console.log('All threads finished. Counter = ' + $0 + ' as expected.'), counter); + emscripten_outf("All threads finished. Counter = %d as expected", counter); else - EM_ASM(console.error('All threads finished, but counter = ' + $0 + ' != ' + $1 + '!'), counter, numThreadsToCreateTotal); + emscripten_errf("All threads finished, but counter = %d != %d!", counter, numThreadsToCreateTotal); assert(counter == 50); emscripten_force_exit(0); return EM_FALSE; diff --git a/test/pthread/test_pthread_preallocates_workers.cpp b/test/pthread/test_pthread_preallocates_workers.cpp index b4478c500878a..57f216d827e9b 100644 --- a/test/pthread/test_pthread_preallocates_workers.cpp +++ b/test/pthread/test_pthread_preallocates_workers.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include pthread_t threads[5]; @@ -28,7 +29,7 @@ static void *thread_start(void *arg) } void CreateThread(int idx) { - EM_ASM(out('Main: Spawning thread '+$0+'...'), idx); + emscripten_outf("Main: Spawning thread %d...", idx); int rc = pthread_create(&threads[idx], NULL, thread_start, (void*)idx); assert(rc == 0); } diff --git a/test/pthread/test_pthread_sbrk.cpp b/test/pthread/test_pthread_sbrk.cpp index 67cd26180df9f..612d2138dbbcc 100644 --- a/test/pthread/test_pthread_sbrk.cpp +++ b/test/pthread/test_pthread_sbrk.cpp @@ -72,7 +72,7 @@ static void *thread_start(void *arg) { ++return_code; // Failed! (but run to completion so that the barriers will all properly proceed without hanging) if (!reported_once) { - EM_ASM(console.error('Memory corrupted! mem[i]: ' + $0 + ' != ' + $1 + ', i: ' + $2 + ', j: ' + $3), allocated_buffers[i][j], id, i, j); + EM_ASM(err('Memory corrupted! mem[i]: ' + $0 + ' != ' + $1 + ', i: ' + $2 + ', j: ' + $3), allocated_buffers[i][j], id, i, j); reported_once = 1; // Avoid print flood that makes debugging hard. } } diff --git a/test/test_browser.py b/test/test_browser.py index e55b3cd53ea76..b737edd7785c2 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -3823,7 +3823,7 @@ def test_pthread_in_pthread_pool_size_strict(self): # Test that the emscripten_ atomics api functions work. @parameterized({ - 'normal': ([],), + '': ([],), 'closure': (['--closure=1'],), }) @requires_threads diff --git a/test/test_closure_warning.c b/test/test_closure_warning.c index 63b90efc4092f..b912f28ef0571 100644 --- a/test/test_closure_warning.c +++ b/test/test_closure_warning.c @@ -2,5 +2,5 @@ int main() { - EM_ASM(foo = 2; var foo; console.log(foo)); + EM_ASM(foo = 2; var foo; out(foo)); } diff --git a/test/test_core.py b/test/test_core.py index 3290519b04356..630105bb5e3dd 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -1596,7 +1596,7 @@ class myexception : public exception { // https://github.com/emscripten-core/emscripten/issues/17115 incrementExceptionRefcount(p); #endif - console.log(getExceptionMessage(p).toString()); + out(getExceptionMessage(p).toString()); decrementExceptionRefcount(p); } } @@ -7662,7 +7662,7 @@ def test_embind_no_rtti(self): #include EM_JS(void, calltest, (), { - console.log("dotest returned: " + Module.dotest()); + out("dotest returned: " + Module.dotest()); }); int main(int argc, char** argv){ @@ -7694,7 +7694,7 @@ def test_embind_no_rtti_followed_by_rtti(self): #include EM_JS(void, calltest, (), { - console.log("dotest returned: " + Module.dotest()); + out("dotest returned: " + Module.dotest()); }); int main(int argc, char** argv){ @@ -8254,9 +8254,9 @@ def test_async_ccall_promise(self, exit_runtime, asyncify): runtimeKeepalivePush(); ccall('stringf', 'string', ['string'], ['first\n'], { async: true }) .then(function(val) { - console.log(val); + out(val); ccall('floatf', 'number', null, null, { async: true }).then(function(arg) { - console.log(arg); + out(arg); runtimeKeepalivePop(); maybeExit(); }); @@ -8609,9 +8609,9 @@ def test_fs_dict(self): out(typeof FS.filesystems['IDBFS']); out(typeof FS.filesystems['NODEFS']); // Globals - console.log(typeof MEMFS); - console.log(typeof IDBFS); - console.log(typeof NODEFS); + out(typeof MEMFS); + out(typeof IDBFS); + out(typeof NODEFS); }; ''') self.emcc_args += ['--pre-js', 'pre.js'] @@ -8627,14 +8627,14 @@ def test_fs_dict_none(self): out(typeof FS.filesystems['IDBFS']); out(typeof FS.filesystems['NODEFS']); // Globals - console.log(typeof MEMFS); - console.log(IDBFS); - console.log(NODEFS); + out(typeof MEMFS); + out(IDBFS); + out(NODEFS); FS.mkdir('/working1'); try { FS.mount(IDBFS, {}, '/working1'); } catch (e) { - console.log('|' + e + '|'); + out('|' + e + '|'); } }; ''') @@ -9489,14 +9489,14 @@ def test_Module_dynamicLibraries(self, args): 'result is 42') # Tests the emscripten_get_exported_function() API. - def test_emscripten_get_exported_function(self): + def test_get_exported_function(self): self.set_setting('ALLOW_TABLE_GROWTH') self.emcc_args += ['-lexports.js'] self.do_core_test('test_get_exported_function.cpp') # Tests the emscripten_get_exported_function() API. @no_asan('TODO: ASan support in minimal runtime') - def test_minimal_runtime_emscripten_get_exported_function(self): + def test_minimal_runtime_get_exported_function(self): self.set_setting('ALLOW_TABLE_GROWTH') self.set_setting('MINIMAL_RUNTIME') self.emcc_args += ['--pre-js', test_file('minimal_runtime_exit_handling.js')] diff --git a/test/test_other.py b/test/test_other.py index 5d6677758783c..98207968214ef 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -1374,7 +1374,7 @@ def test_export_keepalive(self): create_file('pre.js', ''' Module.onRuntimeInitialized = () => { - console.log(Module._libf1 ? Module._libf1() : 'unexported'); + out(Module._libf1 ? Module._libf1() : 'unexported'); }; ''') @@ -2421,7 +2421,7 @@ def test_prepost(self): # Calling main later should still work, filesystem etc. must be set up. print('call main later') src = read_file('a.out.js') - src += '\nconsole.log("callMain -> " + Module.callMain());\n' + src += '\nout("callMain -> " + Module.callMain());\n' create_file('a.out.js', src) self.assertContained('hello from main\ncallMain -> 0\n', self.run_js('a.out.js')) @@ -3372,7 +3372,7 @@ def test_exported_runtime_methods_from_js_library(self): create_file('pre.js', ''' Module.onRuntimeInitialized = () => { Module.setErrNo(88); - console.log('done'); + out('done'); }; ''') self.do_runf(test_file('hello_world.c'), 'done', emcc_args=['--pre-js=pre.js', '-sEXPORTED_RUNTIME_METHODS=setErrNo']) @@ -9073,8 +9073,9 @@ def test_main_module_without_main(self): create_file('pre.js', 'Module.onRuntimeInitialized = () => Module._foo();') create_file('src.c', r''' #include +#include EMSCRIPTEN_KEEPALIVE void foo() { - EM_ASM({ console.log("bar") }); + emscripten_out("bar"); } ''') self.do_runf('src.c', 'bar', emcc_args=['--pre-js', 'pre.js', '-sMAIN_MODULE=2']) @@ -10684,7 +10685,7 @@ def test(args): changed) def test_INCOMING_MODULE_JS_API_missing(self): - create_file('pre.js', 'Module.onRuntimeInitialized = () => console.log("initialized");') + create_file('pre.js', 'Module.onRuntimeInitialized = () => out("initialized");') self.emcc_args += ['--pre-js=pre.js'] self.do_runf(test_file('hello_world.c'), 'initialized') @@ -10863,11 +10864,11 @@ def test_assertions_on_outgoing_module_api_changes(self): #include int main() { EM_ASM({ - console.log(); + out(); function check(name) { try { Module[name]; - console.log("success: " + name); + out("success: " + name); } catch(e) { } } @@ -10952,7 +10953,7 @@ def test_em_asm_duplicate_strings(self): create_file('foo.c', ''' #include void foo() { - EM_ASM({ console.log('Hello, world!'); }); + EM_ASM({ out('Hello, world!'); }); } ''') create_file('main.c', ''' @@ -10962,7 +10963,7 @@ def test_em_asm_duplicate_strings(self): int main() { foo(); - EM_ASM({ console.log('Hello, world!'); }); + EM_ASM({ out('Hello, world!'); }); return 0; } ''') @@ -10975,7 +10976,7 @@ def test_em_asm_c89(self): create_file('src.c', ''' #include int main(void) { - EM_ASM({ console.log('hello'); }); + EM_ASM({ out('hello'); }); }\n''') self.run_process([EMCC, '-c', 'src.c', '-pedantic', '-Wall', '-Werror', @@ -10985,7 +10986,7 @@ def test_em_asm_strict_c(self): create_file('src.c', ''' #include int main() { - EM_ASM({ console.log('Hello, world!'); }); + EM_ASM({ out('Hello, world!'); }); } ''') err = self.expect_fail([EMCC, '-std=c11', 'src.c']) @@ -11003,7 +11004,7 @@ def test_setjmp_em_asm(self): jmp_buf buf; setjmp(buf); EM_ASM({ - console.log("hello world"); + out("hello world"); }); } ''') @@ -11476,7 +11477,7 @@ def test_emcc_size_parsing(self): def test_native_call_before_init(self): self.set_setting('ASSERTIONS') self.set_setting('EXPORTED_FUNCTIONS', ['_foo']) - self.add_pre_run('console.log("calling foo"); Module["_foo"]();') + self.add_pre_run('out("calling foo"); Module["_foo"]();') create_file('foo.c', '#include \nint foo() { puts("foo called"); return 3; }') self.build('foo.c') out = self.run_js('foo.js', assert_returncode=NON_ZERO) @@ -11485,7 +11486,7 @@ def test_native_call_before_init(self): def test_native_call_after_exit(self): self.set_setting('ASSERTIONS') self.set_setting('EXIT_RUNTIME') - self.add_on_exit('console.log("calling main again"); Module["_main"]();') + self.add_on_exit('out("calling main again"); Module["_main"]();') create_file('foo.c', '#include \nint main() { puts("foo called"); return 0; }') self.build('foo.c') out = self.run_js('foo.js', assert_returncode=NON_ZERO) @@ -11590,12 +11591,12 @@ def test_missing_malloc_export(self): try { _malloc(1); } catch(e) { - console.log('exception:', e); + out('exception:', e); } try { _free(); } catch(e) { - console.log('exception:', e); + out('exception:', e); } }); } diff --git a/test/test_webgl2_runtime_no_context.cpp b/test/test_webgl2_runtime_no_context.cpp index 25c822ac63f70..63804bd3563d9 100644 --- a/test/test_webgl2_runtime_no_context.cpp +++ b/test/test_webgl2_runtime_no_context.cpp @@ -20,9 +20,9 @@ int main() EM_ASM({ var original = Module.canvas.getContext; Module.canvas.getContext = function(name, attrs) { - console.log('ask', name, attrs); + out('ask', name, attrs); if (name === "webgl2") return null; - console.log('provide!'); + out('provide!'); return original.call(Module.canvas, name, attrs); }; }); diff --git a/test/test_webgl_context_attributes_common.c b/test/test_webgl_context_attributes_common.c index efcc8c69f3e7b..dfa5d24c4021b 100644 --- a/test/test_webgl_context_attributes_common.c +++ b/test/test_webgl_context_attributes_common.c @@ -12,6 +12,7 @@ #include #include +#include #define BUFFER_OFFSET(i) ((char *)NULL + (i)) @@ -289,18 +290,18 @@ extern int webglAlphaSupported(void); static void checkContextAttributesSupport() { if (!webglAntialiasSupported()) { resultAA = true; - EM_ASM(err('warning: no antialiasing\n')); + emscripten_err("warning: no antialiasing"); } if (!webglDepthSupported()) { resultDepth = true; - EM_ASM(err('warning: no depth\n')); + emscripten_err("warning: no depth"); } if (!webglStencilSupported()) { resultStencil = true; - EM_ASM(err('warning: no stencil\n')); + emscripten_err("warning: no stencil"); } if (!webglAlphaSupported()) { resultAlpha = true; - EM_ASM(err('warning: no alpha\n')); + emscripten_err("warning: no alpha"); } } diff --git a/test/wasm_worker/c11__Thread_local.c b/test/wasm_worker/c11__Thread_local.c index 65c8210ba6dc0..52a9d8c6c77ac 100644 --- a/test/wasm_worker/c11__Thread_local.c +++ b/test/wasm_worker/c11__Thread_local.c @@ -8,7 +8,7 @@ _Thread_local int __attribute__((aligned(64))) tls = 1; void main_thread_func() { assert(!emscripten_current_thread_is_wasm_worker()); - EM_ASM(console.log($0), tls); + EM_ASM(out($0), tls); #ifdef REPORT_RESULT REPORT_RESULT(tls); #endif @@ -29,7 +29,7 @@ char stack[1024]; int main() { - EM_ASM(console.log($0), tls); + EM_ASM(out($0), tls); assert(((intptr_t)&tls % 64) == 0); assert(!emscripten_current_thread_is_wasm_worker()); tls = 42; diff --git a/test/wasm_worker/cpp11_thread_local.cpp b/test/wasm_worker/cpp11_thread_local.cpp index befd9ef43e40b..c214afe4e0bca 100644 --- a/test/wasm_worker/cpp11_thread_local.cpp +++ b/test/wasm_worker/cpp11_thread_local.cpp @@ -7,7 +7,7 @@ thread_local int tls = 1; void main_thread_func() { assert(!emscripten_current_thread_is_wasm_worker()); - EM_ASM(console.log($0), tls); + EM_ASM(out($0), tls); #ifdef REPORT_RESULT REPORT_RESULT(tls); #endif @@ -27,7 +27,7 @@ char stack[1024]; int main() { - EM_ASM(console.log($0), tls); + EM_ASM(out($0), tls); assert(!emscripten_current_thread_is_wasm_worker()); tls = 42; emscripten_wasm_worker_t worker = emscripten_create_wasm_worker(stack, sizeof(stack)); diff --git a/test/wasm_worker/gcc___Thread.c b/test/wasm_worker/gcc___Thread.c index 17d73c246d754..84c93ffd92ae8 100644 --- a/test/wasm_worker/gcc___Thread.c +++ b/test/wasm_worker/gcc___Thread.c @@ -8,7 +8,7 @@ __thread int tls = 1; void main_thread_func() { assert(!emscripten_current_thread_is_wasm_worker()); - EM_ASM(console.log($0), tls); + EM_ASM(out($0), tls); #ifdef REPORT_RESULT REPORT_RESULT(tls); #endif @@ -28,7 +28,7 @@ char stack[1024]; int main() { - EM_ASM(console.log($0), tls); + EM_ASM(out($0), tls); assert(!emscripten_current_thread_is_wasm_worker()); tls = 42; emscripten_wasm_worker_t worker = emscripten_create_wasm_worker(stack, sizeof(stack)); diff --git a/test/wasm_worker/lock_waitinf_acquire.c b/test/wasm_worker/lock_waitinf_acquire.c index 91c7c08c9770f..ebc5dd6816ded 100644 --- a/test/wasm_worker/lock_waitinf_acquire.c +++ b/test/wasm_worker/lock_waitinf_acquire.c @@ -17,7 +17,7 @@ volatile int numWorkersAlive = 0; void test_ended() { - EM_ASM(console.log(`Worker ${$0} last thread to finish. Reporting test end with sharedState0=${$1}, sharedState1=${$2}`), emscripten_wasm_worker_self_id(), sharedState0, sharedState1); + EM_ASM(out(`Worker ${$0} last thread to finish. Reporting test end with sharedState0=${$1}, sharedState1=${$2}`), emscripten_wasm_worker_self_id(), sharedState0, sharedState1); assert(sharedState0 == sharedState1 + 1 || sharedState1 == sharedState0 + 1); #ifdef REPORT_RESULT REPORT_RESULT(sharedState0); @@ -26,7 +26,7 @@ void test_ended() void worker_main() { - EM_ASM(console.log(`Worker ${$0} running...`), emscripten_wasm_worker_self_id()); + EM_ASM(out(`Worker ${$0} running...`), emscripten_wasm_worker_self_id()); // Create contention on the lock from each thread, and stress the shared state // in a racy way that would show a breakage if the lock is not watertight. for(int i = 0; i < 1000; ++i) @@ -50,7 +50,7 @@ void worker_main() emscripten_lock_release(&lock); } - EM_ASM(console.log(`Worker ${$0} finished.`), emscripten_wasm_worker_self_id()); + EM_ASM(out(`Worker ${$0} finished.`), emscripten_wasm_worker_self_id()); // Are we the last thread to finish? If so, test has ended. uint32_t v = emscripten_atomic_sub_u32((void*)&numWorkersAlive, 1); diff --git a/test/wasm_worker/thread_stack.c b/test/wasm_worker/thread_stack.c index 76b9cea12ff5f..b6c7ba913ddb3 100644 --- a/test/wasm_worker/thread_stack.c +++ b/test/wasm_worker/thread_stack.c @@ -13,16 +13,16 @@ volatile int threadsOk = 0; void test_stack(int i) { - EM_ASM(console.log(`In thread ${$0}, stack low addr=0x${$1.toString(16)}, emscripten_stack_get_base()=0x${$2.toString(16)}, emscripten_stack_get_end()=0x${$3.toString(16)}, THREAD_STACK_SIZE=0x${$4.toString(16)}`), + EM_ASM(out(`In thread ${$0}, stack low addr=0x${$1.toString(16)}, emscripten_stack_get_base()=0x${$2.toString(16)}, emscripten_stack_get_end()=0x${$3.toString(16)}, THREAD_STACK_SIZE=0x${$4.toString(16)}`), i, thread_stack[i], emscripten_stack_get_base(), emscripten_stack_get_end(), THREAD_STACK_SIZE); assert(emscripten_stack_get_base() == (uintptr_t)thread_stack[i] + THREAD_STACK_SIZE); assert(emscripten_stack_get_end() == (uintptr_t)thread_stack[i]); int ok = __sync_fetch_and_add(&threadsOk, 1); - EM_ASM(console.log($0), ok); + EM_ASM(out($0), ok); if (ok == 1) { - EM_ASM(console.log(`Test finished!`)); + EM_ASM(out(`Test finished!`)); #ifdef REPORT_RESULT REPORT_RESULT(0); #endif @@ -31,13 +31,13 @@ void test_stack(int i) int main() { - EM_ASM(console.log(`Main thread stack base=0x${$0.toString(16)}, end=0x${$1.toString(16)}`), emscripten_stack_get_base(), emscripten_stack_get_end()); + EM_ASM(out(`Main thread stack base=0x${$0.toString(16)}, end=0x${$1.toString(16)}`), emscripten_stack_get_base(), emscripten_stack_get_end()); for(int i = 0; i < NUM_THREADS; ++i) { thread_stack[i] = memalign(16, THREAD_STACK_SIZE); emscripten_wasm_worker_t worker = emscripten_create_wasm_worker(thread_stack[i], THREAD_STACK_SIZE); - EM_ASM(console.log(`Created thread ${$0} with stack ptr=0x${$1.toString(16)}, size=0x${$2.toString(16)}`), i, thread_stack[i], THREAD_STACK_SIZE); + EM_ASM(out(`Created thread ${$0} with stack ptr=0x${$1.toString(16)}, size=0x${$2.toString(16)}`), i, thread_stack[i], THREAD_STACK_SIZE); emscripten_wasm_worker_post_function_vi(worker, test_stack, i); } } diff --git a/test/wasm_worker/wasm_worker_and_pthread.c b/test/wasm_worker/wasm_worker_and_pthread.c index b6dedb0f9e3d7..1ea129f5df486 100644 --- a/test/wasm_worker/wasm_worker_and_pthread.c +++ b/test/wasm_worker/wasm_worker_and_pthread.c @@ -2,6 +2,7 @@ #include #include #include +#include #include volatile int pthread_ran = 0; @@ -16,7 +17,7 @@ EM_JS(int, am_i_wasm_worker, (), { void *thread_main(void *arg) { - EM_ASM(out('hello from pthread!')); + emscripten_out("hello from pthread!"); assert(am_i_pthread()); assert(!am_i_wasm_worker()); assert(!emscripten_current_thread_is_wasm_worker()); @@ -27,7 +28,7 @@ void *thread_main(void *arg) void worker_main() { - EM_ASM(out('hello from wasm worker!')); + emscripten_out("hello from wasm worker!"); assert(!am_i_pthread()); assert(am_i_wasm_worker()); assert(emscripten_current_thread_is_wasm_worker()); diff --git a/test/wasmfs/wasmfs_opfs_errors.c b/test/wasmfs/wasmfs_opfs_errors.c index 65339b17af645..019cd25317431 100644 --- a/test/wasmfs/wasmfs_opfs_errors.c +++ b/test/wasmfs/wasmfs_opfs_errors.c @@ -82,7 +82,7 @@ EMSCRIPTEN_KEEPALIVE int try_oob_read(void) { int fd = open(file, O_RDWR); if (fd < 0) { - EM_ASM({ console.log('fd', $0); }, fd); + emscripten_outf("fd %d", fd); return 2; } char buf; @@ -95,7 +95,7 @@ int try_oob_read(void) { close(fd); return 0; } - EM_ASM({ console.log('errno', $0); }, errno); + emscripten_outf("errno %d", errno); close(fd); return 2; } @@ -143,7 +143,7 @@ int try_rename_dir(void) { EMSCRIPTEN_KEEPALIVE void report_result(int result) { - EM_ASM({ console.log(new Error().stack); }); + EM_ASM({ out(new Error().stack); }); #ifdef REPORT_RESULT REPORT_RESULT(result); #else From 308fcdb8e6e1b160cf15e2c56ae8efd4f5f210b0 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 3 Aug 2023 11:25:55 -0700 Subject: [PATCH 0616/1523] Fix other.test_argument_match with new clang error message. NFC (#19969) As part of this I pushed support for the `regex` argument down into the lower level `assertContained` test method. --- test/common.py | 26 ++++++++++++++------------ test/test_other.py | 4 +++- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/test/common.py b/test/common.py index 9015a190f5bfb..c37daad31d7a5 100644 --- a/test/common.py +++ b/test/common.py @@ -1169,12 +1169,21 @@ def assertFileContents(self, filename, contents): self.assertTextDataIdentical(expected_content, contents, message, filename, filename + '.new') - def assertContained(self, values, string, additional_info=''): - if type(values) not in [list, tuple]: - values = [values] + def assertContained(self, values, string, additional_info='', regex=False): if callable(string): string = string() + if regex: + if type(values) == str: + self.assertTrue(re.search(values, string), 'Expected regex "%s" to match on:\n%s' % (values, string)) + else: + match_any = any(re.search(o, string) for o in values) + self.assertTrue(match_any, 'Expected at least one of "%s" to match on:\n%s' % (values, string)) + return + + if type(values) not in [list, tuple]: + values = [values] + if not any(v in string for v in values): diff = difflib.unified_diff(values[0].split('\n'), string.split('\n'), fromfile='expected', tofile='actual') diff = ''.join(a.rstrip() + '\n' for a in diff) @@ -1507,16 +1516,9 @@ def _build_and_run(self, filename, expected_output, args=None, output_nicerizer= self.assertIdentical(expected_output, js_output) elif assert_all or len(expected_output) == 1: for o in expected_output: - if regex: - self.assertTrue(re.search(o, js_output), 'Expected regex "%s" to match on:\n%s' % (o, js_output)) - else: - self.assertContained(o, js_output) + self.assertContained(o, js_output, regex=regex) else: - if regex: - match_any = any(re.search(o, js_output) for o in expected_output) - self.assertTrue(match_any, 'Expected at least one of "%s" to match on:\n%s' % (expected_output, js_output)) - else: - self.assertContained(expected_output, js_output) + self.assertContained(expected_output, js_output, regex=regex) if assert_returncode == 0 and check_for_error: self.assertNotContained('ERROR', js_output) except Exception: diff --git a/test/test_other.py b/test/test_other.py index 98207968214ef..6034354de1865 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -11372,7 +11372,9 @@ def test_argument_match(self): # was matched self.run_process([EMCC, test_file('hello_world.c'), '--minify=0']) err = self.expect_fail([EMCC, test_file('hello_world.c'), '--minifyXX']) - self.assertContained("error: unsupported option '--minifyXX'", err) + # The clang error message changed from 'unsupported' to 'unknown' so + # for now handle both options. + self.assertContained("clang: error: (unsupported option|unknown argument:) '--minifyXX'", err, regex=True) def test_argument_missing(self): err = self.expect_fail([EMCC, test_file('hello_world.c'), '--minify']) From 00f4e0bb6a09f64c5a4c01e530f710b12a3a468d Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 3 Aug 2023 11:37:50 -0700 Subject: [PATCH 0617/1523] Ensure MAXIMUM_MEMORY is set correctly (#19960) This avoids issues where MAXIMUM_MEMORY is inconsistent and simplifies check that wants to check for max memory address. Without this change the following check in preable.js was producing the wrong result when INITIAL_MEMORY was set to >4gb but MAXIMUM_MEMORY was not set: ``` #if MEMORY64 && MAXIMUM_MEMORY > FOUR_GB ``` When the user specifies INITIAL_MEMORY that should set a lower bound for MAXIMUM_MEMORY. When memory growth is disallowed MAXIMUM_MEMORY should match INITIAL_MEMORY. --- emcc.py | 36 ++++++++++++++++++++++-------------- test/test_core.py | 4 +--- tools/building.py | 5 +---- 3 files changed, 24 insertions(+), 21 deletions(-) diff --git a/emcc.py b/emcc.py index f362afb9c4cd7..1b485fe99edc0 100755 --- a/emcc.py +++ b/emcc.py @@ -1778,6 +1778,22 @@ def include_and_export(name): settings.EXPORTED_RUNTIME_METHODS += ['ExitStatus'] +def set_max_memory(): + # When memory growth is disallowed set MAXIMUM_MEMORY equal to INITIAL_MEMORY + if not settings.ALLOW_MEMORY_GROWTH: + if 'MAXIMUM_MEMORY' in user_settings: + diagnostics.warning('unused-command-line-argument', 'MAXIMUM_MEMORY is only meaningful with ALLOW_MEMORY_GROWTH') + settings.MAXIMUM_MEMORY = settings.INITIAL_MEMORY + + # INITIAL_MEMORY sets a lower bound for MAXIMUM_MEMORY + if 'MAXIMUM_MEMORY' not in user_settings: + if settings.INITIAL_MEMORY > settings.MAXIMUM_MEMORY: + settings.MAXIMUM_MEMORY = settings.INITIAL_MEMORY + + if settings.MAXIMUM_MEMORY < settings.INITIAL_MEMORY: + exit_with_error('MAXIMUM_MEMORY cannot be less than INITIAL_MEMORY') + + @ToolchainProfiler.profile_block('linker_setup') def phase_linker_setup(options, state, newargs): autoconf = os.environ.get('EMMAKEN_JUST_CONFIGURE') or 'conftest.c' in state.orig_args or 'conftest.cpp' in state.orig_args @@ -2522,12 +2538,6 @@ def check_memory_setting(setting): if settings.MEMORY_GROWTH_LINEAR_STEP != -1: check_memory_setting('MEMORY_GROWTH_LINEAR_STEP') - if settings.ALLOW_MEMORY_GROWTH and settings.MAXIMUM_MEMORY < settings.INITIAL_MEMORY: - exit_with_error('MAXIMUM_MEMORY must be larger then INITIAL_MEMORY') - - if 'MAXIMUM_MEMORY' in user_settings and not settings.ALLOW_MEMORY_GROWTH: - diagnostics.warning('unused-command-line-argument', 'MAXIMUM_MEMORY is only meaningful with ALLOW_MEMORY_GROWTH') - if settings.EXPORT_ES6: if not settings.MODULARIZE: # EXPORT_ES6 requires output to be a module @@ -2774,6 +2784,12 @@ def check_memory_setting(setting): if sanitize and settings.GENERATE_SOURCE_MAP: settings.LOAD_SOURCE_MAP = 1 + set_max_memory() + + # check if we can address the 2GB mark and higher. + if not settings.MEMORY64 and settings.MAXIMUM_MEMORY > 2 * 1024 * 1024 * 1024: + settings.CAN_ADDRESS_2GB = 1 + if settings.MINIMAL_RUNTIME: if settings.EXIT_RUNTIME: settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['proc_exit', '$callRuntimeCallbacks'] @@ -2874,14 +2890,6 @@ def get_full_import_name(name): 'emscripten_stack_get_base', 'emscripten_stack_get_end'] - # check if we can address the 2GB mark and higher: either if we start at - # 2GB, or if we allow growth to either any amount or to 2GB or more. - if not settings.MEMORY64 and (settings.INITIAL_MEMORY > 2 * 1024 * 1024 * 1024 or - (settings.ALLOW_MEMORY_GROWTH and - (settings.MAXIMUM_MEMORY < 0 or - settings.MAXIMUM_MEMORY > 2 * 1024 * 1024 * 1024))): - settings.CAN_ADDRESS_2GB = 1 - settings.EMSCRIPTEN_VERSION = shared.EMSCRIPTEN_VERSION settings.SOURCE_MAP_BASE = options.source_map_base or '' diff --git a/test/test_core.py b/test/test_core.py index 630105bb5e3dd..6f6a7892d34db 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -9781,9 +9781,7 @@ def setUp(self): # Run the wasm64 tests with all memory offsets > 4gb. Be careful running this test # suite with any kind of parallelism. wasm64_4gb = make_run('wasm64_4gb', emcc_args=['-Wno-experimental', '--profiling-funcs'], - settings={'MEMORY64': 1, 'INITIAL_MEMORY': '4200mb', - 'MAXIMUM_MEMORY': '4200mb', # TODO(sbc): should not be needed - 'GLOBAL_BASE': '4gb'}, + settings={'MEMORY64': 1, 'INITIAL_MEMORY': '4200mb', 'GLOBAL_BASE': '4gb'}, require_wasm64=True) # MEMORY64=2, or "lowered" wasm64l = make_run('wasm64l', emcc_args=['-O1', '-Wno-experimental', '--profiling-funcs'], diff --git a/tools/building.py b/tools/building.py index 56d5842c75f45..f5f23dd4c3b29 100644 --- a/tools/building.py +++ b/tools/building.py @@ -213,6 +213,7 @@ def lld_flags_for_executable(external_symbols): cmd += [ '-z', 'stack-size=%s' % settings.STACK_SIZE, '--initial-memory=%d' % settings.INITIAL_MEMORY, + '--max-memory=%d' % settings.MAXIMUM_MEMORY, ] if settings.STANDALONE_WASM: @@ -228,10 +229,6 @@ def lld_flags_for_executable(external_symbols): # `__main_argv_argc`, but we should address that by using a single `_start` # function like we do in STANDALONE_WASM mode. cmd += ['--no-entry'] - if not settings.ALLOW_MEMORY_GROWTH: - cmd.append('--max-memory=%d' % settings.INITIAL_MEMORY) - elif settings.MAXIMUM_MEMORY != -1: - cmd.append('--max-memory=%d' % settings.MAXIMUM_MEMORY) if settings.STACK_FIRST: cmd.append('--stack-first') From 9ad683b973647a2dc8e77bd77029cbd0264e23b8 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 3 Aug 2023 12:37:50 -0700 Subject: [PATCH 0618/1523] Fix for async cancellation during __timedwait. NFC (#19963) Emscripten doesn't have real async cancellation but we don't want __timedwait_cp to return the thread has been canceled while while its running. This fixes a problem in the test_pthread_setcanceltype_1_1 test which was not being correctly reported but shows up as a real problem with the switch to the new proxying system in #19947. Specifically, Without this change, a thread this async canceled during pthread_mutex_lock call will return ECANCELED, but instead it should never return and thread should be canceled, which is the behaviour after this change. --- system/lib/libc/musl/src/thread/__timedwait.c | 13 +++- .../lib/libc/musl/src/thread/pthread_cancel.c | 11 +++ test/pthread/test_pthread_cancel.out | 4 + test/pthread/test_pthread_cancel_async.c | 73 +++++++++++++++++++ test/pthread/test_pthread_cancel_async.out | 6 ++ test/test_core.py | 8 ++ 6 files changed, 111 insertions(+), 4 deletions(-) create mode 100644 test/pthread/test_pthread_cancel.out create mode 100644 test/pthread/test_pthread_cancel_async.c create mode 100644 test/pthread/test_pthread_cancel_async.out diff --git a/system/lib/libc/musl/src/thread/__timedwait.c b/system/lib/libc/musl/src/thread/__timedwait.c index 6c8284f6153e0..eb1e498b879ca 100644 --- a/system/lib/libc/musl/src/thread/__timedwait.c +++ b/system/lib/libc/musl/src/thread/__timedwait.c @@ -69,13 +69,18 @@ int __timedwait_cp(volatile int *addr, int val, // which may be either done by the user of __timedwait() function. if (is_runtime_thread || pthread_self()->canceldisable != PTHREAD_CANCEL_DISABLE || - pthread_self()->cancelasync == PTHREAD_CANCEL_ASYNCHRONOUS) { + pthread_self()->cancelasync) { double sleepUntilTime = emscripten_get_now() + msecsToSleep; do { if (pthread_self()->cancel) { - // Emscripten-specific return value: The wait was canceled by user calling - // pthread_cancel() for this thread, and the caller needs to cooperatively - // cancel execution. + // The thread was canceled by pthread_cancel(). + // In the case of cancelasync or PTHREAD_CANCEL_ENABLE we can just call + // __pthread_testcancel(), which won't return at all. + __pthread_testcancel(); + // If __pthread_testcancel does return here it means that canceldisable + // must be set to PTHREAD_CANCEL_MASKED. This appear to mean "return + // ECANCELLED to the caller". See pthread_cond_timedwait.c for the only + // use of this that I could find. return ECANCELED; } msecsToSleep = sleepUntilTime - emscripten_get_now(); diff --git a/system/lib/libc/musl/src/thread/pthread_cancel.c b/system/lib/libc/musl/src/thread/pthread_cancel.c index ef9ca61dbb4d8..91c779ed6e657 100644 --- a/system/lib/libc/musl/src/thread/pthread_cancel.c +++ b/system/lib/libc/musl/src/thread/pthread_cancel.c @@ -8,7 +8,13 @@ hidden long __cancel(), __syscall_cp_asm(), __syscall_cp_c(); long __cancel() { pthread_t self = __pthread_self(); +#ifdef __EMSCRIPTEN__ + // Emscripten doesn't have actual async cancelation so we make a best effort + // by cancelling cooperatively when self->cancelasync is set. if (self->canceldisable == PTHREAD_CANCEL_ENABLE || self->cancelasync) +#else + if (self->canceldisable == PTHREAD_CANCEL_ENABLE) +#endif pthread_exit(PTHREAD_CANCELED); self->canceldisable = PTHREAD_CANCEL_DISABLE; return -ECANCELED; @@ -77,7 +83,12 @@ static void cancel_handler(int sig, siginfo_t *si, void *ctx) void __testcancel() { pthread_t self = __pthread_self(); +#ifdef __EMSCRIPTEN__ + // See comment above about cancelasync under emscripten. + if (self->cancel && (self->cancelasync || !self->canceldisable)) +#else if (self->cancel && !self->canceldisable) +#endif __cancel(); } diff --git a/test/pthread/test_pthread_cancel.out b/test/pthread/test_pthread_cancel.out new file mode 100644 index 0000000000000..11b060905f0aa --- /dev/null +++ b/test/pthread/test_pthread_cancel.out @@ -0,0 +1,4 @@ +Canceling thread.. +Thread started! +Called clean-up handler with arg 42 +After canceling, shared variable = 1. diff --git a/test/pthread/test_pthread_cancel_async.c b/test/pthread/test_pthread_cancel_async.c new file mode 100644 index 0000000000000..93c8315a15c0c --- /dev/null +++ b/test/pthread/test_pthread_cancel_async.c @@ -0,0 +1,73 @@ +// Copyright 2015 The Emscripten Authors. All rights reserved. +// Emscripten is available under two separate licenses, the MIT license and the +// University of Illinois/NCSA Open Source License. Both these licenses can be +// found in the LICENSE file. + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +_Atomic long res = 43; +_Atomic int started = false; + +static void cleanup_handler(void *arg) +{ + long a = (long)arg; + emscripten_outf("Called clean-up handler with arg %ld", a); + res -= a; +} + +static void *thread_start(void *arg) { + // Setup thread for async cancelation only + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); + + pthread_cleanup_push(cleanup_handler, (void*)42); + + emscripten_out("Thread started!"); + + // Signal the main thread that are started + started = true; + + // This mutex is locked by the main thread so this call should never return. + // pthread_mutex_lock is not a cancellation point so deferred cancellation + // won't work here, async cancelation should. + pthread_mutex_lock(&mutex); + + assert(false && "pthread_mutex_lock returned!"); + pthread_cleanup_pop(0); +} + +int main() { + pthread_mutex_lock(&mutex); + + emscripten_out("Starting thread.."); + pthread_t thr; + int s = pthread_create(&thr, NULL, thread_start, (void*)0); + assert(s == 0); + // Busy wait until thread is started + while (!started) { + sched_yield(); + } + + emscripten_out("Canceling thread.."); + s = pthread_cancel(thr); + assert(s == 0); + // Busy wait until thread cancel handler has been run + while (res != 1) { + sched_yield(); + } + + emscripten_out("Joining thread.."); + s = pthread_join(thr, NULL); + assert(s == 0); + emscripten_out("done"); + return 0; +} diff --git a/test/pthread/test_pthread_cancel_async.out b/test/pthread/test_pthread_cancel_async.out new file mode 100644 index 0000000000000..53e6afcae01bb --- /dev/null +++ b/test/pthread/test_pthread_cancel_async.out @@ -0,0 +1,6 @@ +Starting thread.. +Thread started! +Canceling thread.. +Called clean-up handler with arg 42 +Joining thread.. +done diff --git a/test/test_core.py b/test/test_core.py index 6f6a7892d34db..b4d7e79114166 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -2691,6 +2691,14 @@ def test_atexit_threads(self): self.set_setting('EXIT_RUNTIME') self.do_core_test('test_atexit_threads.cpp') + @node_pthreads + def test_pthread_cancel(self): + self.do_run_in_out_file_test('pthread/test_pthread_cancel.cpp') + + @node_pthreads + def test_pthread_cancel_async(self): + self.do_run_in_out_file_test('pthread/test_pthread_cancel_async.c') + @no_asan('test relies on null pointer reads') def test_pthread_specific(self): self.do_run_in_out_file_test('pthread/specific.c') From 8bb1d1ba84bcb72563bb9f0414e191d842e32e81 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 3 Aug 2023 14:49:07 -0700 Subject: [PATCH 0619/1523] Fix test_pthread_cancel after last two commits raced. NFC (#19975) See #19524 and #19963 --- test/pthread/test_pthread_cancel.cpp | 2 +- test/pthread/test_pthread_cancel.out | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/pthread/test_pthread_cancel.cpp b/test/pthread/test_pthread_cancel.cpp index 9781136e1e594..6b3719f2e3e2f 100644 --- a/test/pthread/test_pthread_cancel.cpp +++ b/test/pthread/test_pthread_cancel.cpp @@ -15,8 +15,8 @@ _Atomic long res = 43; static void cleanup_handler(void *arg) { - emscripten_outf("Called clean-up handler with arg %p", arg); long a = (long)arg; + emscripten_outf("Called clean-up handler with arg %ld", a); res -= a; } diff --git a/test/pthread/test_pthread_cancel.out b/test/pthread/test_pthread_cancel.out index 11b060905f0aa..b3ad8b2613d59 100644 --- a/test/pthread/test_pthread_cancel.out +++ b/test/pthread/test_pthread_cancel.out @@ -1,4 +1,4 @@ Canceling thread.. Thread started! Called clean-up handler with arg 42 -After canceling, shared variable = 1. +After canceling, shared variable = 1 From f4a1fcea4c7b495b594efca22748dd7a729fd260 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 3 Aug 2023 16:16:30 -0700 Subject: [PATCH 0620/1523] Convert JS function proxying to use new proxying API. NFC (#19947) --- emcc.py | 1 - src/generated_struct_info32.json | 1 - src/generated_struct_info64.json | 1 - src/library_html5.js | 6 +- src/library_pthread.js | 6 -- src/struct_info_internal.json | 6 -- system/include/emscripten/threading_legacy.h | 5 +- system/lib/pthread/proxying.c | 59 +++++++++++++++++++ system/lib/pthread/proxying_legacy.c | 42 ------------- system/lib/pthread/threading_internal.h | 4 -- .../test_metadce_minimal_pthreads.funcs | 30 ++++++++-- .../test_metadce_minimal_pthreads.jssize | 2 +- .../test_metadce_minimal_pthreads.size | 2 +- 13 files changed, 95 insertions(+), 70 deletions(-) diff --git a/emcc.py b/emcc.py index 1b485fe99edc0..ef28577329b23 100755 --- a/emcc.py +++ b/emcc.py @@ -1706,7 +1706,6 @@ def setup_pthreads(target): # Functions needs to be exported from the module since they are used in worker.js settings.REQUIRED_EXPORTS += [ - 'emscripten_dispatch_to_thread_', '_emscripten_thread_free_data', 'emscripten_main_runtime_thread_id', 'emscripten_main_thread_process_queued_calls', diff --git a/src/generated_struct_info32.json b/src/generated_struct_info32.json index 37d021e8c86c7..701f8b719aa9a 100644 --- a/src/generated_struct_info32.json +++ b/src/generated_struct_info32.json @@ -230,7 +230,6 @@ "EM_PROMISE_MATCH_RELEASE": 2, "EM_PROMISE_REJECT": 3, "EM_PROXIED_RESIZE_OFFSCREENCANVAS": 654311424, - "EM_QUEUED_JS_CALL_MAX_ARGS": 20, "EM_TIMING_RAF": 1, "EM_TIMING_SETIMMEDIATE": 2, "EM_TIMING_SETTIMEOUT": 0, diff --git a/src/generated_struct_info64.json b/src/generated_struct_info64.json index 39d3d95da6f3b..a607c22d911d9 100644 --- a/src/generated_struct_info64.json +++ b/src/generated_struct_info64.json @@ -230,7 +230,6 @@ "EM_PROMISE_MATCH_RELEASE": 2, "EM_PROMISE_REJECT": 3, "EM_PROXIED_RESIZE_OFFSCREENCANVAS": 654311424, - "EM_QUEUED_JS_CALL_MAX_ARGS": 20, "EM_TIMING_RAF": 1, "EM_TIMING_SETIMMEDIATE": 2, "EM_TIMING_SETTIMEOUT": 0, diff --git a/src/library_html5.js b/src/library_html5.js index 3562ff07710c2..ef04c2e84c7ef 100644 --- a/src/library_html5.js +++ b/src/library_html5.js @@ -5,7 +5,11 @@ */ var LibraryHTML5 = { - $JSEvents__deps: ['$withStackSave'], + $JSEvents__deps: ['$withStackSave', +#if PTHREADS + 'emscripten_dispatch_to_thread_', +#endif + ], $JSEvents: { /* We do not depend on the exact initial values of falsey member fields - these fields can be populated on-demand diff --git a/src/library_pthread.js b/src/library_pthread.js index 088624f7364fa..6440e53b984ab 100644 --- a/src/library_pthread.js +++ b/src/library_pthread.js @@ -965,12 +965,6 @@ var LibraryPThread = { // We also pass 'sync' to C separately, since C needs to look at it. var numCallArgs = arguments.length - 2; var outerArgs = arguments; -#if ASSERTIONS - var maxArgs = {{{ cDefs.EM_QUEUED_JS_CALL_MAX_ARGS - 1 }}}; - if (numCallArgs > maxArgs) { - throw 'proxyToMainThread: Too many arguments ' + numCallArgs + ' to proxied function idx=' + index + ', maximum supported is ' + maxArgs; - } -#endif // Allocate a buffer, which will be copied by the C code. return withStackSave(() => { // First passed parameter specifies the number of arguments to the function. diff --git a/src/struct_info_internal.json b/src/struct_info_internal.json index fa59ad4aaa8c1..473769de71efe 100644 --- a/src/struct_info_internal.json +++ b/src/struct_info_internal.json @@ -24,12 +24,6 @@ "SIGCANCEL" ] }, - { - "file": "threading_internal.h", - "defines": [ - "EM_QUEUED_JS_CALL_MAX_ARGS" - ] - }, { "file": "dynlink.h", "structs": { diff --git a/system/include/emscripten/threading_legacy.h b/system/include/emscripten/threading_legacy.h index 3bc9a0d2027a8..fad3f188a8fa5 100644 --- a/system/include/emscripten/threading_legacy.h +++ b/system/include/emscripten/threading_legacy.h @@ -27,6 +27,10 @@ typedef struct em_queued_call em_queued_call; // in the future. Do not depend on the exact numbers in this scheme. #define EM_FUNC_SIGNATURE unsigned int +// Proxied JS function can support a few more arguments than proxied C/C++ +// functions, because the dispatch is variadic and signature independent. +#define EM_QUEUED_JS_CALL_MAX_ARGS 20 + // The encoding scheme is as follows: // - highest three bits identify the type of the return value #define EM_FUNC_SIG_RETURN_VALUE_MASK (0x7U << 29) @@ -115,7 +119,6 @@ typedef struct em_queued_call em_queued_call; #define EM_PROXIED_FUNC_SPECIAL(x) (EM_FUNC_SIG_SPECIAL_INTERNAL | ((x) << 20)) #define EM_PROXIED_RESIZE_OFFSCREENCANVAS (EM_PROXIED_FUNC_SPECIAL(0) | EM_FUNC_SIG_IIII) -#define EM_PROXIED_JS_FUNCTION (EM_PROXIED_FUNC_SPECIAL(1) | EM_FUNC_SIG_D) // Runs the given function synchronously on the main Emscripten runtime thread. // If this thread is the main thread, the operation is immediately performed, diff --git a/system/lib/pthread/proxying.c b/system/lib/pthread/proxying.c index 5a10c08a6e758..0e8a3eaef1147 100644 --- a/system/lib/pthread/proxying.c +++ b/system/lib/pthread/proxying.c @@ -10,11 +10,13 @@ #include #include #include +#include #include #include #include "em_task_queue.h" #include "thread_mailbox.h" +#include "threading_internal.h" struct em_proxying_queue { // Protects all accesses to em_task_queues, size, and capacity. @@ -580,3 +582,60 @@ em_promise_t emscripten_proxy_promise(em_proxying_queue* q, &block->ctx, &block->promise_ctx); } + +typedef struct proxied_js_func_t { + int funcIndex; + pthread_t callingThread; + int numArgs; + double* argBuffer; + double result; + bool owned; +} proxied_js_func_t; + +static void run_js_func(void* arg) { + proxied_js_func_t* f = (proxied_js_func_t*)arg; + f->result = _emscripten_receive_on_main_thread_js( + f->funcIndex, f->callingThread, f->numArgs, f->argBuffer); + if (f->owned) { + free(f->argBuffer); + free(f); + } +} + +double _emscripten_run_on_main_thread_js(int index, + int num_args, + double* buffer, + int sync) { + proxied_js_func_t f = { + .funcIndex = index, + .callingThread = pthread_self(), + .numArgs = num_args, + .argBuffer = buffer, + .owned = false, + }; + + em_proxying_queue* q = emscripten_proxy_get_system_queue(); + pthread_t target = emscripten_main_runtime_thread_id(); + + if (sync) { + if (!emscripten_proxy_sync(q, target, run_js_func, &f)) { + assert(false && "emscripten_proxy_sync failed"); + return 0; + } + return f.result; + } + + // Make a heap-heap allocated copy of the proxied_js_func_t + proxied_js_func_t* arg = malloc(sizeof(proxied_js_func_t)); + *arg = f; + arg->owned = true; + + // Also make a copyh of the argBuffer. + arg->argBuffer = malloc(num_args*sizeof(double)); + memcpy(arg->argBuffer, buffer, num_args*sizeof(double)); + + if (!emscripten_proxy_async(q, target, run_js_func, arg)) { + assert(false && "emscripten_proxy_async failed"); + } + return 0; +} diff --git a/system/lib/pthread/proxying_legacy.c b/system/lib/pthread/proxying_legacy.c index bf9294fa0474c..6987f5d96703f 100644 --- a/system/lib/pthread/proxying_legacy.c +++ b/system/lib/pthread/proxying_legacy.c @@ -153,10 +153,6 @@ static void _do_call(void* arg) { q->returnValue.i = _emscripten_set_offscreencanvas_size(q->args[0].cp, q->args[1].i, q->args[2].i); break; - case EM_PROXIED_JS_FUNCTION: - q->returnValue.d = - _emscripten_receive_on_main_thread_js((intptr_t)q->functionPtr, q->callingThread, q->args[0].i, &q->args[1].d); - break; case EM_FUNC_SIG_V: ((em_func_v)q->functionPtr)(); break; @@ -413,44 +409,6 @@ int emscripten_sync_run_in_main_runtime_thread_(EM_FUNC_SIGNATURE sig, void* fun return q.returnValue.i; } -double _emscripten_run_on_main_thread_js(int index, int num_args, int64_t* buffer, int sync) { - em_queued_call q; - em_queued_call *c; - if (sync) { - q.operationDone = 0; - q.satelliteData = 0; - c = &q; - } else { - c = em_queued_call_malloc(); - } - c->calleeDelete = !sync; - c->functionEnum = EM_PROXIED_JS_FUNCTION; - // Index not needed to ever be more than 32-bit. - c->functionPtr = (void*)(intptr_t)index; - c->callingThread = pthread_self(); - assert(num_args+1 <= EM_QUEUED_JS_CALL_MAX_ARGS); - // The types are only known at runtime in these calls, so we store values that - // must be able to contain any valid JS value, including a 64-bit BigInt if - // BigInt support is enabled. We store to an i64, which can contain both a - // BigInt and a JS Number which is a 64-bit double. - c->args[0].i = num_args; - for (int i = 0; i < num_args; i++) { - c->args[i+1].i64 = buffer[i]; - } - - if (sync) { - sync_run_in_main_thread(&q); - // TODO: support BigInt return values somehow. - return q.returnValue.d; - } else { - // 'async' runs are fire and forget, where the caller detaches itself from the call object after - // returning here, and it is the callee's responsibility to free up the memory after the call - // has been performed. - emscripten_async_run_in_main_thread(c); - return 0; - } -} - void emscripten_async_run_in_main_runtime_thread_(EM_FUNC_SIGNATURE sig, void* func_ptr, ...) { em_queued_call* q = em_queued_call_malloc(); if (!q) diff --git a/system/lib/pthread/threading_internal.h b/system/lib/pthread/threading_internal.h index a2b6f01f3f73d..bf2606125c7d9 100644 --- a/system/lib/pthread/threading_internal.h +++ b/system/lib/pthread/threading_internal.h @@ -9,10 +9,6 @@ #include -// Proxied JS function can support a few more arguments than proxied C/C++ -// functions, because the dispatch is variadic and signature independent. -#define EM_QUEUED_JS_CALL_MAX_ARGS 20 - #define EM_THREAD_NAME_MAX 32 #define EM_THREAD_STATUS int diff --git a/test/other/metadce/test_metadce_minimal_pthreads.funcs b/test/other/metadce/test_metadce_minimal_pthreads.funcs index e4e874250750f..1fc05ee71778e 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.funcs +++ b/test/other/metadce/test_metadce_minimal_pthreads.funcs @@ -2,27 +2,30 @@ $__emscripten_stdout_seek $__errno_location $__memcpy $__memset +$__pthread_getspecific $__pthread_mutex_lock $__pthread_mutex_trylock $__pthread_mutex_unlock $__pthread_rwlock_rdlock $__pthread_rwlock_timedrdlock $__pthread_rwlock_tryrdlock +$__pthread_rwlock_trywrlock $__pthread_rwlock_unlock $__pthread_self_internal $__pthread_setcancelstate $__set_thread_state $__stdio_write $__timedwait +$__timedwait_cp $__tl_lock $__tl_unlock $__wait $__wake +$__wake.1 $__wasi_syscall_ret $__wasm_call_ctors $__wasm_init_memory $__wasm_init_tls -$_do_call $_emscripten_check_mailbox $_emscripten_proxy_main $_emscripten_run_on_main_thread_js @@ -35,19 +38,27 @@ $_emscripten_tls_init $_emscripten_yield $_main_thread $a_cas +$a_cas.7 $a_cas_p.1 $a_dec $a_fetch_add +$a_fetch_add.1 $a_inc $a_store -$a_swap +$a_swap.1 $add +$call_callback_then_free_ctx +$call_cancel_then_free_ctx +$call_then_finish_task +$call_with_ctx +$cancel_active_ctxs +$cancel_ctx $cancel_notification $dispose_chunk $dlfree $dlmalloc -$do_dispatch_to_thread -$em_queued_call_malloc +$do_proxy +$em_proxying_ctx_deinit $em_task_queue_cancel $em_task_queue_create $em_task_queue_dequeue @@ -55,19 +66,28 @@ $em_task_queue_enqueue $em_task_queue_execute $em_task_queue_free $em_task_queue_is_empty -$emscripten_async_run_in_main_thread $emscripten_current_thread_process_queued_calls $emscripten_futex_wait $emscripten_futex_wake $emscripten_stack_set_limits +$free_ctx $get_tasks_for_thread +$init_active_ctxs $init_file_lock $init_mparams +$lock $main $nodtor $pthread_attr_destroy +$pthread_cond_signal +$pthread_mutex_destroy +$pthread_setspecific $receive_notification +$remove_active_ctx +$run_js_func $sbrk $stackAlloc $stackRestore $stackSave +$undo +$unlock diff --git a/test/other/metadce/test_metadce_minimal_pthreads.jssize b/test/other/metadce/test_metadce_minimal_pthreads.jssize index 16c2210899b3e..303587423265d 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.jssize +++ b/test/other/metadce/test_metadce_minimal_pthreads.jssize @@ -1 +1 @@ -14391 +14383 diff --git a/test/other/metadce/test_metadce_minimal_pthreads.size b/test/other/metadce/test_metadce_minimal_pthreads.size index 686ddd583747b..dedb6e2ae66d5 100644 --- a/test/other/metadce/test_metadce_minimal_pthreads.size +++ b/test/other/metadce/test_metadce_minimal_pthreads.size @@ -1 +1 @@ -18965 +19601 From 6b6f7e7ed4aa8c1f2232443403fc8491056b01f6 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 3 Aug 2023 18:21:06 -0700 Subject: [PATCH 0621/1523] Fix error reporting in fd_sync + ASYNCIFY. NFC (#19974) I think the wakeUp function just takes the value to return to the resumed caller. I looks like this was perhaps wrong since it was first added back in #8808. --- src/library_wasi.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/library_wasi.js b/src/library_wasi.js index 42b96c1432db4..87613f5062f3b 100644 --- a/src/library_wasi.js +++ b/src/library_wasi.js @@ -552,7 +552,7 @@ var WasiLibrary = { } mount.type.syncfs(mount, false, function(err) { if (err) { - wakeUp(function() { return {{{ cDefs.EIO }}} }); + wakeUp({{{ cDefs.EIO }}}); return; } wakeUp(0); From 519986b2b50a46f6e1e59815b355fb02735b5179 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 4 Aug 2023 08:17:38 -0700 Subject: [PATCH 0622/1523] More emscripten_out/err use in test code. NFC (#19972) Some instances that I missed in #19524 --- test/core/test_asyncify_during_exit.cpp | 7 +++-- test/core/test_dlmalloc_partial_2.c | 7 +++-- test/core/test_embind_5.cpp | 15 +++++----- test/other/test_pthread_out_err.c | 28 +++++++------------ test/pthread/test_pthread_create.cpp | 4 +-- test/pthread/test_pthread_sbrk.cpp | 3 +- .../test_pthread_thread_local_storage.cpp | 4 +-- 7 files changed, 32 insertions(+), 36 deletions(-) diff --git a/test/core/test_asyncify_during_exit.cpp b/test/core/test_asyncify_during_exit.cpp index 5b9717f4630de..73f7b9eb926b0 100644 --- a/test/core/test_asyncify_during_exit.cpp +++ b/test/core/test_asyncify_during_exit.cpp @@ -1,16 +1,17 @@ #include #include -#include +#include +#include void during_exit() { // An attempt to sleep during exit, which is not allowed (the exit process is // done in synchronous JS). - EM_ASM({ out("during_exit 1") }); + emscripten_out("during_exit 1"); #ifndef NO_ASYNC emscripten_sleep(100); #endif - EM_ASM({ out("during_exit 2") }); + emscripten_out("during_exit 2"); } int main() { diff --git a/test/core/test_dlmalloc_partial_2.c b/test/core/test_dlmalloc_partial_2.c index 965ee217feac6..ebcc35c9bc8a9 100644 --- a/test/core/test_dlmalloc_partial_2.c +++ b/test/core/test_dlmalloc_partial_2.c @@ -7,12 +7,13 @@ #include #include -#include +#include + void *malloc(size_t size) { return (void *)123; } int main() { void *x = malloc(10); - EM_ASM({ out("got 0x" + $0.toString(16)) }, x); + emscripten_outf("got %p", x); free(0); - EM_ASM({ out("freed a fake") }); + emscripten_outf("freed a fake"); return 1; } diff --git a/test/core/test_embind_5.cpp b/test/core/test_embind_5.cpp index 60fb4f55fea70..291e4a4cff0b0 100644 --- a/test/core/test_embind_5.cpp +++ b/test/core/test_embind_5.cpp @@ -3,7 +3,8 @@ // University of Illinois/NCSA Open Source License. Both these licenses can be // found in the LICENSE file. -#include +#include +#include #include using namespace emscripten; @@ -12,26 +13,26 @@ using namespace emscripten; class MyFoo { public: MyFoo() { - EM_ASM({out("constructing my foo");}); + emscripten_out("constructing my foo"); } virtual void doit() { - EM_ASM({out("doing it");}); + emscripten_out("doing it"); } virtual ~MyFoo() { - EM_ASM({out("destructing my foo");}); + emscripten_out("destructing my foo"); } }; class MyBar : public MyFoo { public: MyBar() { - EM_ASM({out("constructing my bar");}); + emscripten_out("constructing my bar"); } void doit() override { - EM_ASM({out("doing something else");}); + emscripten_out("doing something else"); } virtual ~MyBar() override { - EM_ASM({out("destructing my bar");}); + emscripten_out("destructing my bar"); } }; diff --git a/test/other/test_pthread_out_err.c b/test/other/test_pthread_out_err.c index d81010073eba7..bf84711845af4 100644 --- a/test/other/test_pthread_out_err.c +++ b/test/other/test_pthread_out_err.c @@ -1,27 +1,19 @@ #include -#include - -void out(const char* msg) { - EM_ASM({ out(UTF8ToString($0)); }, msg); -} - -void err(const char* msg) { - EM_ASM({ err(UTF8ToString($0)); }, msg); -} +#include // Test that stdout/printf and emscripten JS logging functions (out() // and err()) are interleaved as expected and all arrive at the console. // See https://github.com/emscripten-core/emscripten/issues/14804 int main() { - printf("printf 1\n"); - out ("out 1"); - err ("err 1"); - printf("printf 2\n"); - out ("out 2"); - err ("err 2"); - printf("printf 3\n"); - out ("out 3"); - err ("err 3"); + printf ("printf 1\n"); + emscripten_out("out 1"); + emscripten_err("err 1"); + printf ("printf 2\n"); + emscripten_out("out 2"); + emscripten_err("err 2"); + printf ("printf 3\n"); + emscripten_out("out 3"); + emscripten_err("err 3"); printf("done\n"); return 0; } diff --git a/test/pthread/test_pthread_create.cpp b/test/pthread/test_pthread_create.cpp index f211e07685ff5..1c2833dc19313 100644 --- a/test/pthread/test_pthread_create.cpp +++ b/test/pthread/test_pthread_create.cpp @@ -49,7 +49,7 @@ void *ThreadMain(void *arg) int numGood = 0; for(unsigned int i = 0; i < N; ++i) if (n[i] == i) ++numGood; - else EM_ASM(err('n['+$0+']='+$1), i, n[i]); + else emscripten_errf("n[%d]=%d", i, n[i]); emscripten_outf("Thread idx %ld with param %d: all done with result %d.", idx, param, numGood); pthread_exit((void*)numGood); @@ -84,7 +84,7 @@ int main() int status; int rc = pthread_join(thread[i], (void**)&status); assert(rc == 0); - EM_ASM(err('Main: Joined thread idx ' + $0 + ' (param ' + $1 + ') with status ' + $2), i, global_shared_data[i], (int)status); + emscripten_errf("Main: Joined thread idx %d (param %d) with status %d", i, global_shared_data[i], (int)status); assert(status == N); thread[i] = 0; if (numThreadsToCreate > 0) diff --git a/test/pthread/test_pthread_sbrk.cpp b/test/pthread/test_pthread_sbrk.cpp index 612d2138dbbcc..1ebde141dcede 100644 --- a/test/pthread/test_pthread_sbrk.cpp +++ b/test/pthread/test_pthread_sbrk.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -72,7 +73,7 @@ static void *thread_start(void *arg) { ++return_code; // Failed! (but run to completion so that the barriers will all properly proceed without hanging) if (!reported_once) { - EM_ASM(err('Memory corrupted! mem[i]: ' + $0 + ' != ' + $1 + ', i: ' + $2 + ', j: ' + $3), allocated_buffers[i][j], id, i, j); + emscripten_errf("Memory corrupted! mem[i]: %d != %d, i: %d, j: %d", allocated_buffers[i][j], id, i, j); reported_once = 1; // Avoid print flood that makes debugging hard. } } diff --git a/test/pthread/test_pthread_thread_local_storage.cpp b/test/pthread/test_pthread_thread_local_storage.cpp index 6496f5c3aead3..a10accf9a984c 100644 --- a/test/pthread/test_pthread_thread_local_storage.cpp +++ b/test/pthread/test_pthread_thread_local_storage.cpp @@ -25,7 +25,7 @@ void *ThreadMain(void *arg) for(int i = 0; i < NUM_KEYS; ++i) { local_keys[i] = (uintptr_t)pthread_getspecific(keys[i]); -// EM_ASM(err('Thread ' + $0 + ': Read value ' + $1 + ' from TLS for key at index ' + $2), pthread_self(), (int)local_keys[i], i); +// emscripten_errf("Thread %d: Read value %d from TLS for key at index %d", pthread_self(), (int)local_keys[i], i); } for(int i = 0; i < NUM_KEYS; ++i) @@ -38,7 +38,7 @@ void *ThreadMain(void *arg) for(int i = 0; i < NUM_KEYS; ++i) { local_keys[i] = (uintptr_t)pthread_getspecific(keys[i]); -// EM_ASM(err('Thread ' + $0 + ' final verify: Read value ' + $1 + ' from TLS for key at index ' + $2), pthread_self(), (int)local_keys[i], i); +// emscripten_errf("Thread %d final verify: Read value %d from TLS for key at index %d", pthread_self(), (int)local_keys[i], i); assert(local_keys[i] == NUM_ITERS); } return 0; From 7b9f1c3661cedacb316e9299af967e854bb5d0e6 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 4 Aug 2023 09:01:27 -0700 Subject: [PATCH 0623/1523] Add new internal setting: MINIFY_WHITESPACE (#19961) This centralizes the control of JS whitespace minification behind a single setting. We have had a feature request to be able to disable this minification so the output can be passed to closure compiler after link time. This change doesn't yet allow the user to directly control this setting. We can consider that part as a followup. The `test_emcc_output_worker_mjs` test expectation changed because we now minify the worker.js file based on the same set of criteria as the main js file. Previously these were independent and had slightly different criteria. --- emcc.py | 19 +++++++------------ src/settings_internal.js | 2 ++ test/test_other.py | 2 +- tools/building.py | 41 ++++++++++++++++++++-------------------- 4 files changed, 31 insertions(+), 33 deletions(-) diff --git a/emcc.py b/emcc.py index ef28577329b23..350ebcece6be5 100755 --- a/emcc.py +++ b/emcc.py @@ -384,10 +384,6 @@ def setup_environment_settings(): exit_with_error('When building with multithreading enabled and a "-sENVIRONMENT=" directive is specified, it must include "worker" as a target! (Try e.g. -sENVIRONMENT=web,worker)') -def minify_whitespace(): - return settings.OPT_LEVEL >= 2 and settings.DEBUG_LEVEL == 0 - - def embed_memfile(options): return (settings.SINGLE_FILE or (settings.WASM2JS and not options.memory_init_file and @@ -2951,6 +2947,8 @@ def get_full_import_name(name): settings.PRE_JS_FILES = [os.path.abspath(f) for f in options.pre_js] settings.POST_JS_FILES = [os.path.abspath(f) for f in options.post_js] + settings.MINIFY_WHITESPACE = settings.OPT_LEVEL >= 2 and settings.DEBUG_LEVEL == 0 + return target, wasm_target @@ -3223,8 +3221,8 @@ def create_worker_file(input_file, target_dir, output_file): contents = shared.read_and_preprocess(input_file, expand_macros=True) write_file(output_file, contents) - # Minify the worker JS files file in optimized builds - if (settings.OPT_LEVEL >= 1 or settings.SHRINK_LEVEL >= 1) and not settings.DEBUG_LEVEL: + # Minify the worker JS file, if JS minification is enabled. + if settings.MINIFY_WHITESPACE: contents = building.acorn_optimizer(output_file, ['minifyWhitespace'], return_output=True) write_file(output_file, contents) @@ -3258,7 +3256,7 @@ def phase_final_emitting(options, state, target, wasm_target, memfile): # Finally, rerun Closure compile with simple optimizations. It will be able # to further minify the code. (n.b. it would not be safe to run in advanced # mode) - final_js = building.closure_compiler(final_js, pretty=False, advanced=False, extra_closure_args=options.closure_args) + final_js = building.closure_compiler(final_js, advanced=False, extra_closure_args=options.closure_args) # Unmangle previously mangled `import.meta` and `await import` references in # both main code and libraries. @@ -3769,7 +3767,6 @@ def phase_binaryen(target, options, wasm_target): final_js = building.minify_wasm_js(js_file=final_js, wasm_file=wasm_target, expensive_optimizations=will_metadce(), - minify_whitespace=minify_whitespace() and not options.use_closure_compiler, debug_info=intermediate_debug_info) save_intermediate_with_wasm('postclean', wasm_target) @@ -3780,11 +3777,10 @@ def phase_binaryen(target, options, wasm_target): if final_js and (options.use_closure_compiler or settings.TRANSPILE_TO_ES5): if options.use_closure_compiler: with ToolchainProfiler.profile_block('closure_compile'): - final_js = building.closure_compiler(final_js, pretty=not minify_whitespace(), - extra_closure_args=options.closure_args) + final_js = building.closure_compiler(final_js, extra_closure_args=options.closure_args) else: with ToolchainProfiler.profile_block('closure_transpile'): - final_js = building.closure_transpile(final_js, pretty=not minify_whitespace()) + final_js = building.closure_transpile(final_js) save_intermediate_with_wasm('closure', wasm_target) symbols_file = None @@ -3810,7 +3806,6 @@ def phase_binaryen(target, options, wasm_target): wasm2js = building.wasm2js(wasm2js_template, wasm_target, opt_level=settings.OPT_LEVEL, - minify_whitespace=minify_whitespace(), use_closure_compiler=options.use_closure_compiler, debug_info=debug_info, symbols_file=symbols_file, diff --git a/src/settings_internal.js b/src/settings_internal.js index 1abe54889f666..98efb02aaaae1 100644 --- a/src/settings_internal.js +++ b/src/settings_internal.js @@ -265,3 +265,5 @@ var POST_JS_FILES = []; var PTHREADS = false; var BULK_MEMORY = false; + +var MINIFY_WHITESPACE = true; diff --git a/test/test_other.py b/test/test_other.py index 6034354de1865..7f26a5c329371 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -306,7 +306,7 @@ def test_emcc_output_worker_mjs(self, args): self.assertContained("new Worker(new URL('hello_world.worker.js', import.meta.url))", src) self.assertContained('export default Module;', src) src = read_file('subdir/hello_world.worker.js') - self.assertContained('import("./hello_world.mjs")', src) + self.assertContained("import('./hello_world.mjs')", src) self.assertContained('hello, world!', self.run_js('subdir/hello_world.mjs')) @node_pthreads diff --git a/tools/building.py b/tools/building.py index f5f23dd4c3b29..472d02c01572f 100644 --- a/tools/building.py +++ b/tools/building.py @@ -485,16 +485,16 @@ def add_to_path(dirname): @ToolchainProfiler.profile() -def closure_transpile(filename, pretty): +def closure_transpile(filename): user_args = [] closure_cmd, env = get_closure_compiler_and_env(user_args) closure_cmd += ['--language_out', 'ES5'] closure_cmd += ['--compilation_level', 'WHITESPACE_ONLY'] - return run_closure_cmd(closure_cmd, filename, env, pretty) + return run_closure_cmd(closure_cmd, filename, env) @ToolchainProfiler.profile() -def closure_compiler(filename, pretty, advanced=True, extra_closure_args=None): +def closure_compiler(filename, advanced=True, extra_closure_args=None): user_args = [] env_args = os.environ.get('EMCC_CLOSURE_ARGS') if env_args: @@ -573,10 +573,10 @@ def closure_compiler(filename, pretty, advanced=True, extra_closure_args=None): args += user_args cmd = closure_cmd + args - return run_closure_cmd(cmd, filename, env, pretty=pretty) + return run_closure_cmd(cmd, filename, env) -def run_closure_cmd(cmd, filename, env, pretty): +def run_closure_cmd(cmd, filename, env): cmd += ['--js', filename] # Closure compiler is unable to deal with path names that are not 7-bit ASCII: @@ -605,7 +605,7 @@ def move_to_safe_7bit_ascii_filename(filename): # Specify output file relative to the temp directory to avoid specifying non-7-bit-ASCII path names. cmd += ['--js_output_file', os.path.relpath(outfile, tempfiles.tmpdir)] - if pretty: + if not settings.MINIFY_WHITESPACE: cmd += ['--formatting', 'PRETTY_PRINT'] shared.print_compiler_stage(cmd) @@ -645,7 +645,7 @@ def move_to_safe_7bit_ascii_filename(filename): # Exit and print final hint to get clearer output msg = f'closure compiler failed (rc: {proc.returncode}): {shared.shlex_join(cmd)}' - if not pretty: + if settings.MINIFY_WHITESPACE: msg += ' the error message may be clearer with -g1 and EMCC_DEBUG=2 set' exit_with_error(msg) @@ -657,7 +657,7 @@ def move_to_safe_7bit_ascii_filename(filename): logger.warn(proc.stderr) # Exit and/or print final hint to get clearer output - if not pretty: + if settings.MINIFY_WHITESPACE: logger.warn('(rerun with -g1 linker flag for an unminified output)') elif DEBUG != 2: logger.warn('(rerun with EMCC_DEBUG=2 enabled to dump Closure input file)') @@ -670,14 +670,16 @@ def move_to_safe_7bit_ascii_filename(filename): # minify the final wasm+JS combination. this is done after all the JS # and wasm optimizations; here we do the very final optimizations on them -def minify_wasm_js(js_file, wasm_file, expensive_optimizations, minify_whitespace, debug_info): +def minify_wasm_js(js_file, wasm_file, expensive_optimizations, debug_info): # start with JSDCE, to clean up obvious JS garbage. When optimizing for size, # use AJSDCE (aggressive JS DCE, performs multiple iterations). Clean up # whitespace if necessary too. passes = [] if not settings.LINKABLE: passes.append('JSDCE' if not expensive_optimizations else 'AJSDCE') - if minify_whitespace: + # Don't minify if we are going to run closure compiler afterwards + minify = settings.MINIFY_WHITESPACE and not settings.USE_CLOSURE_COMPILER + if minify: passes.append('minifyWhitespace') if passes: logger.debug('running cleanup on shell code: ' + ' '.join(passes)) @@ -688,24 +690,23 @@ def minify_wasm_js(js_file, wasm_file, expensive_optimizations, minify_whitespac # if we are optimizing for size, shrink the combined wasm+JS # TODO: support this when a symbol map is used if expensive_optimizations: - js_file = metadce(js_file, wasm_file, minify_whitespace=minify_whitespace, debug_info=debug_info) + js_file = metadce(js_file, wasm_file, debug_info=debug_info) # now that we removed unneeded communication between js and wasm, we can clean up # the js some more. passes = ['AJSDCE'] - if minify_whitespace: + if minify: passes.append('minifyWhitespace') logger.debug('running post-meta-DCE cleanup on shell code: ' + ' '.join(passes)) js_file = acorn_optimizer(js_file, passes) if settings.MINIFY_WASM_IMPORTS_AND_EXPORTS: js_file = minify_wasm_imports_and_exports(js_file, wasm_file, - minify_whitespace=minify_whitespace, minify_exports=settings.MINIFY_WASM_EXPORT_NAMES, debug_info=debug_info) return js_file # run binaryen's wasm-metadce to dce both js and wasm -def metadce(js_file, wasm_file, minify_whitespace, debug_info): +def metadce(js_file, wasm_file, debug_info): logger.debug('running meta-DCE') temp_files = shared.get_temp_files() # first, get the JS part of the graph @@ -788,7 +789,7 @@ def metadce(js_file, wasm_file, minify_whitespace, debug_info): unused.append(name) # remove them passes = ['applyDCEGraphRemovals'] - if minify_whitespace: + if settings.MINIFY_WHITESPACE: passes.append('minifyWhitespace') extra_info = {'unused': unused} return acorn_optimizer(js_file, passes, extra_info=json.dumps(extra_info)) @@ -819,7 +820,7 @@ def asyncify_lazy_load_code(wasm_target, debug): debug=debug) -def minify_wasm_imports_and_exports(js_file, wasm_file, minify_whitespace, minify_exports, debug_info): +def minify_wasm_imports_and_exports(js_file, wasm_file, minify_exports, debug_info): logger.debug('minifying wasm imports and exports') # run the pass if minify_exports: @@ -850,13 +851,13 @@ def minify_wasm_imports_and_exports(js_file, wasm_file, minify_whitespace, minif mapping[old] = new # apply them passes = ['applyImportAndExportNameChanges'] - if minify_whitespace: + if settings.MINIFY_WHITESPACE: passes.append('minifyWhitespace') extra_info = {'mapping': mapping} return acorn_optimizer(js_file, passes, extra_info=json.dumps(extra_info)) -def wasm2js(js_file, wasm_file, opt_level, minify_whitespace, use_closure_compiler, debug_info, symbols_file=None, symbols_file_js=None): +def wasm2js(js_file, wasm_file, opt_level, use_closure_compiler, debug_info, symbols_file=None, symbols_file_js=None): logger.debug('wasm2js') args = ['--emscripten'] if opt_level > 0: @@ -876,7 +877,7 @@ def wasm2js(js_file, wasm_file, opt_level, minify_whitespace, use_closure_compil passes += ['minifyNames'] if symbols_file_js: passes += ['symbolMap=%s' % symbols_file_js] - if minify_whitespace: + if settings.MINIFY_WHITESPACE: passes += ['minifyWhitespace'] passes += ['last'] if passes: @@ -897,7 +898,7 @@ def wasm2js(js_file, wasm_file, opt_level, minify_whitespace, use_closure_compil temp = shared.get_temp_files().get('.js').name with open(temp, 'a') as f: f.write(wasm2js_js) - temp = closure_compiler(temp, pretty=not minify_whitespace, advanced=False) + temp = closure_compiler(temp, advanced=False) wasm2js_js = utils.read_file(temp) # closure may leave a trailing `;`, which would be invalid given where we place # this code (inside parens) From fa099c17ae64c8627fa0bc5e702ac34d8f162ac8 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 4 Aug 2023 09:08:17 -0700 Subject: [PATCH 0624/1523] Perform wasm64 offset calculations at build time. NFC (#19976) --- src/parseTools.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parseTools.js b/src/parseTools.js index 60882d38b3ecc..8f79c8763c35e 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -295,7 +295,7 @@ function getHeapOffset(offset, type) { const sz = getNativeTypeSize(type); const shifts = Math.log(sz) / Math.LN2; if (MEMORY64 == 1) { - return `((${offset})/2**${shifts})`; + return `((${offset})/${2 ** shifts})`; } else { return `((${offset})>>${shifts})`; } From c5d1a856592b788619be11bbdc1dd119dec4e24c Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 4 Aug 2023 09:42:15 -0700 Subject: [PATCH 0625/1523] More use of JS string template literals. NFC (#19971) Also, just `dbg` over `out` where appropriate. --- src/library.js | 2 +- src/library_autodebug.js | 46 +++++++++---------- src/library_browser.js | 12 +++-- src/library_dylink.js | 2 +- src/library_egl.js | 2 +- src/library_glemu.js | 2 +- src/library_glfw.js | 14 +++--- src/library_pthread.js | 40 ++++++++-------- src/library_sdl.js | 46 ++++++++++--------- src/library_webgpu.js | 4 +- src/preamble.js | 16 +++---- src/proxyWorker.js | 2 +- src/runtime_debug.js | 2 +- src/runtime_safe_heap.js | 4 +- src/worker.js | 4 +- .../metadce/test_metadce_cxx_ctors1.jssize | 2 +- .../metadce/test_metadce_cxx_ctors2.jssize | 2 +- .../metadce/test_metadce_cxx_except.jssize | 2 +- .../test_metadce_cxx_except_wasm.jssize | 2 +- .../metadce/test_metadce_cxx_mangle.jssize | 2 +- .../metadce/test_metadce_cxx_noexcept.jssize | 2 +- .../metadce/test_metadce_cxx_wasmfs.jssize | 2 +- .../metadce/test_metadce_files_js_fs.jssize | 2 +- .../metadce/test_metadce_files_wasmfs.jssize | 2 +- .../metadce/test_metadce_hello_O0.jssize | 2 +- .../metadce/test_metadce_hello_O2.jssize | 2 +- .../metadce/test_metadce_hello_O3.jssize | 2 +- .../metadce/test_metadce_hello_Os.jssize | 2 +- .../metadce/test_metadce_hello_Oz.jssize | 2 +- .../metadce/test_metadce_hello_dylink.jssize | 2 +- .../test_metadce_hello_export_nothing.jssize | 2 +- .../metadce/test_metadce_hello_wasmfs.jssize | 2 +- .../test_metadce_libcxxabi_message_O3.jssize | 2 +- ...dce_libcxxabi_message_O3_standalone.jssize | 2 +- test/other/metadce/test_metadce_mem_O3.jssize | 2 +- .../metadce/test_metadce_mem_O3_grow.jssize | 2 +- ...test_metadce_mem_O3_grow_standalone.jssize | 2 +- .../test_metadce_mem_O3_standalone.jssize | 2 +- .../test_metadce_mem_O3_standalone_lib.jssize | 2 +- ...test_metadce_mem_O3_standalone_narg.jssize | 2 +- ...metadce_mem_O3_standalone_narg_flto.jssize | 2 +- .../metadce/test_metadce_minimal_64.jssize | 2 +- .../metadce/test_metadce_minimal_O0.jssize | 2 +- .../metadce/test_metadce_minimal_O2.jssize | 2 +- .../metadce/test_metadce_minimal_O3.jssize | 2 +- .../metadce/test_metadce_minimal_Os.jssize | 2 +- .../test_metadce_minimal_Oz-ctors.jssize | 2 +- .../metadce/test_metadce_minimal_Oz.jssize | 2 +- .../test_metadce_minimal_pthreads.jssize | 2 +- .../test_metadce_minimal_wasmfs.jssize | 2 +- test/other/test_unoptimized_code_size.js.size | 2 +- .../test_unoptimized_code_size_strict.js.size | 2 +- 52 files changed, 138 insertions(+), 134 deletions(-) diff --git a/src/library.js b/src/library.js index 31901ce36e4c8..f837b0827c911 100644 --- a/src/library.js +++ b/src/library.js @@ -283,7 +283,7 @@ mergeInto(LibraryManager.library, { var replacement = growMemory(newSize); #if ASSERTIONS == 2 var t1 = _emscripten_get_now(); - out(`Heap resize call from ${oldSize} to ${newSize} took ${(t1 - t0)} msecs. Success: ${!!replacement}`); + dbg(`Heap resize call from ${oldSize} to ${newSize} took ${(t1 - t0)} msecs. Success: ${!!replacement}`); #endif if (replacement) { #if ASSERTIONS && WASM2JS diff --git a/src/library_autodebug.js b/src/library_autodebug.js index fa53d92d3e99a..e73fcd9c45723 100644 --- a/src/library_autodebug.js +++ b/src/library_autodebug.js @@ -11,102 +11,102 @@ mergeInto(LibraryManager.library, { $log_execution: function(loc) { - out('log_execution ' + loc); + dbg('log_execution ' + loc); }, $get_i32: function(loc, index, value) { - out('get_i32 ' + [loc, index, value]); + dbg('get_i32 ' + [loc, index, value]); return value; }, $get_i64__deps: ['setTempRet0'], $get_i64: function(loc, index, low, high) { - out('get_i64 ' + [loc, index, low, high]); + dbg('get_i64 ' + [loc, index, low, high]); setTempRet0(high); return low; }, $get_f32: function(loc, index, value) { - out('get_f32 ' + [loc, index, value]); + dbg('get_f32 ' + [loc, index, value]); return value; }, $get_f64: function(loc, index, value) { - out('get_f64 ' + [loc, index, value]); + dbg('get_f64 ' + [loc, index, value]); return value; }, $get_anyref: function(loc, index, value) { - out('get_anyref ' + [loc, index, value]); + dbg('get_anyref ' + [loc, index, value]); return value; }, $get_exnref: function(loc, index, value) { - out('get_exnref ' + [loc, index, value]); + dbg('get_exnref ' + [loc, index, value]); return value; }, $set_i32: function(loc, index, value) { - out('set_i32 ' + [loc, index, value]); + dbg('set_i32 ' + [loc, index, value]); return value; }, $set_i64__deps: ['setTempRet0'], $set_i64: function(loc, index, low, high) { - out('set_i64 ' + [loc, index, low, high]); + dbg('set_i64 ' + [loc, index, low, high]); setTempRet0(high); return low; }, $set_f32: function(loc, index, value) { - out('set_f32 ' + [loc, index, value]); + dbg('set_f32 ' + [loc, index, value]); return value; }, $set_f64: function(loc, index, value) { - out('set_f64 ' + [loc, index, value]); + dbg('set_f64 ' + [loc, index, value]); return value; }, $set_anyref: function(loc, index, value) { - out('set_anyref ' + [loc, index, value]); + dbg('set_anyref ' + [loc, index, value]); return value; }, $set_exnref: function(loc, index, value) { - out('set_exnref ' + [loc, index, value]); + dbg('set_exnref ' + [loc, index, value]); return value; }, $load_ptr: function(loc, bytes, offset, ptr) { - out('load_ptr ' + [loc, bytes, offset, ptr]); + dbg('load_ptr ' + [loc, bytes, offset, ptr]); return ptr; }, $load_val_i32: function(loc, value) { - out('load_val_i32 ' + [loc, value]); + dbg('load_val_i32 ' + [loc, value]); return value; }, $load_val_i64__deps: ['setTempRet0'], $load_val_i64: function(loc, low, high) { - out('load_val_i64 ' + [loc, low, high]); + dbg('load_val_i64 ' + [loc, low, high]); setTempRet0(high); return low; }, $load_val_f32: function(loc, value) { - out('load_val_f32 ' + [loc, value]); + dbg('load_val_f32 ' + [loc, value]); return value; }, $load_val_f64: function(loc, value) { - out('load_val_f64 ' + [loc, value]); + dbg('load_val_f64 ' + [loc, value]); return value; }, $store_ptr: function(loc, bytes, offset, ptr) { - out('store_ptr ' + [loc, bytes, offset, ptr]); + dbg('store_ptr ' + [loc, bytes, offset, ptr]); return ptr; }, $store_val_i32: function(loc, value) { - out('store_val_i32 ' + [loc, value]); + dbg('store_val_i32 ' + [loc, value]); return value; }, $store_val_i64__deps: ['setTempRet0'], $store_val_i64: function(loc, low, high) { - out('store_val_i64 ' + [loc, low, high]); + dbg('store_val_i64 ' + [loc, low, high]); setTempRet0(high); return low; }, $store_val_f32: function(loc, value) { - out('store_val_f32 ' + [loc, value]); + dbg('store_val_f32 ' + [loc, value]); return value; }, $store_val_f64: function(loc, value) { - out('store_val_f64 ' + [loc, value]); + dbg('store_val_f64 ' + [loc, value]); return value; }, }); diff --git a/src/library_browser.js b/src/library_browser.js index 7863b243cd2bc..823bb116f7ea5 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -132,7 +132,7 @@ var LibraryBrowser = { #endif var img = new Image(); img.onload = () => { - assert(img.complete, 'Image ' + name + ' could not be decoded'); + assert(img.complete, `Image ${name} could not be decoded`); var canvas = /** @type {!HTMLCanvasElement} */ (document.createElement('canvas')); canvas.width = img.width; canvas.height = img.height; @@ -143,7 +143,7 @@ var LibraryBrowser = { if (onload) onload(byteArray); }; img.onerror = (event) => { - out('Image ' + url + ' could not be decoded'); + err(`Image ${url} could not be decoded`); if (onerror) onerror(); }; img.src = url; @@ -177,7 +177,7 @@ var LibraryBrowser = { audio.addEventListener('canplaythrough', () => finish(audio), false); // use addEventListener due to chromium bug 124926 audio.onerror = function audio_onerror(event) { if (done) return; - err('warning: browser could not fully decode audio ' + name + ', trying slower base64 approach'); + err(`warning: browser could not fully decode audio ${name}, trying slower base64 approach`); function encode64(data) { var BASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; var PAD = '='; @@ -769,7 +769,7 @@ var LibraryBrowser = { #if PTHREADS if (ENVIRONMENT_IS_PTHREAD) { - err('emscripten_async_load_script("' + url + '") failed, emscripten_async_load_script is currently not available in pthreads!'); + err(`emscripten_async_load_script("${url}") failed, emscripten_async_load_script is currently not available in pthreads!`); return onerror ? onerror() : undefined; } #endif @@ -953,7 +953,9 @@ var LibraryBrowser = { Browser.mainLoop.remainingBlockers = (8*remaining + next)/9; } } - out('main loop blocker "' + blocker.name + '" took ' + (Date.now() - start) + ' ms'); //, left: ' + Browser.mainLoop.remainingBlockers); +#if RUNTIME_DEBUG + dbg(`main loop blocker "${blocker.name}" took '${Date.now() - start} ms`); //, left: ' + Browser.mainLoop.remainingBlockers); +#endif Browser.mainLoop.updateStatus(); // catches pause/resume main loop from blocker execution diff --git a/src/library_dylink.js b/src/library_dylink.js index 9d0beac9f200a..6ed55e4e9a2ce 100644 --- a/src/library_dylink.js +++ b/src/library_dylink.js @@ -538,7 +538,7 @@ var LibraryDylink = { var curr = wasmImports[sym], next = exports[sym]; // don't warn on functions - might be odr, linkonce_odr, etc. if (!(typeof curr == 'function' && typeof next == 'function')) { - err("warning: symbol '" + sym + "' from '" + libName + "' already exists (duplicate symbol? or weak linking, which isn't supported yet?)"); // + [curr, ' vs ', next]); + err(`warning: symbol '${sym}' from '${libName}' already exists (duplicate symbol? or weak linking, which isn't supported yet?)`); // + [curr, ' vs ', next]); } } #endif diff --git a/src/library_egl.js b/src/library_egl.js index c78b3fa972bb3..bd06b168a31f5 100644 --- a/src/library_egl.js +++ b/src/library_egl.js @@ -344,7 +344,7 @@ var LibraryEGL = { if (glesContextVersion == 3) { err('When initializing GLES3/WebGL2 via EGL, one must build with -sMAX_WEBGL_VERSION=2!'); } else { - err('When initializing GLES2/WebGL1 via EGL, one must pass EGL_CONTEXT_CLIENT_VERSION = 2 to GL context attributes! GLES version ' + glesContextVersion + ' is not supported!'); + err(`When initializing GLES2/WebGL1 via EGL, one must pass EGL_CONTEXT_CLIENT_VERSION = 2 to GL context attributes! GLES version ${glesContextVersion} is not supported!`); } #endif EGL.setErrorCode(0x3005 /* EGL_BAD_CONFIG */); diff --git a/src/library_glemu.js b/src/library_glemu.js index 76e8845ab7c87..0d91800c72c52 100644 --- a/src/library_glemu.js +++ b/src/library_glemu.js @@ -791,7 +791,7 @@ var LibraryGLEmulation = { default: GL.recordError(0x500/*GL_INVALID_ENUM*/); #if GL_ASSERTIONS - err('GL_INVALID_ENUM in glGetPointerv: Unsupported name ' + name + '!'); + err(`GL_INVALID_ENUM in glGetPointerv: Unsupported name ${name}!`); #endif return; } diff --git a/src/library_glfw.js b/src/library_glfw.js index 5fbb1bc3a3e6c..25fb667fd713d 100644 --- a/src/library_glfw.js +++ b/src/library_glfw.js @@ -866,7 +866,7 @@ var LibraryGLFW = { break; } case 0x00034002: { // GLFW_CURSOR_HIDDEN - out("glfwSetInputMode called with GLFW_CURSOR_HIDDEN value not implemented."); + err('glfwSetInputMode called with GLFW_CURSOR_HIDDEN value not implemented'); break; } case 0x00034003: { // GLFW_CURSOR_DISABLED @@ -876,30 +876,30 @@ var LibraryGLFW = { break; } default: { - out("glfwSetInputMode called with unknown value parameter value: " + value + "."); + err(`glfwSetInputMode called with unknown value parameter value: ${value}`); break; } } break; } case 0x00033002: { // GLFW_STICKY_KEYS - out("glfwSetInputMode called with GLFW_STICKY_KEYS mode not implemented."); + err('glfwSetInputMode called with GLFW_STICKY_KEYS mode not implemented'); break; } case 0x00033003: { // GLFW_STICKY_MOUSE_BUTTONS - out("glfwSetInputMode called with GLFW_STICKY_MOUSE_BUTTONS mode not implemented."); + err('glfwSetInputMode called with GLFW_STICKY_MOUSE_BUTTONS mode not implemented'); break; } case 0x00033004: { // GLFW_LOCK_KEY_MODS - out("glfwSetInputMode called with GLFW_LOCK_KEY_MODS mode not implemented."); + err('glfwSetInputMode called with GLFW_LOCK_KEY_MODS mode not implemented'); break; } case 0x000330005: { // GLFW_RAW_MOUSE_MOTION - out("glfwSetInputMode called with GLFW_RAW_MOUSE_MOTION mode not implemented."); + err('glfwSetInputMode called with GLFW_RAW_MOUSE_MOTION mode not implemented'); break; } default: { - out("glfwSetInputMode called with unknown mode parameter value: " + mode + "."); + err(`glfwSetInputMode called with unknown mode parameter value: ${mode}`); break; } } diff --git a/src/library_pthread.js b/src/library_pthread.js index 6440e53b984ab..de589a680b95f 100644 --- a/src/library_pthread.js +++ b/src/library_pthread.js @@ -265,7 +265,7 @@ var LibraryPThread = { if (targetWorker) { targetWorker.postMessage(d, d['transferList']); } else { - err('Internal error! Worker sent a message "' + cmd + '" to target pthread ' + d['targetThread'] + ', but that thread no longer exists!'); + err(`Internal error! Worker sent a message "${cmd}" to target pthread ${d['targetThread']}, but that thread no longer exists!`); } return; } @@ -308,7 +308,7 @@ var LibraryPThread = { // The received message looks like something that should be handled by this message // handler, (since there is a e.data.cmd field present), but is not one of the // recognized commands: - err("worker sent an unknown command " + cmd); + err(`worker sent an unknown command ${cmd}`); } }; @@ -319,7 +319,7 @@ var LibraryPThread = { message = 'Pthread ' + ptrToString(worker.pthread_ptr) + ' sent an error!'; } #endif - err(message + ' ' + e.filename + ':' + e.lineno + ': ' + e.message); + err(`${message} ${e.filename}:${e.lineno}: ${e.message}`); throw e; }; @@ -467,7 +467,7 @@ var LibraryPThread = { var pthreadMainJs = locateFile('{{{ PTHREAD_WORKER_FILE }}}'); #endif #if PTHREADS_DEBUG - dbg('Allocating a new web worker from ' + pthreadMainJs); + dbg(`Allocating a new web worker from ${pthreadMainJs}`); #endif #if TRUSTED_TYPES // Use Trusted Types compatible wrappers. @@ -519,7 +519,7 @@ var LibraryPThread = { $terminateWorker: function(worker) { #if PTHREADS_DEBUG - dbg('terminateWorker: ' + worker.workerID); + dbg(`terminateWorker: ${worker.workerID}`); #endif worker.terminate(); // terminate() can be asynchronous, so in theory the worker can continue @@ -530,7 +530,7 @@ var LibraryPThread = { worker.onmessage = (e) => { #if ASSERTIONS var cmd = e['data']['cmd']; - err('received "' + cmd + '" command from terminated worker: ' + worker.workerID); + err(`received "${cmd}" command from terminated worker: ${worker.workerID}`); #endif }; }, @@ -538,7 +538,7 @@ var LibraryPThread = { $killThread__deps: ['_emscripten_thread_free_data', '$terminateWorker'], $killThread: function(pthread_ptr) { #if PTHREADS_DEBUG - dbg('killThread ' + ptrToString(pthread_ptr)); + dbg(`killThread ${ptrToString(pthread_ptr)}`); #endif #if ASSERTIONS assert(!ENVIRONMENT_IS_PTHREAD, 'Internal Error! killThread() can only ever be called from main application thread!'); @@ -561,7 +561,7 @@ var LibraryPThread = { // Detached threads are responsible for calling this themselves, // otherwise pthread_join is responsible for calling this. #if PTHREADS_DEBUG - dbg('__emscripten_thread_cleanup: ' + ptrToString(thread)) + dbg(`__emscripten_thread_cleanup: ${ptrToString(thread)}`) #endif if (!ENVIRONMENT_IS_PTHREAD) cleanupThread(thread); else postMessage({ 'cmd': 'cleanupThread', 'thread': thread }); @@ -582,7 +582,7 @@ var LibraryPThread = { $cleanupThread: function(pthread_ptr) { #if PTHREADS_DEBUG - dbg('cleanupThread: ' + ptrToString(pthread_ptr)) + dbg(`cleanupThread: ${ptrToString(pthread_ptr)}`) #endif #if ASSERTIONS assert(!ENVIRONMENT_IS_PTHREAD, 'Internal Error! cleanupThread() can only ever be called from main application thread!'); @@ -610,7 +610,7 @@ var LibraryPThread = { function tlsInitWrapper() { var __tls_base = tlsInitFunc(); #if DYLINK_DEBUG - dbg('tlsInit -> ' + __tls_base); + dbg(`tlsInit -> ${__tls_base}`); #endif if (!__tls_base) { #if ASSERTIONS @@ -777,7 +777,7 @@ var LibraryPThread = { if (transferredCanvasNames) transferredCanvasNames = UTF8ToString(transferredCanvasNames).trim(); if (transferredCanvasNames) transferredCanvasNames = transferredCanvasNames.split(','); #if GL_DEBUG - dbg('pthread_create: transferredCanvasNames="' + transferredCanvasNames + '"'); + dbg(`pthread_create: transferredCanvasNames="${transferredCanvasNames}"`); #endif var offscreenCanvases = {}; // Dictionary of OffscreenCanvas objects we'll transfer to the created thread to own @@ -789,7 +789,7 @@ var LibraryPThread = { try { if (name == '#canvas') { if (!Module['canvas']) { - err('pthread_create: could not find canvas with ID "' + name + '" to transfer to thread!'); + err(`pthread_create: could not find canvas with ID "${name}" to transfer to thread!`); error = {{{ cDefs.EINVAL }}}; break; } @@ -805,12 +805,12 @@ var LibraryPThread = { } else if (!ENVIRONMENT_IS_PTHREAD) { var canvas = (Module['canvas'] && Module['canvas'].id === name) ? Module['canvas'] : document.querySelector(name); if (!canvas) { - err('pthread_create: could not find canvas with ID "' + name + '" to transfer to thread!'); + err(`pthread_create: could not find canvas with ID "${name}" to transfer to thread!`); error = {{{ cDefs.EINVAL }}}; break; } if (canvas.controlTransferredOffscreen) { - err('pthread_create: cannot transfer canvas with ID "' + name + '" to thread, since the current thread does not have control over it!'); + err(`pthread_create: cannot transfer canvas with ID "${name}" to thread, since the current thread does not have control over it!`); error = {{{ cDefs.EPERM }}}; // Operation not permitted, some other thread is accessing the canvas. break; } @@ -839,7 +839,7 @@ var LibraryPThread = { // way to undo this in the spec) canvas.controlTransferredOffscreen = true; } else { - err('pthread_create: cannot transfer control of canvas "' + name + '" to pthread, because current browser does not support OffscreenCanvas!'); + err(`pthread_create: cannot transfer control of canvas "${name}" to pthread, because current browser does not support OffscreenCanvas!`); // If building with OFFSCREEN_FRAMEBUFFER=1 mode, we don't need to // be able to transfer control to offscreen, but WebGL can be // proxied from worker to main thread. @@ -854,7 +854,7 @@ var LibraryPThread = { offscreenCanvases[offscreenCanvasInfo.id] = offscreenCanvasInfo; } } catch(e) { - err('pthread_create: failed to transfer control of canvas "' + name + '" to OffscreenCanvas! Error: ' + e); + err(`pthread_create: failed to transfer control of canvas "${name}" to OffscreenCanvas! Error: ${e}`); return {{{ cDefs.EINVAL }}}; // Hitting this might indicate an implementation bug or some other internal error } } @@ -1049,7 +1049,7 @@ var LibraryPThread = { var stackSize = {{{ makeGetValue('pthread_ptr', C_STRUCTS.pthread.stack_size, 'i32') }}}; var stackLow = stackHigh - stackSize; #if PTHREADS_DEBUG - dbg('establishStackSpace: ' + ptrToString(stackHigh) + ' -> ' + ptrToString(stackLow)); + dbg(`establishStackSpace: ${ptrToString(stackHigh)} -> ${ptrToString(stackLow)}`); #endif #if ASSERTIONS assert(stackHigh != 0); @@ -1077,7 +1077,7 @@ var LibraryPThread = { $invokeEntryPoint__deps: ['_emscripten_thread_exit'], $invokeEntryPoint: function(ptr, arg) { #if PTHREADS_DEBUG - dbg('invokeEntryPoint: ' + ptrToString(ptr)); + dbg(`invokeEntryPoint: ${ptrToString(ptr)}`); #endif #if EXIT_RUNTIME && !MINIMAL_RUNTIME // An old thread on this worker may have been canceled without returning the @@ -1138,7 +1138,7 @@ var LibraryPThread = { $markAsFinshed: function(pthread_ptr) { #if PTHREADS_DEBUG - dbg('markAsFinshed: ' + ptrToString(pthread_ptr)); + dbg(`markAsFinshed: ${ptrToString(pthread_ptr)}`); #endif PThread.finishedThreads.add(pthread_ptr); if (pthread_ptr in PThread.outstandingPromises) { @@ -1258,7 +1258,7 @@ var LibraryPThread = { var worker = PThread.pthreads[targetThreadId]; if (!worker) { #if ASSERTIONS - err('Cannot send message to thread with ID ' + targetThreadId + ', unknown thread ID!'); + err(`Cannot send message to thread with ID ${targetThreadId}, unknown thread ID!`); #endif return; } diff --git a/src/library_sdl.js b/src/library_sdl.js index ff95475beed2d..9d6087b7c4f01 100644 --- a/src/library_sdl.js +++ b/src/library_sdl.js @@ -909,7 +909,7 @@ var LibrarySDL = { switch (event.type) { case 'keydown': case 'keyup': { var down = event.type === 'keydown'; - //out('Received key event: ' + event.keyCode); + //dbg('Received key event: ' + event.keyCode); var key = SDL.lookupKeyCodeForEvent(event); var scan; if (key >= 1024) { @@ -1098,7 +1098,7 @@ var LibrarySDL = { info.audio.volume = info.volume; // For