From 11869008f69e5d14318de2bd24a38cc1a45c328c Mon Sep 17 00:00:00 2001 From: Sam Clegg <sbc@chromium.org> Date: Wed, 19 Feb 2025 15:12:01 -0800 Subject: [PATCH] Fix for vite bundling with pthreads enabled Replaces #23607 Fixes: #22394 --- src/lib/libpthread.js | 51 ++++++++++++++++++++++++------------------- test/test_browser.py | 3 ++- test/test_other.py | 4 ++-- 3 files changed, 32 insertions(+), 26 deletions(-) diff --git a/src/lib/libpthread.js b/src/lib/libpthread.js index a3c4cb4377d23..c009e99a3545e 100644 --- a/src/lib/libpthread.js +++ b/src/lib/libpthread.js @@ -29,6 +29,30 @@ globalThis.MAX_PTR = Number((2n ** 64n) - 1n); #else globalThis.MAX_PTR = (2 ** 32) - 1 #endif +// Use a macro to avoid duplicating pthread worker options. +// We cannot use normal JS variable since the vite bundler requires that worker +// options be inline. +// See https://github.com/emscripten-core/emscripten/issues/22394 +globalThis.pthreadWorkerOptions = `{ +#if EXPORT_ES6 + 'type': 'module', +#endif +#if ENVIRONMENT_MAY_BE_NODE + // This is the way that we signal to the node worker that it is hosting + // a pthread. + 'workerData': 'em-pthread', +#endif +#if ENVIRONMENT_MAY_BE_WEB || ENVIRONMENT_MAY_BE_WORKER + // This is the way that we signal to the Web Worker that it is hosting + // a pthread. +#if ASSERTIONS + 'name': 'em-pthread-' + PThread.nextWorkerID, +#else + 'name': 'em-pthread', +#endif +#endif +}`; +null }}} var LibraryPThread = { @@ -394,25 +418,6 @@ var LibraryPThread = { // Creates a new web Worker and places it in the unused worker pool to wait for its use. allocateUnusedWorker() { var worker; - var workerOptions = { -#if EXPORT_ES6 - 'type': 'module', -#endif -#if ENVIRONMENT_MAY_BE_NODE - // This is the way that we signal to the node worker that it is hosting - // a pthread. - 'workerData': 'em-pthread', -#endif -#if ENVIRONMENT_MAY_BE_WEB || ENVIRONMENT_MAY_BE_WORKER - // This is the way that we signal to the Web Worker that it is hosting - // a pthread. -#if ASSERTIONS - 'name': 'em-pthread-' + PThread.nextWorkerID, -#else - 'name': 'em-pthread', -#endif -#endif - }; #if EXPORT_ES6 && USE_ES6_IMPORT_META // If we're using module output, use bundler-friendly pattern. #if PTHREADS_DEBUG @@ -427,14 +432,14 @@ var LibraryPThread = { createScriptURL: (ignored) => new URL("{{{ TARGET_JS_NAME }}}", import.meta.url) } ); - worker = new Worker(p.createScriptURL('ignored'), workerOptions); + worker = new Worker(p.createScriptURL('ignored'), {{{ pthreadWorkerOptions }}}); } else #endif // We need to generate the URL with import.meta.url as the base URL of the JS file // instead of just using new URL(import.meta.url) because bundler's only recognize // the first case in their bundling step. The latter ends up producing an invalid // URL to import from the server (e.g., for webpack the file:// path). - worker = new Worker(new URL('{{{ TARGET_JS_NAME }}}', import.meta.url), workerOptions); + worker = new Worker(new URL('{{{ TARGET_JS_NAME }}}', import.meta.url), {{{ pthreadWorkerOptions }}}); #else var pthreadMainJs = _scriptName; #if expectToReceiveOnModule('mainScriptUrlOrBlob') @@ -454,10 +459,10 @@ var LibraryPThread = { // Use Trusted Types compatible wrappers. if (typeof trustedTypes != 'undefined' && trustedTypes.createPolicy) { var p = trustedTypes.createPolicy('emscripten#workerPolicy2', { createScriptURL: (ignored) => pthreadMainJs }); - worker = new Worker(p.createScriptURL('ignored'), workerOptions); + worker = new Worker(p.createScriptURL('ignored'), {{{ pthreadWorkerOptions }}}); } else #endif - worker = new Worker(pthreadMainJs, workerOptions); + worker = new Worker(pthreadMainJs, {{{ pthreadWorkerOptions }}}); #endif // EXPORT_ES6 && USE_ES6_IMPORT_META PThread.unusedWorkers.push(worker); }, diff --git a/test/test_browser.py b/test/test_browser.py index 20fa6eadc142c..d0d47ff0010a9 100644 --- a/test/test_browser.py +++ b/test/test_browser.py @@ -5534,10 +5534,11 @@ def test_webpack(self, es6): shutil.copy('webpack/src/hello.wasm', 'webpack/dist/') self.run_browser('webpack/dist/index.html', '/report_result?exit:0') + @also_with_threads def test_vite(self): shutil.copytree(test_file('vite'), 'vite') with common.chdir('vite'): - self.compile_btest('hello_world.c', ['-sEXPORT_ES6', '-sEXIT_RUNTIME', '-sMODULARIZE', '-o', 'hello.mjs']) + self.compile_btest('hello_world.c', ['-sEXPORT_ES6', '-sEXIT_RUNTIME', '-sMODULARIZE', '-sENVIRONMENT=web,worker', '-o', 'hello.mjs']) self.run_process(shared.get_npm_cmd('vite') + ['build']) self.run_browser('vite/dist/index.html', '/report_result?exit:0') diff --git a/test/test_other.py b/test/test_other.py index 5995a90881715..8f9d7049b8d6a 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -380,7 +380,7 @@ def test_emcc_output_worker_mjs(self, args): test_file('hello_world.c')] + args) src = read_file('subdir/hello_world.mjs') self.assertContained("new URL('hello_world.wasm', import.meta.url)", src) - self.assertContained("new Worker(new URL('hello_world.mjs', import.meta.url), workerOptions)", src) + self.assertContained("new Worker(new URL('hello_world.mjs', import.meta.url), {", src) self.assertContained('export default Module;', src) self.assertContained('hello, world!', self.run_js('subdir/hello_world.mjs')) @@ -391,7 +391,7 @@ def test_emcc_output_worker_mjs_single_file(self): test_file('hello_world.c'), '-sSINGLE_FILE']) src = read_file('hello_world.mjs') self.assertNotContained("new URL('data:", src) - self.assertContained("new Worker(new URL('hello_world.mjs', import.meta.url), workerOptions)", src) + self.assertContained("new Worker(new URL('hello_world.mjs', import.meta.url), {", src) self.assertContained('hello, world!', self.run_js('hello_world.mjs')) def test_emcc_output_mjs_closure(self):